[Zope3-checkins] CVS: Zope3/src/zope/tales/tests - test_expressions.py:1.2

Matt Hamilton matth@netsight.co.uk
Tue, 15 Apr 2003 11:54:18 -0400


Update of /cvs-repository/Zope3/src/zope/tales/tests
In directory cvs.zope.org:/tmp/cvs-serv10941/src/zope/tales/tests

Modified Files:
	test_expressions.py 
Log Message:
Implemented namespace:function notation for TALES expressions.  

This involved refactoring the expression compiler and evaluation methods. 




=== Zope3/src/zope/tales/tests/test_expressions.py 1.1 => 1.2 ===
--- Zope3/src/zope/tales/tests/test_expressions.py:1.1	Mon Apr 14 10:06:23 2003
+++ Zope3/src/zope/tales/tests/test_expressions.py	Tue Apr 15 11:54:18 2003
@@ -22,33 +22,44 @@
 
     def __repr__(self): return self.name
 
+    __str__ = __repr__
+
 
 def dict(**kw):
     return kw
 
 
-class ExpressionTests(unittest.TestCase):
+class ExpressionTestBase(unittest.TestCase):
 
     def setUp(self):
         # Test expression compilation
-        self.context = Data(
-            vars = dict(
-              x = Data(
+        d = Data(
                  name = 'xander',
                  y = Data(
                     name = 'yikes',
                     z = Data(name = 'zope')
                     )
-                 ),
+                 )
+        at = Data(
+                  name = 'yikes',
+                  _d = d
+                 )
+        self.context = Data(
+            vars = dict(
+              x = d,
               y = Data(z = 3),
               b = 'boot',
               B = 2,
+              adapterTest = at,
+              dynamic = 'z',
               )
             )
 
-
         self.engine = Engine
 
+
+class ExpressionTests(ExpressionTestBase):        
+
     def testSimple(self):
         expr = self.engine.compile('x')
         context=self.context
@@ -69,6 +80,21 @@
         context=self.context
         self.assertEqual(expr(context), 'boot')
 
+    def testDynamic(self):
+        expr = self.engine.compile('x/y/?dynamic')
+        context=self.context
+        self.assertEqual(expr(context),context.vars['x'].y.z)
+        
+    def testBadInitalDynamic(self):
+        from zope.tales.tales import CompilerError
+        try:
+            self.engine.compile('?x')
+        except CompilerError,e:
+            self.assertEqual(e.args[0],
+                             'Dynamic name specified in first subpath element')
+        else:
+            self.fail('Engine accepted first subpath element as dynamic')
+            
     def testString(self):
         expr = self.engine.compile('string:Fred')
         context=self.context
@@ -94,9 +120,125 @@
         context=self.context
         self.assertEqual(expr(context), 4)
 
-def test_suite():
-    return unittest.makeSuite(ExpressionTests)
+class FunctionTests(ExpressionTestBase):
 
+    def setUp(self):
+        ExpressionTestBase.setUp(self)
+
+        # a test namespace
+        class TestNameSpace:
+
+            def __init__(self, context):
+                self.context = context
+
+            def upper(self):
+                return str(self.context).upper()
+
+            def __getitem__(self,key):
+                if key=='jump':
+                    return self.context._d
+                raise KeyError,key
+            
+        self.TestNameSpace = TestNameSpace
+        self.engine.registerFunctionNamespace('namespace',self.TestNameSpace)
+
+    ## framework-ish tests
+        
+    def testGetFunctionNamespace(self):
+        self.assertEqual(
+            self.engine.getFunctionNamespace('namespace'),
+            self.TestNameSpace
+            )
+
+    def testGetFunctionNamespaceBadNamespace(self):
+        self.assertRaises(KeyError,
+                          self.engine.getFunctionNamespace,
+                          'badnamespace')
+
+    ## compile time tests
+
+    def testBadNamespace(self):
+        # namespace doesn't exist
+        from zope.tales.tales import CompilerError
+        try:
+            self.engine.compile('adapterTest/badnamespace:title')
+        except CompilerError,e:
+            self.assertEqual(e.args[0],'Unknown namespace "badnamespace"')
+        else:
+            self.fail('Engine accepted unknown namespace')
+
+    def testBadInitialNamespace(self):
+        # first segment in a path must not have modifier
+        from zope.tales.tales import CompilerError
+        self.assertRaises(CompilerError,
+                          self.engine.compile,
+                          'namespace:title')
+
+        # In an ideal world ther ewould be another test here to test
+        # that a nicer error was raised when you tried to use
+        # something like:
+        # standard:namespace:upper
+        # ...as a path.
+        # However, the compilation stage of PathExpr currently
+        # allows any expression type to be nested, so something like:
+        # standard:standard:context/attribute
+        # ...will work fine.
+        # When that is changed so that only expression types which
+        # should be nested are nestable, then the additional test
+        # should be added here.
+
+    def testInvalidNamespaceName(self):
+        from zope.tales.tales import CompilerError
+        try:
+            self.engine.compile('adapterTest/1foo:bar')
+        except CompilerError,e:
+            self.assertEqual(e.args[0],
+                             'Invalid namespace name "1foo"')
+        else:
+            self.fail('Engine accepted invalid namespace name')
+
+    def testInvalidFunctionName(self):
+        from zope.tales.tales import CompilerError
+        try:
+            self.engine.compile('adapterTest/foo:1bar')
+        except CompilerError,e:
+            self.assertEqual(e.args[0],
+                             'Invalid function name "1bar"')
+        else:
+            self.fail('Engine accepted invalid function name')
+
+
+    def testBadFunction(self):
+        from zope.tales.tales import CompilerError
+        # namespace is fine, adapter is not defined
+        try:
+            expr = self.engine.compile('adapterTest/namespace:title')
+            expr(self.context)
+        except (NameError,KeyError),e: 
+            self.assertEquals(e.args[0],'title')
+        else:
+            self.fail('Engine accepted unknown function')
+
+    ## runtime tests
+            
+    def testNormalFunction(self):
+        expr = self.engine.compile('adapterTest/namespace:upper')
+        self.assertEqual(expr(self.context), 'YIKES')
+
+    def testFunctionOnFunction(self):
+        expr = self.engine.compile('adapterTest/namespace:jump/namespace:upper')
+        self.assertEqual(expr(self.context), 'XANDER')
+
+    def testPathOnFunction(self):
+        expr = self.engine.compile('adapterTest/namespace:jump/y/z')
+        context = self.context
+        self.assertEqual(expr(context), context.vars['x'].y.z)
+
+def test_suite():
+    return unittest.TestSuite((
+        unittest.makeSuite(ExpressionTests),
+        unittest.makeSuite(FunctionTests),
+                        ))
 
 if __name__ == '__main__':
     unittest.TextTestRunner().run(test_suite())