comparison genshi/template/tests/eval.py @ 820:9755836bb396 experimental-inline

Sync (old) experimental inline branch with trunk@1027.
author cmlenz
date Wed, 11 Mar 2009 17:51:06 +0000
parents 3eb30e4ece8c
children fe25855324dd
comparison
equal deleted inserted replaced
500:3eb30e4ece8c 820:9755836bb396
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 # 2 #
3 # Copyright (C) 2006-2007 Edgewall Software 3 # Copyright (C) 2006-2008 Edgewall Software
4 # All rights reserved. 4 # All rights reserved.
5 # 5 #
6 # This software is licensed as described in the file COPYING, which 6 # This software is licensed as described in the file COPYING, which
7 # you should have received as part of this distribution. The terms 7 # you should have received as part of this distribution. The terms
8 # are also available at http://genshi.edgewall.org/wiki/License. 8 # are also available at http://genshi.edgewall.org/wiki/License.
10 # This software consists of voluntary contributions made by many 10 # This software consists of voluntary contributions made by many
11 # individuals. For the exact contribution history, see the revision 11 # individuals. For the exact contribution history, see the revision
12 # history and logs, available at http://genshi.edgewall.org/log/. 12 # history and logs, available at http://genshi.edgewall.org/log/.
13 13
14 import doctest 14 import doctest
15 import pickle
16 from StringIO import StringIO
15 import sys 17 import sys
16 import unittest 18 import unittest
17 19
18 from genshi.core import Markup 20 from genshi.core import Markup
21 from genshi.template.base import Context
19 from genshi.template.eval import Expression, Suite, Undefined, UndefinedError, \ 22 from genshi.template.eval import Expression, Suite, Undefined, UndefinedError, \
20 UNDEFINED 23 UNDEFINED
21 24
22 25
23 class ExpressionTestCase(unittest.TestCase): 26 class ExpressionTestCase(unittest.TestCase):
29 32
30 def test_hash(self): 33 def test_hash(self):
31 expr = Expression('x,y') 34 expr = Expression('x,y')
32 self.assertEqual(hash(expr), hash(Expression('x,y'))) 35 self.assertEqual(hash(expr), hash(Expression('x,y')))
33 self.assertNotEqual(hash(expr), hash(Expression('y, x'))) 36 self.assertNotEqual(hash(expr), hash(Expression('y, x')))
37
38 def test_pickle(self):
39 expr = Expression('1 < 2')
40 buf = StringIO()
41 pickle.dump(expr, buf, 2)
42 buf.seek(0)
43 unpickled = pickle.load(buf)
44 assert unpickled.evaluate({}) is True
34 45
35 def test_name_lookup(self): 46 def test_name_lookup(self):
36 self.assertEqual('bar', Expression('foo').evaluate({'foo': 'bar'})) 47 self.assertEqual('bar', Expression('foo').evaluate({'foo': 'bar'}))
37 self.assertEqual(id, Expression('id').evaluate({})) 48 self.assertEqual(id, Expression('id').evaluate({}))
38 self.assertEqual('bar', Expression('id').evaluate({'id': 'bar'})) 49 self.assertEqual('bar', Expression('id').evaluate({'id': 'bar'}))
182 self.assertEqual(True, Expression("x == y").evaluate({'x': 1, 'y': 1})) 193 self.assertEqual(True, Expression("x == y").evaluate({'x': 1, 'y': 1}))
183 194
184 def test_compare_ne(self): 195 def test_compare_ne(self):
185 self.assertEqual(False, Expression("1 != 1").evaluate({})) 196 self.assertEqual(False, Expression("1 != 1").evaluate({}))
186 self.assertEqual(False, Expression("x != y").evaluate({'x': 1, 'y': 1})) 197 self.assertEqual(False, Expression("x != y").evaluate({'x': 1, 'y': 1}))
187 self.assertEqual(False, Expression("1 <> 1").evaluate({})) 198 if sys.version < '3':
188 self.assertEqual(False, Expression("x <> y").evaluate({'x': 1, 'y': 1})) 199 self.assertEqual(False, Expression("1 <> 1").evaluate({}))
200 self.assertEqual(False, Expression("x <> y").evaluate({'x': 1, 'y': 1}))
189 201
190 def test_compare_lt(self): 202 def test_compare_lt(self):
191 self.assertEqual(True, Expression("1 < 2").evaluate({})) 203 self.assertEqual(True, Expression("1 < 2").evaluate({}))
192 self.assertEqual(True, Expression("x < y").evaluate({'x': 1, 'y': 2})) 204 self.assertEqual(True, Expression("x < y").evaluate({'x': 1, 'y': 2}))
193 205
228 return x 240 return x
229 expr = Expression("foo(**bar)") 241 expr = Expression("foo(**bar)")
230 self.assertEqual(42, expr.evaluate({'foo': foo, 'bar': {"x": 42}})) 242 self.assertEqual(42, expr.evaluate({'foo': foo, 'bar': {"x": 42}}))
231 243
232 def test_lambda(self): 244 def test_lambda(self):
233 # Define a custom `sorted` function cause the builtin isn't available 245 data = {'items': range(5)}
234 # on Python 2.3 246 expr = Expression("filter(lambda x: x > 2, items)")
235 def sorted(items, compfunc): 247 self.assertEqual([3, 4], expr.evaluate(data))
236 items.sort(compfunc)
237 return items
238 data = {'items': [{'name': 'b', 'value': 0}, {'name': 'a', 'value': 1}],
239 'sorted': sorted}
240 expr = Expression("sorted(items, lambda a, b: cmp(a.name, b.name))")
241 self.assertEqual([{'name': 'a', 'value': 1}, {'name': 'b', 'value': 0}],
242 expr.evaluate(data))
243 248
244 def test_list_comprehension(self): 249 def test_list_comprehension(self):
245 expr = Expression("[n for n in numbers if n < 2]") 250 expr = Expression("[n for n in numbers if n < 2]")
246 self.assertEqual([0, 1], expr.evaluate({'numbers': range(5)})) 251 self.assertEqual([0, 1], expr.evaluate({'numbers': range(5)}))
247 252
261 def test_list_comprehension_with_getitem(self): 266 def test_list_comprehension_with_getitem(self):
262 items = [{'name': 'a', 'value': 1}, {'name': 'b', 'value': 2}] 267 items = [{'name': 'a', 'value': 1}, {'name': 'b', 'value': 2}]
263 expr = Expression("[i['name'] for i in items if i['value'] > 1]") 268 expr = Expression("[i['name'] for i in items if i['value'] > 1]")
264 self.assertEqual(['b'], expr.evaluate({'items': items})) 269 self.assertEqual(['b'], expr.evaluate({'items': items}))
265 270
266 if sys.version_info >= (2, 4): 271 def test_generator_expression(self):
267 # Generator expressions only supported in Python 2.4 and up 272 expr = Expression("list(n for n in numbers if n < 2)")
268 273 self.assertEqual([0, 1], expr.evaluate({'numbers': range(5)}))
269 def test_generator_expression(self): 274
270 expr = Expression("list(n for n in numbers if n < 2)") 275 expr = Expression("list((i, n + 1) for i, n in enumerate(numbers))")
271 self.assertEqual([0, 1], expr.evaluate({'numbers': range(5)})) 276 self.assertEqual([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)],
272 277 expr.evaluate({'numbers': range(5)}))
273 expr = Expression("list((i, n + 1) for i, n in enumerate(numbers))") 278
274 self.assertEqual([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)], 279 expr = Expression("list(offset + n for n in numbers)")
275 expr.evaluate({'numbers': range(5)})) 280 self.assertEqual([2, 3, 4, 5, 6],
276 281 expr.evaluate({'numbers': range(5), 'offset': 2}))
277 expr = Expression("list(offset + n for n in numbers)") 282
278 self.assertEqual([2, 3, 4, 5, 6], 283 def test_generator_expression_with_getattr(self):
279 expr.evaluate({'numbers': range(5), 'offset': 2})) 284 items = [{'name': 'a', 'value': 1}, {'name': 'b', 'value': 2}]
280 285 expr = Expression("list(i.name for i in items if i.value > 1)")
281 def test_generator_expression_with_getattr(self): 286 self.assertEqual(['b'], expr.evaluate({'items': items}))
282 items = [{'name': 'a', 'value': 1}, {'name': 'b', 'value': 2}] 287
283 expr = Expression("list(i.name for i in items if i.value > 1)") 288 def test_generator_expression_with_getitem(self):
284 self.assertEqual(['b'], expr.evaluate({'items': items})) 289 items = [{'name': 'a', 'value': 1}, {'name': 'b', 'value': 2}]
285 290 expr = Expression("list(i['name'] for i in items if i['value'] > 1)")
286 def test_generator_expression_with_getitem(self): 291 self.assertEqual(['b'], expr.evaluate({'items': items}))
287 items = [{'name': 'a', 'value': 1}, {'name': 'b', 'value': 2}]
288 expr = Expression("list(i['name'] for i in items if i['value'] > 1)")
289 self.assertEqual(['b'], expr.evaluate({'items': items}))
290 292
291 if sys.version_info >= (2, 5): 293 if sys.version_info >= (2, 5):
292 def test_conditional_expression(self): 294 def test_conditional_expression(self):
293 expr = Expression("'T' if foo else 'F'") 295 expr = Expression("'T' if foo else 'F'")
294 self.assertEqual('T', expr.evaluate({'foo': True})) 296 self.assertEqual('T', expr.evaluate({'foo': True}))
319 def test_slice_negative_end(self): 321 def test_slice_negative_end(self):
320 expr = Expression("numbers[:-1]") 322 expr = Expression("numbers[:-1]")
321 self.assertEqual([0, 1, 2, 3], expr.evaluate({'numbers': range(5)})) 323 self.assertEqual([0, 1, 2, 3], expr.evaluate({'numbers': range(5)}))
322 324
323 def test_access_undefined(self): 325 def test_access_undefined(self):
324 expr = Expression("nothing", filename='index.html', lineno=50) 326 expr = Expression("nothing", filename='index.html', lineno=50,
327 lookup='lenient')
325 retval = expr.evaluate({}) 328 retval = expr.evaluate({})
326 assert isinstance(retval, Undefined) 329 assert isinstance(retval, Undefined)
327 self.assertEqual('nothing', retval._name) 330 self.assertEqual('nothing', retval._name)
328 assert retval._owner is UNDEFINED 331 assert retval._owner is UNDEFINED
329 332
330 def test_getattr_undefined(self): 333 def test_getattr_undefined(self):
331 class Something(object): 334 class Something(object):
332 def __repr__(self): 335 def __repr__(self):
333 return '<Something>' 336 return '<Something>'
334 something = Something() 337 something = Something()
335 expr = Expression('something.nil', filename='index.html', lineno=50) 338 expr = Expression('something.nil', filename='index.html', lineno=50,
339 lookup='lenient')
336 retval = expr.evaluate({'something': something}) 340 retval = expr.evaluate({'something': something})
337 assert isinstance(retval, Undefined) 341 assert isinstance(retval, Undefined)
338 self.assertEqual('nil', retval._name) 342 self.assertEqual('nil', retval._name)
339 assert retval._owner is something 343 assert retval._owner is something
344
345 def test_getattr_exception(self):
346 class Something(object):
347 def prop_a(self):
348 raise NotImplementedError
349 prop_a = property(prop_a)
350 def prop_b(self):
351 raise AttributeError
352 prop_b = property(prop_b)
353 self.assertRaises(NotImplementedError,
354 Expression('s.prop_a').evaluate, {'s': Something()})
355 self.assertRaises(AttributeError,
356 Expression('s.prop_b').evaluate, {'s': Something()})
340 357
341 def test_getitem_undefined_string(self): 358 def test_getitem_undefined_string(self):
342 class Something(object): 359 class Something(object):
343 def __repr__(self): 360 def __repr__(self):
344 return '<Something>' 361 return '<Something>'
345 something = Something() 362 something = Something()
346 expr = Expression('something["nil"]', filename='index.html', lineno=50) 363 expr = Expression('something["nil"]', filename='index.html', lineno=50,
364 lookup='lenient')
347 retval = expr.evaluate({'something': something}) 365 retval = expr.evaluate({'something': something})
348 assert isinstance(retval, Undefined) 366 assert isinstance(retval, Undefined)
349 self.assertEqual('nil', retval._name) 367 self.assertEqual('nil', retval._name)
350 assert retval._owner is something 368 assert retval._owner is something
369
370 def test_getitem_exception(self):
371 class Something(object):
372 def __getitem__(self, key):
373 raise NotImplementedError
374 self.assertRaises(NotImplementedError,
375 Expression('s["foo"]').evaluate, {'s': Something()})
351 376
352 def test_error_access_undefined(self): 377 def test_error_access_undefined(self):
353 expr = Expression("nothing", filename='index.html', lineno=50, 378 expr = Expression("nothing", filename='index.html', lineno=50,
354 lookup='strict') 379 lookup='strict')
355 try: 380 try:
418 self.assertEqual(50, frame.tb_lineno) 443 self.assertEqual(50, frame.tb_lineno)
419 444
420 445
421 class SuiteTestCase(unittest.TestCase): 446 class SuiteTestCase(unittest.TestCase):
422 447
448 def test_pickle(self):
449 suite = Suite('foo = 42')
450 buf = StringIO()
451 pickle.dump(suite, buf, 2)
452 buf.seek(0)
453 unpickled = pickle.load(buf)
454 data = {}
455 unpickled.execute(data)
456 self.assertEqual(42, data['foo'])
457
458 def test_internal_shadowing(self):
459 # The context itself is stored in the global execution scope of a suite
460 # It used to get stored under the name 'data', which meant the
461 # following test would fail, as the user defined 'data' variable
462 # shadowed the Genshi one. We now use the name '__data__' to avoid
463 # conflicts
464 suite = Suite("""data = []
465 bar = foo
466 """)
467 data = {'foo': 42}
468 suite.execute(data)
469 self.assertEqual(42, data['bar'])
470
423 def test_assign(self): 471 def test_assign(self):
424 suite = Suite("foo = 42") 472 suite = Suite("foo = 42")
425 data = {} 473 data = {}
426 suite.execute(data) 474 suite.execute(data)
427 self.assertEqual(42, data['foo']) 475 self.assertEqual(42, data['foo'])
432 suite.execute(data) 480 suite.execute(data)
433 assert 'donothing' in data 481 assert 'donothing' in data
434 self.assertEqual(None, data['donothing']()) 482 self.assertEqual(None, data['donothing']())
435 483
436 def test_def_with_multiple_statements(self): 484 def test_def_with_multiple_statements(self):
437 suite = Suite("""def donothing(): 485 suite = Suite("""
486 def donothing():
438 if True: 487 if True:
439 return foo 488 return foo
440 """) 489 """)
441 data = {'foo': 'bar'} 490 data = {'foo': 'bar'}
442 suite.execute(data) 491 suite.execute(data)
443 assert 'donothing' in data 492 assert 'donothing' in data
444 self.assertEqual('bar', data['donothing']()) 493 self.assertEqual('bar', data['donothing']())
494
495 def test_def_using_nonlocal(self):
496 suite = Suite("""
497 values = []
498 def add(value):
499 if value not in values:
500 values.append(value)
501 add('foo')
502 add('bar')
503 """)
504 data = {}
505 suite.execute(data)
506 self.assertEqual(['foo', 'bar'], data['values'])
507
508 def test_def_some_defaults(self):
509 suite = Suite("""
510 def difference(v1, v2=10):
511 return v1 - v2
512 x = difference(20, 19)
513 y = difference(20)
514 """)
515 data = {}
516 suite.execute(data)
517 self.assertEqual(1, data['x'])
518 self.assertEqual(10, data['y'])
519
520 def test_def_all_defaults(self):
521 suite = Suite("""
522 def difference(v1=100, v2=10):
523 return v1 - v2
524 x = difference(20, 19)
525 y = difference(20)
526 z = difference()
527 """)
528 data = {}
529 suite.execute(data)
530 self.assertEqual(1, data['x'])
531 self.assertEqual(10, data['y'])
532 self.assertEqual(90, data['z'])
533
534 def test_def_vararg(self):
535 suite = Suite("""
536 def mysum(*others):
537 rv = 0
538 for n in others:
539 rv = rv + n
540 return rv
541 x = mysum(1, 2, 3)
542 """)
543 data = {}
544 suite.execute(data)
545 self.assertEqual(6, data['x'])
546
547 def test_def_kwargs(self):
548 suite = Suite("""
549 def smash(**kw):
550 return [''.join(i) for i in kw.items()]
551 x = smash(foo='abc', bar='def')
552 """)
553 data = {}
554 suite.execute(data)
555 self.assertEqual(['fooabc', 'bardef'], data['x'])
556
557 def test_def_nested(self):
558 suite = Suite("""
559 def doit():
560 values = []
561 def add(value):
562 if value not in values:
563 values.append(value)
564 add('foo')
565 add('bar')
566 return values
567 x = doit()
568 """)
569 data = {}
570 suite.execute(data)
571 self.assertEqual(['foo', 'bar'], data['x'])
445 572
446 def test_delete(self): 573 def test_delete(self):
447 suite = Suite("""foo = 42 574 suite = Suite("""foo = 42
448 del foo 575 del foo
449 """) 576 """)
455 suite = Suite("class plain(object): pass") 582 suite = Suite("class plain(object): pass")
456 data = {} 583 data = {}
457 suite.execute(data) 584 suite.execute(data)
458 assert 'plain' in data 585 assert 'plain' in data
459 586
587 def test_class_in_def(self):
588 suite = Suite("""
589 def create():
590 class Foobar(object):
591 def __str__(self):
592 return 'foobar'
593 return Foobar()
594 x = create()
595 """)
596 data = {}
597 suite.execute(data)
598 self.assertEqual('foobar', str(data['x']))
599
600 def test_class_with_methods(self):
601 suite = Suite("""class plain(object):
602 def donothing():
603 pass
604 """)
605 data = {}
606 suite.execute(data)
607 assert 'plain' in data
608
460 def test_import(self): 609 def test_import(self):
461 suite = Suite("from itertools import ifilter") 610 suite = Suite("from itertools import ifilter")
462 data = {} 611 data = {}
463 suite.execute(data) 612 suite.execute(data)
464 assert 'ifilter' in data 613 assert 'ifilter' in data
614
615 def test_import_star(self):
616 suite = Suite("from itertools import *")
617 data = Context()
618 suite.execute(data)
619 assert 'ifilter' in data
620
621 def test_import_in_def(self):
622 suite = Suite("""def fun():
623 from itertools import ifilter
624 return ifilter(None, xrange(3))
625 """)
626 data = Context()
627 suite.execute(data)
628 assert 'ifilter' not in data
629 self.assertEqual([1, 2], list(data['fun']()))
465 630
466 def test_for(self): 631 def test_for(self):
467 suite = Suite("""x = [] 632 suite = Suite("""x = []
468 for i in range(3): 633 for i in range(3):
469 x.append(i**2) 634 x.append(i**2)
470 """) 635 """)
471 data = {} 636 data = {}
472 suite.execute(data) 637 suite.execute(data)
473 self.assertEqual([0, 1, 4], data['x']) 638 self.assertEqual([0, 1, 4], data['x'])
639
640 def test_for_in_def(self):
641 suite = Suite("""def loop():
642 for i in range(10):
643 if i == 5:
644 break
645 return i
646 """)
647 data = {}
648 suite.execute(data)
649 assert 'loop' in data
650 self.assertEqual(5, data['loop']())
474 651
475 def test_if(self): 652 def test_if(self):
476 suite = Suite("""if foo == 42: 653 suite = Suite("""if foo == 42:
477 x = True 654 x = True
478 """) 655 """)
523 self.assertEqual(43, d["k"]) 700 self.assertEqual(43, d["k"])
524 701
525 def test_local_augmented_assign(self): 702 def test_local_augmented_assign(self):
526 Suite("x = 1; x += 42; assert x == 43").execute({}) 703 Suite("x = 1; x += 42; assert x == 43").execute({})
527 704
705 def test_augmented_assign_in_def(self):
706 d = {}
707 Suite("""def foo():
708 i = 1
709 i += 1
710 return i
711 x = foo()""").execute(d)
712 self.assertEqual(2, d['x'])
713
714 def test_augmented_assign_in_loop_in_def(self):
715 d = {}
716 Suite("""def foo():
717 i = 0
718 for n in range(5):
719 i += n
720 return i
721 x = foo()""").execute(d)
722 self.assertEqual(10, d['x'])
723
528 def test_assign_in_list(self): 724 def test_assign_in_list(self):
529 suite = Suite("[d['k']] = 'foo',; assert d['k'] == 'foo'") 725 suite = Suite("[d['k']] = 'foo',; assert d['k'] == 'foo'")
530 d = {"k": "bar"} 726 d = {"k": "bar"}
531 suite.execute({"d": d}) 727 suite.execute({"d": d})
532 self.assertEqual("foo", d["k"]) 728 self.assertEqual("foo", d["k"])
567 self.failIf(hasattr(obj, 'attr')) 763 self.failIf(hasattr(obj, 'attr'))
568 764
569 def test_delitem(self): 765 def test_delitem(self):
570 d = {'k': 'foo'} 766 d = {'k': 'foo'}
571 Suite("del d['k']").execute({'d': d}) 767 Suite("del d['k']").execute({'d': d})
572 self.failIf('k' in d, `d`) 768 self.failIf('k' in d, repr(d))
573 769
574 770
575 def suite(): 771 def suite():
576 suite = unittest.TestSuite() 772 suite = unittest.TestSuite()
577 suite.addTest(doctest.DocTestSuite(Expression.__module__)) 773 suite.addTest(doctest.DocTestSuite(Expression.__module__))
Copyright (C) 2012-2017 Edgewall Software