[pitivi/gtktimeline: 6/28] tests: Move all our integration testsuite to GstValidate



commit 5bf7aa54d9108cc72702ebc1353ec6d2c8bc5035
Author: Thibault Saunier <tsaunier gnome org>
Date:   Fri Feb 13 16:47:58 2015 +0100

    tests: Move all our integration testsuite to GstValidate
    
    Summary: And start implementing a few simple tests for the timeline.
    
    Reviewers: Mathieu_Du
    
    Differential Revision: http://phabricator.freedesktop.org/D112

 pitivi/application.py                              |    4 +-
 pitivi/check.py                                    |    2 +-
 pitivi/project.py                                  |   22 +-
 pitivi/timeline/elements.py                        |    6 +-
 pitivi/timeline/timeline.py                        |   49 ++-
 pitivi/undo/timeline.py                            |   12 +-
 pitivi/undo/undo.py                                |    3 +-
 pitivi/utils/timeline.py                           |    6 +
 pitivi/utils/validate.py                           |  433 +++++++++++++++--
 pitivi/utils/widgets.py                            |    3 +
 pitivi/viewer.py                                   |    2 -
 tests/dogtail_scripts/common.py                    |  485 --------------------
 tests/dogtail_scripts/test_clipproperties.py       |  114 -----
 .../dogtail_scripts/test_dialogs_clipmediaprops.py |   76 ---
 tests/dogtail_scripts/test_dialogs_prefs.py        |   56 ---
 .../dogtail_scripts/test_dialogs_startupwizard.py  |   22 -
 tests/dogtail_scripts/test_effects.py              |   91 ----
 tests/dogtail_scripts/test_medialibrary.py         |   68 ---
 tests/dogtail_scripts/test_project.py              |  369 ---------------
 tests/dogtail_scripts/test_timeline.py             |  252 ----------
 tests/samples/30fps_numeroted_frames_blue.webm     |  Bin 0 -> 82107 bytes
 tests/samples/one_fps_numeroted_blue.mkv           |  Bin 0 -> 405852 bytes
 tests/test_utils.py                                |    2 +-
 tests/validate-tests/pitivi.py                     |   35 ++
 tests/validate-tests/pitivivalidate.py             |  125 +++++
 tests/validate-tests/runtests                      |   17 +
 tests/validate-tests/select_clip.scenario          |   18 +
 tests/validate-tests/simple_play.scenario          |   13 +
 tests/validate-tests/simple_ripple.scenario        |  126 +++++
 tests/validate-tests/simple_split_clips.scenario   |   17 +
 30 files changed, 805 insertions(+), 1623 deletions(-)
---
diff --git a/pitivi/application.py b/pitivi/application.py
index c2eb101..01a819e 100644
--- a/pitivi/application.py
+++ b/pitivi/application.py
@@ -42,6 +42,7 @@ from pitivi.dialogs.startupwizard import StartUpWizard
 from pitivi.utils.misc import quote_uri, path_from_uri
 from pitivi.utils.system import getSystem
 from pitivi.utils.loggable import Loggable
+from pitivi.utils.timeline import Zoomable
 import pitivi.utils.loggable as log
 
 
@@ -88,6 +89,7 @@ class Pitivi(Gtk.Application, Loggable):
         self._scenario_file = None
         self._first_action = True
 
+        Zoomable.app = self
         self.connect("startup", self._startupCb)
         self.connect("activate", self._activateCb)
         self.connect("open", self.openCb)
@@ -224,8 +226,6 @@ class Pitivi(Gtk.Application, Loggable):
         self.quit()
         return True
 
-        self._first_action = True
-
     def _setScenarioFile(self, uri):
         if 'PITIVI_SCENARIO_FILE' in os.environ:
             uri = quote_uri(os.environ['PITIVI_SCENARIO_FILE'])
diff --git a/pitivi/check.py b/pitivi/check.py
index a3d3627..c427427 100644
--- a/pitivi/check.py
+++ b/pitivi/check.py
@@ -263,7 +263,7 @@ def initialize_modules():
     from gi.repository import Gst
     Gst.init(None)
     from gi.repository import GES
-    GES.init()
+    res, sys.argv = GES.init_check(sys.argv)
 
     from pitivi.utils import validate
     validate.init()
diff --git a/pitivi/project.py b/pitivi/project.py
index 7ef75ad..9da0cbd 100644
--- a/pitivi/project.py
+++ b/pitivi/project.py
@@ -40,7 +40,7 @@ from pwd import getpwuid
 from pitivi.undo.undo import UndoableAction
 from pitivi.configure import get_ui_dir
 
-from pitivi.utils.validate import has_validate
+from pitivi.utils.validate import has_validate, create_monitor
 from pitivi.utils.misc import quote_uri, path_from_uri, isWritable, unicode_error_dialog
 from pitivi.utils.pipeline import PipelineError, Seeker
 from pitivi.utils.loggable import Loggable
@@ -189,6 +189,7 @@ class ProjectManager(GObject.Object, Loggable):
         self.current_project = None
         self.disable_save = False
         self._backup_lock = 0
+        self.exitcode = 0
 
     def _tryUsingBackupFile(self, uri):
         backup_path = self._makeBackupURI(path_from_uri(uri))
@@ -317,7 +318,7 @@ class ProjectManager(GObject.Object, Loggable):
         # Load the project:
         self.current_project = Project(self.app, uri=uri, scenario=scenario)
 
-        self.current_project.connect("missing-uri", self._missingURICb)
+        self.current_project.connect_after("missing-uri", self._missingURICb)
         self.current_project.connect("loaded", self._projectLoadedCb)
 
         if self.current_project.createTimeline():
@@ -564,7 +565,7 @@ class ProjectManager(GObject.Object, Loggable):
             self.debug(
                 "Tried disconnecting signals, but they were not connected")
         self._cleanBackup(self.current_project.uri)
-        self.current_project.release()
+        self.exitcode = self.current_project.release()
         self.current_project = None
 
         return True
@@ -800,12 +801,14 @@ class Project(Loggable, GES.Project):
 
         self.info("Setting up validate scenario")
         self.runner = GstValidate.Runner.new()
+        create_monitor(self.runner, self.app.gui)
         self.monitor = GstValidate.Monitor.factory_create(
             self.pipeline, self.runner, None)
         self._scenario = GstValidate.Scenario.factory_create(
             self.runner, self.pipeline, self.scenario)
         self.pipeline.setForcePositionListener(True)
         self._scenario.connect("done", self._scenarioDoneCb)
+        self._scenario.props.execute_on_idle = True
 
     # --------------- #
     # Our properties  #
@@ -1028,8 +1031,9 @@ class Project(Loggable, GES.Project):
             return
         self.nb_imported_files += 1
         assets = self.get_loading_assets()
-        self.nb_remaining_file_to_import = len([asset for asset in assets if
-                                                GObject.type_is_a(asset.get_extractable_type(), 
GES.UriClip)])
+        self.nb_remaining_file_to_import = len([tmpasset for tmpasset in assets if
+                                                GObject.type_is_a(tmpasset.get_extractable_type(),
+                                                                  GES.UriClip)])
         if self.nb_remaining_file_to_import == 0:
             self.nb_imported_files = 0
             # We do not take into account asset comming from project
@@ -1155,19 +1159,23 @@ class Project(Loggable, GES.Project):
         return self.list_assets(GES.UriClip)
 
     def release(self):
-        if self.runner:
-            self.runner.printf()
+        res = 0
 
         if self.pipeline:
             self.pipeline.release()
 
         if self.runner:
+            res = self.runner.printf()
+
+        if self.runner:
             self.runner = None
             self.monitor = None
 
         self.pipeline = None
         self.timeline = None
 
+        return res
+
     def setModificationState(self, state):
         self._dirty = state
         if state:
diff --git a/pitivi/timeline/elements.py b/pitivi/timeline/elements.py
index a91db08..9836b9d 100644
--- a/pitivi/timeline/elements.py
+++ b/pitivi/timeline/elements.py
@@ -566,10 +566,12 @@ class Clip(Gtk.EventBox, timelineUtils.Zoomable, Loggable):
         pass
 
     def sendFakeEvent(self, event, event_widget):
+        follow_up = True
         if event.type == Gdk.EventType.BUTTON_RELEASE:
-            self._clickedCb(event_widget, event)
+            follow_up = self._clickedCb(event_widget, event)
 
-        self.timeline.sendFakeEvent(event, event_widget)
+        if follow_up:
+            self.timeline.sendFakeEvent(event, event_widget)
 
     def do_draw(self, cr):
         self.updatePosition()
diff --git a/pitivi/timeline/timeline.py b/pitivi/timeline/timeline.py
index 508eac0..5cdd616 100644
--- a/pitivi/timeline/timeline.py
+++ b/pitivi/timeline/timeline.py
@@ -170,7 +170,7 @@ class Marquee(Gtk.Box, Loggable):
                     else:
                         res.append(clip)
 
-        self.debug("Selected clips: %s" % res)
+        self.debug("Result is %s" % res)
 
         return tuple(set(res))
 
@@ -279,7 +279,7 @@ class Timeline(Gtk.EventBox, timelineUtils.Zoomable, Loggable):
         self.get_accessible().set_name("timeline canvas")
         self.__fake_event_widget = None
 
-    def sendFakeEvent(self, event, event_widget):
+    def sendFakeEvent(self, event, event_widget=None):
         # Member usefull for testsing
         self.__fake_event_widget = event_widget
 
@@ -290,6 +290,8 @@ class Timeline(Gtk.EventBox, timelineUtils.Zoomable, Loggable):
             self.__buttonReleaseEventCb(self, event)
         elif event.type == Gdk.EventType.MOTION_NOTIFY:
             self.__motionNotifyEventCb(self, event)
+        else:
+            self.parent.sendFakeEvent(event)
 
         self.__fake_event_widget = None
 
@@ -387,10 +389,8 @@ class Timeline(Gtk.EventBox, timelineUtils.Zoomable, Loggable):
         self.layout.move(self.__snap_bar, self.nsToPixel(position), 0)
         self.__snap_bar.show()
         self.__snap_position = position
-        self.debug("-> Snap START!")
 
     def hideSnapBar(self):
-        self.debug("-> Force hiding snap bar")
         self.__snap_position = 0
         self.__snap_bar.hide()
 
@@ -784,13 +784,14 @@ class Timeline(Gtk.EventBox, timelineUtils.Zoomable, Loggable):
     # Edition handling
     def __setupTimelineEdition(self):
         self.draggingElement = None
-        self.__editing_context = None
+        self.editing_context = None
         self.__got_dragged = False
         self.__drag_start_x = 0
         self.__on_separators = []
         self._on_layer = None
 
     def __getLayerAt(self, y, bLayer=None):
+        self.error("Y is %s" % y)
         if y < 20 or not self.bTimeline.get_layers():
             try:
                 bLayer = self.bTimeline.get_layers()[0]
@@ -844,22 +845,22 @@ class Timeline(Gtk.EventBox, timelineUtils.Zoomable, Loggable):
         if self.__got_dragged is False:
             self.__got_dragged = True
             self.allowSeek = False
-            self.__editing_context = timelineUtils.EditingContext(self.draggingElement.bClip,
-                                                                  self.bTimeline,
-                                                                  self.draggingElement.edit_mode,
-                                                                  self.draggingElement.dragging_edge,
-                                                                  None,
-                                                                  self.app.action_log)
+            self.editing_context = timelineUtils.EditingContext(self.draggingElement.bClip,
+                                                                self.bTimeline,
+                                                                self.draggingElement.edit_mode,
+                                                                self.draggingElement.dragging_edge,
+                                                                None,
+                                                                self.app.action_log)
 
         x, y = event_widget.translate_coordinates(self, x, y)
         x -= ui.CONTROL_WIDTH
         x += self.hadj.get_value()
         y += self.vadj.get_value()
 
-        mode = self.get_parent().getEditionMode(isAHandle=self.__editing_context.edge != GES.Edge.EDGE_NONE)
-        self.__editing_context.setMode(mode)
+        mode = self.get_parent().getEditionMode(isAHandle=self.editing_context.edge != GES.Edge.EDGE_NONE)
+        self.editing_context.setMode(mode)
 
-        if self.__editing_context.edge is GES.Edge.EDGE_END:
+        if self.editing_context.edge is GES.Edge.EDGE_END:
             position = self.pixelToNs(x)
         else:
             position = self.pixelToNs(x - self.__drag_start_x)
@@ -873,10 +874,10 @@ class Timeline(Gtk.EventBox, timelineUtils.Zoomable, Loggable):
         if self.__on_separators:
             self.__setHoverSeparators()
 
-        self.__editing_context.editTo(position, priority)
+        self.editing_context.editTo(position, priority)
 
     def createLayer(self, priority):
-        self.info("Creating layer %s" % priority)
+        self.error("Creating layer %s" % priority)
         new_bLayer = GES.Layer.new()
         new_bLayer.props.priority = priority
         self.bTimeline.add_layer(new_bLayer)
@@ -917,16 +918,17 @@ class Timeline(Gtk.EventBox, timelineUtils.Zoomable, Loggable):
                 if self.__on_separators[0] == self._on_layer.ui.after_sep:
                     priority = self._on_layer.props.priority + 1
 
+                self.error("On separator --> %s" % priority)
                 self.createLayer(max(0, priority))
                 self._onSeparatorStartTime = None
-                self.__editing_context.editTo(self.__editing_context.new_position, priority)
+                self.editing_context.editTo(self.editing_context.new_position, priority)
             self.layout.props.width = self._computeTheoricalWidth()
 
-            self.__editing_context.finish()
+            self.editing_context.finish()
 
         self.draggingElement = None
         self.__got_dragged = False
-        self.__editing_context = None
+        self.editing_context = None
         self.hideSnapBar()
 
         self.__unsetHoverSeparators()
@@ -1034,7 +1036,7 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable):
 
     def zoomFit(self):
         # self._hscrollbar.set_value(0)
-        self.app.write_action("set-zoom-fit", {"not-mandatory-action-type": True})
+        self.app.write_action("zoom-fit", {"not-mandatory-action-type": True})
 
         self._setBestZoomRatio(allow_zoom_in=True)
 
@@ -1532,6 +1534,13 @@ class TimelineContainer(Gtk.Grid, Zoomable, Loggable):
 
     # Gtk widget virtual methods
 
+    def sendFakeEvent(self, event):
+        self.info("Faking %s" % event)
+        if event.type == Gdk.EventType.KEY_PRESS:
+            self.do_key_press_event(event)
+        elif event.type == Gdk.EventType.KEY_RELEASE:
+            self.do_key_release_event(event)
+
     def do_key_press_event(self, event):
         # This is used both for changing the selection modes and for affecting
         # the seek keyboard shortcuts further below
diff --git a/pitivi/undo/timeline.py b/pitivi/undo/timeline.py
index 465d06f..62b2ea9 100644
--- a/pitivi/undo/timeline.py
+++ b/pitivi/undo/timeline.py
@@ -323,6 +323,8 @@ class ClipAdded(UndoableAction):
         if hasattr(self.layer, "splitting_object") and \
                 self.layer.splitting_object is True:
             return None
+        elif self.layer.get_timeline().ui.editing_context is not None:
+            return None
 
         st = Gst.Structure.new_empty("add-clip")
         st.set_value("name", self.clip.get_name())
@@ -354,6 +356,9 @@ class ClipRemoved(UndoableAction):
         self._undone()
 
     def asScenarioAction(self):
+        if self.layer.get_timeline().ui.editing_context is not None:
+            return None
+
         st = Gst.Structure.new_empty("remove-clip")
         st.set_value("name", self.clip.get_name())
         return st
@@ -580,7 +585,8 @@ class TimelineLogObserver(Loggable):
 
     def _connectToTrackElement(self, track_element):
         for prop, binding in track_element.get_all_control_bindings().items():
-            self._connectToControlSource(track_element, binding)
+            self._connectToControlSource(track_element, binding,
+                                         existed=True)
         track_element.connect("control-binding-added",
                               self._controlBindingAddedCb)
         if isinstance(track_element, GES.BaseEffect):
@@ -592,7 +598,7 @@ class TimelineLogObserver(Loggable):
         for prop, binding in track_element.get_all_control_bindings().items():
             self._disconnectFromControlSource(binding)
 
-    def _connectToControlSource(self, track_element, binding):
+    def _connectToControlSource(self, track_element, binding, existed=False):
         control_source = binding.props.control_source
 
         control_source.connect("value-added",
@@ -610,7 +616,7 @@ class TimelineLogObserver(Loggable):
         tracker.connect("keyframe-moved", self._controlSourceKeyFrameMovedCb)
         self.control_source_keyframe_trackers[control_source] = tracker
 
-        if self.log.app:
+        if self.log.app and not existed:
             self.log.app.write_action("set-control-source",
                                       {"element-name": track_element.get_name(),
                                        "property-name": binding.props.name,
diff --git a/pitivi/undo/undo.py b/pitivi/undo/undo.py
index 4eb1590..c6f803f 100644
--- a/pitivi/undo/undo.py
+++ b/pitivi/undo/undo.py
@@ -42,7 +42,7 @@ class UndoWrongStateError(UndoError):
     pass
 
 
-class UndoableAction(GObject.Object):
+class UndoableAction(GObject.Object, Loggable):
 
     """
     An action that can be undone.
@@ -57,6 +57,7 @@ class UndoableAction(GObject.Object):
 
     def __init__(self):
         GObject.Object.__init__(self)
+        Loggable.__init__(self)
 
     def do(self):
         raise NotImplementedError()
diff --git a/pitivi/utils/timeline.py b/pitivi/utils/timeline.py
index 854396c..dcff246 100644
--- a/pitivi/utils/timeline.py
+++ b/pitivi/utils/timeline.py
@@ -328,6 +328,8 @@ class Zoomable(object):
     _cur_zoom = 20
     zoomratio = None
 
+    app = None
+
     def __init__(self):
         # FIXME: ideally we should deprecate this
         Zoomable.addInstance(self)
@@ -367,10 +369,14 @@ class Zoomable(object):
     @classmethod
     def zoomIn(cls):
         cls.setZoomLevel(cls._cur_zoom + 1)
+        cls.app.write_action("zoom-in",
+                             {"not-mandatory-action-type": True})
 
     @classmethod
     def zoomOut(cls):
         cls.setZoomLevel(cls._cur_zoom - 1)
+        cls.app.write_action("zoom-out",
+                             {"not-mandatory-action-type": True})
 
     @classmethod
     def computeZoomRatio(cls, x):
diff --git a/pitivi/utils/validate.py b/pitivi/utils/validate.py
index 3583082..b69657a 100644
--- a/pitivi/utils/validate.py
+++ b/pitivi/utils/validate.py
@@ -18,8 +18,10 @@
 # License along with this program; if not, write to the
 # Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 # Boston, MA 02110-1301, USA.
-import sys
+import locale
+import subprocess
 
+from gi.repository import Gtk
 from gi.repository import Gst
 from gi.repository import GES
 from gi.repository import Gdk
@@ -28,62 +30,256 @@ from gi.repository import GLib
 from pitivi.utils import ui
 from pitivi.utils import timeline as timelineUtils
 
+
+CAT = "validate"
+
+
 try:
     from gi.repository import GstValidate
 except ImportError:
     GstValidate = None
 
+monitor = None
 has_validate = False
 
 
+def Event(event_type, **kwargs):
+    event_types_constructors = {
+        Gdk.EventType.BUTTON_PRESS: Gdk.EventButton.new,
+        Gdk.EventType.BUTTON_RELEASE: Gdk.EventButton.new,
+        Gdk.EventType.MOTION_NOTIFY: Gdk.EventMotion.new
+    }
+
+    try:
+        event = event_types_constructors[event_type](event_type)
+    except KeyError:
+        event = Gdk.Event.new(event_type)
+
+    for arg, value in kwargs.items():
+        setattr(event, arg, value)
+
+    return event
+
+if GstValidate:
+    class PitiviMonitor(GstValidate.Monitor):
+        def __init__(self, runner, object):
+            GstValidate.Monitor.__init__(self, object=object, validate_runner=runner)
+
+            if GstValidate:
+                try:
+                    from gi.repository import Wnck
+                    Wnck.Screen.get_default().connect("window-opened", self._windowOpenedCb)
+                except ImportError:
+                    print("Wnck not present on the system,"
+                          " not checking the sink does not open a new window")
+                    pass
+
+        def _windowOpenedCb(self, screen, window):
+            global monitor
+
+            if window.get_name() == 'OpenGL renderer' and monitor:
+                monitor.report_simple(GLib.quark_from_string("pitivi::wrong-window-creation"),
+                                      "New window created by the sink,"
+                                      " that should not happen")
+
+        def checkWrongWindow(self):
+            try:
+                windows = subprocess.check_output(["xwininfo", "-tree", 
"-root"]).decode(locale.getdefaultlocale()[1])
+                for w in windows.split('\n'):
+                    if "OpenGL renderer" in w and w.startswith("     0x"):
+                        monitor.report_simple(GLib.quark_from_string("pitivi::wrong-window-creation"),
+                                              "New window created by the sink,"
+                                              " that should not happen, (current windows: %s)"
+                                              % windows)
+                        break
+            except subprocess.CalledProcessError:
+                pass
+
+
+def create_monitor(runner, app):
+    global monitor
+    global has_validate
+
+    if not monitor and has_validate:
+        monitor = PitiviMonitor(runner, app)
+        GstValidate.Reporter.set_name(monitor, "Pitivi")
+
+
 def stop(scenario, action):
+    global monitor
+
+    if monitor:
+        monitor.checkWrongWindow()
+
     if action.structure.get_boolean("force")[0]:
+        GstValidate.execute_action(GstValidate.get_action_type(action.type).overriden_type,
+                                   action)
+
         timeline = scenario.pipeline.props.timeline
         project = timeline.get_asset()
 
         if project:
             project.setModificationState(False)
             GstValidate.print_action(action, "Force quiting, ignoring any"
-                                     " changes in the project")
+
+                                     " changes in the project\n")
         timeline.ui.app.shutdown()
 
         return 1
 
-    GstValidate.print_action(action, "not doing anything in pitivi")
+    GstValidate.print_action(action, "STOP: not doing anything in pitivi\n")
 
     return 1
 
 
-def editContainer(scenario, action):
-    # edit-container, edge=(string)edge_end, position=(double)2.2340325289999998, 
edit-mode=(string)edit_trim, container-name=(string)uriclip0, new-layer-priority=(int)-1;
-    timeline = scenario.pipeline.props.timeline
-    container = timeline.get_element(action.structure["container-name"])
+def set_state(scenario, action):
+    wanted_state = action.structure["state"]
+    if wanted_state is None:
+        wanted_state = action.structure.get_name()
+        if wanted_state == "play":
+            wanted_state = "playing"
+        elif wanted_state == "pause":
+            wanted_state = "paused"
+
+    if wanted_state == "paused":
+        if scenario.__dict__.get("started", None) is None:
+
+            return 1
 
+    return GstValidate.execute_action(GstValidate.get_action_type(action.type).overriden_type,
+                                      action)
+
+
+def get_edge(structure):
     try:
-        res, edge = GstValidate.utils_enum_from_str(GES.Edge, action.structure["edge"])
+        res, edge = GstValidate.utils_enum_from_str(GES.Edge, structure["edge"])
         if not res:
             edge = GES.Edge.EDGE_NONE
         else:
             edge = GES.Edge(edge)
+
     except KeyError:
         edge = GES.Edge.EDGE_NONE
 
+    return edge
+
+
+def _releaseButtonIfNeeded(scenario, action, timeline, container, edge, layer_prio,
+                           position, y):
+    try:
+        next_actions = scenario.get_actions()
+        for next_action in next_actions[1:]:
+            if next_action.type not in ["wait", "add-layer"]:
+                break
+    except KeyError:
+        return
+
+    if next_action is None or next_action.type != "edit-container":
+        scenario.dragging = False
+        event = Gdk.EventButton.new(Gdk.EventType.BUTTON_RELEASE)
+        event.button = 1
+        event.x = timelineUtils.Zoomable.nsToPixelAccurate(position)
+        event.y = y
+        container.ui.sendFakeEvent(event, container.ui)
+
+        if isinstance(container, GES.SourceClip):
+            if edge == GES.Edge.EDGE_START:
+                container.ui.leftHandle._eventCb(container.ui.leftHandle, 
Gdk.Event.new(Gdk.EventType.LEAVE_NOTIFY))
+            if edge == GES.Edge.EDGE_END:
+                container.ui.rightHandle._eventCb(container.ui.rightHandle, 
Gdk.Event.new(Gdk.EventType.LEAVE_NOTIFY))
+
+        if layer_prio > 0 and container.get_layer().get_priority() != layer_prio:
+            scenario.report_simple(GLib.quark_from_string("scenario::execution-error"),
+                                   "Resulting clip priority: %s"
+                                   " is not the same as the wanted one: %s"
+                                   % (container.get_layer().get_priority(),
+                                      layer_prio))
+
+        cleanEditModes(timeline, scenario)
+
+
+def cleanEditModes(timeline, scenario):
+    if scenario.last_mode == GES.EditMode.EDIT_RIPPLE:
+        timeline.ui.sendFakeEvent(Event(Gdk.EventType.KEY_RELEASE, keyval=Gdk.KEY_Shift_L))
+    elif scenario.last_mode == GES.EditMode.EDIT_ROLL:
+        timeline.ui.sendFakeEvent(Event(Gdk.EventType.KEY_RELEASE, keyval=Gdk.KEY_Control_L))
+
+    scenario.last_mode = None
+
+
+def setEditingMode(timeline, scenario, action):
+    try:
+        mode = scenario.last_mode
+        mode
+    except AttributeError:
+        scenario.last_mode = None
+
+    try:
+        res, mode = GstValidate.utils_enum_from_str(GES.EditMode, action.structure["edit-mode"])
+        if not res:
+            mode = GES.EditMode.EDIT_NORMAL
+        else:
+            mode = GES.EditMode(mode)
+    except KeyError:
+        mode = GES.EditMode.EDIT_NORMAL
+
+    if mode == GES.EditMode.EDIT_RIPPLE:
+        timeline.ui.sendFakeEvent(Event(Gdk.EventType.KEY_PRESS, keyval=Gdk.KEY_Shift_L))
+
+        if scenario.last_mode == GES.EditMode.EDIT_ROLL:
+            timeline.ui.sendFakeEvent(Event(Gdk.EventType.KEY_RELEASE, keyval=Gdk.KEY_Control_L))
+
+    elif mode == GES.EditMode.EDIT_ROLL:
+        timeline.ui.sendFakeEvent(Event(Gdk.EventType.KEY_PRESS, keyval=Gdk.KEY_Control_L))
+
+        if scenario.last_mode == GES.EditMode.EDIT_RIPPLE:
+            timeline.ui.sendFakeEvent(Event(Gdk.EventType.KEY_RELEASE, keyval=Gdk.KEY_Shift_L))
+    else:
+        cleanEditModes(timeline, scenario)
+
+    scenario.last_mode = mode
+
+
+def editContainer(scenario, action):
+    timeline = scenario.pipeline.props.timeline
+    container = timeline.get_element(action.structure["container-name"])
+
+    if container is None:
+        for layer in timeline.get_layers():
+            for clip in layer.get_clips():
+                Gst.info("Exisiting clip: %s" % clip.get_name())
+
+        scenario.report_simple(GLib.quark_from_string("scenario::execution-error"),
+                               "Could not find container: %s"
+                               % action.structure["container-name"])
+
+        return 1
+
     res, position = GstValidate.action_get_clocktime(scenario, action, "position")
     layer_prio = action.structure["new-layer-priority"]
 
     if res is False:
         return 0
 
+    edge = get_edge(action.structure)
     container_ui = container.ui
 
-    y = 21
-    if container.get_layer().get_priority() != layer_prio:
+    setEditingMode(timeline, scenario, action)
+
+    y = 21 - container_ui.translate_coordinates(timeline.ui, 0, 0)[1]
+
+    if container.get_layer().get_priority() != layer_prio and layer_prio != -1:
         try:
             layer = timeline.get_layers()[layer_prio]
+            Gst.info("Y is: %s Realized?? %s Priori: %s layer prio: %s"
+                     % (layer.ui.get_allocation().y,
+                        container_ui.get_realized(),
+                        container.get_layer().get_priority(),
+                        layer_prio))
             y = layer.ui.get_allocation().y - container_ui.translate_coordinates(timeline.ui, 0, 0)[1]
             if y < 0:
                 y += 21
-            else:
+            elif y > 0:
                 y -= 21
         except IndexError:
             if layer_prio == -1:
@@ -96,53 +292,36 @@ def editContainer(scenario, action):
     if not hasattr(scenario, "dragging") or scenario.dragging is False:
         if isinstance(container, GES.SourceClip):
             if edge == GES.Edge.EDGE_START:
-                container.ui.leftHandle._eventCb(Gdk.Event.new(Gdk.Event.ENTER_NOTIFY))
+                container.ui.leftHandle._eventCb(container.ui.leftHandle, 
Gdk.Event.new(Gdk.EventType.ENTER_NOTIFY))
             elif edge == GES.Edge.EDGE_END:
-                container.ui.leftHandle._eventCb(Gdk.Event.new(Gdk.Event.ENTER_NOTIFY))
+                container.ui.rightHandle._eventCb(container.ui.rightHandle, 
Gdk.Event.new(Gdk.EventType.ENTER_NOTIFY))
 
         scenario.dragging = True
-        event = Gdk.EventButton.new(Gdk.EventType.BUTTON_PRESS)
-        event.button = 1
-        event.y = y
+        event = Event(Gdk.EventType.BUTTON_PRESS, button=1, y=y)
         container.ui.sendFakeEvent(event, container.ui)
 
-    event = Gdk.EventMotion.new(Gdk.EventType.MOTION_NOTIFY)
-    event.button = 1
-    event.x = timelineUtils.Zoomable.nsToPixelAccurate(position) - 
container_ui.translate_coordinates(timeline.ui, 0, 0)[0] + ui.CONTROL_WIDTH
-    event.y = y
-    event.state = Gdk.ModifierType.BUTTON1_MASK
+    event = Event(Gdk.EventType.MOTION_NOTIFY, button=1,
+                  x=timelineUtils.Zoomable.nsToPixelAccurate(position) -
+                  container_ui.translate_coordinates(timeline.ui, 0, 0)[0] + ui.CONTROL_WIDTH,
+                  y=y, state=Gdk.ModifierType.BUTTON1_MASK)
     container.ui.sendFakeEvent(event, container.ui)
 
     GstValidate.print_action(action, "Editing %s to %s in %s mode, edge: %s "
-          "with new layer prio: %d\n" % (action.structure["container-name"],
-                                         Gst.TIME_ARGS(position),
-                                         timeline.ui.draggingElement.edit_mode,
-                                         timeline.ui.draggingElement.dragging_edge,
-                                         layer_prio))
+                             "with new layer prio: %d\n" % (action.structure["container-name"],
+                                                            Gst.TIME_ARGS(position),
+                                                            timeline.ui.draggingElement.edit_mode,
+                                                            timeline.ui.draggingElement.dragging_edge,
+                                                            layer_prio))
 
-    next_action = scenario.get_next_action()
-    if next_action is None or next_action.type != "edit-container":
-        scenario.dragging = False
-        event = Gdk.EventButton.new(Gdk.EventType.BUTTON_RELEASE)
-        event.button = 1
-        event.x = timelineUtils.Zoomable.nsToPixelAccurate(position)
-        event.y = y
-        container.ui.sendFakeEvent(event, container.ui)
+    _releaseButtonIfNeeded(scenario, action, timeline, container, edge, layer_prio,
+                           position, y)
 
-        if isinstance(container, GES.SourceClip):
-            if edge == GES.Edge.EDGE_START:
-                container.ui.leftHandle._eventCb(Gdk.Event.new(Gdk.Event.LEAVE_NOTIFY))
-            if edge == GES.Edge.EDGE_END:
-                container.ui.leftHandle._eventCb(Gdk.Event.new(Gdk.Event.LEAVE_NOTIFY))
+    return 1
 
-        if container.get_layer().get_priority() != layer_prio:
-            scenario.report_simple(GLib.quark_from_string("scenario::execution-error"),
-                                   "Resulting clip priority: %s"
-                                   " is not the same as the wanted one: %s"
-                                   % (container.get_layer().get_priority(),
-                                      layer_prio))
 
-    return 1
+# def commit(scenario, action):
+
+#     return True
 
 
 def splitClip(scenario, action):
@@ -152,13 +331,122 @@ def splitClip(scenario, action):
     return True
 
 
-def setZoomFit(scenario, action):
+def zoom(scenario, action):
     timeline = scenario.pipeline.props.timeline.ui
-    timeline.parent.zoomFit()
+
+    GstValidate.print_action(action, action.type.replace('-', ' ') + "\n")
+
+    {"zoom-fit": timeline.parent.zoomFit,
+     "zoom-out": timelineUtils.Zoomable.zoomOut,
+     "zoom-in": timelineUtils.Zoomable.zoomIn}[action.type]()
+
+    return True
+
+
+def setZoomLevel(scenario, action):
+    timelineUtils.Zoomable.setZoomLevel(action.structure["level"])
 
     return True
 
 
+def add_layer(scenario, action):
+    timeline = scenario.pipeline.props.timeline
+    if len(timeline.get_layers()) == 0:
+        GstValidate.print_action(action, "Adding first layer\n")
+        timeline.append_layer()
+    else:
+        GstValidate.print_action(action, "Not adding layer, should be done by pitivi itself\n")
+
+    return True
+
+
+def remove_clip(scenario, action):
+    try:
+        next_action = scenario.get_actions()[1]
+    except KeyError:
+        next_action = None
+
+    if next_action and next_action.type == "add-clip":
+        if next_action.structure["element-name"] == action.structure["element-name"]:
+            scenario.no_next_add_element = True
+            GstValidate.print_action(action,
+                                     "Just moving %s between layers, not removing it\n"
+                                     % action.structure["element-name"])
+            return True
+
+    action_type = GstValidate.get_action_type(action.type)
+
+    return GstValidate.execute_action(action_type.overriden_type, action)
+
+
+def select_clips(scenario, action):
+    should_select = True
+    timeline = scenario.pipeline.props.timeline
+    clip = timeline.get_element(action.structure["clip-name"])
+
+    if clip is None:
+        scenario.report_simple(GLib.quark_from_string("scenario::execution-error"),
+                               "Could not find container: %s"
+                               % action.structure["container-name"])
+
+        return 1
+
+    mode = action.structure["mode"]
+    if mode:
+        mode = mode.lower()
+
+    if mode == "ctrl":
+        if clip.ui.get_state_flags() & Gtk.StateFlags.SELECTED:
+            should_select = False
+
+        timeline.ui.sendFakeEvent(Event(event_type=Gdk.EventType.KEY_PRESS,
+                                        keyval=Gdk.KEY_Control_L))
+
+    event = Gdk.EventButton.new(Gdk.EventType.BUTTON_RELEASE)
+    clip.ui.sendFakeEvent(event, clip.ui)
+
+    selection = action.structure["selection"]
+    if not selection:
+        if should_select:
+            if not clip.ui.get_state_flags() & Gtk.StateFlags.SELECTED:
+                scenario.report_simple(GLib.quark_from_string("scenario::execution-error"),
+                                       "Clip %s should be selected but is not"
+                                       % clip.get_name())
+        elif clip.ui.get_state_flags() & Gtk.StateFlags.SELECTED:
+            scenario.report_simple(GLib.quark_from_string("scenario::execution-error"),
+                                   "Clip %s should be UNselected but is not"
+                                   % clip.get_name())
+    else:
+        for l in timeline.get_layers():
+            for c in l.get_clips():
+                if c.get_name() in selection:
+                    if not c.ui.get_state_flags() & Gtk.StateFlags.SELECTED:
+                        scenario.report_simple(GLib.quark_from_string("scenario::execution-error"),
+                                               "Clip %s should be selected (as defined in selection %s)"
+                                               " but is not" % (selection, clip.get_name()))
+                else:
+                    if c.ui.get_state_flags() & Gtk.StateFlags.SELECTED:
+                        scenario.report_simple(GLib.quark_from_string("scenario::execution-error"),
+                                               "Clip %s should NOT be selected (as defined in selection %s)"
+                                               " but it is" % (selection, clip.get_name()))
+
+    if mode == "ctrl":
+        timeline.ui.sendFakeEvent(Event(Gdk.EventType.KEY_RELEASE, keyval=Gdk.KEY_Control_L))
+
+    return 1
+
+
+def Parametter(name, desc, mandatory=False, possible_variables=None, types=None):
+    p = GstValidate.ActionParameter()
+    p.description = desc
+    p.mandatory = mandatory
+    p.name = name
+    p.possible_variables = possible_variables
+    p.types = types
+
+    return p
+
+
 def init():
     global has_validate
     try:
@@ -170,6 +458,21 @@ def init():
                                          "Pitivi override for the stop action",
                                          GstValidate.ActionTypeFlags.NONE)
 
+        GstValidate.register_action_type("pause", "pitivi",
+                                         set_state, None,
+                                         "Pitivi override for the pause action",
+                                         GstValidate.ActionTypeFlags.NONE)
+
+        GstValidate.register_action_type("play", "pitivi",
+                                         set_state, None,
+                                         "Pitivi override for the pause action",
+                                         GstValidate.ActionTypeFlags.NONE)
+
+        GstValidate.register_action_type("set-state", "pitivi",
+                                         set_state, None,
+                                         "Pitivi override for the pause action",
+                                         GstValidate.ActionTypeFlags.NONE)
+
         GstValidate.register_action_type("edit-container", "pitivi",
                                          editContainer, None,
                                          "Start dragging a clip in the timeline",
@@ -179,9 +482,37 @@ def init():
                                          splitClip, None,
                                          "Split a clip",
                                          GstValidate.ActionTypeFlags.NONE)
-        GstValidate.register_action_type("set-zoom-fit", "pitivi",
-                                         setZoomFit, None,
-                                         "Split a clip",
+
+        GstValidate.register_action_type("add-layer", "pitivi",
+                                         add_layer, None,
+                                         "Add layer",
+                                         GstValidate.ActionTypeFlags.NONE)
+
+        GstValidate.register_action_type("remove-clip", "pitivi",
+                                         remove_clip, None,
+                                         "Remove clip",
+                                         GstValidate.ActionTypeFlags.NONE)
+
+        GstValidate.register_action_type("select-clips", "pitivi",
+                                         select_clips, [Parametter("clip-name",
+                                                                   "The name of the clip to select",
+                                                                   True, None, "str")],
+                                         "Select clips",
+                                         GstValidate.ActionTypeFlags.NONE)
+
+        for z in ["zoom-fit", "zoom-out", "zoom-in"]:
+            GstValidate.register_action_type(z, "pitivi", zoom, None, z,
+                                             GstValidate.ActionTypeFlags.NO_EXECUTION_NOT_FATAL)
+        GstValidate.register_action_type('set-zoom-level', "pitivi", setZoomLevel, None, z,
                                          GstValidate.ActionTypeFlags.NO_EXECUTION_NOT_FATAL)
+
+        Gst.info("Adding pitivi::wrong-window-creation")
+        GstValidate.Issue.register(GstValidate.Issue.new(
+                                   GLib.quark_from_string("pitivi::wrong-window-creation"),
+                                   "A new window for the sink has wrongly been created",
+                                   "All sink should display their images in an embedded "
+                                   "widget and thus not create a new window",
+                                   GstValidate.ReportLevel.CRITICAL))
+
     except ImportError:
         has_validate = False
diff --git a/pitivi/utils/widgets.py b/pitivi/utils/widgets.py
index 645ebf8..9c96dac 100644
--- a/pitivi/utils/widgets.py
+++ b/pitivi/utils/widgets.py
@@ -1073,6 +1073,9 @@ class ZoomBox(Gtk.Grid, Zoomable):
 
     def _zoomAdjustmentChangedCb(self, adjustment):
         Zoomable.setZoomLevel(adjustment.get_value())
+        self.timeline.app.write_action("set-zoom-level",
+                                       {"level": adjustment.get_value(),
+                                        "not-mandatory-action-type": True})
 
         if self._manual_set is False:
             self.timeline.scrollToPlayhead()
diff --git a/pitivi/viewer.py b/pitivi/viewer.py
index 5fa035d..c681fe2 100644
--- a/pitivi/viewer.py
+++ b/pitivi/viewer.py
@@ -38,8 +38,6 @@ from pitivi.utils.pipeline import AssetPipeline, Seeker
 from pitivi.utils.ui import SPACING, hex_to_rgb
 from pitivi.utils.widgets import TimeWidget
 
-import platform
-
 GlobalSettings.addConfigSection("viewer")
 GlobalSettings.addConfigOption("viewerDocked", section="viewer",
                                key="docked",
diff --git a/tests/samples/30fps_numeroted_frames_blue.webm b/tests/samples/30fps_numeroted_frames_blue.webm
new file mode 100644
index 0000000..c7aa550
Binary files /dev/null and b/tests/samples/30fps_numeroted_frames_blue.webm differ
diff --git a/tests/samples/one_fps_numeroted_blue.mkv b/tests/samples/one_fps_numeroted_blue.mkv
new file mode 100644
index 0000000..4e866b7
Binary files /dev/null and b/tests/samples/one_fps_numeroted_blue.mkv differ
diff --git a/tests/test_utils.py b/tests/test_utils.py
index b2b2029..618ec19 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -25,7 +25,7 @@ from unittest import TestCase
 
 from gi.repository import Gst
 from pitivi.utils.ui import beautify_length
-from pitivi.check import *
+from pitivi.check import *  # noqa
 
 second = Gst.SECOND
 minute = second * 60
diff --git a/tests/validate-tests/pitivi.py b/tests/validate-tests/pitivi.py
new file mode 100644
index 0000000..d36d23d
--- /dev/null
+++ b/tests/validate-tests/pitivi.py
@@ -0,0 +1,35 @@
+# -*- Mode: Python -*- vi:si:et:sw=4:sts=4:ts=4:syntax=python
+#
+# Copyright (c) 2014,Thibault Saunier <thibault saunier collabora com>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program; if not, write to the
+# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+# Boston, MA 02110-1301, USA.
+
+"""
+The GES GstValidate default testsuite
+"""
+import os
+
+
+TEST_MANAGER = "pitivi"
+
+
+def setup_tests(test_manager, options):
+    print("Setting up Pitivi default tests")
+    options.pitivi_scenario_paths = [os.path.abspath(os.path.join(os.path.dirname(__file__)))]
+    options.add_paths(os.path.abspath(os.path.join(os.path.dirname(__file__),
+                      "..", "samples")))
+    test_manager.register_defaults()
+    return True
diff --git a/tests/validate-tests/pitivivalidate.py b/tests/validate-tests/pitivivalidate.py
new file mode 100644
index 0000000..5ffb5c6
--- /dev/null
+++ b/tests/validate-tests/pitivivalidate.py
@@ -0,0 +1,125 @@
+#!/usr/bin/env python2
+#
+# Copyright (c) 2013,Thibault Saunier <thibault saunier collabora com>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program; if not, write to the
+# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+# Boston, MA 02110-1301, USA.
+
+import os
+import sys
+import urlparse
+import utils
+from urllib import unquote
+from baseclasses import GstValidateTest, TestsManager, ScenarioManager
+
+Pitivi_DURATION_TOLERANCE = utils.GST_SECOND / 2
+
+PITIVI_COMMAND = "pitivi"
+if "win32" in sys.platform:
+    PITIVI_COMMAND += ".exe"
+
+
+def quote_uri(uri):
+    """
+    Encode a URI/path according to RFC 2396, without touching the file:/// part.
+    """
+    # Split off the "file:///" part, if present.
+    parts = urlparse.urlsplit(uri, allow_fragments=False)
+    # Make absolutely sure the string is unquoted before quoting again!
+    raw_path = unquote(parts.path)
+    return utils.path2url(raw_path)
+
+
+class PitiviTest(GstValidateTest):
+    def __init__(self, classname, options, reporter, scenario,
+                 combination=None):
+
+        super(PitiviTest, self).__init__(PITIVI_COMMAND, classname, options, reporter,
+                                         scenario=None)
+        self._scenario = scenario
+
+    def set_sample_paths(self):
+        paths = self.options.paths
+
+        if not isinstance(paths, list):
+            paths = [paths]
+
+        for path in paths:
+            # We always want paths separator to be cut with '/' for ges-launch
+            path = path.replace("\\", "/")
+            self.add_arguments("--ges-sample-path-recurse", quote_uri(path))
+
+    def build_arguments(self):
+        GstValidateTest.build_arguments(self)
+
+        self.set_sample_paths()
+        self.add_arguments(self._scenario.path)
+
+
+class PitiviTestsManager(TestsManager):
+    name = "pitivi"
+
+    _scenarios = ScenarioManager()
+
+    def __init__(self):
+        super(PitiviTestsManager, self).__init__()
+
+    def init(self):
+        self.fixme("Implement init checking")
+
+        return True
+
+    def add_options(self, parser):
+        group = parser.add_argument_group("Pitivi specific option group"
+                                          " and behaviours",
+                                          description="")
+        group.add_argument("--pitivi-scenarios-paths", dest="pitivi_scenario_paths",
+                           default=os.path.join(os.path.basename(__file__),
+                                                "pitivi",
+                                                "pitivi scenarios"),
+                           help="Paths in which to look for scenario files")
+
+    def set_settings(self, options, args, reporter):
+        TestsManager.set_settings(self, options, args, reporter)
+        self._scenarios.config = self.options
+
+        try:
+            os.makedirs(utils.url2path(options.dest)[0])
+        except OSError:
+            pass
+
+    def list_tests(self):
+        return self.tests
+
+    def register_defaults(self):
+        scenarios = list()
+        for path in self.options.pitivi_scenario_paths:
+            for root, dirs, files in os.walk(path):
+                for f in files:
+                    if not f.endswith(".scenario"):
+                        continue
+                    scenarios.append(os.path.join(path, root, f))
+
+        for scenario_name in scenarios:
+            scenario = self._scenarios.get_scenario(scenario_name)
+            if scenario is None:
+                continue
+
+            classname = "pitivi.%s" % (scenario.name)
+            self.add_test(PitiviTest(classname,
+                                     self.options,
+                                     self.reporter,
+                                     scenario=scenario)
+                          )
diff --git a/tests/validate-tests/runtests b/tests/validate-tests/runtests
new file mode 100755
index 0000000..76e627f
--- /dev/null
+++ b/tests/validate-tests/runtests
@@ -0,0 +1,17 @@
+#!/usr/bin/env python3
+
+import os
+import sys
+
+GST_VALIDATE_LAUNCHER_COMMAND = "gst-validate-launcher"
+
+if (os.system(GST_VALIDATE_LAUNCHER_COMMAND + " -h > %s 2>&1" % os.devnull) != 0):
+    print("Make sure to install gst-validate: 
http://cgit.freedesktop.org/gstreamer/gst-devtools/tree/validate/";
+          " before running the testsuite")
+    sys.exit(127)
+
+sys.exit(os.system("GST_VALIDATE_APPS_DIR=%s %s %s %s"
+         % (os.path.abspath(os.path.join(os.path.dirname(__file__))),
+            GST_VALIDATE_LAUNCHER_COMMAND,
+            os.path.join(os.path.abspath(os.path.join(os.path.dirname(__file__))), "pitivi.py"),
+            ' '.join(sys.argv[1:]))))
diff --git a/tests/validate-tests/select_clip.scenario b/tests/validate-tests/select_clip.scenario
new file mode 100644
index 0000000..253d6c2
--- /dev/null
+++ b/tests/validate-tests/select_clip.scenario
@@ -0,0 +1,18 @@
+description, seek=true, handles-states=true
+pause;
+add-asset, 
id=(string)file:///home/someone/devel/pitivi/1.0-uninstalled/pitivi/tests/samples/30fps_numeroted_frames_blue.webm,
 type=(string)GESUriClip;
+add-layer, priority=(int)0;
+add-clip, name=(string)uriclip0, layer-priority=(int)0, 
asset-id=(string)file:///home/someone/devel/pitivi/1.0-uninstalled/pitivi/tests/samples/30fps_numeroted_frames_blue.webm,
 type=(string)GESUriClip, start=(double)0, inpoint=(double)0, duration=(double)2;
+commit;
+add-clip, name=(string)uriclip1, layer-priority=(int)0, 
asset-id=(string)file:///home/someone/devel/pitivi/1.0-uninstalled/pitivi/tests/samples/30fps_numeroted_frames_blue.webm,
 type=(string)GESUriClip, start=(double)2, inpoint=(double)0, duration=(double)2;
+commit;
+zoom-fit, not-mandatory-action-type=(boolean)true;
+select-clips, clip-name=uriclip1;
+wait, duration=0.5
+select-clips, clip-name=uriclip0;
+wait, duration=0.5
+select-clips, clip-name=uriclip1, mode=ctrl;
+wait, duration=0.5
+select-clips, clip-name=uriclip1, mode=ctrl, selection="uriclip0";
+wait, duration=0.5
+stop, force=true;
diff --git a/tests/validate-tests/simple_play.scenario b/tests/validate-tests/simple_play.scenario
new file mode 100644
index 0000000..c7d2586
--- /dev/null
+++ b/tests/validate-tests/simple_play.scenario
@@ -0,0 +1,13 @@
+description, seek=false, handles-states=true
+add-asset, 
id=(string)file:///home/someone/devel/pitivi/1.0-uninstalled/pitivi/tests/samples/tears_of_steel.webm, 
type=(string)GESUriClip;
+add-layer, priority=(int)0;
+add-clip, name=(string)uriclip0, layer-priority=(int)0, 
asset-id=(string)file:///home/someone/devel/pitivi/1.0-uninstalled/pitivi/tests/samples/tears_of_steel.webm, 
type=(string)GESUriClip, start=(double)0, inpoint=(double)0, duration=(double)2;
+commit;
+add-clip, name=(string)uriclip1, layer-priority=(int)0, 
asset-id=(string)file:///home/someone/devel/pitivi/1.0-uninstalled/pitivi/tests/samples/tears_of_steel.webm, 
type=(string)GESUriClip, start=(double)2, inpoint=(double)0, duration=(double)2;
+set-control-source, binding-type=(string)direct, interpolation-mode=(string)linear, 
element-name=(string)videourisource1, property-name=(string)alpha, source-type=(string)interpolation;
+set-control-source, binding-type=(string)direct, interpolation-mode=(string)linear, 
element-name=(string)audiourisource1, property-name=(string)volume, source-type=(string)interpolation;
+commit;
+zoom-fit, optional-action-type=(boolean)true;
+set-zoom-level, optional-action-type=(boolean)true, level=(double)73;
+commit;
+stop, force=true;
diff --git a/tests/validate-tests/simple_ripple.scenario b/tests/validate-tests/simple_ripple.scenario
new file mode 100644
index 0000000..6f2d18a
--- /dev/null
+++ b/tests/validate-tests/simple_ripple.scenario
@@ -0,0 +1,126 @@
+description, seek=true, handles-states=true
+pause;
+add-asset, 
id=(string)file:///home/someone/devel/pitivi/1.0-uninstalled/pitivi/tests/samples/30fps_numeroted_frames_blue.webm,
 type=(string)GESUriClip;
+add-layer, priority=(int)0;
+add-clip, name=(string)uriclip0, layer-priority=(int)0, 
asset-id=(string)file:///home/someone/devel/pitivi/1.0-uninstalled/pitivi/tests/samples/30fps_numeroted_frames_blue.webm,
 type=(string)GESUriClip, start=(double)0, inpoint=(double)0, duration=(double)2;
+commit;
+add-clip, name=(string)uriclip1, layer-priority=(int)0, 
asset-id=(string)file:///home/someone/devel/pitivi/1.0-uninstalled/pitivi/tests/samples/30fps_numeroted_frames_blue.webm,
 type=(string)GESUriClip, start=(double)2, inpoint=(double)0, duration=(double)2;
+commit;
+zoom-fit, not-mandatory-action-type=(boolean)true;
+set-zoom-level, not-mandatory-action-type=(boolean)true, level=(double)73;
+edit-container, position=(double)1.993988506, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.9914189330000001, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.9888493599999999, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.986279787, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.978571069, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.9246100399999999, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.875788156, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.855231574, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.832105418, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.798700972, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.7807139620000001, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.7498790879999999, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.7241833600000001, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.711335496, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.6907789129999999, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.659944039, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.6214004470000001, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.6008438650000001, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.5854264280000001, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.567439418, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.546882836, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.52375668, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.503200098, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.487782661, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.4620869329999999, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.4415303500000001, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.4029867579999999, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.3798606019999999, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.3618735930000001, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.343886583, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.3104821360000001, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.27707769, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.2462428160000001, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.2025600780000001, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.1665860589999999, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.1306120390000001, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.1151946020000001, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.0843597279999999, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)1.0483857089999999, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.99185510700000001, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.953311515, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.93532450499999997, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.87879390300000004, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.80427629099999998, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.76316312600000002, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.72975867999999999, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.68607594199999999, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.64496277700000004, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.61155833000000004, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.57301473800000002, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.54217986399999996, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.52676242699999998, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.52162328099999999, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.52162328099999999, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.52162328099999999, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.52162328099999999, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.52162328099999999, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.52162328099999999, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.52162328099999999, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.52162328099999999, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.52162328099999999, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.52162328099999999, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.50877541699999995, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.501066699, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.49078840800000001, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.48821883500000002, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.48307968899999998, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.48307968899999998, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.48307968899999998, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.48051011599999999, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.467662252, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.467662252, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.45481438800000001, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.44710567000000001, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.44453609700000002, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.44453609700000002, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.44453609700000002, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.44453609700000002, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.44453609700000002, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.44453609700000002, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.44196652400000003, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.44196652400000003, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.44196652400000003, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.43939695099999998, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.43939695099999998, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.43682737799999999, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.43682737799999999, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.43425780600000002, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.43425780600000002, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.43425780600000002, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.43425780600000002, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.43168823299999998, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.43168823299999998, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.43168823299999998, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.43168823299999998, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.42911865999999999, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.42911865999999999, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.42911865999999999, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.42911865999999999, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.42654908699999999, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.423979514, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.42140994199999998, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.41884036899999999, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.416270796, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.41370122300000001, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.41113165000000002, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.41113165000000002, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.40856207700000002, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.40856207700000002, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.405992505, edge=(string)edge_end, container-name=(string)uriclip0, 
new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.40342293200000001, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.40342293200000001, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.40342293200000001, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+edit-container, position=(double)0.40342293200000001, edge=(string)edge_end, 
container-name=(string)uriclip0, new-layer-priority=(int)-1, edit-mode=(string)edit_ripple;
+commit;
+stop, force=True;
diff --git a/tests/validate-tests/simple_split_clips.scenario 
b/tests/validate-tests/simple_split_clips.scenario
new file mode 100644
index 0000000..5927477
--- /dev/null
+++ b/tests/validate-tests/simple_split_clips.scenario
@@ -0,0 +1,17 @@
+description, seek=true, handles-states=true
+pause;
+add-asset, 
id=(string)file:///home/thiblahute/devel/pitivi/1.0-uninstalled/pitivi/tests/samples/30fps_numeroted_frames_red.mkv,
 type=(string)GESUriClip;
+add-asset, 
id=(string)file:///home/thiblahute/devel/pitivi/1.0-uninstalled/pitivi/tests/samples/30fps_numeroted_frames_blue.webm,
 type=(string)GESUriClip;
+add-layer, priority=(int)0;
+add-clip, name=(string)uriclip0, layer-priority=(int)0, 
asset-id=(string)file:///home/thiblahute/devel/pitivi/1.0-uninstalled/pitivi/tests/samples/30fps_numeroted_frames_blue.webm,
 type=(string)GESUriClip, start=(double)0, inpoint=(double)0, duration=(double)1.228;
+add-clip, name=(string)uriclip1, layer-priority=(int)0, 
asset-id=(string)file:///home/thiblahute/devel/pitivi/1.0-uninstalled/pitivi/tests/samples/30fps_numeroted_frames_red.mkv,
 type=(string)GESUriClip, start=(double)1.228, inpoint=(double)0, duration=(double)2;
+commit;
+zoom-fit, not-mandatory-action-type=(boolean)true;
+set-zoom-level, level=(double)69, not-mandatory-action-type=(boolean)true;
+seek, start=(double)0.62812454799999995, flags=(string)accurate+flush;
+split-clip, clip-name=(string)uriclip0, position=(double)0.62812454799999995;
+commit;
+seek, start=(double)2.0066820710000002, flags=(string)accurate+flush;
+split-clip, clip-name=(string)uriclip1, position=(double)2.0066820710000002;
+commit;
+stop, force=true;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]