1#!/usr/bin/env python
2
3import sys
4import types
5import os
6import os.path
7
8import unittest
9from Cheetah.NameMapper import NotFound, valueForKey, \
10     valueForName, valueFromSearchList, valueFromFrame, valueFromFrameOrSearchList
11
12
13class DummyClass(object):
14    classVar1 = 123
15
16    def __init__(self):
17        self.instanceVar1 = 123
18
19    def __str__(self):
20        return 'object'
21
22    def meth(self, arg="arff"):
23        return str(arg)
24
25    def meth1(self, arg="doo"):
26        return arg
27
28    def meth2(self, arg1="a1", arg2="a2"):
29        raise ValueError
30
31    def meth3(self):
32        """Tests a bug that Jeff Johnson reported on Oct 1, 2001"""
33
34        x = 'A string'
35        try:
36            for i in [1, 2, 3, 4]:
37                if x == 2:
38                    pass
39
40                if x == 'xx':
41                    pass
42            return x
43        except:
44            raise
45
46class DummyClassGetAttrRaises(object):
47    def __getattr__(self, name):
48        raise ValueError
49
50
51def dummyFunc(arg="Scooby"):
52    return arg
53
54def funcThatRaises():
55    raise ValueError
56
57
58testNamespace = {
59    'aStr': 'blarg',
60    'anInt': 1,
61    'aFloat': 1.5,
62    'aDict': {'one': 'item1',
63              'two': 'item2',
64              'nestedDict': {'one': 'nestedItem1',
65                            'two': 'nestedItem2',
66                            'funcThatRaises': funcThatRaises,
67                            'aClass': DummyClass,
68                            },
69              'nestedFunc': dummyFunc,
70              },
71    'aClass': DummyClass,
72    'aFunc': dummyFunc,
73    'anObj': DummyClass(),
74    'anObjThatRaises': DummyClassGetAttrRaises(),
75    'aMeth': DummyClass().meth1,
76    'none': None,
77    'emptyString': '',
78    'funcThatRaises': funcThatRaises,
79    }
80
81autoCallResults = {'aFunc': 'Scooby',
82                   'aMeth': 'doo',
83                   }
84
85results = testNamespace.copy()
86results.update({'anObj.meth1': 'doo',
87                'aDict.one': 'item1',
88                'aDict.nestedDict': testNamespace['aDict']['nestedDict'],
89                'aDict.nestedDict.one': 'nestedItem1',
90                'aDict.nestedDict.aClass': DummyClass,
91                'aDict.nestedFunc': 'Scooby',
92                'aClass.classVar1': 123,
93                'anObj.instanceVar1': 123,
94                'anObj.meth3': 'A string',
95                })
96
97for k in testNamespace.keys():
98    # put them in the globals for the valueFromFrame tests
99    exec('%s = testNamespace[k]'%k)
100
101##################################################
102## TEST BASE CLASSES
103
104class NameMapperTest(unittest.TestCase):
105    failureException = NotFound
106    _testNamespace = testNamespace
107    _results = results
108
109    def namespace(self):
110        return self._testNamespace
111
112    def VFN(self, name, autocall=True):
113        return valueForName(self.namespace(), name, autocall)
114
115    def VFS(self, searchList, name, autocall=True):
116        return valueFromSearchList(searchList, name, autocall)
117
118
119    # alias to be overriden later
120    get = VFN
121
122    def check(self, name):
123        got = self.get(name)
124        if name in autoCallResults:
125            expected = autoCallResults[name]
126        else:
127            expected = self._results[name]
128        assert got == expected
129
130
131##################################################
132## TEST CASE CLASSES
133
134class VFN(NameMapperTest):
135
136    def test1(self):
137        """string in dict lookup"""
138        self.check('aStr')
139
140    def test2(self):
141        """string in dict lookup in a loop"""
142        for i in range(10):
143            self.check('aStr')
144
145    def test3(self):
146        """int in dict lookup"""
147        self.check('anInt')
148
149    def test4(self):
150        """int in dict lookup in a loop"""
151        for i in range(10):
152            self.check('anInt')
153
154    def test5(self):
155        """float in dict lookup"""
156        self.check('aFloat')
157
158    def test6(self):
159        """float in dict lookup in a loop"""
160        for i in range(10):
161            self.check('aFloat')
162
163    def test7(self):
164        """class in dict lookup"""
165        self.check('aClass')
166
167    def test8(self):
168        """class in dict lookup in a loop"""
169        for i in range(10):
170            self.check('aClass')
171
172    def test9(self):
173        """aFunc in dict lookup"""
174        self.check('aFunc')
175
176    def test10(self):
177        """aFunc in dict lookup in a loop"""
178        for i in range(10):
179            self.check('aFunc')
180
181    def test11(self):
182        """aMeth in dict lookup"""
183        self.check('aMeth')
184
185    def test12(self):
186        """aMeth in dict lookup in a loop"""
187        for i in range(10):
188            self.check('aMeth')
189
190    def test13(self):
191        """aMeth in dict lookup"""
192        self.check('aMeth')
193
194    def test14(self):
195        """aMeth in dict lookup in a loop"""
196        for i in range(10):
197            self.check('aMeth')
198
199    def test15(self):
200        """anObj in dict lookup"""
201        self.check('anObj')
202
203    def test16(self):
204        """anObj in dict lookup in a loop"""
205        for i in range(10):
206            self.check('anObj')
207
208    def test17(self):
209        """aDict in dict lookup"""
210        self.check('aDict')
211
212    def test18(self):
213        """aDict in dict lookup in a loop"""
214        for i in range(10):
215            self.check('aDict')
216
217    def test17(self):
218        """aDict in dict lookup"""
219        self.check('aDict')
220
221    def test18(self):
222        """aDict in dict lookup in a loop"""
223        for i in range(10):
224            self.check('aDict')
225
226    def test19(self):
227        """aClass.classVar1 in dict lookup"""
228        self.check('aClass.classVar1')
229
230    def test20(self):
231        """aClass.classVar1 in dict lookup in a loop"""
232        for i in range(10):
233            self.check('aClass.classVar1')
234
235
236    def test23(self):
237        """anObj.instanceVar1 in dict lookup"""
238        self.check('anObj.instanceVar1')
239
240    def test24(self):
241        """anObj.instanceVar1 in dict lookup in a loop"""
242        for i in range(10):
243            self.check('anObj.instanceVar1')
244
245    ## tests 22, 25, and 26 removed when the underscored lookup was removed
246
247    def test27(self):
248        """anObj.meth1 in dict lookup"""
249        self.check('anObj.meth1')
250
251    def test28(self):
252        """anObj.meth1 in dict lookup in a loop"""
253        for i in range(10):
254            self.check('anObj.meth1')
255
256    def test29(self):
257        """aDict.one in dict lookup"""
258        self.check('aDict.one')
259
260    def test30(self):
261        """aDict.one in dict lookup in a loop"""
262        for i in range(10):
263            self.check('aDict.one')
264
265    def test31(self):
266        """aDict.nestedDict in dict lookup"""
267        self.check('aDict.nestedDict')
268
269    def test32(self):
270        """aDict.nestedDict in dict lookup in a loop"""
271        for i in range(10):
272            self.check('aDict.nestedDict')
273
274    def test33(self):
275        """aDict.nestedDict.one in dict lookup"""
276        self.check('aDict.nestedDict.one')
277
278    def test34(self):
279        """aDict.nestedDict.one in dict lookup in a loop"""
280        for i in range(10):
281            self.check('aDict.nestedDict.one')
282
283    def test35(self):
284        """aDict.nestedFunc in dict lookup"""
285        self.check('aDict.nestedFunc')
286
287    def test36(self):
288        """aDict.nestedFunc in dict lookup in a loop"""
289        for i in range(10):
290            self.check('aDict.nestedFunc')
291
292    def test37(self):
293        """aDict.nestedFunc in dict lookup - without autocalling"""
294        assert self.get('aDict.nestedFunc', False) == dummyFunc
295
296    def test38(self):
297        """aDict.nestedFunc in dict lookup in a loop - without autocalling"""
298        for i in range(10):
299            assert self.get('aDict.nestedFunc', False) == dummyFunc
300
301    def test39(self):
302        """aMeth in dict lookup - without autocalling"""
303        assert self.get('aMeth', False) == self.namespace()['aMeth']
304
305    def test40(self):
306        """aMeth in dict lookup in a loop - without autocalling"""
307        for i in range(10):
308            assert self.get('aMeth', False) == self.namespace()['aMeth']
309
310    def test41(self):
311        """anObj.meth3 in dict lookup"""
312        self.check('anObj.meth3')
313
314    def test42(self):
315        """aMeth in dict lookup in a loop"""
316        for i in range(10):
317            self.check('anObj.meth3')
318
319    def test43(self):
320        """NotFound test"""
321
322        def test(self=self):
323            self.get('anObj.methX')
324        self.assertRaises(NotFound, test)
325
326    def test44(self):
327        """NotFound test in a loop"""
328        def test(self=self):
329            self.get('anObj.methX')
330
331        for i in range(10):
332            self.assertRaises(NotFound, test)
333
334    def test45(self):
335        """Other exception from meth test"""
336
337        def test(self=self):
338            self.get('anObj.meth2')
339        self.assertRaises(ValueError, test)
340
341    def test46(self):
342        """Other exception from meth test in a loop"""
343        def test(self=self):
344            self.get('anObj.meth2')
345
346        for i in range(10):
347            self.assertRaises(ValueError, test)
348
349    def test47(self):
350        """None in dict lookup"""
351        self.check('none')
352
353    def test48(self):
354        """None in dict lookup in a loop"""
355        for i in range(10):
356            self.check('none')
357
358    def test49(self):
359        """EmptyString in dict lookup"""
360        self.check('emptyString')
361
362    def test50(self):
363        """EmptyString in dict lookup in a loop"""
364        for i in range(10):
365            self.check('emptyString')
366
367    def test51(self):
368        """Other exception from func test"""
369
370        def test(self=self):
371            self.get('funcThatRaises')
372        self.assertRaises(ValueError, test)
373
374    def test52(self):
375        """Other exception from func test in a loop"""
376        def test(self=self):
377            self.get('funcThatRaises')
378
379        for i in range(10):
380            self.assertRaises(ValueError, test)
381
382
383    def test53(self):
384        """Other exception from func test"""
385
386        def test(self=self):
387            self.get('aDict.nestedDict.funcThatRaises')
388        self.assertRaises(ValueError, test)
389
390    def test54(self):
391        """Other exception from func test in a loop"""
392        def test(self=self):
393            self.get('aDict.nestedDict.funcThatRaises')
394
395        for i in range(10):
396            self.assertRaises(ValueError, test)
397
398    def test55(self):
399        """aDict.nestedDict.aClass in dict lookup"""
400        self.check('aDict.nestedDict.aClass')
401
402    def test56(self):
403        """aDict.nestedDict.aClass in dict lookup in a loop"""
404        for i in range(10):
405            self.check('aDict.nestedDict.aClass')
406
407    def test57(self):
408        """aDict.nestedDict.aClass in dict lookup - without autocalling"""
409        assert self.get('aDict.nestedDict.aClass', False) == DummyClass
410
411    def test58(self):
412        """aDict.nestedDict.aClass in dict lookup in a loop - without autocalling"""
413        for i in range(10):
414            assert self.get('aDict.nestedDict.aClass', False) == DummyClass
415
416    def test59(self):
417        """Other exception from func test -- but without autocalling shouldn't raise"""
418
419        self.get('aDict.nestedDict.funcThatRaises', False)
420
421    def test60(self):
422        """Other exception from func test in a loop -- but without autocalling shouldn't raise"""
423
424        for i in range(10):
425            self.get('aDict.nestedDict.funcThatRaises', False)
426
427    def test61(self):
428        """Accessing attribute where __getattr__ raises shouldn't segfault if something follows it"""
429
430        def test(self=self):
431            self.get('anObjThatRaises.willraise.anything')
432        self.assertRaises(ValueError, test)
433
434
435class VFS(VFN):
436    _searchListLength = 1
437
438    def searchList(self):
439        lng = self._searchListLength
440        if lng == 1:
441            return [self.namespace()]
442        elif lng == 2:
443            return [self.namespace(), {'dummy':1234}]
444        elif lng == 3:
445            # a tuple for kicks
446            return ({'dummy':1234}, self.namespace(), {'dummy':1234})
447        elif lng == 4:
448            # a generator for more kicks
449            return self.searchListGenerator()
450
451    def searchListGenerator(self):
452        class Test:
453            pass
454        for i in [Test(), {'dummy':1234}, self.namespace(), {'dummy':1234}]:
455            yield i
456
457    def get(self, name, autocall=True):
458        return self.VFS(self.searchList(), name, autocall)
459
460class VFS_2namespaces(VFS):
461    _searchListLength = 2
462
463class VFS_3namespaces(VFS):
464    _searchListLength = 3
465
466class VFS_4namespaces(VFS):
467    _searchListLength = 4
468
469class VFF(VFN):
470    def get(self, name, autocall=True):
471        ns = self._testNamespace
472        aStr = ns['aStr']
473        aFloat = ns['aFloat']
474        none = 'some'
475        return valueFromFrame(name, autocall)
476
477    def setUp(self):
478        """Mod some of the data
479        """
480        self._testNamespace = ns = self._testNamespace.copy()
481        self._results = res = self._results.copy()
482        ns['aStr'] = res['aStr'] = 'BLARG'
483        ns['aFloat'] = res['aFloat'] = 0.1234
484        res['none'] = 'some'
485        res['True'] = True
486        res['False'] = False
487        res['None'] = None
488        res['eval'] = eval
489
490    def test_VFF_1(self):
491        """Builtins"""
492        self.check('True')
493        self.check('None')
494        self.check('False')
495        assert self.get('eval', False)==eval
496        assert self.get('range', False)==range
497
498class VFFSL(VFS):
499    _searchListLength = 1
500
501    def setUp(self):
502        """Mod some of the data
503        """
504        self._testNamespace = ns = self._testNamespace.copy()
505        self._results = res = self._results.copy()
506        ns['aStr'] = res['aStr'] = 'BLARG'
507        ns['aFloat'] = res['aFloat'] = 0.1234
508        res['none'] = 'some'
509
510        del ns['anInt'] # will be picked up by globals
511
512    def VFFSL(self, searchList, name, autocall=True):
513        anInt = 1
514        none = 'some'
515        return valueFromFrameOrSearchList(searchList, name, autocall)
516
517    def get(self, name, autocall=True):
518        return self.VFFSL(self.searchList(), name, autocall)
519
520class VFFSL_2(VFFSL):
521    _searchListLength = 2
522
523class VFFSL_3(VFFSL):
524    _searchListLength = 3
525
526class VFFSL_4(VFFSL):
527    _searchListLength = 4
528
529if sys.platform.startswith('java'):
530    del VFF, VFFSL, VFFSL_2, VFFSL_3, VFFSL_4
531
532
533class MapBuiltins(unittest.TestCase):
534    def test_int(self):
535        from Cheetah.Template import Template
536        t = Template('''
537            #def intify(val)
538                #return $int(val)
539            #end def''', compilerSettings={'useStackFrames' : False})
540        self.assertEquals(5, t.intify('5'))
541
542
543
544##################################################
545## if run from the command line ##
546
547if __name__ == '__main__':
548    unittest.main()
549