Convert test_global, test_scope and test_grammar to unittest.

I tried to enclose all tests which must be run at the toplevel
(instead of inside a method) in exec statements.
This commit is contained in:
Georg Brandl 2006-10-28 13:10:17 +00:00
parent 3a3d8ea497
commit c6fdec6d7e
8 changed files with 1203 additions and 1228 deletions

View File

@ -379,8 +379,8 @@ test_support provides the following useful objects:
point numbers when you expect them to only be approximately equal point numbers when you expect them to only be approximately equal
withing a fuzz factor (``test_support.FUZZ``, which defaults to 1e-6). withing a fuzz factor (``test_support.FUZZ``, which defaults to 1e-6).
* ``check_syntax(statement)`` - make sure that the statement is *not* * ``check_syntax_error(testcase, statement)`` - make sure that the
correct Python syntax. statement is *not* correct Python syntax.
Python and C statement coverage results are currently available at Python and C statement coverage results are currently available at

View File

@ -1,5 +0,0 @@
test_global
got SyntaxError as expected
got SyntaxError as expected
got SyntaxError as expected
as expected, no SyntaxError

View File

@ -1,69 +0,0 @@
test_grammar
1. Parser
1.1 Tokens
1.1.1 Backslashes
1.1.2 Numeric literals
1.1.2.1 Plain integers
1.1.2.2 Long integers
1.1.2.3 Floating point
1.1.3 String literals
1.2 Grammar
single_input
file_input
expr_input
eval_input
funcdef
lambdef
simple_stmt
expr_stmt
print_stmt
1 2 3
1 2 3
1 1 1
extended print_stmt
1 2 3
1 2 3
1 1 1
hello world
del_stmt
pass_stmt
flow_stmt
break_stmt
continue_stmt
continue + try/except ok
continue + try/finally ok
testing continue and break in try/except in loop
return_stmt
yield_stmt
raise_stmt
import_name
import_from
global_stmt
exec_stmt
assert_stmt
if_stmt
while_stmt
for_stmt
try_stmt
suite
test
comparison
binary mask ops
shift ops
additive ops
multiplicative ops
unary ops
selectors
[1, (1,), (1, 2), (1, 2, 3)]
atoms
classdef
['Apple', 'Banana', 'Coco nut']
[3, 6, 9, 12, 15]
[3, 4, 5]
[(1, 'Apple'), (1, 'Banana'), (1, 'Coconut'), (2, 'Apple'), (2, 'Banana'), (2, 'Coconut'), (3, 'Apple'), (3, 'Banana'), (3, 'Coconut'), (4, 'Apple'), (4, 'Banana'), (4, 'Coconut'), (5, 'Apple'), (5, 'Banana'), (5, 'Coconut')]
[(1, 'Banana'), (1, 'Coconut'), (2, 'Banana'), (2, 'Coconut'), (3, 'Banana'), (3, 'Coconut'), (4, 'Banana'), (4, 'Coconut'), (5, 'Banana'), (5, 'Coconut')]
[[1], [1, 1], [1, 2, 4], [1, 3, 9, 27], [1, 4, 16, 64, 256]]
[False, False, False]
[[1, 2], [3, 4], [5, 6]]
[('Boeing', 'Airliner'), ('Boeing', 'Engine'), ('Ford', 'Engine'), ('Macdonalds', 'Cheeseburger')]

View File

@ -1,24 +0,0 @@
test_scope
1. simple nesting
2. extra nesting
3. simple nesting + rebinding
4. nesting with global but no free
5. nesting through class
6. nesting plus free ref to global
7. nearest enclosing scope
8. mixed freevars and cellvars
9. free variable in method
10. recursion
11. unoptimized namespaces
12. lambdas
13. UnboundLocal
14. complex definitions
15. scope of global statements
16. check leaks
17. class and global
18. verify that locals() works
19. var is bound and free in class
20. interaction with trace function
20. eval and exec with free variables
21. list comprehension with local variables
22. eval with free variables

View File

@ -1,51 +1,51 @@
"""Verify that warnings are issued for global statements following use.""" """Verify that warnings are issued for global statements following use."""
from test.test_support import check_syntax from test.test_support import run_unittest, check_syntax_error
import unittest
import warnings import warnings
warnings.filterwarnings("error", module="<test string>")
warnings.filterwarnings("error", module="<test code>") class GlobalTests(unittest.TestCase):
def compile_and_check(text, should_fail=1): def test1(self):
try: prog_text_1 = """\
compile(text, "<test code>", "exec")
except SyntaxError, msg:
if should_fail:
print "got SyntaxError as expected"
else:
print "raised unexpected SyntaxError:", text
else:
if should_fail:
print "should have raised SyntaxError:", text
else:
print "as expected, no SyntaxError"
prog_text_1 = """
def wrong1(): def wrong1():
a = 1 a = 1
b = 2 b = 2
global a global a
global b global b
""" """
compile_and_check(prog_text_1) check_syntax_error(self, prog_text_1)
prog_text_2 = """ def test2(self):
prog_text_2 = """\
def wrong2(): def wrong2():
print x print x
global x global x
""" """
compile_and_check(prog_text_2) check_syntax_error(self, prog_text_2)
prog_text_3 = """ def test3(self):
prog_text_3 = """\
def wrong3(): def wrong3():
print x print x
x = 2 x = 2
global x global x
""" """
compile_and_check(prog_text_3) check_syntax_error(self, prog_text_3)
prog_text_4 = """ def test4(self):
prog_text_4 = """\
global x global x
x = 2 x = 2
""" """
compile_and_check(prog_text_4, 0) # this should work
compile(prog_text_4, "<test string>", "exec")
def test_main():
run_unittest(GlobalTests)
if __name__ == "__main__":
test_main()

File diff suppressed because it is too large Load Diff

View File

@ -1,53 +1,57 @@
from test.test_support import verify, TestFailed, check_syntax, vereq import unittest
from test.test_support import check_syntax_error, run_unittest
import warnings import warnings
warnings.filterwarnings("ignore", r"import \*", SyntaxWarning, "<test string>")
warnings.filterwarnings("ignore", r"import \*", SyntaxWarning, "<string>") warnings.filterwarnings("ignore", r"import \*", SyntaxWarning, "<string>")
print "1. simple nesting" class ScopeTests(unittest.TestCase):
def make_adder(x): def testSimpleNesting(self):
def make_adder(x):
def adder(y): def adder(y):
return x + y return x + y
return adder return adder
inc = make_adder(1) inc = make_adder(1)
plus10 = make_adder(10) plus10 = make_adder(10)
vereq(inc(1), 2) self.assertEqual(inc(1), 2)
vereq(plus10(-2), 8) self.assertEqual(plus10(-2), 8)
print "2. extra nesting" def testExtraNesting(self):
def make_adder2(x): def make_adder2(x):
def extra(): # check freevars passing through non-use scopes def extra(): # check freevars passing through non-use scopes
def adder(y): def adder(y):
return x + y return x + y
return adder return adder
return extra() return extra()
inc = make_adder2(1) inc = make_adder2(1)
plus10 = make_adder2(10) plus10 = make_adder2(10)
vereq(inc(1), 2) self.assertEqual(inc(1), 2)
vereq(plus10(-2), 8) self.assertEqual(plus10(-2), 8)
print "3. simple nesting + rebinding" def testSimpleAndRebinding(self):
def make_adder3(x): def make_adder3(x):
def adder(y): def adder(y):
return x + y return x + y
x = x + 1 # check tracking of assignment to x in defining scope x = x + 1 # check tracking of assignment to x in defining scope
return adder return adder
inc = make_adder3(0) inc = make_adder3(0)
plus10 = make_adder3(9) plus10 = make_adder3(9)
vereq(inc(1), 2) self.assertEqual(inc(1), 2)
vereq(plus10(-2), 8) self.assertEqual(plus10(-2), 8)
print "4. nesting with global but no free" def testNestingGlobalNoFree(self):
def make_adder4(): # XXX add exta level of indirection def make_adder4(): # XXX add exta level of indirection
def nest(): def nest():
def nest(): def nest():
def adder(y): def adder(y):
@ -56,45 +60,45 @@ def make_adder4(): # XXX add exta level of indirection
return nest() return nest()
return nest() return nest()
global_x = 1 global_x = 1
adder = make_adder4() adder = make_adder4()
vereq(adder(1), 2) self.assertEqual(adder(1), 2)
global_x = 10 global_x = 10
vereq(adder(-2), 8) self.assertEqual(adder(-2), 8)
print "5. nesting through class" def testNestingThroughClass(self):
def make_adder5(x): def make_adder5(x):
class Adder: class Adder:
def __call__(self, y): def __call__(self, y):
return x + y return x + y
return Adder() return Adder()
inc = make_adder5(1) inc = make_adder5(1)
plus10 = make_adder5(10) plus10 = make_adder5(10)
vereq(inc(1), 2) self.assertEqual(inc(1), 2)
vereq(plus10(-2), 8) self.assertEqual(plus10(-2), 8)
print "6. nesting plus free ref to global" def testNestingPlusFreeRefToGlobal(self):
def make_adder6(x): def make_adder6(x):
global global_nest_x global global_nest_x
def adder(y): def adder(y):
return global_nest_x + y return global_nest_x + y
global_nest_x = x global_nest_x = x
return adder return adder
inc = make_adder6(1) inc = make_adder6(1)
plus10 = make_adder6(10) plus10 = make_adder6(10)
vereq(inc(1), 11) # there's only one global self.assertEqual(inc(1), 11) # there's only one global
vereq(plus10(-2), 8) self.assertEqual(plus10(-2), 8)
print "7. nearest enclosing scope" def testNearestEnclosingScope(self):
def f(x): def f(x):
def g(y): def g(y):
x = 42 # check that this masks binding in f() x = 42 # check that this masks binding in f()
def h(z): def h(z):
@ -102,15 +106,15 @@ def f(x):
return h return h
return g(2) return g(2)
test_func = f(10) test_func = f(10)
vereq(test_func(5), 47) self.assertEqual(test_func(5), 47)
print "8. mixed freevars and cellvars" def testMixedFreevarsAndCellvars(self):
def identity(x): def identity(x):
return x return x
def f(x, y, z): def f(x, y, z):
def g(a, b, c): def g(a, b, c):
a = a + x # 3 a = a + x # 3
def h(): def h():
@ -121,13 +125,13 @@ def f(x, y, z):
return h return h
return g return g
g = f(1, 2, 3) g = f(1, 2, 3)
h = g(2, 4, 6) h = g(2, 4, 6)
vereq(h(), 39) self.assertEqual(h(), 39)
print "9. free variable in method" def testFreeVarInMethod(self):
def test(): def test():
method_and_var = "var" method_and_var = "var"
class Test: class Test:
def method_and_var(self): def method_and_var(self):
@ -140,13 +144,13 @@ def test():
return str(self) return str(self)
return Test() return Test()
t = test() t = test()
vereq(t.test(), "var") self.assertEqual(t.test(), "var")
vereq(t.method_and_var(), "method") self.assertEqual(t.method_and_var(), "method")
vereq(t.actual_global(), "global") self.assertEqual(t.actual_global(), "global")
method_and_var = "var" method_and_var = "var"
class Test: class Test:
# this class is not nested, so the rules are different # this class is not nested, so the rules are different
def method_and_var(self): def method_and_var(self):
return "method" return "method"
@ -157,14 +161,14 @@ class Test:
def str(self): def str(self):
return str(self) return str(self)
t = Test() t = Test()
vereq(t.test(), "var") self.assertEqual(t.test(), "var")
vereq(t.method_and_var(), "method") self.assertEqual(t.method_and_var(), "method")
vereq(t.actual_global(), "global") self.assertEqual(t.actual_global(), "global")
print "10. recursion" def testRecursion(self):
def f(x): def f(x):
def fact(n): def fact(n):
if n == 0: if n == 0:
return 1 return 1
@ -175,12 +179,12 @@ def f(x):
else: else:
raise ValueError, "x must be >= 0" raise ValueError, "x must be >= 0"
vereq(f(6), 720) self.assertEqual(f(6), 720)
print "11. unoptimized namespaces" def testUnoptimizedNamespaces(self):
check_syntax("""\ check_syntax_error(self, """\
def unoptimized_clash1(strip): def unoptimized_clash1(strip):
def f(s): def f(s):
from string import * from string import *
@ -188,7 +192,7 @@ def unoptimized_clash1(strip):
return f return f
""") """)
check_syntax("""\ check_syntax_error(self, """\
def unoptimized_clash2(): def unoptimized_clash2():
from string import * from string import *
def f(s): def f(s):
@ -196,7 +200,7 @@ def unoptimized_clash2():
return f return f
""") """)
check_syntax("""\ check_syntax_error(self, """\
def unoptimized_clash2(): def unoptimized_clash2():
from string import * from string import *
def g(): def g():
@ -205,8 +209,8 @@ def unoptimized_clash2():
return f return f
""") """)
# XXX could allow this for exec with const argument, but what's the point # XXX could allow this for exec with const argument, but what's the point
check_syntax("""\ check_syntax_error(self, """\
def error(y): def error(y):
exec "a = 1" exec "a = 1"
def f(x): def f(x):
@ -214,23 +218,23 @@ def error(y):
return f return f
""") """)
check_syntax("""\ check_syntax_error(self, """\
def f(x): def f(x):
def g(): def g():
return x return x
del x # can't del name del x # can't del name
""") """)
check_syntax("""\ check_syntax_error(self, """\
def f(): def f():
def g(): def g():
from string import * from string import *
return strip # global or local? return strip # global or local?
""") """)
# and verify a few cases that should work # and verify a few cases that should work
exec """ exec """
def noproblem1(): def noproblem1():
from string import * from string import *
f = lambda x:x f = lambda x:x
@ -247,59 +251,60 @@ def noproblem3():
y = x y = x
""" """
print "12. lambdas" def testLambdas(self):
f1 = lambda x: lambda y: x + y f1 = lambda x: lambda y: x + y
inc = f1(1) inc = f1(1)
plus10 = f1(10) plus10 = f1(10)
vereq(inc(1), 2) self.assertEqual(inc(1), 2)
vereq(plus10(5), 15) self.assertEqual(plus10(5), 15)
f2 = lambda x: (lambda : lambda y: x + y)() f2 = lambda x: (lambda : lambda y: x + y)()
inc = f2(1) inc = f2(1)
plus10 = f2(10) plus10 = f2(10)
vereq(inc(1), 2) self.assertEqual(inc(1), 2)
vereq(plus10(5), 15) self.assertEqual(plus10(5), 15)
f3 = lambda x: lambda y: global_x + y f3 = lambda x: lambda y: global_x + y
global_x = 1 global_x = 1
inc = f3(None) inc = f3(None)
vereq(inc(2), 3) self.assertEqual(inc(2), 3)
f8 = lambda x, y, z: lambda a, b, c: lambda : z * (b + y) f8 = lambda x, y, z: lambda a, b, c: lambda : z * (b + y)
g = f8(1, 2, 3) g = f8(1, 2, 3)
h = g(2, 4, 6) h = g(2, 4, 6)
vereq(h(), 18) self.assertEqual(h(), 18)
print "13. UnboundLocal" def testUnboundLocal(self):
def errorInOuter(): def errorInOuter():
print y print y
def inner(): def inner():
return y return y
y = 1 y = 1
def errorInInner(): def errorInInner():
def inner(): def inner():
return y return y
inner() inner()
y = 1 y = 1
try: try:
errorInOuter() errorInOuter()
except UnboundLocalError: except UnboundLocalError:
pass pass
else: else:
raise TestFailed self.fail()
try: try:
errorInInner() errorInInner()
except NameError: except NameError:
pass pass
else: else:
raise TestFailed self.fail()
# test for bug #1501934: incorrect LOAD/STORE_GLOBAL generation # test for bug #1501934: incorrect LOAD/STORE_GLOBAL generation
exec """
global_x = 1 global_x = 1
def f(): def f():
global_x += 1 global_x += 1
@ -308,34 +313,36 @@ try:
except UnboundLocalError: except UnboundLocalError:
pass pass
else: else:
raise TestFailed, 'scope of global_x not correctly determined' fail('scope of global_x not correctly determined')
""" in {'fail': self.fail}
print "14. complex definitions" def testComplexDefinitions(self):
def makeReturner(*lst): def makeReturner(*lst):
def returner(): def returner():
return lst return lst
return returner return returner
vereq(makeReturner(1,2,3)(), (1,2,3)) self.assertEqual(makeReturner(1,2,3)(), (1,2,3))
def makeReturner2(**kwargs): def makeReturner2(**kwargs):
def returner(): def returner():
return kwargs return kwargs
return returner return returner
vereq(makeReturner2(a=11)()['a'], 11) self.assertEqual(makeReturner2(a=11)()['a'], 11)
def makeAddPair((a, b)): def makeAddPair((a, b)):
def addPair((c, d)): def addPair((c, d)):
return (a + c, b + d) return (a + c, b + d)
return addPair return addPair
vereq(makeAddPair((1, 2))((100, 200)), (101,202)) self.assertEqual(makeAddPair((1, 2))((100, 200)), (101,202))
print "15. scope of global statements" def testScopeOfGlobalStmt(self):
# Examples posted by Samuele Pedroni to python-dev on 3/1/2001 # Examples posted by Samuele Pedroni to python-dev on 3/1/2001
exec """\
# I # I
x = 7 x = 7
def f(): def f():
@ -348,8 +355,8 @@ def f():
return h() return h()
return i() return i()
return g() return g()
vereq(f(), 7) self.assertEqual(f(), 7)
vereq(x, 7) self.assertEqual(x, 7)
# II # II
x = 7 x = 7
@ -363,8 +370,8 @@ def f():
return h() return h()
return i() return i()
return g() return g()
vereq(f(), 2) self.assertEqual(f(), 2)
vereq(x, 7) self.assertEqual(x, 7)
# III # III
x = 7 x = 7
@ -379,8 +386,8 @@ def f():
return h() return h()
return i() return i()
return g() return g()
vereq(f(), 2) self.assertEqual(f(), 2)
vereq(x, 2) self.assertEqual(x, 2)
# IV # IV
x = 7 x = 7
@ -395,8 +402,8 @@ def f():
return h() return h()
return i() return i()
return g() return g()
vereq(f(), 2) self.assertEqual(f(), 2)
vereq(x, 2) self.assertEqual(x, 2)
# XXX what about global statements in class blocks? # XXX what about global statements in class blocks?
# do they affect methods? # do they affect methods?
@ -411,13 +418,14 @@ class Global:
return x return x
g = Global() g = Global()
vereq(g.get(), 13) self.assertEqual(g.get(), 13)
g.set(15) g.set(15)
vereq(g.get(), 13) self.assertEqual(g.get(), 13)
"""
print "16. check leaks" def testLeaks(self):
class Foo: class Foo:
count = 0 count = 0
def __init__(self): def __init__(self):
@ -426,19 +434,20 @@ class Foo:
def __del__(self): def __del__(self):
Foo.count -= 1 Foo.count -= 1
def f1(): def f1():
x = Foo() x = Foo()
def f2(): def f2():
return x return x
f2() f2()
for i in range(100): for i in range(100):
f1() f1()
vereq(Foo.count, 0) self.assertEqual(Foo.count, 0)
print "17. class and global" def testClassAndGlobal(self):
exec """\
def test(x): def test(x):
class Foo: class Foo:
global x global x
@ -447,9 +456,9 @@ def test(x):
return Foo() return Foo()
x = 0 x = 0
vereq(test(6)(2), 8) self.assertEqual(test(6)(2), 8)
x = -1 x = -1
vereq(test(3)(2), 5) self.assertEqual(test(3)(2), 5)
looked_up_by_load_name = False looked_up_by_load_name = False
class X: class X:
@ -458,11 +467,12 @@ class X:
locals()['looked_up_by_load_name'] = True locals()['looked_up_by_load_name'] = True
passed = looked_up_by_load_name passed = looked_up_by_load_name
verify(X.passed) self.assert_(X.passed)
"""
print "18. verify that locals() works" def testLocalsFunction(self):
def f(x): def f(x):
def g(y): def g(y):
def h(z): def h(z):
return y + z return y + z
@ -471,91 +481,92 @@ def f(x):
return locals() return locals()
return g return g
d = f(2)(4) d = f(2)(4)
verify(d.has_key('h')) self.assert_(d.has_key('h'))
del d['h'] del d['h']
vereq(d, {'x': 2, 'y': 7, 'w': 6}) self.assertEqual(d, {'x': 2, 'y': 7, 'w': 6})
print "19. var is bound and free in class" def testBoundAndFree(self):
# var is bound and free in class
def f(x): def f(x):
class C: class C:
def m(self): def m(self):
return x return x
a = x a = x
return C return C
inst = f(3)() inst = f(3)()
vereq(inst.a, inst.m()) self.assertEqual(inst.a, inst.m())
print "20. interaction with trace function" def testInteractionWithTraceFunc(self):
import sys import sys
def tracer(a,b,c): def tracer(a,b,c):
return tracer return tracer
def adaptgetter(name, klass, getter): def adaptgetter(name, klass, getter):
kind, des = getter kind, des = getter
if kind == 1: # AV happens when stepping from this line to next if kind == 1: # AV happens when stepping from this line to next
if des == "": if des == "":
des = "_%s__%s" % (klass.__name__, name) des = "_%s__%s" % (klass.__name__, name)
return lambda obj: getattr(obj, des) return lambda obj: getattr(obj, des)
class TestClass: class TestClass:
pass pass
sys.settrace(tracer) sys.settrace(tracer)
adaptgetter("foo", TestClass, (1, "")) adaptgetter("foo", TestClass, (1, ""))
sys.settrace(None) sys.settrace(None)
try: sys.settrace() self.assertRaises(TypeError, sys.settrace)
except TypeError: pass
else: raise TestFailed, 'sys.settrace() did not raise TypeError'
print "20. eval and exec with free variables" def testEvalExecFreeVars(self):
def f(x): def f(x):
return lambda: x + 1 return lambda: x + 1
g = f(3) g = f(3)
try: self.assertRaises(TypeError, eval, g.func_code)
eval(g.func_code)
except TypeError: try:
exec g.func_code in {}
except TypeError:
pass pass
else: else:
print "eval() should have failed, because code contained free vars" self.fail("exec should have failed, because code contained free vars")
try: def testListCompLocalVars(self):
exec g.func_code
except TypeError:
pass
else:
print "exec should have failed, because code contained free vars"
print "21. list comprehension with local variables" try:
try:
print bad print bad
except NameError: except NameError:
pass pass
else: else:
print "bad should not be defined" print "bad should not be defined"
def x(): def x():
[bad for s in 'a b' for bad in s.split()] [bad for s in 'a b' for bad in s.split()]
x() x()
try: try:
print bad print bad
except NameError: except NameError:
pass pass
print "22. eval with free variables" def testEvalFreeVars(self):
def f(x): def f(x):
def g(): def g():
x x
eval("x + 1") eval("x + 1")
return g return g
f(4)() f(4)()
def test_main():
run_unittest(ScopeTests)
if __name__ == '__main__':
test_main()

View File

@ -245,13 +245,13 @@ def sortdict(dict):
withcommas = ", ".join(reprpairs) withcommas = ", ".join(reprpairs)
return "{%s}" % withcommas return "{%s}" % withcommas
def check_syntax(statement): def check_syntax_error(testcase, statement):
try: try:
compile(statement, '<string>', 'exec') compile(statement, '<test string>', 'exec')
except SyntaxError: except SyntaxError:
pass pass
else: else:
print 'Missing SyntaxError: "%s"' % statement testcase.fail('Missing SyntaxError: "%s"' % statement)
def open_urlresource(url): def open_urlresource(url):
import urllib, urlparse import urllib, urlparse