From 7fe5df7a198f345a9a5597106099a702b577f89a Mon Sep 17 00:00:00 2001 From: Rafael Monnerat <rafael@nexedi.com> Date: Mon, 22 Jan 2007 21:08:00 +0000 Subject: [PATCH] Added ContentExistence Constraint (Made by romain) Added StringAttributeMatch Constraint (made by Romain, modified by Me) Added tests for both Constraints. git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@12216 20353a03-c40f-0410-a6d1-a30d3c3de9de --- .../ERP5Type/Constraint/ContentExistence.py | 63 ++++++++++ .../Constraint/StringAttributeMatch.py | 65 ++++++++++ product/ERP5Type/Constraint/__init__.py | 2 + product/ERP5Type/tests/testConstraint.py | 116 ++++++++++++++++++ 4 files changed, 246 insertions(+) create mode 100644 product/ERP5Type/Constraint/ContentExistence.py create mode 100644 product/ERP5Type/Constraint/StringAttributeMatch.py diff --git a/product/ERP5Type/Constraint/ContentExistence.py b/product/ERP5Type/Constraint/ContentExistence.py new file mode 100644 index 0000000000..6d35cd7b6b --- /dev/null +++ b/product/ERP5Type/Constraint/ContentExistence.py @@ -0,0 +1,63 @@ +############################################################################## +# +# Copyright (c) 2006 Nexedi SARL and Contributors. All Rights Reserved. +# Romain Courteaud <romain@nexedi.com> +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsability of assessing all potential +# consequences resulting from its eventual inadequacies and bugs +# End users who are looking for a ready-to-use solution with commercial +# garantees and support are strongly adviced to contract a Free Software +# Service Company +# +# This program is Free Software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# 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 General Public License for more details. +# +# You should have received a copy of the GNU 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 Products.ERP5Type.Constraint import Constraint + +class ContentExistence(Constraint): + """ + This constraint class allows to check / fix + that object contains one subobject. + Configuration example: + { 'id' : 'line', + 'description' : 'Object have to contain a Line', + 'type' : 'ContentExistence', + 'portal_type' : ('Line', ), + }, + """ + + def checkConsistency(self, object, fixit=0): + """ + This is the check method, we return a list of string, + each string corresponds to an error. + We are checking that object contains a subobject. + """ + obj = object + errors = [] + if self._checkConstraintCondition(object): + # Retrieve values inside de PropertySheet (_constraints) + portal_type = self.constraint_definition['portal_type'] + # Check arity and compare it with the min and max + arity = len(obj.contentValues(portal_type=portal_type)) + if (arity == 0): + # Generate error message + error_message = "Does not contain any subobject" + if portal_type is not (): + error_message += " of portal type: '%s'" % str(portal_type) + # Add error + errors.append(self._generateError(obj, error_message)) + return errors diff --git a/product/ERP5Type/Constraint/StringAttributeMatch.py b/product/ERP5Type/Constraint/StringAttributeMatch.py new file mode 100644 index 0000000000..80571ad1af --- /dev/null +++ b/product/ERP5Type/Constraint/StringAttributeMatch.py @@ -0,0 +1,65 @@ +############################################################################## +# +# Copyright (c) 2006 Nexedi SARL and Contributors. All Rights Reserved. +# Romain Courteaud <romain@nexedi.com> +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsability of assessing all potential +# consequences resulting from its eventual inadequacies and bugs +# End users who are looking for a ready-to-use solution with commercial +# garantees and support are strongly adviced to contract a Free Software +# Service Company +# +# This program is Free Software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# 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 General Public License for more details. +# +# You should have received a copy of the GNU 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. +# +############################################################################## + +import re +from Products.ERP5Type.Constraint.PropertyExistence import PropertyExistence + +class StringAttributeMatch(PropertyExistence): + """ + This constraint class allows to check + that a string property match a regular + expression. Configuration example: + { 'id' : 'title_not_empty', + 'description' : 'Title must be defined', + 'type' : 'StringAttributeMatch', + 'title' : '^[^ ]' + }, + """ + + def checkConsistency(self, object, fixit=0): + """ + This is the check method, we return a list of string, + each string corresponds to an error. + Check that each attribute does not match the RE + """ + errors = PropertyExistence.checkConsistency(self, object, fixit=fixit) + for attribute_name, attribute_value in self.constraint_definition.items(): + error_message = None + # If property does not exist, error will be raise by + # PropertyExistence Constraint. + current_value = object.getProperty(attribute_name) + regexp = re.compile(attribute_value) + if (current_value is not None) and \ + (regexp.match(current_value) is None): + # Generate error_message + error_message = "Attribute %s is '%s' and not match '%s'" % \ + (attribute_name, current_value, + attribute_value) + # Generate error + errors.append(self._generateError(object, error_message)) + return errors diff --git a/product/ERP5Type/Constraint/__init__.py b/product/ERP5Type/Constraint/__init__.py index 314b62836e..9387388719 100644 --- a/product/ERP5Type/Constraint/__init__.py +++ b/product/ERP5Type/Constraint/__init__.py @@ -8,3 +8,5 @@ from CategoryExistence import CategoryExistence from PortalTypeClass import PortalTypeClass from CategoryAcquiredMembershipArity import CategoryAcquiredMembershipArity from TALESConstraint import TALESConstraint +from ContentExistence import ContentExistence +from StringAttributeMatch import StringAttributeMatch diff --git a/product/ERP5Type/tests/testConstraint.py b/product/ERP5Type/tests/testConstraint.py index 2044099491..74f8ddb2c0 100644 --- a/product/ERP5Type/tests/testConstraint.py +++ b/product/ERP5Type/tests/testConstraint.py @@ -44,6 +44,7 @@ class TestConstraint(PropertySheetTestCase): quiet = 1 object_portal_type = "Organisation" + object_content_portal_type = "Address" object_title = "Title test" def getTitle(self): @@ -1174,6 +1175,121 @@ class TestConstraint(PropertySheetTestCase): # now we can use testing_category as any category accessor self.assertEquals(obj, obj.getTestingCategoryValue()) + def stepCreateContentExistence(self, sequence=None, sequence_list=None, **kw): + """ + Create a Content Existence Constraint + """ + self._createGenericConstraint( + sequence, + klass_name='ContentExistence', + id='ContentExistence', + description='ContentExistence test', + portal_type=(self.object_content_portal_type, ) + ) + + def stepCreateContentObject(self, sequence=None, sequence_list=None, **kw): + """ + Create a Content Object inside one Object + """ + object = sequence.get('object') + content_object = object.newContent(portal_type=self.object_content_portal_type) + sequence.edit( + content_object = content_object, + ) + + def test_ContentExistenceConstraint(self, quiet=quiet, run=run_all_test): + """ + Tests Content Existence + """ + + if not run: return + sequence_list = SequenceList() + # Test Constraint without any content + sequence_string = '\ + CreateObject \ + CreateContentExistence \ + CallCheckConsistency \ + CheckIfConstraintFailed \ + ' + sequence_list.addSequenceString(sequence_string) + # Test Constraint with content + sequence_string = '\ + CreateObject \ + CreateContentExistence \ + CreateContentObject \ + CallCheckConsistency \ + CheckIfConstraintSucceeded \ + ' + sequence_list.addSequenceString(sequence_string) + sequence_list.play(self, quiet=quiet) + + def stepCreateStringAttributeMatch(self, sequence=None, sequence_list=None, **kw): + """ + Create a String Atribute Match Constraint + """ + self._createGenericConstraint( + sequence, + klass_name='StringAttributeMatch', + id='StringAttributeMatch', + description='StringAttributeMatch test', + title='^[^ ]' + ) + + def stepSetObjectTitle0(self, sequence=None, sequence_list=None, **kw): + """ + Set valid Title to Object + """ + object = sequence.get('object') + object.setTitle(self.object_title) + sequence.edit( + object = object, + ) + + def stepSetObjectTitle1(self, sequence=None, sequence_list=None, **kw): + """ + Set empty (or invalid string) to Object + """ + object = sequence.get('object') + object.setTitle(' ') + sequence.edit( + object = object, + ) + + def test_StringAttributeMatchConstraint(self, quiet=quiet, run=run_all_test): + """ + Tests Content Existence + """ + if not run: return + sequence_list = SequenceList() + # Test Constraint with empty Title + sequence_string = '\ + CreateObject \ + CreateStringAttributeMatch \ + CallCheckConsistency \ + CheckIfConstraintFailed \ + ' + sequence_list.addSequenceString(sequence_string) + # Test Constraint with Title + sequence_string = '\ + CreateObject \ + CreateStringAttributeMatch \ + SetObjectTitle0 \ + CallCheckConsistency \ + CheckIfConstraintSucceeded \ + ' + sequence_list.addSequenceString(sequence_string) + # Test Constraint with invalid Title + # Not match with regex + sequence_string = '\ + CreateObject \ + CreateStringAttributeMatch \ + SetObjectTitle1 \ + CallCheckConsistency \ + CheckIfConstraintFailed \ + ' + sequence_list.addSequenceString(sequence_string) + + sequence_list.play(self, quiet=quiet) if __name__ == '__main__': framework() -- 2.30.9