[pitivi] tests: Update the ProjectManager unittests



commit 2806feb969df997f85486db26b6547d40543a5d9
Author: Alexandru Băluț <alexandru balut gmail com>
Date:   Wed Jan 29 20:54:20 2014 +0100

    tests: Update the ProjectManager unittests
    
    Also moved them to test_project.py so they can be found easily since the
    ProjectManager class is in project.py.

 pitivi/project.py            |   13 +-
 pitivi/utils/misc.py         |    4 +-
 tests/Makefile.am            |    1 -
 tests/test_project.py        |  268 +++++++++++++++++++++++++++++-
 tests/test_projectmanager.py |  378 ------------------------------------------
 5 files changed, 275 insertions(+), 389 deletions(-)
---
diff --git a/pitivi/project.py b/pitivi/project.py
index 55b2c7a..41bd23c 100644
--- a/pitivi/project.py
+++ b/pitivi/project.py
@@ -250,7 +250,7 @@ class ProjectManager(Signallable, Loggable):
         """
         if self.disable_save is True and (backup is True or uri is None):
             self.log("Read-only mode is enforced and no new URI was specified, ignoring save request")
-            return
+            return False
 
         if backup:
             if self.current_project is not None and self.current_project.uri is not None:
@@ -260,7 +260,7 @@ class ProjectManager(Signallable, Loggable):
                 # Do not try to save backup files for blank projects.
                 # It is possible that self.current_project.uri == None when the backup
                 # timer sent us an old instance of the (now closed) project.
-                return
+                return False
         elif uri is None:
             # "Normal save" scenario. The filechoosers in mainwindow ask users
             # for permission to overwrite the file (if needed), so we're safe.
@@ -274,7 +274,7 @@ class ProjectManager(Signallable, Loggable):
                 # TODO: this will not be needed when GTK+ bug #601451 is fixed
                 self.emit("save-project-failed", uri,
                           _("You do not have permissions to write to this folder."))
-                return
+                return False
 
         try:
             # "overwrite" is always True: our GTK filechooser save dialogs are
@@ -509,8 +509,6 @@ class Project(Loggable, GES.Project):
     @type timeline: L{GES.Timeline}
     @ivar pipeline: The timeline's pipeline
     @type pipeline: L{Pipeline}
-    @ivar format: The format under which the project is currently stored.
-    @type format: L{FormatterClass}
     @ivar loaded: Whether the project is fully loaded or not.
     @type loaded: C{bool}
 
@@ -867,11 +865,12 @@ class Project(Loggable, GES.Project):
     #--------------------------------------------#
     #               Our API                      #
     #--------------------------------------------#
+
     def createTimeline(self):
         """
-        The pitivi.Project handle 1 timeline at a time
-        unlike GES.Project
+        Load the project.
         """
+        # In this extract call the project is loaded from the file.
         self.timeline = self.extract()
         if self.timeline is None:
             return False
diff --git a/pitivi/utils/misc.py b/pitivi/utils/misc.py
index 85e2d22..e1a7f1b 100644
--- a/pitivi/utils/misc.py
+++ b/pitivi/utils/misc.py
@@ -123,7 +123,7 @@ def uri_is_valid(uri):
     Will also check if the size is valid (> 0).
 
     @param uri: The location to check
-    @type uri: C{URI}
+    @type uri: C{str}
     """
     return (Gst.uri_is_valid(uri) and
             Gst.uri_get_protocol(uri) == "file" and
@@ -134,7 +134,7 @@ def uri_is_reachable(uri):
     """ Check whether the given uri is reachable by GStreamer.
 
     @param uri: The location to check
-    @type uri: C{URI}
+    @type uri: C{str}
     @return: C{True} if the uri is reachable.
     @rtype: C{bool}
     """
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 69a1cfb..a2ae3ea 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -11,7 +11,6 @@ tests =       \
        test_prefs.py \
        test_preset.py \
        test_project.py \
-       test_projectmanager.py \
        test_projectsettings.py \
        test_signallable.py \
        test_system_gnome.py \
diff --git a/tests/test_project.py b/tests/test_project.py
index 1f3f43c..41c9adf 100644
--- a/tests/test_project.py
+++ b/tests/test_project.py
@@ -1,5 +1,6 @@
 # -*- coding: utf-8 -*-
 #
+# Copyright (c) 2009, Alessandro Decina <alessandro d gmail com>
 # Copyright (c) 2013, Alex Băluț <alexandru balut gmail com>
 #
 # This program is free software; you can redistribute it and/or
@@ -19,13 +20,278 @@
 
 import os
 import tempfile
+import time
 
 from unittest import TestCase
 
 from gi.repository import GES
 from gi.repository import GLib
 
-from pitivi.project import Project
+from pitivi.project import Project, ProjectManager
+from pitivi.utils.misc import uri_is_reachable
+
+
+class MockProject(object):
+    settings = None
+    format = None
+    uri = None
+    has_mods = True
+
+    def hasUnsavedModifications(self):
+        return self.has_mods
+
+    def release(self):
+        pass
+
+    def disconnect_by_function(self, ignored):
+        pass
+
+
+class ProjectManagerListener(object):
+    def __init__(self, manager):
+        self.manager = manager
+        self.connectToProjectManager(self.manager)
+        self._reset()
+
+    def _reset(self):
+        self.signals = []
+
+    def connectToProjectManager(self, manager):
+        for signal in ("new-project-loading", "new-project-loaded",
+                "new-project-created", "new-project-failed", "missing-uri",
+                "closing-project", "project-closed"):
+            self.manager.connect(signal, self._recordSignal, signal)
+
+    def _recordSignal(self, *args):
+        signal = args[-1]
+        args = args[1:-1]
+        self.signals.append((signal, args))
+
+        return True
+
+
+class TestProjectManager(TestCase):
+    def setUp(self):
+        self.manager = ProjectManager(None)
+        self.listener = ProjectManagerListener(self.manager)
+        self.signals = self.listener.signals
+
+    def testLoadProjectFailedUnknownFormat(self):
+        """
+        Check that new-project-failed is emitted when we don't have a suitable
+        formatter.
+        """
+        uri = "file:///Untitled.meh"
+        self.manager.loadProject(uri)
+
+        # loading
+        name, args = self.signals[0]
+        self.assertEqual(uri, args[0], self.signals)
+
+        # failed
+        name, args = self.signals[1]
+        self.assertEqual("new-project-failed", name)
+        signalUri, unused_message = args
+        self.assertEqual(uri, signalUri, self.signals)
+
+    def testLoadProjectClosesCurrent(self):
+        """
+        Check that new-project-failed is emited if we can't close the current
+        project instance.
+        """
+        state = {"tried-close": False}
+
+        def close():
+            state["tried-close"] = True
+            return False
+        self.manager.closeRunningProject = close
+
+        uri = "file:///Untitled.xptv"
+        self.manager.current_project = MockProject()
+        self.manager.loadProject(uri)
+
+        self.assertEqual(0, len(self.signals))
+        self.failUnless(state["tried-close"], self.signals)
+
+    def testLoadProject(self):
+        self.manager.newBlankProject()
+
+        name, args = self.signals[0]
+        self.assertEqual("new-project-loading", name, self.signals)
+
+        name, args = self.signals[1]
+        self.assertEqual("new-project-created", name, self.signals)
+
+        name, args = self.signals[2]
+        self.assertEqual("new-project-loaded", name, self.signals)
+
+    def testMissingUriForwarded(self):
+        def quit(mainloop):
+            mainloop.quit()
+
+        def missingUriCb(self, project, error, clip_asset, mainloop, result):
+            print project, error, clip_asset, mainloop, result
+            result[0] = True
+            mainloop.quit()
+
+        self.mainloop = GLib.MainLoop()
+
+        result = [False]
+        self.manager.connect("missing-uri", missingUriCb, self.mainloop, result)
+
+        # Load a project with a missing asset.
+        unused, xges_path = tempfile.mkstemp()
+        with open(xges_path, "w") as xges:
+            xges.write("""<ges version='0.1'>
+  <project>
+    <ressources>
+      <asset id='file:///icantpossiblyexist.png' extractable-type-name='GESUriClip' />
+    </ressources>
+    <timeline>
+      <track caps='video/x-raw' track-type='4' track-id='0' />
+      <layer priority='0'>
+        <clip id='0' asset-id='file:///icantpossiblyexist.png' type-name='GESUriClip' layer-priority='0' 
track-types='4' start='0' duration='2590000000' inpoint='0' rate='0' />
+      </layer>
+    </timeline>
+</project>
+</ges>""")
+        uri = "file://%s" % xges_path
+        try:
+            self.assertTrue(self.manager.loadProject(uri))
+
+            GLib.timeout_add_seconds(5, quit, self.mainloop)
+            self.mainloop.run()
+            self.assertTrue(result[0], "missing not missing")
+        finally:
+            os.remove(xges_path)
+
+    def testCloseRunningProjectNoProject(self):
+        self.failUnless(self.manager.closeRunningProject())
+        self.failIf(self.signals)
+
+    def testCloseRunningProjectRefuseFromSignal(self):
+        def closing(manager, project):
+            return False
+
+        self.manager.current_project = MockProject()
+        self.manager.current_project.uri = "file:///ciao"
+        self.manager.connect("closing-project", closing)
+
+        self.failIf(self.manager.closeRunningProject())
+        self.assertEqual(1, len(self.signals))
+        name, args = self.signals[0]
+        self.assertEqual("closing-project", name)
+        project = args[0]
+        self.failUnless(project is self.manager.current_project)
+
+    def testCloseRunningProject(self):
+        current = self.manager.current_project = MockProject()
+        self.failUnless(self.manager.closeRunningProject())
+        self.assertEqual(2, len(self.signals))
+
+        name, args = self.signals[0]
+        self.assertEqual("closing-project", name)
+        project = args[0]
+        self.failUnless(project is current)
+
+        name, args = self.signals[1]
+        self.assertEqual("project-closed", name)
+        project = args[0]
+        self.failUnless(project is current)
+
+        self.failUnless(self.manager.current_project is None)
+
+    def testNewBlankProjectCantCloseCurrent(self):
+        def closing(manager, project):
+            return False
+
+        self.manager.current_project = MockProject()
+        self.manager.current_project.uri = "file:///ciao"
+        self.manager.connect("closing-project", closing)
+        self.failIf(self.manager.newBlankProject())
+        self.assertEqual(1, len(self.signals))
+        signal, args = self.signals[0]
+        self.assertEqual("closing-project", signal)
+
+    def testNewBlankProject(self):
+        self.failUnless(self.manager.newBlankProject())
+        self.assertEqual(3, len(self.signals))
+
+        name, args = self.signals[0]
+        self.assertEqual("new-project-loading", name)
+        uri = args[0]
+        self.failUnless(uri is None)
+
+        name, args = self.signals[1]
+        self.assertEqual("new-project-created", name)
+        project = args[0]
+        self.assertEqual(uri, project.uri)
+
+        name, args = self.signals[2]
+        self.assertEqual("new-project-loaded", name)
+        project = args[0]
+        self.failUnless(project is self.manager.current_project)
+
+    def testSaveProject(self):
+        self.failUnless(self.manager.newBlankProject())
+
+        unused, path = tempfile.mkstemp(suffix=".xges")
+        unused, path2 = tempfile.mkstemp(suffix=".xges")
+        try:
+            uri = "file://" + os.path.abspath(path)
+            uri2 = "file://" + os.path.abspath(path2)
+
+            # Save the project.
+            self.failUnless(self.manager.saveProject(uri=uri, backup=False))
+            self.failUnless(uri_is_reachable(uri))
+
+            # Wait a bit.
+            time.sleep(0.1)
+
+            # Save the project at a new location.
+            self.failUnless(self.manager.saveProject(uri2, backup=False))
+            self.failUnless(uri_is_reachable(uri2))
+
+            # Make sure the old path and the new path have different mtimes.
+            mtime = os.path.getmtime(path)
+            mtime2 = os.path.getmtime(path2)
+            self.assertLess(mtime, mtime2)
+
+            # Wait a bit more.
+            time.sleep(0.1)
+
+            # Save project again under the new path (by omitting uri arg)
+            self.failUnless(self.manager.saveProject(backup=False))
+
+            # regression test for bug 594396
+            # make sure we didn't save to the old URI
+            self.assertEqual(mtime, os.path.getmtime(path))
+            # make sure we did save to the new URI
+            self.assertLess(mtime2, os.path.getmtime(path2))
+        finally:
+            os.remove(path)
+            os.remove(path2)
+
+    def testMakeBackupUri(self):
+        uri = "file:///tmp/x.xges"
+        self.assertEqual(uri + "~", self.manager._makeBackupURI(uri))
+
+    def testBackupProject(self):
+        self.manager.newBlankProject()
+
+        # Assign an uri to the project where it's saved by default.
+        unused, xges_path = tempfile.mkstemp(suffix=".xges")
+        uri = "file://" + os.path.abspath(xges_path)
+        self.manager.current_project.uri = uri
+        # This is where the automatic backup file is saved.
+        backup_uri = self.manager._makeBackupURI(uri)
+
+        # Save the backup
+        self.assertTrue(self.manager.saveProject(self.manager.current_project, backup=True))
+        self.failUnless(uri_is_reachable(backup_uri))
+
+        self.manager.closeRunningProject()
+        self.assertFalse(uri_is_reachable(backup_uri), "Backup file not deleted when project closed")
 
 
 class TestProjectLoading(TestCase):


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