Пример #1
0
class InMemoryUndoStackTests(TestCase):
    """
    Tests for the in memory undo stack.
    """
    def setUp(self):
        """
        Configure an empty stack.
        """
        def termination():
            return lambda: True

        def run_immediately(f):
            f()

        self.cooperator = Cooperator(
            terminationPredicateFactory=termination,
            scheduler=run_immediately)
        self.undo = InMemoryUndoStack(self.cooperator.coiterate)

    def test_provides_IUndoStack(self):
        """
        InMemoryUndoStack provides IUndoStack.
        """
        verifyObject(IUndoStack, self.undo)

    def test_push(self):
        """
        push puts an operation and it's arguments onto the stack.
        """
        calls = []

        def op(*args, **kwargs):
            calls.append((args, kwargs))

        self.undo.push(op, 'foo', bar='baz')

        self.undo.rewind()

        self.assertEqual(calls, [(('foo',), {'bar': 'baz'})])

    def test_rewind_in_reverse_order(self):
        """
        rewind invokes operations in the reverse of the order they are
        pushed onto the stack.  (Because it is a stack.)
        """
        calls = []

        def op(*args, **kwargs):
            calls.append((args, kwargs))

        self.undo.push(op, 'foo')
        self.undo.push(op, 'bar')
        self.undo.push(op, 'baz')

        self.undo.rewind()

        self.assertEqual(calls, [(('baz',), {}),
                                 (('bar',), {}),
                                 (('foo',), {})])

    def test_rewind_handles_deferreds(self):
        """
        rewind will wait on any deferreds returned by the undo operation
        function.
        """
        def op(op_d):
            return op_d

        op_d = Deferred()
        self.undo.push(op, op_d)

        d = self.undo.rewind()
        self.assertNoResult(d)

        op_d.callback(None)

        self.successResultOf(d)

    def test_rewind_blocks_on_deferreds_returned_by_ops(self):
        """
        rewind will serialize operations waiting on any deferreds returned
        before running the next operation.
        """
        called = [0]

        def op(op_d):
            called[0] += 1
            return op_d

        op_d1 = Deferred()
        self.undo.push(op, op_d1)
        op_d2 = Deferred()
        self.undo.push(op, op_d2)

        d = self.undo.rewind()
        self.assertEqual(called[0], 1)
        self.assertNoResult(d)

        op_d2.callback(None)
        self.assertEqual(called[0], 2)
        self.assertNoResult(d)

        op_d1.callback(None)
        self.successResultOf(d)

    def test_rewind_stops_on_error(self):
        """
        rewind errbacks it's completion deferred when it encounters an
        error.
        """
        called = [0]

        def op(op_d):
            called[0] += 1
            return op_d

        self.undo.push(op, None)

        op_d1 = Deferred()
        self.undo.push(op, op_d1)

        d = self.undo.rewind()
        self.assertNoResult(d)

        class DummyOpFailure(Exception):
            pass

        op_d1.errback(DummyOpFailure())
        self.assertEqual(called[0], 1)
        self.failureResultOf(d, DummyOpFailure)

    def test_rewind_empty_stack(self):
        """
        rewind completes successfully if the stack is empty.
        """
        self.successResultOf(self.undo.rewind())
Пример #2
0
class InMemoryUndoStackTests(SynchronousTestCase):
    """
    Tests for the in memory undo stack.
    """
    def setUp(self):
        """
        Configure an empty stack.
        """
        def termination():
            return lambda: True

        def run_immediately(f):
            f()

        self.cooperator = Cooperator(terminationPredicateFactory=termination,
                                     scheduler=run_immediately)
        self.undo = InMemoryUndoStack(self.cooperator.coiterate)

    def test_provides_IUndoStack(self):
        """
        InMemoryUndoStack provides IUndoStack.
        """
        verifyObject(IUndoStack, self.undo)

    def test_push(self):
        """
        push puts an operation and it's arguments onto the stack.
        """
        calls = []

        def op(*args, **kwargs):
            calls.append((args, kwargs))

        self.undo.push(op, 'foo', bar='baz')

        self.undo.rewind()

        self.assertEqual(calls, [(('foo', ), {'bar': 'baz'})])

    def test_rewind_in_reverse_order(self):
        """
        rewind invokes operations in the reverse of the order they are
        pushed onto the stack.  (Because it is a stack.)
        """
        calls = []

        def op(*args, **kwargs):
            calls.append((args, kwargs))

        self.undo.push(op, 'foo')
        self.undo.push(op, 'bar')
        self.undo.push(op, 'baz')

        self.undo.rewind()

        self.assertEqual(calls, [(('baz', ), {}), (('bar', ), {}),
                                 (('foo', ), {})])

    def test_rewind_handles_deferreds(self):
        """
        rewind will wait on any deferreds returned by the undo operation
        function.
        """
        def op(op_d):
            return op_d

        op_d = Deferred()
        self.undo.push(op, op_d)

        d = self.undo.rewind()
        self.assertNoResult(d)

        op_d.callback(None)

        self.successResultOf(d)

    def test_rewind_blocks_on_deferreds_returned_by_ops(self):
        """
        rewind will serialize operations waiting on any deferreds returned
        before running the next operation.
        """
        called = [0]

        def op(op_d):
            called[0] += 1
            return op_d

        op_d1 = Deferred()
        self.undo.push(op, op_d1)
        op_d2 = Deferred()
        self.undo.push(op, op_d2)

        d = self.undo.rewind()
        self.assertEqual(called[0], 1)
        self.assertNoResult(d)

        op_d2.callback(None)
        self.assertEqual(called[0], 2)
        self.assertNoResult(d)

        op_d1.callback(None)
        self.successResultOf(d)

    def test_rewind_stops_on_error(self):
        """
        rewind errbacks it's completion deferred when it encounters an
        error.
        """
        called = [0]

        def op(op_d):
            called[0] += 1
            return op_d

        self.undo.push(op, None)

        op_d1 = Deferred()
        self.undo.push(op, op_d1)

        d = self.undo.rewind()
        self.assertNoResult(d)

        class DummyOpFailure(Exception):
            pass

        op_d1.errback(DummyOpFailure())
        self.assertEqual(called[0], 1)
        self.failureResultOf(d, DummyOpFailure)

    def test_rewind_empty_stack(self):
        """
        rewind completes successfully if the stack is empty.
        """
        self.successResultOf(self.undo.rewind())