[pitivi] Implement UI testing with Dogtail



commit d44d440fba85c35c9a453fe6a3eb15e5e514e204
Author: Matas Brazdeikis <matas brazdeikis lt>
Date:   Fri Jul 20 17:00:33 2012 -0400

    Implement UI testing with Dogtail
    
    This provides a basic set of tests to simulate user interaction.

 tests/dogtail_scripts/helper_functions.py          |   25 ++
 tests/dogtail_scripts/test_base.py                 |   41 +++
 tests/dogtail_scripts/test_clipproperties.py       |   83 ++++++
 .../dogtail_scripts/test_dialogs_clipmediaprops.py |   59 +++++
 tests/dogtail_scripts/test_dialogs_prefs.py        |   50 ++++
 .../dogtail_scripts/test_dialogs_startupwizard.py  |   19 ++
 tests/dogtail_scripts/test_effects.py              |   79 ++++++
 tests/dogtail_scripts/test_help_func.py            |  125 +++++++++
 tests/dogtail_scripts/test_medialibrary.py         |   30 +++
 tests/dogtail_scripts/test_project.py              |  267 ++++++++++++++++++++
 tests/dogtail_scripts/test_timeline.py             |  235 +++++++++++++++++
 tests/samples/1sec_simpsons_trailer.mp4            |  Bin 0 -> 232417 bytes
 tests/samples/flat_colour4_1600x1200.jpg           |  Bin 0 -> 23048 bytes
 tests/samples/flat_colour5_1600x1200.jpg           |  Bin 0 -> 23048 bytes
 14 files changed, 1013 insertions(+), 0 deletions(-)
---
diff --git a/tests/dogtail_scripts/helper_functions.py b/tests/dogtail_scripts/helper_functions.py
new file mode 100644
index 0000000..0a30ad9
--- /dev/null
+++ b/tests/dogtail_scripts/helper_functions.py
@@ -0,0 +1,25 @@
+import os
+from dogtail.predicate import GenericPredicate
+import dogtail.rawinput
+from time import sleep
+
+
+def improved_drag(fromcord, tocord, middle=[], absolute=True, moveAround=True):
+    dogtail.rawinput.press(fromcord[0], fromcord[1])
+    if moveAround:
+        dogtail.rawinput.relativeMotion(5, 5)
+        dogtail.rawinput.relativeMotion(-5, -5)
+    if absolute:
+        fun = dogtail.rawinput.absoluteMotion
+    else:
+        fun = dogtail.rawinput.relativeMotion
+    for mid in middle:
+        fun(mid[0], mid[1])
+        if moveAround:
+            dogtail.rawinput.relativeMotion(5, 5)
+            dogtail.rawinput.relativeMotion(-5, -5)
+    dogtail.rawinput.absoluteMotion(tocord[0], tocord[1])
+    if moveAround:
+        dogtail.rawinput.relativeMotion(5, 5)
+        dogtail.rawinput.relativeMotion(-5, -5)
+    dogtail.rawinput.release(tocord[0], tocord[1])
diff --git a/tests/dogtail_scripts/test_base.py b/tests/dogtail_scripts/test_base.py
new file mode 100644
index 0000000..5c1e5c4
--- /dev/null
+++ b/tests/dogtail_scripts/test_base.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+import unittest
+import os
+from dogtail.predicate import GenericPredicate
+
+
+class BaseDogTail(unittest.TestCase):
+    def setUp(self):
+        # Force the locale/language to English.
+        # Otherwise we won't be able to grab the right widgets.
+        os.environ["LC_ALL"] = 'C'
+        # Try to speed up UI interaction a little
+        from dogtail.config import config
+        config.load({'actionDelay': 0.1,
+                     'typingDelay': 0.02,
+                     'runTimeout': 1,
+                     'searchCutoffCount': 5,
+                     'defaultDelay': 0.1})
+        from dogtail.utils import run
+        from dogtail.tree import root
+        # Setting appName is critically important here.
+        # Otherwise it will try to look for "bin/pitivi" through AT-SPI and fail,
+        # making the tests take ages to start up.
+        self.pid = run('bin/pitivi', dumb=False, appName="pitivi")
+        self.pitivi = root.application('pitivi')
+        self.menubar = self.pitivi.child(roleName='menu bar')
+        try:
+            self.unlink
+        except AttributeError:
+            self.unlink = []
+
+    def tearDown(self, clean=True):
+        # Try to kill pitivi before leaving test
+        os.system("kill -9 %i" % self.pid)
+        if clean:
+            for filename in self.unlink:
+                try:
+                    os.unlink(filename)
+                except:
+                    None
diff --git a/tests/dogtail_scripts/test_clipproperties.py b/tests/dogtail_scripts/test_clipproperties.py
new file mode 100644
index 0000000..22233e6
--- /dev/null
+++ b/tests/dogtail_scripts/test_clipproperties.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env python
+from test_help_func import HelpFunc
+from dogtail.predicate import GenericPredicate
+import dogtail.rawinput
+from time import sleep
+
+
+class ClipTransforamtionTest(HelpFunc):
+    def test_transformation_options(self):
+        #Load sample
+        sample = self.import_media()
+        self.insert_clip(sample)
+
+        timeline = self.get_timeline()
+        clippos = []
+        clippos.append((timeline.position[0] + 20, timeline.position[1] + 20))
+        clippos.append((timeline.position[0] + timeline.size[0] / 2, timeline.position[1] + 20))
+        dogtail.rawinput.click(clippos[0][0], clippos[0][1])
+
+        conftab = self.pitivi.tab("Clip configuration")
+        conftab.click()
+        conftab.child(name="Transformation", roleName="toggle button").click()
+        #Just try changing values
+        #Test slider
+        self.assertEqual(conftab.child(roleName="slider").value, 1)
+        conftab.child(roleName="slider").click()
+        self.assertNotEqual(conftab.child(roleName="slider").value, 1)
+
+        #Test position
+        spinb = conftab.child(roleName="panel", name="Position").findChildren(GenericPredicate(roleName="spin button"))
+        self.assertEqual(len(spinb), 2)
+        spinb[0].text = "0.3"
+        spinb[1].text = "0.2"
+
+        #Test size
+        spinb = conftab.child(roleName="panel", name="Size").findChildren(GenericPredicate(roleName="spin button"))
+        self.assertEqual(len(spinb), 2)
+        spinb[0].text = "0.4"
+        spinb[1].text = "0.1"
+
+        #Test crop
+        spinb = conftab.child(roleName="panel", name="Crop").findChildren(GenericPredicate(roleName="spin button"))
+        self.assertEqual(len(spinb), 4)
+        spinb[0].text = "0.05"
+        spinb[1].text = "0.12"
+        spinb[2].text = "0.14"
+        spinb[3].text = "0.07"
+
+        #Click second clip, look that settings not changed(not linked)
+        dogtail.rawinput.click(clippos[1][0], clippos[1][1])
+        self.assertEqual(conftab.child(roleName="slider").value, 1.0)
+
+        #Click back, look if settings saved
+        dogtail.rawinput.click(clippos[0][0], clippos[0][1])
+        self.assertNotEqual(conftab.child(roleName="slider").value, 1.0)
+
+        self.assertNotNone(self.search_by_text("0.3", conftab.child(roleName="panel", name="Position")))
+        self.assertNotNone(self.search_by_text("0.2", conftab.child(roleName="panel", name="Position")))
+
+        self.assertNotNone(self.search_by_text("0.4", conftab.child(roleName="panel", name="Size")))
+        self.assertNotNone(self.search_by_text("0.1", conftab.child(roleName="panel", name="Size")))
+
+        self.assertNotNone(self.search_by_text("0.05", conftab.child(roleName="panel", name="Crop")))
+        self.assertNotNone(self.search_by_text("0.12", conftab.child(roleName="panel", name="Crop")))
+        self.assertNotNone(self.search_by_text("0.14", conftab.child(roleName="panel", name="Crop")))
+        self.assertNotNone(self.search_by_text("0.07", conftab.child(roleName="panel", name="Crop")))
+
+        #Push clear
+        conftab.child(roleName="scroll bar").value = 140
+        conftab.button("Clear")
+
+        self.assertEqual(conftab.child(roleName="slider").value, 1.0)
+
+        self.assertNone(self.search_by_text("0.3", conftab.child(roleName="panel", name="Position")))
+        self.assertNone(self.search_by_text("0.2", conftab.child(roleName="panel", name="Position")))
+
+        self.assertNone(self.search_by_text("0.4", conftab.child(roleName="panel", name="Size")))
+        self.assertNone(self.search_by_text("0.1", conftab.child(roleName="panel", name="Size")))
+
+        self.assertNone(self.search_by_text("0.05", conftab.child(roleName="panel", name="Crop")))
+        self.assertNone(self.search_by_text("0.12", conftab.child(roleName="panel", name="Crop")))
+        self.assertNone(self.search_by_text("0.14", conftab.child(roleName="panel", name="Crop")))
+        self.assertNone(self.search_by_text("0.07", conftab.child(roleName="panel", name="Crop")))
diff --git a/tests/dogtail_scripts/test_dialogs_clipmediaprops.py b/tests/dogtail_scripts/test_dialogs_clipmediaprops.py
new file mode 100644
index 0000000..1853b47
--- /dev/null
+++ b/tests/dogtail_scripts/test_dialogs_clipmediaprops.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+from test_help_func import HelpFunc
+from dogtail.tree import SearchError
+from dogtail.predicate import GenericPredicate, IsATextEntryNamed
+
+
+class DialogsClipMediaPropsTest(HelpFunc):
+    def test_clip_props_dialog(self):
+        sample = self.import_media("flat_colour1_640x480.png")
+        sample.click(3)
+        buttons = self.pitivi.findChildren(GenericPredicate(name="Clip Properties..."))
+        buttons[1].click()
+
+        #Check if we have real info, can't check if in correct place.
+        dialog = self.pitivi.child(name="Clip Properties", roleName="dialog")
+        labels = {"640", "480"}
+        real_labels = set([])
+        for label in dialog.findChildren(GenericPredicate(roleName="label")):
+            real_labels.add(label.text)
+        self.assertEqual(len(labels.difference(real_labels)), 0, "Not all info is displayed")
+        self.assertFalse(dialog.child(name="Audio:", roleName="panel").showing)
+        dialog.child(name="Cancel").click()
+        sample.deselect()
+
+        sample = self.import_media()
+        sample.select()
+        self.menubar.menu("Library").click()
+        self.menubar.menuItem("Clip Properties...").click()
+
+        #Check if we have real info, can't check if in correct place.
+        dialog = self.pitivi.child(name="Clip Properties", roleName="dialog")
+        labels = {"1280", "544", "23.976 fps", "Square", "Stereo", "48 KHz", "16 bit"}
+        real_labels = set([])
+        for label in dialog.findChildren(GenericPredicate(roleName="label")):
+            real_labels.add(label.text)
+        self.assertEqual(len(labels.difference(real_labels)), 0, "Not all info is displayed")
+
+        #Uncheck frame rate
+        dialog.child(name="Frame rate:").click()
+        dialog.child(name="Apply to project").click()
+
+        #Check if correctly applied
+        self.menubar.menu("Edit").click()
+        self.pitivi.child(name="Project Settings", roleName="menu item").click()
+        dialog = self.pitivi.child(name="Project Settings", roleName="dialog")
+
+        children = dialog.findChildren(IsATextEntryNamed(""))
+        childtext = {}
+        for child in children:
+                childtext[child.text] = child
+
+        self.assertIn("25:1", childtext)
+        self.assertIn("1:1", childtext)
+        children = dialog.findChildren(GenericPredicate(roleName="spin button"))
+        spintext = {}
+        for child in children:
+                spintext[child.text] = child
+        self.assertIn("1280", spintext)
+        self.assertIn("544", spintext)
diff --git a/tests/dogtail_scripts/test_dialogs_prefs.py b/tests/dogtail_scripts/test_dialogs_prefs.py
new file mode 100644
index 0000000..9181443
--- /dev/null
+++ b/tests/dogtail_scripts/test_dialogs_prefs.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+from test_help_func import HelpFunc
+from dogtail.tree import SearchError
+import dogtail.rawinput
+
+
+class DialogsPreferencesTest(HelpFunc):
+    def test_pref_dialog(self):
+        dogtail.rawinput.pressKey("Esc")
+        self.menubar.menu("Edit").click()
+        self.menubar.child(name="Preferences", roleName="menu item").click()
+        dialog = self.pitivi.child(name="Preferences", roleName="dialog")
+        dialog.child("Reset to Factory Settings", roleName="push button").click()
+
+        #Try choose the font
+        dialog.child(name="Sans", roleName="label").click()
+        fontchooser = self.pitivi.child(name="Pick a Font", roleName="fontchooser")
+        fontchooser.child(name="Serif").click()
+        fontchooser.child(name="OK", roleName="push button").click()
+
+        #Try choose thumbnail gap
+        dialog.child(roleName="spin button").text = "12"
+
+        #Restart pitivi, look if saved
+        dialog.button("Close")
+
+        self.tearDown()
+        self.setUp()
+
+        dogtail.rawinput.pressKey("Esc")
+        self.menubar.menu("Edit").click()
+        self.menubar.child(name="Preferences", roleName="menu item").click()
+        dialog = self.pitivi.child(name="Preferences", roleName="dialog")
+
+        #Just search of such item
+        try:
+            dialog.child(name="Serif", roleName="label")
+        except SearchError:
+            self.fail("Font is not saved")
+        self.assertEqual(dialog.child(roleName="spin button").text, 12)
+
+        #Check revert
+        dialog.child(roleName="spin button").text = "7"
+        dialog.child("Revert", roleName="push button").click()
+        self.assertEqual(dialog.child(roleName="spin button").text, 12, "Spacing is not reverted")
+
+        #Check reset to factory settings
+        dialog.child("Reset to Factory Settings", roleName="push button").click()
+        dialog.child(name="Sans", roleName="label")
+        self.assertEqual(dialog.child(roleName="spin button").text, 5, "Spacing is not reseted")
diff --git a/tests/dogtail_scripts/test_dialogs_startupwizard.py b/tests/dogtail_scripts/test_dialogs_startupwizard.py
new file mode 100644
index 0000000..7ba0545
--- /dev/null
+++ b/tests/dogtail_scripts/test_dialogs_startupwizard.py
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+from test_help_func import HelpFunc
+from time import time, sleep
+
+
+class DialogsStartupWizardTest(HelpFunc):
+    def test_welcome(self):
+        filename = "test_project%i.xptv" % time()
+        #Save project
+        self.pitivi.child(name="New", roleName='push button').click()
+        self.pitivi.child(name="OK", roleName="push button").click()
+        self.saveProject("/tmp/" + filename)
+        sleep(1)
+        #Hacky, but we need to open once more
+        self.tearDown(clean=False)
+        self.setUp()
+        welcome = self.pitivi.child(name="Welcome", roleName="frame")
+        #We expect that just saved project will be in welcome window
+        welcome.child(name=filename)
diff --git a/tests/dogtail_scripts/test_effects.py b/tests/dogtail_scripts/test_effects.py
new file mode 100644
index 0000000..aa88b60
--- /dev/null
+++ b/tests/dogtail_scripts/test_effects.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python
+from test_help_func import HelpFunc
+from helper_functions import improved_drag
+import dogtail.rawinput
+
+
+class EffectLibraryTest(HelpFunc):
+    def test_effect_library(self):
+        #Load sample
+        self.import_media()
+        tab = self.pitivi.tab("Effect Library")
+        tab.click()
+        search = tab.textentry("")
+        iconview = tab.child(roleName="layered pane")
+        combotypes = tab.child(name="All effects", roleName="combo box")
+        #Some test of video effects and search
+        search.text = "Crop"
+        self.assertEqual(len(iconview.children), 3)
+        combotypes.click()
+        tab.menuItem("Colors").click()
+        self.assertEqual(len(iconview.children), 0)
+        combotypes.click()
+        tab.menuItem("Geometry").click()
+        self.assertEqual(len(iconview.children), 3)
+
+        #Audio effects
+        tab.child(name="Video effects", roleName="combo box").click()
+        tab.menuItem("Audio effects").click()
+        search.text = "Equa"
+        #Titles plus 3 plugins, two collumns = 8
+        self.assertEqual(len(tab.child(roleName="table").children), 8)
+
+    def help_test_effect_drag(self):
+        sample = self.import_media()
+        self.insert_clip(sample)
+        timeline = self.get_timeline()
+        clippos = (timeline.position[0] + 20, timeline.position[1] + 20)
+
+        tab = self.pitivi.tab("Effect Library")
+        tab.click()
+        conftab = self.pitivi.tab("Clip configuration")
+        conftab.click()
+        table = conftab.child(roleName="table")
+
+        dogtail.rawinput.click(clippos[0], clippos[1])
+        self.assertTrue(table.sensitive)
+        #No effects added
+        self.assertEqual(len(table.children), 3)
+
+        center = lambda obj: (obj.position[0] + obj.size[0] / 2, obj.position[1] + obj.size[1] / 2)
+        icon = self.search_by_text("Agingtv ", tab, roleName="icon")
+
+        #Drag video effect on the clip
+        improved_drag(center(icon), clippos)
+        self.assertEqual(len(table.children), 6)
+        #Drag video effect to the table
+        icon = self.search_by_text("3Dflippo", tab, roleName="icon")
+        improved_drag(center(icon), center(table))
+        self.assertEqual(len(table.children), 9)
+
+        #Drag audio effect on the clip
+        tab.child(name="Video effects", roleName="combo box").click()
+        tab.menuItem("Audio effects").click()
+        effect = tab.child(name="Amplifier")
+        improved_drag(center(effect), clippos)
+        self.assertEqual(len(table.children), 12)
+
+        #Drag audio effect on the table
+        effect = tab.child(name="Audiokaraoke")
+        improved_drag(center(effect), center(table))
+        self.assertEqual(len(table.children), 15)
+
+    def test_change_effect_settings(self):
+        self.help_test_effect_drag()
+        conftab = self.pitivi.tab("Clip configuration")
+        conftab.child(roleName="table").child(name="audioamplify").click()
+        eftab = conftab.child(name="Effects", roleName="toggle button")
+        eftab.child(name="Normal clipping (default)", roleName="combo box")
+        eftab.child(roleName="spin button").text = "2"
diff --git a/tests/dogtail_scripts/test_help_func.py b/tests/dogtail_scripts/test_help_func.py
new file mode 100644
index 0000000..66a0705
--- /dev/null
+++ b/tests/dogtail_scripts/test_help_func.py
@@ -0,0 +1,125 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+import unittest
+import os
+from dogtail.predicate import GenericPredicate
+from test_base import BaseDogTail
+import dogtail.rawinput
+from time import sleep
+from pyatspi import Registry as registry
+from pyatspi import (KEY_SYM, KEY_PRESS, KEY_PRESSRELEASE, KEY_RELEASE)
+
+
+class HelpFunc(BaseDogTail):
+    def saveProject(self, url=None, saveAs=True):
+        self.menubar.menu("Project").click()
+        if saveAs:
+            #FIXME: cant get working with searching for Save Asâ
+            self.menubar.menu("Project").children[4].click()
+            saveas = self.pitivi.child(roleName='dialog')
+            saveas.child(roleName='text').text = url
+            #Click the Save button.
+            saveas.button('Save').click()
+            #Save for deleting afterwards
+            self.unlink.append(url)
+        else:
+            #Just save
+            self.menubar.menu("Project").menuItem("Save").click()
+
+    def loadProject(self, url, save=False):
+        self.menubar.menu("Project").click()
+        self.menubar.menu("Project").children[2].click()
+        load = self.pitivi.child(roleName='dialog')
+        load.child(name="Type a file name", roleName="toggle button").click()
+        load.child(roleName='text').text = url
+        load.button('Open').click()
+        try:
+            if save:
+                load.child(name="Close without saving", roleName="push button")
+        except:
+            return
+
+    def search_by_text(self, text, parent, name=None, roleName=None):
+        children = parent.findChildren(GenericPredicate(roleName=roleName,
+                                                        name=name))
+        searched = None
+        for child in children:
+            if child.text == text:
+                searched = child
+        return searched
+
+    def insert_clip(self, icon, n=1):
+        icon.select()
+        lib = self.menubar.menu("Library")
+        insert = lib.child("Insert at End of Timeline")
+        for i in range(n):
+            sleep(0.3)
+            lib.click()
+            sleep(0.1)
+            insert.click()
+        icon.deselect()
+
+    def import_media(self, filename="1sec_simpsons_trailer.mp4"):
+        #Just try search for object without retries
+        dogtail.rawinput.pressKey("Esc")
+        self.pitivi.child(name="Import Files...",
+                          roleName="push button").click()
+        add = self.pitivi.child(roleName='dialog')
+        textf = add.findChildren(GenericPredicate(roleName="text"))
+        if len(textf) == 0:
+            add.child(name="Type a file name", roleName="toggle button").click()
+        filepath = os.path.realpath(__file__).split("dogtail_scripts/test_help_func.py")[0]
+        filepath += "samples/" + filename
+        add.child(roleName='text').text = filepath
+        add.button('Add').click()
+        libtab = self.pitivi.tab("Media Library")
+        for i in range(5):
+            icons = libtab.findChildren(GenericPredicate(roleName="icon"))
+            sample = None
+            for icon in icons:
+                if icon.text == filename:
+                    sample = icon
+            if sample is not None:
+                break
+            sleep(0.5)
+        self.assertIsNotNone(sample)
+        return sample
+
+    def import_media_multiple(self, files):
+        dogtail.rawinput.pressKey("Esc")
+        self.pitivi.child(name="Import Files...",
+                          roleName="push button").click()
+        add = self.pitivi.child(roleName='dialog')
+        textf = add.findChildren(GenericPredicate(roleName="text"))
+        if len(textf) == 0:
+            add.child(name="Type a file name", roleName="toggle button").click()
+        filepath = os.path.realpath(__file__).split("dogtail_scripts/test_help_func.py")[0]
+        filepath += "samples/"
+        add.child(roleName='text').click()
+        add.child(roleName='text').text = filepath
+        dogtail.rawinput.pressKey("Enter")
+        #Now select them
+        code = dogtail.rawinput.keyNameToKeyCode("Control_L")
+        registry.generateKeyboardEvent(code, None, KEY_PRESS)
+        for f in files:
+            sleep(1)
+            add.child(name=f).click()
+        registry.generateKeyboardEvent(code, None, KEY_RELEASE)
+        add.button('Add').click()
+        libtab = self.pitivi.tab("Media Library")
+        samples = []
+        for i in range(5):
+            icons = libtab.findChildren(GenericPredicate(roleName="icon"))
+            for icon in icons:
+                for f in files:
+                    if icon.text == f:
+                        samples.append(icon)
+                        files.remove(f)
+            if len(files) == 0:
+                break
+            sleep(0.5)
+        return samples
+
+    def get_timeline(self):
+        #TODO: found better way to identify
+        return self.pitivi.children[0].children[0].children[2].children[1].children[3]
diff --git a/tests/dogtail_scripts/test_medialibrary.py b/tests/dogtail_scripts/test_medialibrary.py
new file mode 100644
index 0000000..dd93b4c
--- /dev/null
+++ b/tests/dogtail_scripts/test_medialibrary.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+from test_help_func import HelpFunc
+
+
+class MediaLibraryTest(HelpFunc):
+    def test_medialibrary(self):
+        #Load few samples
+        samples = []
+        samples.append(self.import_media("flat_colour1_640x480.png"))
+        samples.append(self.import_media("flat_colour2_640x480.png"))
+        samples.append(self.import_media("flat_colour3_320x180.png"))
+        self.insert_clip(samples[0])
+        self.insert_clip(samples[2])
+
+        self.menubar.menu("Library").click()
+        self.menubar.menu("Library").menuItem("Select Unused Media").click()
+        self.assertFalse(samples[0].isSelected)
+        self.assertTrue(samples[1].isSelected)
+        self.assertFalse(samples[2].isSelected)
+
+        tab = self.pitivi.tab("Media Library")
+        iconview = tab.child(roleName="layered pane")
+        self.assertEqual(len(iconview.children), 3)
+        search = tab.textentry("")
+        search.text = "colour2"
+        self.assertEqual(len(iconview.children), 1)
+        search.text = "640"
+        self.assertEqual(len(iconview.children), 2)
+        search.text = ""
+        self.assertEqual(len(iconview.children), 3)
diff --git a/tests/dogtail_scripts/test_project.py b/tests/dogtail_scripts/test_project.py
new file mode 100644
index 0000000..94c4ade
--- /dev/null
+++ b/tests/dogtail_scripts/test_project.py
@@ -0,0 +1,267 @@
+#!/usr/bin/env python
+from test_help_func import HelpFunc
+from dogtail.predicate import IsATextEntryNamed, GenericPredicate
+from time import time, sleep
+import os
+
+
+class ProjectPropertiesTest(HelpFunc):
+    def test_settings_video(self):
+        #Just create new project
+        self.pitivi.child(name="New", roleName='push button').click()
+
+        #Play with project settings, look if they are correctly represented
+        dialog = self.pitivi.child(name="Project Settings", roleName="dialog")
+        video = self.pitivi.tab("Video")
+
+        #Test presets
+        video.child(name="720p24", roleName="table cell").click()
+        children = video.findChildren(IsATextEntryNamed(""))
+        childtext = {}
+        for child in children:
+                childtext[child.text] = child
+
+        self.assertIn("1:1", childtext)
+        self.assertIn("24M", childtext)
+        self.assertIn("16:9", childtext)
+
+        children = video.findChildren(GenericPredicate(roleName="spin button"))
+        spintext = {}
+        for child in children:
+                spintext[child.text] = child
+        self.assertIn("1280", spintext)
+        self.assertIn("720", spintext)
+
+        #Test frame rate combinations, link button
+        frameCombo = video.child(name="23.976 fps", roleName="combo box")
+        frameText = childtext["24M"]
+        frameCombo.click()
+        video.child(name="120 fps", roleName="menu item").click()
+        self.assertEqual(frameText.text, "120:1")
+        frameText.click()
+        frameText.typeText("0")
+        video.child(name="12 fps", roleName="combo box")
+
+        #Test pixel and display ascpect ratio
+        pixelCombo = video.child(name="Square", roleName="combo box")
+        pixelText = childtext["1:1"]
+        displayCombo = video.child(name="DV Widescreen (16:9)",
+                                   roleName="combo box")
+        displayText = childtext["16:9"]
+
+        pixelCombo.click()
+        video.child(name="576p", roleName="menu item").click()
+        self.assertEqual(pixelCombo.combovalue, "576p")
+        self.assertEqual(pixelText.text, "12:11")
+        #self.assertEqual(displayCombo.combovalue, "")
+        self.assertEqual(displayText.text, "64:33")
+
+        pixelText.doubleClick()
+        pixelText.click()
+        pixelText.typeText("3:4")
+        #self.assertEqual(pixelCombo.combovalue, "")
+        self.assertEqual(pixelText.text, "3:4")
+        self.assertEqual(displayCombo.combovalue, "Standard (4:3)")
+        self.assertEqual(displayText.text, "4:3")
+
+        video.child(name="Display aspect ratio",
+                    roleName="radio button").click()
+        displayCombo.click()
+        video.child(name="Cinema (1.37)", roleName="menu item").click()
+        #self.assertEqual(pixelCombo.combovalue, "")
+        self.assertEqual(pixelText.text, "99:128")
+        self.assertEqual(displayCombo.combovalue, "Cinema (1.37)")
+        self.assertEqual(displayText.text, "11:8")
+
+        displayText.doubleClick()
+        displayText.click()
+        displayText.typeText("37:20")
+        #self.assertEqual(pixelCombo.combovalue, "")
+        self.assertEqual(pixelText.text, "333:320")
+        self.assertEqual(displayCombo.combovalue, "Cinema (1.85)")
+        self.assertEqual(displayText.text, "37:20")
+
+        #Test size spin buttons
+        spin = video.findChildren(GenericPredicate(roleName="spin button"))
+        oldtext = spin[1].text
+        spin[0].doubleClick()
+        spin[0].typeText("1000")
+        self.assertEqual(spin[1].text, oldtext)
+        spin[1].doubleClick()
+        spin[1].typeText("2000")
+        video.child(name="Link").click()
+        spin[1].doubleClick()
+        spin[1].typeText("1000")
+        spin[0].click()
+        self.assertEqual(spin[0].text, "500")
+
+        #Create project, test saving without any object
+        self.pitivi.child(name="OK", roleName="push button").click()
+        self.saveProject("/tmp/settings.xptv")
+        #Load project and test settings
+        self.loadProject("/tmp/settings.xptv")
+        self.pitivi.menu("Edit").click()
+        self.pitivi.child(name="Project Settings", roleName="menu item").click()
+
+        video = self.pitivi.tab("Video")
+
+        children = video.findChildren(IsATextEntryNamed(""))
+        childtext = {}
+        for child in children:
+                childtext[child.text] = child
+
+        self.assertIn("333:320", childtext, "Pixel aspect ration not saved")
+        self.assertIn("37:20", childtext, "Display aspect ratio not saved")
+
+        children = video.findChildren(GenericPredicate(roleName="spin button"))
+        spintext = {}
+        for child in children:
+                spintext[child.text] = child
+        self.assertIn("500", spintext, "Video height is not saved")
+        self.assertIn("1000", spintext, "Video width is not saved")
+
+    def wait_for_file(self, path, time_out=20):
+        sleeped = 0
+        exists = False
+        while (sleeped <= time_out) and not exists:
+            sleeped += 2
+            sleep(2)
+            exists = os.path.exists(path)
+        return exists
+
+    def wait_for_update(self, path, timestamp, time_out=20):
+        sleeped = 0
+        new_timestamp = False
+        while (sleeped <= time_out) and new_timestamp == timestamp:
+            sleeped += 2
+            sleep(2)
+            new_timestamp = os.path.getmtime(path)
+        return new_timestamp != timestamp
+
+    def test_backup(self):
+        #Create empty project
+        sample = self.import_media()
+
+        #Save project
+        filename = "test_project%i.xptv" % time()
+        path = "/tmp/" + filename
+        backup_path = path + "~"
+        self.unlink.append(backup_path)
+        self.saveProject("/tmp/" + filename)
+
+        #Change somthing
+        seektime = self.search_by_text("0:00:00.000", self.pitivi, roleName="text")
+        self.assertIsNotNone(seektime)
+        self.insert_clip(sample)
+        self.nextb = self.pitivi.child(name="Next", roleName="push button")
+        self.nextb.click()
+        self.assertEqual(seektime.text, "0:00:01.227")
+
+        #It should save after 10 seconds if no changes made
+        self.assertTrue(self.wait_for_file(backup_path), "Backup not created")
+        self.assertTrue(os.path.getmtime(backup_path) -
+                        os.path.getmtime(path) > 0,
+                        "Backup is older than saved file")
+
+        #Try to quit, it should warn us
+        self.menubar.menu("Project").click()
+        self.menubar.menu("Project").menuItem("Quit").click()
+
+        #If finds button, means it warned
+        self.pitivi.child("Cancel").click()
+        self.saveProject(url=None, saveAs=False)
+        #Backup should be deleted, and no warning displayed
+        self.menubar.menu("Project").click()
+        self.menubar.menu("Project").menuItem("Quit").click()
+        self.assertFalse(os.path.exists(backup_path))
+        #Test if backup is found
+        self.setUp()
+        self.pitivi.child(name=filename).doubleClick()
+        sample = self.import_media("flat_colour1_640x480.png")
+        self.assertTrue(self.wait_for_file(backup_path, 120), "Backup not created")
+        self.tearDown(clean=False)
+        self.setUp()
+        self.pitivi.child(name=filename).doubleClick()
+        #Try restoring from backup
+        self.pitivi.child(name="Restore from backup").click()
+        samples = self.pitivi.tab("Media Library").findChildren(GenericPredicate(roleName="icon"))
+        self.assertEqual(len(samples), 2)
+        self.menubar.menu("Project").click()
+        self.assertFalse(self.menubar.menu("Project").menuItem("Save").sensitive)
+        #Behaved as saveAs
+
+        #Kill once more
+        self.tearDown(clean=False)
+        timestamp = os.path.getmtime(backup_path)
+        self.setUp()
+        self.pitivi.child(name=filename).doubleClick()
+        self.pitivi.child(name="Ignore backup").click()
+        #Backup is not deleted, not changed
+        self.assertEqual(timestamp, os.path.getmtime(backup_path))
+
+        #Look if backup updated, even it is newer than saved project
+
+        sample = self.import_media("flat_colour2_640x480.png")
+        self.assertTrue(self.wait_for_update(backup_path, timestamp))
+        #Try to quit, it should warn us (still newer version)
+        self.menubar.menu("Project").click()
+        self.menubar.menu("Project").menuItem("Quit").click()
+
+        #If finds button, means it warned
+        self.pitivi.child("Cancel").click()
+        self.saveProject(url=None, saveAs=False)
+
+        #Backup should be deleted, and no warning displayed
+        self.menubar.menu("Project").click()
+        self.menubar.menu("Project").menuItem("Quit").click()
+        self.assertFalse(os.path.exists(backup_path))
+
+    def test_load_save(self):
+        self.nextb = self.pitivi.child(name="Next", roleName="push button")
+        tab = self.pitivi.tab("Media Library")
+        seektime = self.search_by_text("0:00:00.000", self.pitivi, roleName="text")
+        infobar_media = tab.child(name="Add media to your project by dragging files and folders here or by using the \"Import Files...\" button.")
+        filename1 = "/tmp/test_project%i.xptv" % time()
+        filename2 = "/tmp/test_project%i.xptv" % time()
+
+        #Create project
+        self.assertTrue(infobar_media.showing)
+        sample = self.import_media()
+        self.insert_clip(sample)
+        self.saveProject(filename1)
+        self.assertFalse(infobar_media.showing)
+
+        #Create new, check if cleaned
+        sleep(0.5)
+        self.menubar.menu("Project").click()
+        self.menubar.menu("Project").menuItem("New").click()
+        self.pitivi.child(name="OK", roleName="push button").click()
+
+        icons = tab.findChildren(GenericPredicate(roleName="icon"))
+        self.nextb.click()
+        self.assertEqual(len(icons), 0)
+        self.assertEqual(seektime.text, "0:00:00.000")
+        self.assertTrue(infobar_media.showing)
+
+        #Create bigger project
+        sample = self.import_media()
+        self.import_media("flat_colour1_640x480.png")
+        self.insert_clip(sample, 2)
+        self.saveProject(filename2)
+        self.assertFalse(infobar_media.showing)
+
+        #Load first, check if populated
+        self.load_project(filename1)
+        icons = tab.findChildren(GenericPredicate(roleName="icon"))
+        self.nextb.click()
+        self.assertEqual(len(icons), 1)
+        self.assertEqual(seektime.text, "0:00:01.227")
+        self.assertFalse(infobar_media.showing)
+
+        #Load second, check if populated
+        self.load_project(filename2)
+        icons = tab.findChildren(GenericPredicate(roleName="icon"))
+        self.nextb.click()
+        self.assertEqual(len(icons), 2)
+        self.assertEqual(seektime.text, "0:00:02.455")
+        self.assertFalse(infobar_media.showing)
diff --git a/tests/dogtail_scripts/test_timeline.py b/tests/dogtail_scripts/test_timeline.py
new file mode 100644
index 0000000..0053a4a
--- /dev/null
+++ b/tests/dogtail_scripts/test_timeline.py
@@ -0,0 +1,235 @@
+#!/usr/bin/env python
+from test_help_func import HelpFunc
+from dogtail.predicate import GenericPredicate
+from helper_functions import improved_drag
+import dogtail.rawinput
+from time import sleep
+from pyatspi import Registry as registry
+from pyatspi import (KEY_SYM, KEY_PRESS, KEY_PRESSRELEASE, KEY_RELEASE)
+
+
+class TimelineTest(HelpFunc):
+    def setUp(self):
+        super(TimelineTest, self).setUp()
+        self.nextb = self.pitivi.child(name="Next", roleName="push button")
+
+    def help_test_insertEnd(self):
+        sample = self.import_media()
+        #Right click
+        seektime = self.search_by_text("0:00:00.000", self.pitivi, roleName="text")
+
+        self.assertIsNotNone(seektime)
+
+        sample.click(3)
+        buttons = self.pitivi.findChildren(
+            GenericPredicate(name="Insert at End of Timeline"))
+        buttons[1].click()
+        self.nextb.click()
+        self.assertEqual(seektime.text, "0:00:01.227")
+
+        #Add one more
+        sample.click(3)
+        buttons = self.pitivi.findChildren(
+            GenericPredicate(name="Insert at End of Timeline"))
+        buttons[1].click()
+        self.nextb.click()
+
+        self.assertEqual(seektime.text, "0:00:02.455")
+
+    def help_test_insertEndFast(self):
+        sample = self.import_media()
+        self.insert_clip(sample, 2)
+        self.nextb.click()
+
+    def test_drag_clip(self):
+        sample = self.import_media()
+        seektime = self.search_by_text("0:00:00.000", self.pitivi, roleName="text")
+        self.assertIsNotNone(seektime)
+
+        timeline = self.get_timeline()
+
+        center = lambda obj: (obj.position[0] + obj.size[0] / 2, obj.position[1] + obj.size[1] / 2)
+        improved_drag(center(sample), center(timeline))
+        self.nextb.click()
+        self.assertNotEqual(seektime.text, "0:00:00.000")
+
+    def test_multiple_drag(self):
+        sample = self.import_media()
+        seektime = self.search_by_text("0:00:00.000", self.pitivi, roleName="text")
+        timeline = self.get_timeline()
+        self.assertIsNotNone(seektime)
+        oldseek = seektime.text
+        center = lambda obj: (obj.position[0] + obj.size[0] / 2, obj.position[1] + obj.size[1] / 2)
+        endpos = []
+        endpos.append((timeline.position[0] + timeline.size[0] - 30, timeline.position[1] + 30))
+        endpos.append((timeline.position[0] + timeline.size[0] - 30, timeline.position[1] + 120))
+        endpos.append((timeline.position[0] + timeline.size[0] - 30, timeline.position[1] + 80))
+        for i in range(20):
+            if (i % 4 == 0):
+                #Drag to center, next layer, out, and then back in
+                improved_drag(center(sample), endpos[i % 3], middle=[center(timeline), endpos[(i + 1) % 2], center(sample)])
+            else:
+                #Simple drag
+                improved_drag(center(sample), endpos[i % 3])
+            #Give time to insert object
+            sleep(0.5)
+            self.nextb.click()
+            self.assertNotEqual(oldseek, seektime.text)
+            oldseek = seektime.text
+
+    def test_split(self):
+        self.help_test_insertEnd()
+        seektime = self.search_by_text("0:00:02.455", self.pitivi, roleName="text")
+        timeline = self.get_timeline()
+        #Adjust to different screen sizes
+        adj = (float)(timeline.size[0]) / 883
+
+        dogtail.rawinput.click(timeline.position[0] + 500 * adj, timeline.position[1] + 50)
+        self.pitivi.child(name="Split", roleName="push button").click()
+        dogtail.rawinput.click(timeline.position[0] + 450 * adj, timeline.position[1] + 50)
+        self.pitivi.child(name="Delete", roleName="push button").click()
+
+        self.nextb.click()
+        self.assertEqual(seektime.text, "0:00:02.455")
+
+        dogtail.rawinput.click(timeline.position[0] + 550 * adj, timeline.position[1] + 50)
+        dogtail.rawinput.pressKey("Del")
+        #self.pitivi.child(name="Delete", roleName="push button").click()
+
+        self.nextb.click()
+        self.assertEqual(seektime.text, "0:00:01.227")
+
+    def test_multiple_split(self):
+        self.help_test_insertEndFast()
+        seektime = self.search_by_text("0:00:02.455", self.pitivi, roleName="text")
+        timeline = self.get_timeline()
+        #Adjust to different screen sizes
+        adj = (float)(timeline.size[0]) / 883
+        tpos = timeline.position
+        pos = [50, 480, 170, 240, 350, 610, 410, 510]
+        #Sleeps needed for atspi
+        for k in pos:
+            for p in pos:
+                dogtail.rawinput.click(tpos[0] + (p + k / 10) * adj, tpos[1] + 50)
+                sleep(0.1)
+                dogtail.rawinput.pressKey("s")
+                #Just search some object to look if it still alive
+                self.pitivi.child(roleName="icon")
+
+    def test_transition(self):
+        self.help_test_insertEndFast()
+        seektime = self.search_by_text("0:00:02.455", self.pitivi, roleName="text")
+        timeline = self.get_timeline()
+        tpos = timeline.position
+
+        #Adjust to different screen sizes
+        adj = (float)(timeline.size[0]) / 883
+
+        dogtail.rawinput.press(tpos[0] + 500 * adj, tpos[1] + 50)
+        #Drag in, drag out, drag in and release
+        dogtail.rawinput.relativeMotion(-200 * adj, 10)
+        sleep(1)
+        dogtail.rawinput.relativeMotion(300 * adj, -10)
+        sleep(1)
+        dogtail.rawinput.absoluteMotion(tpos[0] + 300 * adj, tpos[1] + 50)
+        sleep(1)
+        dogtail.rawinput.release(tpos[0] + 300 * adj, tpos[1] + 50)
+        sleep(1)
+        dogtail.rawinput.click(tpos[0] + 250 * adj, tpos[1] + 50)
+        #Check if we selected transition
+        transitions = self.pitivi.child(name="Transitions", roleName="page tab")
+        iconlist = transitions.child(roleName="layered pane")
+        self.assertTrue(iconlist.sensitive)
+        iconlist.children[-2].select()
+        self.assertTrue(transitions.child(roleName="slider").sensitive)
+        transitions.child(roleName="slider").value = 50
+
+    def search_clip_end(self, y, seek, timeline):
+        minx = timeline.position[0] + 10.
+        maxx = timeline.position[0] + timeline.size[0] - 10.
+        minx = (minx + maxx) / 2
+        y += timeline.position[1]
+        dogtail.rawinput.click(maxx, y)
+        maxseek = seek.text
+        print maxseek
+        while maxx - minx > 2:
+            middle = (maxx + minx) / 2
+            dogtail.rawinput.click(middle, y)
+            sleep(0.1)
+            if seek.text == maxseek:
+                maxx = middle
+            else:
+                minx = middle
+        #+5 due to handle size
+        return maxx - timeline.position[0] + 5
+
+    def test_riple_roll(self):
+        self.help_test_insertEndFast()
+        seektime = self.search_by_text("0:00:02.455", self.pitivi, roleName="text")
+        timeline = self.get_timeline()
+        tpos = timeline.position
+        end = self.search_clip_end(30, seektime, timeline)
+
+        dogtail.rawinput.absoluteMotion(tpos[0] + end / 2 - 2, tpos[1] + 30)
+        registry.generateKeyboardEvent(dogtail.rawinput.keyNameToKeyCode("Control_L"), None, KEY_PRESS)
+        dogtail.rawinput.press(tpos[0] + end / 2 - 2, tpos[1] + 30)
+        sleep(0.5)
+        dogtail.rawinput.absoluteMotion(tpos[0] + end / 2 - 100, tpos[1] + 30)
+        sleep(0.5)
+        dogtail.rawinput.release(tpos[0] + end / 2 - 100, tpos[1] + 30)
+        registry.generateKeyboardEvent(dogtail.rawinput.keyNameToKeyCode("Control_L"), None, KEY_RELEASE)
+        self.nextb.click()
+        self.assertNotEqual(seektime.text, "0:00:02.455", "Not ripled, but trimed")
+
+        #Regresion test of adding effect
+        #Add effect
+        tab = self.pitivi.tab("Effect Library")
+        tab.click()
+        conftab = self.pitivi.tab("Clip configuration")
+        conftab.click()
+        center = lambda obj: (obj.position[0] + obj.size[0] / 2, obj.position[1] + obj.size[1] / 2)
+        table = conftab.child(roleName="table")
+        icon = self.search_by_text("Agingtv ", tab, roleName="icon")
+        improved_drag(center(icon), center(table))
+        self.nextb.click()
+        seekbefore = seektime.text
+        #Try riple and roll
+        dogtail.rawinput.absoluteMotion(tpos[0] + end / 2 - 102, tpos[1] + 30)
+        registry.generateKeyboardEvent(dogtail.rawinput.keyNameToKeyCode("Control_L"), None, KEY_PRESS)
+        dogtail.rawinput.press(tpos[0] + end / 2 - 102, tpos[1] + 30)
+        sleep(0.5)
+        dogtail.rawinput.absoluteMotion(tpos[0] + end / 2 - 200, tpos[1] + 30)
+        sleep(0.5)
+        dogtail.rawinput.release(tpos[0] + end / 2 - 200, tpos[1] + 30)
+        registry.generateKeyboardEvent(dogtail.rawinput.keyNameToKeyCode("Control_L"), None, KEY_RELEASE)
+        self.nextb.click()
+        self.assertNotEqual(seektime.text, seekbefore, "Not ripled affter adding effect")
+
+    def test_image_video_mix(self):
+        files = ["1sec_simpsons_trailer.mp4", "flat_colour2_640x480.png",
+                 "flat_colour4_1600x1200.jpg", "flat_colour1_640x480.png",
+                 "flat_colour3_320x180.png", "flat_colour5_1600x1200.jpg"]
+        samples = self.import_media_multiple(files)
+        seektime = self.search_by_text("0:00:00.000", self.pitivi, roleName="text")
+        timeline = self.get_timeline()
+        tpos = timeline.position
+
+        #One video, one image
+        for sample in samples[1:]:
+            self.insert_clip(sample)
+            self.insert_clip(samples[0])
+
+        end = self.search_clip_end(30, seektime, timeline)
+        cend = end / 11.139
+        dogtail.rawinput.absoluteMotion(tpos[0] + cend - 2, tpos[1] + 30)
+        registry.generateKeyboardEvent(dogtail.rawinput.keyNameToKeyCode("Shift_L"), None, KEY_PRESS)
+        dogtail.rawinput.press(tpos[0] + cend - 2, tpos[1] + 30)
+        sleep(0.5)
+        dogtail.rawinput.absoluteMotion(tpos[0] + cend - 40, tpos[1] + 30)
+        sleep(0.5)
+        dogtail.rawinput.release(tpos[0] + cend - 40, tpos[1] + 30)
+        registry.generateKeyboardEvent(dogtail.rawinput.keyNameToKeyCode("Shift_L"), None, KEY_RELEASE)
+        self.nextb.click()
+        self.assertNotEqual(seektime.text, "0:00:11.139")
+
+        #TODO: do something more with clips
diff --git a/tests/samples/1sec_simpsons_trailer.mp4 b/tests/samples/1sec_simpsons_trailer.mp4
new file mode 100644
index 0000000..640a27d
Binary files /dev/null and b/tests/samples/1sec_simpsons_trailer.mp4 differ
diff --git a/tests/samples/flat_colour4_1600x1200.jpg b/tests/samples/flat_colour4_1600x1200.jpg
new file mode 100644
index 0000000..80499d4
Binary files /dev/null and b/tests/samples/flat_colour4_1600x1200.jpg differ
diff --git a/tests/samples/flat_colour5_1600x1200.jpg b/tests/samples/flat_colour5_1600x1200.jpg
new file mode 100644
index 0000000..ccab6c5
Binary files /dev/null and b/tests/samples/flat_colour5_1600x1200.jpg differ



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