Contact: fumanchu@aminus.org

Log in as guest/geniusql to create tickets

root/trunk/geniusql/test/test_codewalk.py

Revision 320 (checked in by lakin, 2 months ago)

properly deal with our new python jumps and fix the related tests. all of test_codewalk, test_astwalk and test_logic should now run properly in python 2.6 and 2.7

  • Property svn:eol-style set to native
Line 
1 import datetime
2 import decimal
3
4 import sys
5
6
7 import unittest
8
9 from geniusql import codewalk
10 nums = codewalk.numeric_opcodes
11 from geniusql.test.lambdas import *
12
13 #-------------------------------------------------------------------------------
14 # Now we'll map up these same functions to their decompiled versions based on
15 # the appropriate version of python.
16 class Results_Python26(object):
17     # Python 2.5 stopped putting arguments in co_names,
18     # and stopped prepending None to co_consts (except when CO_NESTED?).
19     const_idx = 0
20     attr_idx = 0
21
22     localizer_tests = [
23         {
24             'function': f_in_op,
25             'results': [
26                 'LOAD_FAST', 0, 0,
27                 'LOAD_CONST', const_idx, 0,
28                 'COMPARE_OP', 6, 0,
29                 'RETURN_VALUE',
30             ],
31         },
32         {
33             'function': f_add_op,
34             'results': [
35                 'LOAD_FAST', 0, 0,
36                 'LOAD_CONST', const_idx + 2, 0,
37                 'LOAD_ATTR', attr_idx + 1, 0,
38                 'LOAD_CONST', const_idx, 0,
39                 'LOAD_CONST', const_idx + 1, 0,
40                 'LOAD_CONST', const_idx + 1, 0,
41                 'CALL_FUNCTION', 3, 0,
42                 'BINARY_ADD',
43                 'RETURN_VALUE',
44             ],
45         },
46         {
47             'function': f_kwargs_and_op,
48             'results': [
49                 'LOAD_FAST', 0, 0,
50                 'LOAD_ATTR', attr_idx, 0,
51                 'LOAD_CONST', const_idx + 3, 0,
52                 'LOAD_ATTR', attr_idx + 2, 0,
53                 'LOAD_CONST', const_idx, 0,
54                 'LOAD_CONST', const_idx + 1, 0,
55                 'LOAD_CONST', const_idx + 1, 0,
56                 'CALL_FUNCTION', 3, 0,
57                 'COMPARE_OP', 2, 0,
58                 'JUMP_IF_FALSE', 17, 0,
59                 'POP_TOP',
60                 'LOAD_FAST', 0, 0,
61                 'LOAD_ATTR', attr_idx + 3, 0,
62                 'LOAD_FAST', 1, 0,
63                 'LOAD_CONST', const_idx + 2, 0,
64                 'BINARY_SUBSCR',
65                 'COMPARE_OP', 0, 0,
66                 'RETURN_VALUE',
67             ],
68         },
69         {
70             'function': f_mix_names_global_locals_attrs,
71             'results': [
72                 'LOAD_CONST', const_idx, 0,
73                 'LOAD_FAST', 0, 0,
74                 'LOAD_ATTR', attr_idx, 0,
75                 'COMPARE_OP', 3, 0,
76                 'JUMP_IF_TRUE', 14, 0,
77                 'POP_TOP',
78                 'LOAD_FAST', 1, 0,
79                 'LOAD_CONST', const_idx + 1, 0,
80                 'BINARY_MULTIPLY',
81                 'LOAD_CONST', const_idx + 2, 0,
82                 'COMPARE_OP', 4, 0,
83                 'RETURN_VALUE',
84             ],
85         },
86     ]
87
88     early_binder_tests = [
89         { # 0
90             'function': f_add_op,
91             'results': [
92                 'LOAD_FAST', 0, 0,
93                 'LOAD_CONST', const_idx + 4, 0,
94                 'BINARY_ADD',
95                 'RETURN_VALUE',
96             ],
97         },
98         { # 1
99             'function': f_kwargs_and_op,
100             'results': [
101                 'LOAD_FAST', 0, 0,
102                 'LOAD_ATTR', attr_idx, 0,
103                 'LOAD_CONST', const_idx + 5, 0,
104                 'COMPARE_OP', 2, 0,
105                 'JUMP_IF_FALSE', 17, 0,
106                 'POP_TOP',
107                 'LOAD_FAST', 0, 0,
108                 'LOAD_ATTR', attr_idx + 3, 0,
109                 'LOAD_FAST', 1, 0,
110                 'LOAD_CONST', const_idx + 2, 0,
111                 'BINARY_SUBSCR',
112                 'COMPARE_OP', 0, 0,
113                 'RETURN_VALUE',
114             ],
115         },
116         { # 2
117             'function': f_constant_multiplication,
118             'results': [
119                 'LOAD_CONST', const_idx + 4, 0,
120                 'LOAD_FAST', 0, 0,
121                 'BINARY_MULTIPLY',
122                 'RETURN_VALUE',
123             ]
124         },
125         { # 3
126             'function': f_array_slice_subscript,
127             'results': [
128                 'LOAD_CONST', const_idx + 4, 0,
129                 'LOAD_FAST', 0, 0,
130                 'LOAD_CONST', const_idx + 2, 0,
131                 'BINARY_SUBSCR',
132                 'UNARY_NEGATIVE',
133                 'COMPARE_OP', 2, 0,
134                 'RETURN_VALUE',
135             ]
136         },
137         { # 4
138             'function': f_const_attr,
139             'results': [
140                 'LOAD_CONST', const_idx + 1, 0,
141                 'JUMP_IF_TRUE', 13, 0,
142                 'POP_TOP',
143                 'LOAD_CONST', const_idx, 0,
144                 'LOAD_FAST', 0, 0,
145                 'LOAD_ATTR', attr_idx + 1, 0,
146                 'COMPARE_OP', 2, 0,
147                 'RETURN_VALUE',
148             ]
149         },
150         { # 5
151             'function': f_unicode_const_getattr,
152             'results': [
153                 'LOAD_FAST', 0, 0,
154                 # 2, since co_names was ('getattr', 'x').
155                 'LOAD_ATTR', attr_idx + 1, 0,
156                 'LOAD_CONST', const_idx + 1, 0,
157                 'COMPARE_OP', 2, 0,
158                 'RETURN_VALUE',
159             ]
160         },
161         { # 6
162
163             # Test a tainted (late-bound) function
164             'function': f_late_binding,
165             'bind_late': [datetime.date.today],
166             'results': [
167                 'LOAD_FAST', 0, 0,
168                 'LOAD_ATTR', attr_idx, 0,
169                 'LOAD_CONST', const_idx + 2, 0,
170                 'CALL_FUNCTION', 0, 0,
171                 'COMPARE_OP', 5, 0,
172                 'RETURN_VALUE',
173             ]
174         },
175         { # 7
176
177             # Closures (dereferencing of func_closure)
178             'function': f_closure_example,
179             'results': [
180                 'LOAD_CONST', const_idx + 2, 0,
181                 'RETURN_VALUE',
182             ]
183         },
184     ]
185
186     lambda_decompiler_tests = [
187         {
188             'function': f_in_op,
189             'results': 'lambda x: x in a',
190         },
191         {
192             'function': f_add_op,
193             'results': 'lambda x: x + datetime.date(2004, 1, 1)',
194         },
195         {
196             'function': f_kwargs_and_op,
197             'results': "lambda x, **kw: (x.Date == datetime.date(2004, 1, 1)) and (x.Qty < kw['Size'])",
198         },
199         {
200             'function': f_mix_names_global_locals_attrs,
201             'results': "lambda x, amount: (4 != x.amount) or (amount * 3 > 20)",
202         },
203         {
204             'function': f_constant_multiplication,
205             'results': "lambda x: 60 * x",
206         },
207         {
208             'function': f_array_slice_subscript,
209             'results': "lambda x: a[2:4] == -(x['offset'])",
210         },
211         {
212             'function': f_const_attr,
213             'results': "lambda x: (amount == 5) or (amount == x.Qty)",
214         },
215         {
216             'function': f_nested_conditionals,
217             'results': "lambda x: not ((x.a == 3) and ((x.b > 1) or (x.b < -10)))",
218         },
219         {
220             'function': f_nested_conditionals_2,
221             'results': "lambda x: not (((x.a == 3) and (x.b > 1)) or (x.b < -10))",
222         },
223         {
224             'function': f_unicode_const,
225             'results': "lambda x: x.Name == u'Dimsdale'",
226         },
227         {
228             'function': f_unicode_const_getattr,
229             'results': "lambda x: getattr(x, 'Name') == u'Dimsdale'",
230         },
231         {
232             'function': f_unicode_multiple_args,
233             'results': "lambda x, y, z, **kw: (x.Qty > 1) and ((y.Qty > 20) and (z.Type == 'A'))",
234         },
235         # Skipping the closure one until we can figure out how to write a closure as a lambda
236         {
237             'function': f_fixed_point,
238             'results': "lambda x: x.Amount > decimal.Decimal(3, 2)",
239         },
240     ]
241
242     branch_tracker_tests = [
243         {
244             'function': f_const_attr,
245             'results': [9, 22],
246         },
247     ]
248
249 #-------------------------------------------------------------------------------
250 class Results_Python27(object):
251     const_idx = 1
252     attr_idx = 0
253
254     localizer_tests = [
255         { # 0
256             'function': f_in_op,
257             'results': [
258                 'LOAD_FAST', 0, 0,
259                 'LOAD_CONST', const_idx, 0,
260                 'COMPARE_OP', 6, 0,
261                 'RETURN_VALUE',
262             ],
263         },
264         { # 1
265             'function': f_add_op,
266             'results': [
267                 'LOAD_FAST', 0, 0,
268                 'LOAD_CONST', const_idx + 2, 0,
269                 'LOAD_ATTR', attr_idx + 1, 0,
270                 'LOAD_CONST', const_idx, 0,
271                 'LOAD_CONST', const_idx + 1, 0,
272                 'LOAD_CONST', const_idx + 1, 0,
273                 'CALL_FUNCTION', 3, 0,
274                 'BINARY_ADD',
275                 'RETURN_VALUE',
276             ],
277         },
278         { # 2
279             'function': f_kwargs_and_op,
280             'results': [
281                 'LOAD_FAST', 0, 0,
282                 'LOAD_ATTR', attr_idx, 0,
283                 'LOAD_CONST', const_idx + 3, 0,
284                 'LOAD_ATTR', attr_idx + 2, 0,
285                 'LOAD_CONST', const_idx, 0,
286                 'LOAD_CONST', const_idx + 1, 0,
287                 'LOAD_CONST', const_idx + 1, 0,
288                 'CALL_FUNCTION', 3, 0,
289                 'COMPARE_OP', 2, 0,
290                 'JUMP_IF_FALSE_OR_POP', 46, 0,
291                 'LOAD_FAST', 0, 0,
292                 'LOAD_ATTR', attr_idx + 3, 0,
293                 'LOAD_FAST', 1, 0,
294                 'LOAD_CONST', const_idx + 2, 0,
295                 'BINARY_SUBSCR',
296                 'COMPARE_OP', 0, 0,
297                 'RETURN_VALUE',
298             ],
299         },
300         {
301             'function': f_mix_names_global_locals_attrs,
302             'results': [
303                 'LOAD_CONST', const_idx, 0,
304                 'LOAD_FAST', 0, 0,
305                 'LOAD_ATTR', attr_idx, 0,
306                 'COMPARE_OP', 3, 0,
307                 'JUMP_IF_TRUE_OR_POP', 28, 0,
308                 'LOAD_FAST', 1, 0,
309                 'LOAD_CONST', const_idx + 1, 0,
310                 'BINARY_MULTIPLY',
311                 'LOAD_CONST', const_idx + 2, 0,
312                 'COMPARE_OP', 4, 0,
313                 'RETURN_VALUE',
314             ],
315         },
316     ]
317
318     early_binder_tests = [
319         { # 0
320             'function': f_add_op,
321             'results': [
322                 'LOAD_FAST', 0, 0,
323                 'LOAD_CONST', const_idx + 4, 0,
324                 'BINARY_ADD',
325                 'RETURN_VALUE',
326             ],
327         },
328         { # 1
329             'function': f_kwargs_and_op,
330             'results': [
331                 'LOAD_FAST', 0, 0,
332                 'LOAD_ATTR', attr_idx, 0,
333                 'LOAD_CONST', const_idx + 5, 0,
334                 'COMPARE_OP', 2, 0,
335                 'JUMP_IF_FALSE_OR_POP', 46, 0,
336                 'LOAD_FAST', 0, 0,
337                 'LOAD_ATTR', attr_idx + 3, 0,
338                 'LOAD_FAST', 1, 0,
339                 'LOAD_CONST', const_idx + 2, 0,
340                 'BINARY_SUBSCR',
341                 'COMPARE_OP', 0, 0,
342                 'RETURN_VALUE',
343             ],
344         },
345         { # 2
346             'function': f_constant_multiplication,
347             'results': [
348                 'LOAD_CONST', const_idx + 4, 0,
349                 'LOAD_FAST', 0, 0,
350                 'BINARY_MULTIPLY',
351                 'RETURN_VALUE',
352             ]
353         },
354         { # 3
355             'function': f_array_slice_subscript,
356             'results': [
357                 'LOAD_CONST', const_idx + 4, 0,
358                 'LOAD_FAST', 0, 0,
359                 'LOAD_CONST', const_idx + 2, 0,
360                 'BINARY_SUBSCR',
361                 'UNARY_NEGATIVE',
362                 'COMPARE_OP', 2, 0,
363                 'RETURN_VALUE',
364             ]
365         },
366         { # 4
367             'function': f_const_attr,
368             'results': [
369                 'LOAD_CONST', const_idx + 1, 0,
370                 'JUMP_IF_TRUE_OR_POP', 24, 0,
371                 'LOAD_CONST', const_idx, 0,
372                 'LOAD_FAST', 0, 0,
373                 'LOAD_ATTR', attr_idx + 1, 0,
374                 'COMPARE_OP', 2, 0,
375                 'RETURN_VALUE',
376             ]
377         },
378         { # 5
379             'function': f_unicode_const_getattr,
380             'results': [
381                 'LOAD_FAST', 0, 0,
382                 # 2, since co_names was ('getattr', 'x').
383                 'LOAD_ATTR', attr_idx + 1, 0,
384                 'LOAD_CONST', const_idx + 1, 0,
385                 'COMPARE_OP', 2, 0,
386                 'RETURN_VALUE',
387             ]
388         },
389         { # 6
390
391             # Test a tainted (late-bound) function
392             'function': f_late_binding,
393             'bind_late': [datetime.date.today],
394             'results': [
395                 'LOAD_FAST', 0, 0,
396                 'LOAD_ATTR', attr_idx, 0,
397                 'LOAD_CONST', const_idx + 2, 0,
398                 'CALL_FUNCTION', 0, 0,
399                 'COMPARE_OP', 5, 0,
400                 'RETURN_VALUE',
401             ]
402         },
403         { # 7
404
405             # Closures (dereferencing of func_closure)
406             'function': f_closure_example,
407             'results': [
408                 'LOAD_CONST', const_idx + 1, 0,
409                 'RETURN_VALUE',
410             ]
411         },
412     ]
413
414     lambda_decompiler_tests = [
415         { # 0
416             'function': f_in_op,
417             'results': 'lambda x: x in a',
418         },
419         { # 1
420             'function': f_add_op,
421             'results': 'lambda x: x + datetime.date(2004, 1, 1)',
422         },
423         { # 2
424             'function': f_kwargs_and_op,
425             'results': "lambda x, **kw: (x.Date == datetime.date(2004, 1, 1)) and (x.Qty < kw['Size'])",
426         },
427         { # 3
428             'function': f_mix_names_global_locals_attrs,
429             'results': "lambda x, amount: (4 != x.amount) or (amount * 3 > 20)",
430         },
431         { # 4
432             'function': f_constant_multiplication,
433             'results': "lambda x: 60 * x",
434         },
435         { # 5
436             'function': f_array_slice_subscript,
437             'results': "lambda x: a[2:4] == -(x['offset'])",
438         },
439         { # 6
440             'function': f_const_attr,
441             'results': "lambda x: (amount == 5) or (amount == x.Qty)",
442         },
443         { # 7
444             'function': f_nested_conditionals,
445             'results': "lambda x: not ((x.a == 3) and ((x.b > 1) or (x.b < -10)))",
446         },
447         {
448             'function': f_nested_conditionals_2,
449             'results': "lambda x: not (((x.a == 3) and (x.b > 1)) or (x.b < -10))",
450         },
451         { # 8
452             'function': f_unicode_const,
453             'results': "lambda x: x.Name == u'Dimsdale'",
454         },
455         { # 9
456             'function': f_unicode_const_getattr,
457             'results': "lambda x: getattr(x, 'Name') == u'Dimsdale'",
458         },
459         { # 10
460             'function': f_unicode_multiple_args,
461             'results': "lambda x, y, z, **kw: (x.Qty > 1) and ((y.Qty > 20) and (z.Type == 'A'))",
462         },
463         # Skipping the closure one until we can figure out how to write a closure as a lambda
464         { # 12
465             'function': f_fixed_point,
466             'results': "lambda x: x.Amount > decimal.Decimal(3, 2)",
467         },
468     ]
469     branch_tracker_tests = [
470         {
471             'function': f_const_attr,
472             'results': [9, 21],
473         },
474     ]
475
476 Results = Results_Python26
477 if sys.version_info >= (2, 7):
478     Results = Results_Python27
479 elif sys.version_info >= (2, 5):
480     Results = Results_Python26
481 else:
482     raise RuntimeError("Python 2.5 and below no longer supported.")
483
484
485 class VisitorTests(unittest.TestCase):
486
487     def test_safe_tuple(self):
488         l = ['logic', 'icontains', 'getattr', 'x', 'field', 'criteria', u'GroupName']
489         self.assertEqual(codewalk.safe_tuple(l), ('logic', 'icontains', 'getattr',
490                                                   'x', 'field', 'criteria', 'GroupName'))
491
492     def test_Localizer(self):
493         count = 0
494         for test_case in Results.localizer_tests:
495             localized_code = codewalk.Localizer(test_case['function']).bytecode()
496             self.assertEqual(localized_code, nums(test_case['results']))
497             count += 1
498
499         self.assertEqual(count, 4, "We have 4 localizer tests, not all ran.")
500
501     def test_EarlyBinder(self):
502         count = 0
503         for test_case in Results.early_binder_tests:
504             early_bound_code = codewalk.EarlyBinder(
505                     test_case['function'],
506                     bind_late=test_case.get('bind_late', [])
507                 ).bytecode()
508             self.assertEqual(early_bound_code, nums(test_case['results']))
509             count += 1
510
511         self.assertEqual(count, 8, "We have 8 localizer tests, not all ran.")
512
513     def test_LambdaDecompiler(self):
514         count = 0
515         for test_case in Results.lambda_decompiler_tests:
516             ld = codewalk.LambdaDecompiler(test_case['function'])
517 ##            ld.verbose = True
518             lambda_string = ld.code()
519             self.assertEqual(lambda_string, test_case['results'])
520             count += 1
521         self.assertEqual(count, 13, "We have 13 lambda decompiler tests, not all ran")
522
523         # Test BUILD_LIST, BUILD_TUPLE
524         builder = lambda a, b: [a, min(b)]
525         self.assertEqual(codewalk.LambdaDecompiler(builder).code(),
526                          "lambda a, b: [a, min(b)]")
527         builder = lambda a, b, c: (c, [b.next(), a], c.ID)
528         self.assertEqual(codewalk.LambdaDecompiler(builder).code(),
529                          "lambda a, b, c: (c, [b.next(), a], c.ID)")
530
531         # Test MapStackObject
532         e = lambda t: {'x': 3, 'y': 5}
533         ld = codewalk.LambdaDecompiler(e)
534         c = ld.code()
535         self.assertEqual(c, "lambda t: {'y': 5, 'x': 3}", (c, ld.stack))
536
537         e = lambda t:{'x':{'a':10}, 'y':5}
538         ld = codewalk.LambdaDecompiler(e)
539         c = ld.code()
540         self.assertEqual(c, "lambda t: {'y': 5, 'x': {'a': 10}}", (c, ld.stack))
541
542         e = lambda t:{'x':str({'a':10}), 'y':5}
543         ld = codewalk.LambdaDecompiler(e)
544         c = ld.code()
545         self.assertEqual(c, "lambda t: {'y': 5, 'x': str({'a': 10})}", (c, ld.stack))
546
547         e = lambda t: [{'x': 10}, {'y': 5}]
548         ld = codewalk.LambdaDecompiler(e)
549         c = ld.code()
550         self.assertEqual(c, "lambda t: [{'x': 10}, {'y': 5}]", (c, ld.stack))
551
552     def test_BranchTracker(self):
553         count = 0
554         for test_case in Results.branch_tracker_tests:
555             branches = codewalk.BranchTracker(test_case['function']).branches()
556             self.assertEqual(branches, test_case['results'])
557             count += 1
558         self.assertEqual(1, count, "There are only 1 tests for the branch tracker - and it didn't run")
559
560     def test_KeywordInspector(self):
561         e = lambda x, **kw: x.Size > kw['Size']
562         self.assertEqual(codewalk.KeywordInspector(e).kwargs(), ["Size"])
563         e = lambda x: x.Size > kw['Size']
564         self.assertRaises(ValueError, codewalk.KeywordInspector, e)
565         e = lambda x, **kw: x.Date > x.newdate(kw['Year'], 1, 1)
566         self.assertEqual(codewalk.KeywordInspector(e).kwargs(), ["Year"])
567 ##
568 ##    def test_GenexpDecompiler(self):
569 ##        t = ([([t1.a, t2.b + 3] for t1, t2 in [1, 2, 3] if t1.x == 0),
570 ##              '([t1.a, t2.b + 3] for t1, t2 in [1, 2, 3] if t1.x == 0)'],
571 ##             )
572 ##        for g, s in t:
573 ##            g = codewalk.GenexpDecompiler(g)
574 ####            g.verbose = True
575 ##            r = g.code()
576 ##            self.assertEqual(r, s)
577
578
579 if __name__ == "__main__":
580     unittest.main(__name__)
581
Note: See TracBrowser for help on using the browser.