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