[pitivi] Add tests for ProjectManager.loadProject and fix things in the process.
- From: Edward Hervey <edwardrv src gnome org>
- To: svn-commits-list gnome org
- Subject: [pitivi] Add tests for ProjectManager.loadProject and fix things in the process.
- Date: Fri, 5 Jun 2009 11:38:35 -0400 (EDT)
commit 013ef2efdd64efc216b2e9a552559b4608b0e145
Author: Alessandro Decina <alessandro d gmail com>
Date: Thu Jun 4 19:27:54 2009 +0200
Add tests for ProjectManager.loadProject and fix things in the process.
---
pitivi/application.py | 6 +-
pitivi/formatters/base.py | 22 +++---
pitivi/project.py | 16 +---
pitivi/projectmanager.py | 33 ++++---
pitivi/ui/mainwindow.py | 2 +-
pitivi/ui/propertyeditor.py | 2 +-
tests/test_projectmanager.py | 188 ++++++++++++++++++++++++++++++++++++++++++
7 files changed, 225 insertions(+), 44 deletions(-)
diff --git a/pitivi/application.py b/pitivi/application.py
index 7ed7a4a..b2f506a 100644
--- a/pitivi/application.py
+++ b/pitivi/application.py
@@ -88,7 +88,7 @@ class Pitivi(Loggable, Signallable):
__signals__ = {
"new-project" : ["project"],
- "new-project-loading" : ["project"],
+ "new-project-loading" : ["uri"],
"new-project-loaded" : ["project"],
"new-project-failed" : ["uri", "exception"],
"closing-project" : ["project"],
@@ -172,8 +172,8 @@ class Pitivi(Loggable, Signallable):
projectManager.connect("project-closed",
self._projectManagerProjectClosed)
- def _projectManagerNewProjectLoading(self, projectManager, project):
- self.emit("new-project-loading", project)
+ def _projectManagerNewProjectLoading(self, projectManager, uri):
+ self.emit("new-project-loading", uri)
def _projectManagerNewProjectLoaded(self, projectManager, project):
self.current = project
diff --git a/pitivi/formatters/base.py b/pitivi/formatters/base.py
index c02ab5b..707ca84 100644
--- a/pitivi/formatters/base.py
+++ b/pitivi/formatters/base.py
@@ -33,7 +33,7 @@ from pitivi.factories.base import SourceFactory
class FormatterError(Exception):
pass
-class FormatterURIError(Exception):
+class FormatterURIError(FormatterError):
"""An error occured with a URI"""
class FormatterLoadError(FormatterError):
@@ -63,7 +63,6 @@ class Formatter(Signallable, Loggable):
"""
__signals__ = {
- "new-project-loading": ["project"],
"new-project-loaded": ["project"],
"new-project-failed": ["uri", "exception"],
"missing-uri" : ["uri"]
@@ -92,6 +91,15 @@ class Formatter(Signallable, Loggable):
except FormatterError, e:
self.emit("new-project-failed", location, e)
+ def _validateUri(self, uri):
+ # check if the location is
+ # .. a uri
+ # .. a valid uri
+ # .. a reachable valid uri
+ # FIXME : Allow subclasses to handle this for 'online' (non-file://) URI
+ if not uri_is_valid(uri) or not uri_is_reachable(uri):
+ raise FormatterURIError()
+
def _loadProjectUnchecked(self, location, project=None):
"""
Loads the project from the given location.
@@ -111,15 +119,7 @@ class Formatter(Signallable, Loggable):
project.uri = location
self.log("location:%s, project:%r", location, project)
- self.emit("new-project-loading", project)
-
- # check if the location is
- # .. a uri
- # .. a valid uri
- # .. a reachable valid uri
- # FIXME : Allow subclasses to handle this for 'online' (non-file://) URI
- if not uri_is_valid(location) or not uri_is_reachable(location):
- raise FormatterURIError()
+ self._validateUri(location)
# parse the format (subclasses)
# FIXME : maybe have a convenience method for opening a location
diff --git a/pitivi/project.py b/pitivi/project.py
index a7ad77c..e3eda3b 100644
--- a/pitivi/project.py
+++ b/pitivi/project.py
@@ -24,19 +24,13 @@
Project class
"""
-import os.path
-import gst
-import traceback
-from gettext import gettext as _
from pitivi.log.loggable import Loggable
from pitivi.timeline.timeline import Timeline
-from pitivi.timeline.track import Track
from pitivi.stream import AudioStream, VideoStream
from pitivi.pipeline import Pipeline
from pitivi.factories.timeline import TimelineSourceFactory
from pitivi.sourcelist import SourceList
from pitivi.settings import ExportSettings
-from pitivi.configure import APPNAME
from pitivi.signalinterface import Signallable
from pitivi.action import ViewAction
@@ -44,10 +38,6 @@ class ProjectError(Exception):
"""Project error"""
pass
-class ProjectSaveLoadError(ProjectError):
- """Error while loading/saving project"""
- pass
-
class Project(Signallable, Loggable):
"""The base class for PiTiVi projects
@@ -189,18 +179,16 @@ class Project(Signallable, Loggable):
@type location: C{URI}
@param overwrite: Whether to overwrite existing location.
@type overwrite: C{bool}
-
- @raises ProjectSaveLoadError: If no uri was provided and none was set
- previously.
"""
# import here to break circular import
from pitivi.formatters.format import save_project
+ from pitivi.formatters.base import FormatterError
self.log("saving...")
location = location or self.uri
if location == None:
- raise ProjectSaveLoadError("Location unknown")
+ raise FormatterError("Location unknown")
save_project(self, location or self.uri, self.format,
overwrite)
diff --git a/pitivi/projectmanager.py b/pitivi/projectmanager.py
index 5fd8d69..a4130fb 100644
--- a/pitivi/projectmanager.py
+++ b/pitivi/projectmanager.py
@@ -26,19 +26,21 @@ import gst
from pitivi.project import Project
from pitivi.formatters.format import get_formatter_for_uri
+from pitivi.formatters.base import FormatterLoadError
+
from pitivi.signalinterface import Signallable
from pitivi.log.loggable import Loggable
from pitivi.stream import AudioStream, VideoStream
from pitivi.timeline.track import Track
-
class ProjectManager(Signallable, Loggable):
__signals__ = {
- "new-project-loading": ["project"],
- "new-project-loaded": ["project"],
+ "new-project-loading": ["uri"],
"new-project-failed": ["uri", "exception"],
+ "new-project-loaded": ["project"],
"closing-project": ["project"],
"project-closed": ["project"],
+ "missing-uri": ["formatter", "uri"],
}
def __init__(self):
@@ -49,15 +51,17 @@ class ProjectManager(Signallable, Loggable):
def loadProject(self, uri):
""" Load the given project file"""
- formatter = get_formatter_for_uri(uri)
+ self.emit("new-project-loading", uri)
+
+ formatter = self._getFormatterForUri(uri)
if not formatter:
self.emit("new-project-failed", uri,
- Exception(_("Not a valid project file.")))
+ FormatterLoadError(_("Not a valid project file.")))
return
if not self.closeRunningProject():
self.emit("new-project-failed", uri,
- Exception(_("Couldn't close current project")))
+ FormatterLoadError(_("Couldn't close current project")))
return
project = formatter.newProject()
@@ -69,6 +73,9 @@ class ProjectManager(Signallable, Loggable):
""" close the current project """
self.info("closing running project")
+ if self.current is None:
+ return True
+
if self.current.hasUnsavedModifications():
if not self.current.save():
return False
@@ -88,8 +95,9 @@ class ProjectManager(Signallable, Loggable):
if self.current is not None and not self.closeRunningProject():
return
+ # we don't have an URI here, None means we're loading a new project
+ self.emit("new-project-loading", None)
project = Project(_("New Project"))
- self.emit("new-project-loading", project)
self.current = project
# FIXME: this should not be hard-coded
@@ -104,10 +112,11 @@ class ProjectManager(Signallable, Loggable):
self.emit("new-project-loaded", self.current)
+ def _getFormatterForUri(self, uri):
+ return get_formatter_for_uri(uri)
+
def _connectToFormatter(self, formatter):
formatter.connect("missing-uri", self._formatterMissingURICb)
- formatter.connect("new-project-loading",
- self._formatterNewProjectLoading)
formatter.connect("new-project-loaded",
self._formatterNewProjectLoaded)
formatter.connect("new-project-failed",
@@ -115,13 +124,9 @@ class ProjectManager(Signallable, Loggable):
def _disconnectFromFormatter(self, formatter):
formatter.disconnect_by_function(self._formatterMissingURICb)
- formatter.disconnect_by_function(self._formatterNewProjectLoading)
formatter.disconnect_by_function(self._formatterNewProjectLoaded)
formatter.disconnect_by_function(self._formatterNewProjectFailed)
- def _formatterNewProjectLoading(self, formatter, project):
- self.emit("new-project-loading", project)
-
def _formatterNewProjectLoaded(self, formatter, project):
self._disconnectFromFormatter(formatter)
@@ -137,4 +142,4 @@ class ProjectManager(Signallable, Loggable):
self.emit("new-project-failed", uri, exception)
def _formatterMissingURICb(self, formatter, uri):
- self.emit("missing-uri", formatter, uri)
+ return self.emit("missing-uri", formatter, uri)
diff --git a/pitivi/ui/mainwindow.py b/pitivi/ui/mainwindow.py
index 60bdd11..469b1b9 100644
--- a/pitivi/ui/mainwindow.py
+++ b/pitivi/ui/mainwindow.py
@@ -638,13 +638,13 @@ class PitiviMainWindow(gtk.Window, Loggable):
@handler(app, "new-project-loaded")
def _newProjectLoadedCb(self, unused_pitivi, project):
self.log("A NEW project is loaded, update the UI!")
+ self.project = project
# ungrey UI
self.set_sensitive(True)
@handler(app, "new-project-loading")
def _newProjectLoadingCb(self, unused_instance, project):
self.log("A NEW project is being loaded, deactivate UI")
- self.project = project
# grey UI
self.set_sensitive(False)
diff --git a/pitivi/ui/propertyeditor.py b/pitivi/ui/propertyeditor.py
index e35e73a..556e71f 100644
--- a/pitivi/ui/propertyeditor.py
+++ b/pitivi/ui/propertyeditor.py
@@ -87,7 +87,7 @@ class PropertyEditor(gtk.ScrolledWindow):
instance = receiver()
- @handler(instance, "new-project-loading")
+ @handler(instance, "new-project-loaded")
def _newProjectLoading(self, unused_inst, project):
self.timeline = project.timeline
diff --git a/tests/test_projectmanager.py b/tests/test_projectmanager.py
new file mode 100644
index 0000000..9a930b5
--- /dev/null
+++ b/tests/test_projectmanager.py
@@ -0,0 +1,188 @@
+# PiTiVi , Non-linear video editor
+#
+# tests/test_projectmanager.py
+#
+# Copyright (c) 2009, Alessandro Decina <alessandro d gmail 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., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+from unittest import TestCase
+
+from pitivi.projectmanager import ProjectManager
+from pitivi.formatters.base import Formatter, \
+ FormatterError, FormatterLoadError
+
+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-failed", "missing-uri"):
+ self.manager.connect(signal, self._recordSignal, signal)
+
+ def _recordSignal(self, *args):
+ signal = args[-1]
+ args = args[1:-1]
+ self.signals.append((signal, args))
+
+
+class TestProjectManager(TestCase):
+ def setUp(self):
+ self.manager = ProjectManager()
+ 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)
+ self.failUnlessEqual(len(self.signals), 2)
+
+ # loading
+ name, args = self.signals[0]
+ self.failUnlessEqual(args[0], uri)
+
+ # failed
+ name, args = self.signals[1]
+ self.failUnlessEqual(name, "new-project-failed")
+ signalUri, exception = args
+ self.failUnlessEqual(uri, signalUri)
+ self.failUnless(isinstance(exception, FormatterLoadError))
+
+ def testLoadProjectFailedCloseCurrent(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.loadProject(uri)
+ self.failUnlessEqual(len(self.signals), 2)
+
+ # loading
+ name, args = self.signals[0]
+ self.failUnlessEqual(args[0], uri)
+
+ # failed
+ name, args = self.signals[1]
+ self.failUnlessEqual(name, "new-project-failed")
+ signalUri, exception = args
+ self.failUnlessEqual(uri, signalUri)
+ self.failUnless(isinstance(exception, FormatterLoadError))
+ self.failUnless(state["tried-close"])
+
+ def testLoadProjectFailedProxyFormatter(self):
+ """
+ Check that new-project-failed is proxied when a formatter emits it.
+ """
+ class FailFormatter(Formatter):
+ def _validateUri(self, uri):
+ pass
+
+ def _parse(self, location, project=None):
+ raise FormatterError()
+ self.manager._getFormatterForUri = lambda uri: FailFormatter()
+
+ uri = "file:///Untitled.xptv"
+ self.manager.loadProject(uri)
+ self.failUnlessEqual(len(self.signals), 2)
+
+ # loading
+ name, args = self.signals[0]
+ self.failUnlessEqual(args[0], uri)
+
+ # failed
+ name, args = self.signals[1]
+ self.failUnlessEqual(name, "new-project-failed")
+ signalUri, exception = args
+ self.failUnlessEqual(uri, signalUri)
+ self.failUnless(isinstance(exception, FormatterError))
+
+ def testLoadProjectMissingUri(self):
+ class FailFormatter(Formatter):
+ def _validateUri(self, uri):
+ pass
+
+ def _parse(self, location, project=None):
+ pass
+
+ def _getSources(self):
+ # this will emit missing-uri
+ self.validateSourceURI("file:///icantpossiblyexist")
+ return []
+
+ def _fillTimeline(self):
+ pass
+ self.manager._getFormatterForUri = lambda uri: FailFormatter()
+
+ uri = "file:///Untitled.xptv"
+ self.manager.loadProject(uri)
+ self.failUnlessEqual(len(self.signals), 3)
+
+ # loading
+ name, args = self.signals[0]
+ self.failUnlessEqual(args[0], uri)
+
+ # failed
+ name, args = self.signals[1]
+ self.failUnlessEqual(name, "missing-uri")
+ formatter, signalUri = args
+ self.failUnlessEqual(signalUri, "file:///icantpossiblyexist")
+
+
+ def testLoadProjectLoaded(self):
+ class FailFormatter(Formatter):
+ def _validateUri(self, uri):
+ pass
+
+ def _parse(self, location, project=None):
+ pass
+
+ def _getSources(self):
+ return []
+
+ def _fillTimeline(self):
+ pass
+ self.manager._getFormatterForUri = lambda uri: FailFormatter()
+
+ uri = "file:///Untitled.xptv"
+ self.manager.loadProject(uri)
+ self.failUnlessEqual(len(self.signals), 2)
+
+ # loading
+ name, args = self.signals[0]
+ self.failUnlessEqual(args[0], uri)
+
+ # failed
+ name, args = self.signals[1]
+ self.failUnlessEqual(name, "new-project-loaded")
+ project = args[0]
+ self.failUnlessEqual(uri, project.uri)
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]