From fe07a6fa0fa0d67d2ada6be1f3da2cb128f9038b Mon Sep 17 00:00:00 2001 From: mike Date: Fri, 06 Nov 2009 02:57:47 +0000 Subject: LP 448319 : Provide a Resource Property for addons --- diff --git a/tests/constraintstests.py b/tests/constraintstests.py index 4e19a92..a5ccf26 100644 --- a/tests/constraintstests.py +++ b/tests/constraintstests.py @@ -240,5 +240,47 @@ class FileConstraintTest(unittest.TestCase): except FileConstraintError: pass +class ResourceConstraintTest(unittest.TestCase): + def test_valid_names(self): + name1 = "file_" + unicode(uuid.uuid1()) + ".png" + name2 = unicode(uuid.uuid1()) + "_" + unicode(uuid.uuid1()) + ".extension" + name3 = "/home/user/.sugar/_random/new_image1231_" + unicode(uuid.uuid1()).upper() + ".mp3" + name4 = "a_" + unicode(uuid.uuid1()) + name5 = "" + + cons = ResourceConstraint() + + # All of those names should pass without exceptions + cons.validate(name1) + cons.validate(name2) + cons.validate(name3) + cons.validate(name4) + cons.validate(name5) + + def test_invalid_names(self): + bad_name1 = ".jpg" + bad_name2 = "_.jpg" + bad_name3 = "_" + unicode(uuid.uuid1()) + + cons = ResourceConstraint() + + try: + cons.validate(bad_name1) + assert False, "%s should not be a valid resource name" % bad_name1 + except ResourceConstraintError: + pass + + try: + cons.validate(bad_name2) + assert False, "%s should not be a valid resource name" % bad_name2 + except ResourceConstraintError: + pass + + try: + cons.validate(bad_name3) + assert False, "%s should not be a valid resource name" % bad_name3 + except ResourceConstraintError: + pass + if __name__ == "__main__": unittest.main() diff --git a/tests/propertiestests.py b/tests/propertiestests.py index 2494ea6..f07bd43 100644 --- a/tests/propertiestests.py +++ b/tests/propertiestests.py @@ -579,6 +579,63 @@ class TAddonPropertyList(unittest.TestCase): obj1.addonlist = [klass1(), klass1(), wrongAddon(), klass1()] except ValueError: pass + +class TResourcePropertyTest(unittest.TestCase): + def test_valid_names(self): + class klass1(TPropContainer): + res = TResourceProperty() + + name1 = "file_" + unicode(uuid.uuid1()) + ".png" + name2 = unicode(uuid.uuid1()) + "_" + unicode(uuid.uuid1()) + ".extension" + name3 = "/home/user/.sugar/_random/new_image1231_" + unicode(uuid.uuid1()).upper() + ".mp3" + name4 = "a_" + unicode(uuid.uuid1()) + name5 = "" + + obj1 = klass1() + + obj1.res = name1 + assert obj1.res == name1, "Could not assign the valid name correctly : %s" % name1 + + obj1.res = name2 + assert obj1.res == name2, "Could not assign the valid name correctly : %s" % name2 + + obj1.res = name3 + assert obj1.res == name3, "Could not assign the valid name correctly : %s" % name3 + + obj1.res = name4 + assert obj1.res == name4, "Could not assign the valid name correctly : %s" % name4 + + obj1.res = name5 + assert obj1.res == name5, "Could not assign the valid name correctly : %s" % name5 + + def test_invalid_names(self): + class klass1(TPropContainer): + res = TResourceProperty() + + bad_name1 = ".jpg" + bad_name2 = "_.jpg" + bad_name3 = "_" + unicode(uuid.uuid1()) + + obj1 = klass1() + + try: + obj1.res = bad_name1 + assert False, "A invalid name was accepted : %s" % bad_name1 + except ResourceConstraintError: + pass + + try: + obj1.res = bad_name2 + assert False, "A invalid name was accepted : %s" % bad_name2 + except ResourceConstraintError: + pass + + try: + obj1.res = bad_name3 + assert False, "A invalid name was accepted : %s" % bad_name3 + except ResourceConstraintError: + pass + if __name__ == "__main__": unittest.main() diff --git a/tutorius/constraints.py b/tutorius/constraints.py index 519bce8..cd71167 100644 --- a/tutorius/constraints.py +++ b/tutorius/constraints.py @@ -24,6 +24,8 @@ for some properties. # For the File Constraint import os +# For the Resource Constraint +import re class ConstraintException(Exception): """ @@ -214,3 +216,40 @@ class FileConstraint(Constraint): raise FileConstraintError("Non-existing file : %s"%value) return +class ResourceConstraintError(ConstraintException): + pass + +class ResourceConstraint(Constraint): + """ + Ensures that the value is looking like a resource name, like + _[.]. We are not validating that this is a + valid resource for the reason that the property does not have any notion + of tutorial guid. + + TODO : Find a way to properly validate resources by looking them up in the + Vault. + """ + + # Regular expression to parse a resource-like name + resource_regexp_text = "(.+)_([a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})(\..*)?$" + resource_regexp = re.compile(resource_regexp_text) + + def validate(self, value): + # TODO : Validate that we will not use an empty resource or if we can + # have transitory resource names + if value is None: + raise ResourceConstraintError("Resource not allowed to have a null value!") + + # Special case : We allow the empty resource name for now + if value == "": + return value + + # Attempt to see if the value has a resource name inside it + match = self.resource_regexp.search(value) + + # If there was no match on the reg exp + if not match: + raise ResourceConstraintError("Resource name does not seem to be valid : %s" % value) + + # If the name matched, then the value is _PROBABLY_ good + return value diff --git a/tutorius/properties.py b/tutorius/properties.py index 5422532..ba3c211 100644 --- a/tutorius/properties.py +++ b/tutorius/properties.py @@ -24,7 +24,8 @@ from copy import copy, deepcopy from .constraints import Constraint, \ UpperLimitConstraint, LowerLimitConstraint, \ MaxSizeConstraint, MinSizeConstraint, \ - ColorConstraint, FileConstraint, BooleanConstraint, EnumConstraint + ColorConstraint, FileConstraint, BooleanConstraint, EnumConstraint, \ + ResourceConstraint class TPropContainer(object): """ @@ -261,8 +262,6 @@ class TFileProperty(TutoriusProperty): For now, the path may be relative or absolute, as long as it exists on the local machine. - TODO : Make sure that we have a file scheme that supports distribution - on other computers (LP 355197) """ TutoriusProperty.__init__(self) @@ -351,7 +350,7 @@ class TEventType(TutoriusProperty): class TAddonListProperty(TutoriusProperty): """ - Reprensents an embedded tutorius Addon List Component. + Represents an embedded tutorius Addon List Component. See TAddonProperty """ def __init__(self): @@ -367,3 +366,34 @@ class TAddonListProperty(TutoriusProperty): return value raise ValueError("Value proposed to TAddonListProperty is not a list") +class TResourceProperty(TutoriusProperty): + """ + Represents a resource in the tutorial. A resource is a file with a specific + name that exists under the tutorials folder. It is distributed alongside the + tutorial itself. + + When the system encounters a resource, it knows that it refers to a file in + the resource folder and that it should translate this resource name to an + absolute file name before it is executed. + + E.g. An image is added to a tutorial in an action. On doing so, the creator + adds a resource to the tutorial, then saves its name in the resource + property of that action. When this tutorial is executed, the Engine + replaces all the TResourceProperties inside the action by their equivalent + TFileProperties with absolute paths, so that they can be used on any + machine. + """ + def __init__(self, resource_name=""): + """ + Creates a new resource pointing to an existing resource. + + @param resource_name The file name of the resource (should be only the + file name itself, no directory information) + """ + TutoriusProperty.__init__(self) + self.type = "resource" + + self.resource_cons = ResourceConstraint() + + self.default = self.validate("") + -- cgit v0.9.1