Exemplo n.º 1
0
class  TestTimelineUndo(TestCase):
    def setUp(self):
        self.stream = new_stream()
        self.factory = new_source_factory()
        self.effect_factory = TestEffectFactory(self.stream)
        self.track1 = Track(self.stream)
        self.track2 = Track(self.stream)
        self.timeline = Timeline()
        self.timeline.addTrack(self.track1)
        self.timeline.addTrack(self.track2)
        self.track_object1 = SourceTrackObject(self.factory, self.stream)
        self.track_object2 = SourceTrackObject(self.factory, self.stream)
        self.track_effect1 = TrackEffect(self.effect_factory, self.stream)
        self.track_effect2 = TrackEffect(self.effect_factory, self.stream)
        self.track1.addTrackObject(self.track_object1)
        self.track2.addTrackObject(self.track_object2)
        self.timeline_object1 = TimelineObject(self.factory)
        self.timeline_object1.addTrackObject(self.track_object1)
        self.timeline_object1.addTrackObject(self.track_object2)
        self.action_log = UndoableActionLog()
        self.observer = TestTimelineLogObserver(self.action_log)
        self.observer.startObserving(self.timeline)

    def testAddTimelineObject(self):
        stacks = []

        def commitCb(action_log, stack, nested):
            stacks.append(stack)
        self.action_log.connect("commit", commitCb)

        self.action_log.begin("add clip")
        self.timeline.addTimelineObject(self.timeline_object1)
        self.action_log.commit()

        self.failUnlessEqual(len(stacks), 1)
        stack = stacks[0]
        self.failUnlessEqual(len(stack.done_actions), 1)
        action = stack.done_actions[0]
        self.failUnless(isinstance(action, TimelineObjectAdded))

        self.failUnless(self.timeline_object1 \
                in self.timeline.timeline_objects)
        self.action_log.undo()
        self.failIf(self.timeline_object1 \
                in self.timeline.timeline_objects)

        self.action_log.redo()
        self.failUnless(self.timeline_object1 \
                in self.timeline.timeline_objects)

    def testRemoveTimelineObject(self):
        stacks = []

        def commitCb(action_log, stack, nested):
            stacks.append(stack)
        self.action_log.connect("commit", commitCb)

        self.timeline.addTimelineObject(self.timeline_object1)
        self.action_log.begin("remove clip")
        self.timeline.removeTimelineObject(self.timeline_object1, deep=True)
        self.action_log.commit()

        self.failUnlessEqual(len(stacks), 1)
        stack = stacks[0]
        self.failUnlessEqual(len(stack.done_actions), 1)
        action = stack.done_actions[0]
        self.failUnless(isinstance(action, TimelineObjectRemoved))

        self.failIf(self.timeline_object1 \
                in self.timeline.timeline_objects)
        self.action_log.undo()
        self.failUnless(self.timeline_object1 \
                in self.timeline.timeline_objects)

        self.action_log.redo()
        self.failIf(self.timeline_object1 \
                in self.timeline.timeline_objects)

    def testAddEffectToTimelineObject(self):
        stacks = []
        pipeline = Pipeline()

        def commitCb(action_log, stack, nested):
            stacks.append(stack)
        self.action_log.connect("commit", commitCb)
        self.observer.pipeline = pipeline

        #FIXME Should I commit it and check there are 2 elements
        #in the stacks
        self.timeline.addTimelineObject(self.timeline_object1)
        self.track1.addTrackObject(self.track_effect1)

        self.action_log.begin("add effect")
        self.timeline_object1.addTrackObject(self.track_effect1)
        self.action_log.commit()

        self.failUnlessEqual(len(stacks), 1)
        stack = stacks[0]
        self.failUnlessEqual(len(stack.done_actions), 1)
        action = stack.done_actions[0]
        self.failUnless(isinstance(action, TrackEffectAdded))

        self.failUnless(self.track_effect1 \
                in self.timeline_object1.track_objects)
        self.failUnless(self.track_effect1 \
                in self.track1.track_objects)
        self.failUnless(len([effect for effect in \
                                self.timeline_object1.track_objects
                                if isinstance(effect, TrackEffect)]) == 1)
        self.failUnless(len([effect for effect in self.track1.track_objects
                             if isinstance(effect, TrackEffect)]) == 1)

        self.action_log.undo()
        self.failIf(self.track_effect1 \
                in self.timeline_object1.track_objects)
        self.failIf(self.track_effect1 \
                in self.track1.track_objects)

        self.action_log.redo()
        self.failUnless(len([effect for effect in
                                self.timeline_object1.track_objects
                                if isinstance(effect, TrackEffect)]) == 1)
        self.failUnless(len([effect for effect in self.track1.track_objects
                             if isinstance(effect, TrackEffect)]) == 1)

        self.timeline.removeTimelineObject(self.timeline_object1, deep=True)

    def testTimelineObjectPropertyChange(self):
        stacks = []

        def commitCb(action_log, stack, nested):
            stacks.append(stack)
        self.action_log.connect("commit", commitCb)

        self.timeline_object1.start = 5 * gst.SECOND
        self.timeline_object1.duration = 20 * gst.SECOND
        self.timeline.addTimelineObject(self.timeline_object1)
        self.action_log.begin("modify clip")
        self.timeline_object1.start = 10 * gst.SECOND
        self.action_log.commit()

        self.failUnlessEqual(len(stacks), 1)
        stack = stacks[0]
        self.failUnlessEqual(len(stack.done_actions), 1)
        action = stack.done_actions[0]
        self.failUnless(isinstance(action, TimelineObjectPropertyChanged))

        self.failUnlessEqual(self.timeline_object1.start, 10 * gst.SECOND)
        self.action_log.undo()
        self.failUnlessEqual(self.timeline_object1.start, 5 * gst.SECOND)
        self.action_log.redo()
        self.failUnlessEqual(self.timeline_object1.start, 10 * gst.SECOND)

        self.timeline_object1.priority = 10
        self.action_log.begin("priority change")
        self.timeline_object1.priority = 20
        self.action_log.commit()

        self.failUnlessEqual(self.timeline_object1.priority, 20)
        self.action_log.undo()
        self.failUnlessEqual(self.timeline_object1.priority, 10)
        self.action_log.redo()
        self.failUnlessEqual(self.timeline_object1.priority, 20)

    def testUngroup(self):
        self.timeline_object1.start = 5 * gst.SECOND
        self.timeline_object1.duration = 20 * gst.SECOND

        self.timeline.addTimelineObject(self.timeline_object1)
        self.timeline.setSelectionToObj(self.track_object1, SELECT_ADD)

        self.failUnlessEqual(len(self.timeline.timeline_objects), 1)
        self.failUnlessEqual(self.timeline.timeline_objects[0].start,
                5 * gst.SECOND)
        self.failUnlessEqual(self.timeline.timeline_objects[0].duration,
                20 * gst.SECOND)

        self.action_log.begin("ungroup")
        self.timeline.ungroupSelection()
        self.action_log.commit()

        self.failUnlessEqual(len(self.timeline.timeline_objects), 2)
        self.failUnlessEqual(self.timeline.timeline_objects[0].start,
                5 * gst.SECOND)
        self.failUnlessEqual(self.timeline.timeline_objects[0].duration,
                20 * gst.SECOND)
        self.failUnlessEqual(self.timeline.timeline_objects[1].start,
                5 * gst.SECOND)
        self.failUnlessEqual(self.timeline.timeline_objects[1].duration,
                20 * gst.SECOND)

        self.action_log.undo()

        self.failUnlessEqual(len(self.timeline.timeline_objects), 1)
        self.failUnlessEqual(self.timeline.timeline_objects[0].start,
                5 * gst.SECOND)
        self.failUnlessEqual(self.timeline.timeline_objects[0].duration,
                20 * gst.SECOND)
Exemplo n.º 2
0
class  TestTimelineUndo(TestCase):
    def setUp(self):
        self.stream = new_stream()
        self.factory = new_source_factory()
        self.effect_factory = TestEffectFactory(self.stream)
        self.track1 = Track(self.stream)
        self.track2 = Track(self.stream)
        self.timeline = Timeline()
        self.timeline.addTrack(self.track1)
        self.timeline.addTrack(self.track2)
        self.track_object1 = SourceTrackObject(self.factory, self.stream)
        self.track_object2 = SourceTrackObject(self.factory, self.stream)
        self.track_effect1 = TrackEffect(self.effect_factory, self.stream)
        self.track_effect2 = TrackEffect(self.effect_factory, self.stream)
        self.track1.addTrackObject(self.track_object1)
        self.track2.addTrackObject(self.track_object2)
        self.timeline_object1 = TimelineObject(self.factory)
        self.timeline_object1.addTrackObject(self.track_object1)
        self.timeline_object1.addTrackObject(self.track_object2)
        self.action_log = UndoableActionLog()
        self.observer = TestTimelineLogObserver(self.action_log)
        self.observer.startObserving(self.timeline)

    def testAddTimelineObject(self):
        stacks = []
        def commitCb(action_log, stack, nested):
            stacks.append(stack)
        self.action_log.connect("commit", commitCb)

        self.action_log.begin("add clip")
        self.timeline.addTimelineObject(self.timeline_object1)
        self.action_log.commit()

        self.failUnlessEqual(len(stacks), 1)
        stack = stacks[0]
        self.failUnlessEqual(len(stack.done_actions), 1)
        action = stack.done_actions[0]
        self.failUnless(isinstance(action, TimelineObjectAdded))

        self.failUnless(self.timeline_object1 \
                in self.timeline.timeline_objects)
        self.action_log.undo()
        self.failIf(self.timeline_object1 \
                in self.timeline.timeline_objects)

        self.action_log.redo()
        self.failUnless(self.timeline_object1 \
                in self.timeline.timeline_objects)

    def testRemoveTimelineObject(self):
        stacks = []
        def commitCb(action_log, stack, nested):
            stacks.append(stack)
        self.action_log.connect("commit", commitCb)

        self.timeline.addTimelineObject(self.timeline_object1)
        self.action_log.begin("remove clip")
        self.timeline.removeTimelineObject(self.timeline_object1, deep=True)
        self.action_log.commit()

        self.failUnlessEqual(len(stacks), 1)
        stack = stacks[0]
        self.failUnlessEqual(len(stack.done_actions), 1)
        action = stack.done_actions[0]
        self.failUnless(isinstance(action, TimelineObjectRemoved))

        self.failIf(self.timeline_object1 \
                in self.timeline.timeline_objects)
        self.action_log.undo()
        self.failUnless(self.timeline_object1 \
                in self.timeline.timeline_objects)

        self.action_log.redo()
        self.failIf(self.timeline_object1 \
                in self.timeline.timeline_objects)

    def testAddEffectToTimelineObject(self):
        stacks = []
        pipeline = Pipeline()
        def commitCb(action_log, stack, nested):
            stacks.append(stack)
        self.action_log.connect("commit", commitCb)
        self.observer.pipeline = pipeline

        #FIXME Should I commit it and check there are 2 elements
        #in the stacks
        self.timeline.addTimelineObject(self.timeline_object1)
        self.track1.addTrackObject(self.track_effect1)

        self.action_log.begin("add effect")
        self.timeline_object1.addTrackObject(self.track_effect1)
        self.action_log.commit()

        self.failUnlessEqual(len(stacks), 1)
        stack = stacks[0]
        self.failUnlessEqual(len(stack.done_actions), 1)
        action = stack.done_actions[0]
        self.failUnless(isinstance(action, TrackEffectAdded))

        self.failUnless(self.track_effect1 \
                in self.timeline_object1.track_objects)
        self.failUnless(self.track_effect1 \
                in self.track1.track_objects)
        self.failUnless(len([effect for effect in \
                                self.timeline_object1.track_objects
                                if isinstance(effect, TrackEffect)]) == 1)
        self.failUnless(len([effect for effect in self.track1.track_objects
                             if isinstance(effect, TrackEffect)]) == 1)

        self.action_log.undo()
        self.failIf(self.track_effect1 \
                in self.timeline_object1.track_objects)
        self.failIf(self.track_effect1 \
                in self.track1.track_objects)

        self.action_log.redo()
        self.failUnless(len([effect for effect in
                                self.timeline_object1.track_objects
                                if isinstance(effect, TrackEffect)]) == 1)
        self.failUnless(len([effect for effect in self.track1.track_objects
                             if isinstance(effect, TrackEffect)]) == 1)

        self.timeline.removeTimelineObject(self.timeline_object1, deep=True)

    def testTimelineObjectPropertyChange(self):
        stacks = []
        def commitCb(action_log, stack, nested):
            stacks.append(stack)
        self.action_log.connect("commit", commitCb)

        self.timeline_object1.start = 5 * gst.SECOND
        self.timeline_object1.duration = 20 * gst.SECOND
        self.timeline.addTimelineObject(self.timeline_object1)
        self.action_log.begin("modify clip")
        self.timeline_object1.start = 10 * gst.SECOND
        self.action_log.commit()

        self.failUnlessEqual(len(stacks), 1)
        stack = stacks[0]
        self.failUnlessEqual(len(stack.done_actions), 1)
        action = stack.done_actions[0]
        self.failUnless(isinstance(action, TimelineObjectPropertyChanged))

        self.failUnlessEqual(self.timeline_object1.start, 10 * gst.SECOND)
        self.action_log.undo()
        self.failUnlessEqual(self.timeline_object1.start, 5 * gst.SECOND)
        self.action_log.redo()
        self.failUnlessEqual(self.timeline_object1.start, 10 * gst.SECOND)

        self.timeline_object1.priority = 10
        self.action_log.begin("priority change")
        self.timeline_object1.priority = 20
        self.action_log.commit()

        self.failUnlessEqual(self.timeline_object1.priority, 20)
        self.action_log.undo()
        self.failUnlessEqual(self.timeline_object1.priority, 10)
        self.action_log.redo()
        self.failUnlessEqual(self.timeline_object1.priority, 20)

    def testUngroup(self):
        self.timeline_object1.start = 5 * gst.SECOND
        self.timeline_object1.duration = 20 * gst.SECOND

        self.timeline.addTimelineObject(self.timeline_object1)
        self.timeline.setSelectionToObj(self.track_object1, SELECT_ADD)

        self.failUnlessEqual(len(self.timeline.timeline_objects), 1)
        self.failUnlessEqual(self.timeline.timeline_objects[0].start,
                5 * gst.SECOND)
        self.failUnlessEqual(self.timeline.timeline_objects[0].duration,
                20 * gst.SECOND)

        self.action_log.begin("ungroup")
        self.timeline.ungroupSelection()
        self.action_log.commit()

        self.failUnlessEqual(len(self.timeline.timeline_objects), 2)
        self.failUnlessEqual(self.timeline.timeline_objects[0].start,
                5 * gst.SECOND)
        self.failUnlessEqual(self.timeline.timeline_objects[0].duration,
                20 * gst.SECOND)
        self.failUnlessEqual(self.timeline.timeline_objects[1].start,
                5 * gst.SECOND)
        self.failUnlessEqual(self.timeline.timeline_objects[1].duration,
                20 * gst.SECOND)

        self.action_log.undo()

        self.failUnlessEqual(len(self.timeline.timeline_objects), 1)
        self.failUnlessEqual(self.timeline.timeline_objects[0].start,
                5 * gst.SECOND)
        self.failUnlessEqual(self.timeline.timeline_objects[0].duration,
                20 * gst.SECOND)
Exemplo n.º 3
0
class TestUndoableActionLog(TestCase):
    def setUp(self):
        self.log = UndoableActionLog()
        self._connectToUndoableActionLog(self.log)
        self.signals = []

    def tearDown(self):
        self._disconnectFromUndoableActionLog(self.log)

    def _undoActionLogSignalCb(self, log, *args):
        args = list(args)
        signalName = args.pop(-1)
        self.signals.append((signalName, args))

    def _connectToUndoableActionLog(self, log):
        for signalName in ("begin", "push", "rollback", "commit", "undo",
                           "redo"):
            log.connect(signalName, self._undoActionLogSignalCb, signalName)

    def _disconnectFromUndoableActionLog(self, log):
        self.log.disconnect_by_func(self._undoActionLogSignalCb)

    def testRollbackWrongState(self):
        self.failUnlessRaises(UndoWrongStateError, self.log.rollback)

    def testCommitWrongState(self):
        self.failUnlessRaises(UndoWrongStateError, self.log.commit)

    def testPushWrongState(self):
        # no error in this case
        self.log.push(None)

    def testUndoWrongState(self):
        self.failUnlessRaises(UndoWrongStateError, self.log.undo)

    def testRedoWrongState(self):
        self.failUnlessRaises(UndoWrongStateError, self.log.redo)

    def testCheckpoint(self):
        self.log.begin("meh")
        self.log.push(DummyUndoableAction())
        self.failUnlessRaises(UndoWrongStateError, self.log.checkpoint)
        self.log.rollback()
        self.log.checkpoint()
        self.failIfEqual(self.log._checkpoint, None)

    def testDirty(self):
        self.failIf(self.log.dirty())
        self.log.begin("meh")
        self.log.push(DummyUndoableAction())
        self.log.commit()
        self.failUnless(self.log.dirty())
        self.log.checkpoint()
        self.failIf(self.log.dirty())
        self.log.undo()
        self.failUnless(self.log.dirty())
        self.log.redo()
        self.failIf(self.log.dirty())

    def testCommit(self):
        """
        Commit a stack.
        """
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)
        self.log.begin("meh")
        self.failUnlessEqual(len(self.signals), 1)
        name, (stack, nested) = self.signals[0]
        self.failUnlessEqual(name, "begin")
        self.failIf(nested)

        self.failUnlessEqual(self.log.undo_stacks, [])
        self.log.commit()
        self.failUnlessEqual(len(self.signals), 2)
        name, (stack, nested) = self.signals[1]
        self.failUnlessEqual(name, "commit")
        self.failIf(nested)
        self.failUnlessEqual(len(self.log.undo_stacks), 1)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)

    def testNestedCommit(self):
        """
        Do two nested commits.
        """
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)
        self.log.begin("meh")
        self.failUnlessEqual(len(self.signals), 1)
        name, (stack, nested) = self.signals[0]
        self.failUnlessEqual(name, "begin")
        self.failIf(nested)

        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)
        self.log.begin("nested")
        self.failUnlessEqual(len(self.signals), 2)
        name, (stack, nested) = self.signals[1]
        self.failUnlessEqual(name, "begin")
        self.failUnless(nested)

        self.failUnlessEqual(self.log.undo_stacks, [])
        self.log.commit()
        self.failUnlessEqual(len(self.signals), 3)
        name, (stack, nested) = self.signals[2]
        self.failUnlessEqual(name, "commit")
        self.failUnless(nested)
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)

        self.failUnlessEqual(self.log.undo_stacks, [])
        self.log.commit()
        self.failUnlessEqual(len(self.signals), 4)
        name, (stack, nested) = self.signals[3]
        self.failUnlessEqual(name, "commit")
        self.failIf(nested)
        self.failUnlessEqual(len(self.log.undo_stacks), 1)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)

    def testRollback(self):
        """
        Test a rollback.
        """
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)
        self.log.begin("meh")
        self.failUnlessEqual(len(self.signals), 1)
        name, (stack, nested) = self.signals[0]
        self.failUnlessEqual(name, "begin")
        self.failIf(nested)

        self.log.rollback()
        self.failUnlessEqual(len(self.signals), 2)
        name, (stack, nested) = self.signals[1]
        self.failUnlessEqual(name, "rollback")
        self.failIf(nested)
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)

    def testNestedRollback(self):
        """
        Test two nested rollbacks.
        """
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)
        self.log.begin("meh")
        self.failUnlessEqual(len(self.signals), 1)
        name, (stack, nested) = self.signals[0]
        self.failUnlessEqual(name, "begin")
        self.failIf(nested)

        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)
        self.log.begin("nested")
        self.failUnlessEqual(len(self.signals), 2)
        name, (stack, nested) = self.signals[1]
        self.failUnlessEqual(name, "begin")
        self.failUnless(nested)

        self.log.rollback()
        self.failUnlessEqual(len(self.signals), 3)
        name, (stack, nested) = self.signals[2]
        self.failUnlessEqual(name, "rollback")
        self.failUnless(nested)
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)

        self.log.rollback()
        self.failUnlessEqual(len(self.signals), 4)
        name, (stack, nested) = self.signals[3]
        self.failUnlessEqual(name, "rollback")
        self.failIf(nested)
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)

    def testUndoRedo(self):
        """
        Try an undo() redo() sequence.
        """
        # begin
        self.log.begin("meh")
        self.failUnlessEqual(len(self.signals), 1)
        name, (stack, nested) = self.signals[0]
        self.failUnlessEqual(name, "begin")
        self.failIf(nested)

        # push two actions
        action1 = DummyUndoableAction()
        self.log.push(action1)
        self.failUnlessEqual(len(self.signals), 2)
        name, (stack, signalAction) = self.signals[1]
        self.failUnlessEqual(name, "push")
        self.failUnless(action1 is signalAction)

        action2 = DummyUndoableAction()
        self.log.push(action2)
        self.failUnlessEqual(len(self.signals), 3)
        name, (stack, signalAction) = self.signals[2]
        self.failUnlessEqual(name, "push")
        self.failUnless(action2 is signalAction)

        # commit
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)
        self.log.commit()
        self.failUnlessEqual(len(self.signals), 4)
        name, (stack, nested) = self.signals[3]
        self.failUnlessEqual(name, "commit")
        self.failIf(nested)
        self.failUnlessEqual(len(self.log.undo_stacks), 1)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)

        self.failUnless(action1.done_)
        self.failUnless(action2.done_)

        # undo what we just committed
        self.log.undo()
        self.failUnlessEqual(len(self.signals), 5)
        name, stack = self.signals[4]
        self.failUnlessEqual(name, "undo")
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 1)

        self.failIf(action1.done_)
        self.failIf(action2.done_)

        # redo
        self.log.redo()
        self.failUnlessEqual(len(self.signals), 6)
        name, stack = self.signals[5]
        self.failUnlessEqual(name, "redo")
        self.failUnlessEqual(len(self.log.undo_stacks), 1)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)

        self.failUnless(action1.done_)
        self.failUnless(action2.done_)

    def testOrder(self):
        """
        Test that actions are undone and redone in the correct order.
        """
        call_sequence = []

        class Action(UndoableAction):
            def __init__(self, n):
                self.n = n

            def do(self):
                call_sequence.append("do%s" % self.n)
                self._done()

            def undo(self):
                call_sequence.append("undo%s" % self.n)
                self._undone()

        action1 = Action(1)
        action2 = Action(2)
        action3 = Action(3)

        self.log.begin("meh")
        self.log.push(action1)
        self.log.begin("nested")
        self.log.push(action2)
        self.log.commit()
        self.log.push(action3)
        self.log.commit()

        self.log.undo()
        self.failUnlessEqual(call_sequence, ["undo3", "undo2", "undo1"])

        call_sequence[:] = []
        self.log.redo()
        self.failUnlessEqual(call_sequence, ["do1", "do2", "do3"])

        call_sequence[:] = []
        self.log.undo()
        self.failUnlessEqual(call_sequence, ["undo3", "undo2", "undo1"])
Exemplo n.º 4
0
class TestUndoableActionLog(TestCase):
    def setUp(self):
        self.log = UndoableActionLog()
        self._connectToUndoableActionLog(self.log)
        self.signals = []

    def tearDown(self):
        self._disconnectFromUndoableActionLog(self.log)

    def _undoActionLogSignalCb(self, log, *args):
        args = list(args)
        signalName = args.pop(-1)
        self.signals.append((signalName, args))

    def _connectToUndoableActionLog(self, log):
        for signalName in ("begin", "push", "rollback", "commit",
                    "undo", "redo"):
            log.connect(signalName, self._undoActionLogSignalCb, signalName)

    def _disconnectFromUndoableActionLog(self, log):
        self.log.disconnect_by_func(self._undoActionLogSignalCb)

    def testRollbackWrongState(self):
        self.failUnlessRaises(UndoWrongStateError, self.log.rollback)

    def testCommitWrongState(self):
        self.failUnlessRaises(UndoWrongStateError, self.log.commit)

    def testPushWrongState(self):
        # no error in this case
        self.log.push(None)

    def testUndoWrongState(self):
        self.failUnlessRaises(UndoWrongStateError, self.log.undo)

    def testRedoWrongState(self):
        self.failUnlessRaises(UndoWrongStateError, self.log.redo)

    def testCheckpoint(self):
        self.log.begin("meh")
        self.log.push(DummyUndoableAction())
        self.failUnlessRaises(UndoWrongStateError, self.log.checkpoint)
        self.log.rollback()
        self.log.checkpoint()
        self.failIfEqual(self.log._checkpoint, None)

    def testDirty(self):
        self.failIf(self.log.dirty())
        self.log.begin("meh")
        self.log.push(DummyUndoableAction())
        self.log.commit()
        self.failUnless(self.log.dirty())
        self.log.checkpoint()
        self.failIf(self.log.dirty())
        self.log.undo()
        self.failUnless(self.log.dirty())
        self.log.redo()
        self.failIf(self.log.dirty())

    def testCommit(self):
        """
        Commit a stack.
        """
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)
        self.log.begin("meh")
        self.failUnlessEqual(len(self.signals), 1)
        name, (stack, nested) = self.signals[0]
        self.failUnlessEqual(name, "begin")
        self.failIf(nested)

        self.failUnlessEqual(self.log.undo_stacks, [])
        self.log.commit()
        self.failUnlessEqual(len(self.signals), 2)
        name, (stack, nested) = self.signals[1]
        self.failUnlessEqual(name, "commit")
        self.failIf(nested)
        self.failUnlessEqual(len(self.log.undo_stacks), 1)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)

    def testNestedCommit(self):
        """
        Do two nested commits.
        """
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)
        self.log.begin("meh")
        self.failUnlessEqual(len(self.signals), 1)
        name, (stack, nested) = self.signals[0]
        self.failUnlessEqual(name, "begin")
        self.failIf(nested)

        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)
        self.log.begin("nested")
        self.failUnlessEqual(len(self.signals), 2)
        name, (stack, nested) = self.signals[1]
        self.failUnlessEqual(name, "begin")
        self.failUnless(nested)

        self.failUnlessEqual(self.log.undo_stacks, [])
        self.log.commit()
        self.failUnlessEqual(len(self.signals), 3)
        name, (stack, nested) = self.signals[2]
        self.failUnlessEqual(name, "commit")
        self.failUnless(nested)
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)

        self.failUnlessEqual(self.log.undo_stacks, [])
        self.log.commit()
        self.failUnlessEqual(len(self.signals), 4)
        name, (stack, nested) = self.signals[3]
        self.failUnlessEqual(name, "commit")
        self.failIf(nested)
        self.failUnlessEqual(len(self.log.undo_stacks), 1)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)

    def testRollback(self):
        """
        Test a rollback.
        """
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)
        self.log.begin("meh")
        self.failUnlessEqual(len(self.signals), 1)
        name, (stack, nested) = self.signals[0]
        self.failUnlessEqual(name, "begin")
        self.failIf(nested)

        self.log.rollback()
        self.failUnlessEqual(len(self.signals), 2)
        name, (stack, nested) = self.signals[1]
        self.failUnlessEqual(name, "rollback")
        self.failIf(nested)
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)

    def testNestedRollback(self):
        """
        Test two nested rollbacks.
        """
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)
        self.log.begin("meh")
        self.failUnlessEqual(len(self.signals), 1)
        name, (stack, nested) = self.signals[0]
        self.failUnlessEqual(name, "begin")
        self.failIf(nested)

        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)
        self.log.begin("nested")
        self.failUnlessEqual(len(self.signals), 2)
        name, (stack, nested) = self.signals[1]
        self.failUnlessEqual(name, "begin")
        self.failUnless(nested)

        self.log.rollback()
        self.failUnlessEqual(len(self.signals), 3)
        name, (stack, nested) = self.signals[2]
        self.failUnlessEqual(name, "rollback")
        self.failUnless(nested)
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)

        self.log.rollback()
        self.failUnlessEqual(len(self.signals), 4)
        name, (stack, nested) = self.signals[3]
        self.failUnlessEqual(name, "rollback")
        self.failIf(nested)
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)

    def testUndoRedo(self):
        """
        Try an undo() redo() sequence.
        """
        # begin
        self.log.begin("meh")
        self.failUnlessEqual(len(self.signals), 1)
        name, (stack, nested) = self.signals[0]
        self.failUnlessEqual(name, "begin")
        self.failIf(nested)

        # push two actions
        action1 = DummyUndoableAction()
        self.log.push(action1)
        self.failUnlessEqual(len(self.signals), 2)
        name, (stack, signalAction) = self.signals[1]
        self.failUnlessEqual(name, "push")
        self.failUnless(action1 is signalAction)

        action2 = DummyUndoableAction()
        self.log.push(action2)
        self.failUnlessEqual(len(self.signals), 3)
        name, (stack, signalAction) = self.signals[2]
        self.failUnlessEqual(name, "push")
        self.failUnless(action2 is signalAction)

        # commit
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)
        self.log.commit()
        self.failUnlessEqual(len(self.signals), 4)
        name, (stack, nested) = self.signals[3]
        self.failUnlessEqual(name, "commit")
        self.failIf(nested)
        self.failUnlessEqual(len(self.log.undo_stacks), 1)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)

        self.failUnless(action1.done_)
        self.failUnless(action2.done_)

        # undo what we just committed
        self.log.undo()
        self.failUnlessEqual(len(self.signals), 5)
        name, stack = self.signals[4]
        self.failUnlessEqual(name, "undo")
        self.failUnlessEqual(len(self.log.undo_stacks), 0)
        self.failUnlessEqual(len(self.log.redo_stacks), 1)

        self.failIf(action1.done_)
        self.failIf(action2.done_)

        # redo
        self.log.redo()
        self.failUnlessEqual(len(self.signals), 6)
        name, stack = self.signals[5]
        self.failUnlessEqual(name, "redo")
        self.failUnlessEqual(len(self.log.undo_stacks), 1)
        self.failUnlessEqual(len(self.log.redo_stacks), 0)

        self.failUnless(action1.done_)
        self.failUnless(action2.done_)

    def testOrder(self):
        """
        Test that actions are undone and redone in the correct order.
        """
        call_sequence = []

        class Action(UndoableAction):
            def __init__(self, n):
                self.n = n

            def do(self):
                call_sequence.append("do%s" % self.n)
                self._done()

            def undo(self):
                call_sequence.append("undo%s" % self.n)
                self._undone()

        action1 = Action(1)
        action2 = Action(2)
        action3 = Action(3)

        self.log.begin("meh")
        self.log.push(action1)
        self.log.begin("nested")
        self.log.push(action2)
        self.log.commit()
        self.log.push(action3)
        self.log.commit()

        self.log.undo()
        self.failUnlessEqual(call_sequence, ["undo3", "undo2", "undo1"])

        call_sequence[:] = []
        self.log.redo()
        self.failUnlessEqual(call_sequence, ["do1", "do2", "do3"])

        call_sequence[:] = []
        self.log.undo()
        self.failUnlessEqual(call_sequence, ["undo3", "undo2", "undo1"])