[Checkins] SVN: AccessControl/trunk/src/AccessControl/ make sure generated protected decorators are used

Florian Friesdorf flo at chaoflow.net
Thu Nov 17 03:25:17 UTC 2011


Log message for revision 123399:
  make sure generated protected decorators are used

Changed:
  U   AccessControl/trunk/src/AccessControl/SecurityInfo.py
  U   AccessControl/trunk/src/AccessControl/tests/testClassSecurityInfo.py

-=-
Modified: AccessControl/trunk/src/AccessControl/SecurityInfo.py
===================================================================
--- AccessControl/trunk/src/AccessControl/SecurityInfo.py	2011-11-17 03:25:08 UTC (rev 123398)
+++ AccessControl/trunk/src/AccessControl/SecurityInfo.py	2011-11-17 03:25:16 UTC (rev 123399)
@@ -66,6 +66,7 @@
     def __init__(self):
         self.names = {}
         self.roles = {}
+        self._unused_protected_decorators = set()
 
     def _setaccess(self, names, access):
         for name in names:
@@ -119,9 +120,18 @@
     protected__roles__=ACCESS_PRIVATE
     def protected(self, permission_name):
         """Return a decorator to associate a function with a permission."""
+        # the decorator returned is remembered in a set and will
+        # remove itself upon call. self.apply will check for an empty
+        # set and raise an AssertionError otherwise.
+        key = "'%s':%s" % (permission_name, id(lambda x:x))
         def decor(func):
             self.declareProtected(permission_name, func.__name__)
+            self._unused_protected_decorators.remove(key)
             return func
+        # make sure our key algo creates unique-enough keys
+        if key in self._unused_protected_decorators:
+            raise KeyError("Duplicate key: %s" % (key,))
+        self._unused_protected_decorators.add(key)
         return decor
 
     setPermissionDefault__roles__=ACCESS_PRIVATE
@@ -163,6 +173,12 @@
     def apply(self, classobj):
         """Apply security information to the given class object."""
 
+        # make sure all decorators handed out by security.protected were used
+        if self._unused_protected_decorators:
+            msg = "Class '%r' has %d non-decorator security.protected calls!"
+            raise AssertionError(msg % (classobj,
+                                        len(self._unused_protected_decorators)))
+
         dict = classobj.__dict__
 
         # Check the class for an existing __ac_permissions__ and

Modified: AccessControl/trunk/src/AccessControl/tests/testClassSecurityInfo.py
===================================================================
--- AccessControl/trunk/src/AccessControl/tests/testClassSecurityInfo.py	2011-11-17 03:25:08 UTC (rev 123398)
+++ AccessControl/trunk/src/AccessControl/tests/testClassSecurityInfo.py	2011-11-17 03:25:16 UTC (rev 123399)
@@ -112,7 +112,36 @@
         self.assertEquals([t for t in Test.__ac_permissions__ if not t[1]],
                           [('Make food', (), ('Chef',))])
 
+    def test_EnsureProtectedDecoCall(self):
+        from AccessControl.class_init import InitializeClass
+        from ExtensionClass import Base
 
+        ClassSecurityInfo = self._getTargetClass()
+
+        class Test(Base):
+            """Test class
+            """
+            meta_type = "Test"
+
+            security = ClassSecurityInfo()
+
+            security.protected('Test permission 1')
+            def unprotected1(self, REQUEST=None):
+                """ """
+
+            security.protected('Test permission 2')
+            def unprotected2(self, REQUEST=None):
+                """ """
+
+            @security.protected('Test permission 3')
+            def protected(self, REQUEST=None):
+                """ """
+
+        # Do class initialization.
+        with self.assertRaisesRegexp(AssertionError, 'has 2 non-decorator'):
+            InitializeClass(Test)
+
+
 def test_suite():
     suite = unittest.TestSuite()
     suite.addTest(unittest.makeSuite(ClassSecurityInfoTests))



More information about the checkins mailing list