13e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton"""This module includes tests of the code object representation. 23e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton 33e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton>>> def f(x): 43e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton... def g(y): 53e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton... return x + y 63e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton... return g 73e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton... 83e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton 9221085de89afa861c49ff4306979dbbad949d393Neal Norwitz>>> dump(f.__code__) 103e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonname: f 113e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonargcount: 1 124f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossumkwonlyargcount: 0 133e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonnames: () 143e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonvarnames: ('x', 'g') 153e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltoncellvars: ('x',) 163e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonfreevars: () 173e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonnlocals: 2 183e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonflags: 3 1986a36b500a7f7581194382ce4df914e4bb487873Antoine Pitrouconsts: ('None', '<code object g>', "'f.<locals>.g'") 203e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton 21221085de89afa861c49ff4306979dbbad949d393Neal Norwitz>>> dump(f(4).__code__) 223e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonname: g 233e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonargcount: 1 244f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossumkwonlyargcount: 0 253e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonnames: () 263e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonvarnames: ('y',) 273e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltoncellvars: () 283e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonfreevars: ('x',) 293e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonnlocals: 1 303e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonflags: 19 313e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonconsts: ('None',) 323e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton 333e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton>>> def h(x, y): 343e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton... a = x + y 353e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton... b = x - y 363e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton... c = a * b 373e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton... return c 38536cf99536bce562cfcb44a856fac1c84b9de4c3Tim Peters... 394f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossum 40221085de89afa861c49ff4306979dbbad949d393Neal Norwitz>>> dump(h.__code__) 413e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonname: h 423e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonargcount: 2 434f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossumkwonlyargcount: 0 443e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonnames: () 453e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonvarnames: ('x', 'y', 'a', 'b', 'c') 463e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltoncellvars: () 473e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonfreevars: () 483e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonnlocals: 5 493e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonflags: 67 503e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonconsts: ('None',) 513e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton 523e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton>>> def attrs(obj): 537131f84400d85d35d0323c262cc0926bef5a18cfGuido van Rossum... print(obj.attr1) 547131f84400d85d35d0323c262cc0926bef5a18cfGuido van Rossum... print(obj.attr2) 557131f84400d85d35d0323c262cc0926bef5a18cfGuido van Rossum... print(obj.attr3) 563e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton 57221085de89afa861c49ff4306979dbbad949d393Neal Norwitz>>> dump(attrs.__code__) 583e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonname: attrs 593e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonargcount: 1 604f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossumkwonlyargcount: 0 6188fc6646d1b97cb3ba6188808e7c016884d44a73Georg Brandlnames: ('print', 'attr1', 'attr2', 'attr3') 623e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonvarnames: ('obj',) 633e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltoncellvars: () 643e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonfreevars: () 653e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonnlocals: 1 663e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonflags: 67 673e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltonconsts: ('None',) 683e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton 690e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Wouters>>> def optimize_away(): 700e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Wouters... 'doc string' 710e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Wouters... 'not a docstring' 720e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Wouters... 53 73e2a383d062434c05b73031f0da57fe82b9da8942Guido van Rossum... 0x53 740e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Wouters 75221085de89afa861c49ff4306979dbbad949d393Neal Norwitz>>> dump(optimize_away.__code__) 760e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Woutersname: optimize_away 770e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Woutersargcount: 0 784f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossumkwonlyargcount: 0 790e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Woutersnames: () 800e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Woutersvarnames: () 810e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Wouterscellvars: () 820e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Woutersfreevars: () 830e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Woutersnlocals: 0 840e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Woutersflags: 67 850e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Woutersconsts: ("'doc string'", 'None') 860e3f591aeeef9ed715f8770320f4c4c7332a8794Thomas Wouters 874f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossum>>> def keywordonly_args(a,b,*,k1): 884f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossum... return a,b,k1 894f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossum... 904f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossum 91221085de89afa861c49ff4306979dbbad949d393Neal Norwitz>>> dump(keywordonly_args.__code__) 924f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossumname: keywordonly_args 934f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossumargcount: 2 944f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossumkwonlyargcount: 1 954f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossumnames: () 964f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossumvarnames: ('a', 'b', 'k1') 974f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossumcellvars: () 984f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossumfreevars: () 994f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossumnlocals: 3 1004f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossumflags: 67 1014f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossumconsts: ('None',) 1024f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossum 1033e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton""" 1043e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton 10500a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchakaimport sys 1067b82b40a47498bea476746d6e69f2de4434810d9Alexandre Vassalottiimport unittest 1074222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winterimport weakref 1085cfc79deaeabf4af3c767665098a37da9f375edaSerhiy Storchakafrom test.support import run_doctest, run_unittest, cpython_only 1097b82b40a47498bea476746d6e69f2de4434810d9Alexandre Vassalotti 1104222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter 1113e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltondef consts(t): 1123e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton """Yield a doctest-safe sequence of object reprs.""" 1133e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton for elt in t: 1143e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton r = repr(elt) 1153e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton if r.startswith("<code object"): 1163e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton yield "<code object %s>" % elt.co_name 1173e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton else: 1183e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton yield r 1193e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton 1203e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltondef dump(co): 1213e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton """Print out a text representation of a code object.""" 1224f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossum for attr in ["name", "argcount", "kwonlyargcount", "names", "varnames", 1234f72a78684bbfcdc43ceeabb240ceee54706c4b0Guido van Rossum "cellvars", "freevars", "nlocals", "flags"]: 124be19ed77ddb047e02fe94d142181062af6d99dccGuido van Rossum print("%s: %s" % (attr, getattr(co, "co_" + attr))) 125be19ed77ddb047e02fe94d142181062af6d99dccGuido van Rossum print("consts:", tuple(consts(co.co_consts))) 1263e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton 1277b82b40a47498bea476746d6e69f2de4434810d9Alexandre Vassalotti 1287b82b40a47498bea476746d6e69f2de4434810d9Alexandre Vassalotticlass CodeTest(unittest.TestCase): 1297b82b40a47498bea476746d6e69f2de4434810d9Alexandre Vassalotti 1305cfc79deaeabf4af3c767665098a37da9f375edaSerhiy Storchaka @cpython_only 1317b82b40a47498bea476746d6e69f2de4434810d9Alexandre Vassalotti def test_newempty(self): 1325cfc79deaeabf4af3c767665098a37da9f375edaSerhiy Storchaka import _testcapi 1337b82b40a47498bea476746d6e69f2de4434810d9Alexandre Vassalotti co = _testcapi.code_newempty("filename", "funcname", 15) 134b3aedd48621ed9d33b5f42f946b256bce4a50673Ezio Melotti self.assertEqual(co.co_filename, "filename") 135b3aedd48621ed9d33b5f42f946b256bce4a50673Ezio Melotti self.assertEqual(co.co_name, "funcname") 136b3aedd48621ed9d33b5f42f946b256bce4a50673Ezio Melotti self.assertEqual(co.co_firstlineno, 15) 1377b82b40a47498bea476746d6e69f2de4434810d9Alexandre Vassalotti 13809f3d080fe0cadab0db6380c58dd4968db20287dSerhiy Storchaka 13909f3d080fe0cadab0db6380c58dd4968db20287dSerhiy Storchakadef isinterned(s): 14009f3d080fe0cadab0db6380c58dd4968db20287dSerhiy Storchaka return s is sys.intern(('_' + s + '_')[1:-1]) 14109f3d080fe0cadab0db6380c58dd4968db20287dSerhiy Storchaka 14200a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchakaclass CodeConstsTest(unittest.TestCase): 14300a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka 14400a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka def find_const(self, consts, value): 14500a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka for v in consts: 14600a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka if v == value: 14700a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka return v 14809f3d080fe0cadab0db6380c58dd4968db20287dSerhiy Storchaka self.assertIn(value, consts) # raises an exception 14909f3d080fe0cadab0db6380c58dd4968db20287dSerhiy Storchaka self.fail('Should never be reached') 15000a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka 15100a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka def assertIsInterned(self, s): 15209f3d080fe0cadab0db6380c58dd4968db20287dSerhiy Storchaka if not isinterned(s): 15300a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka self.fail('String %r is not interned' % (s,)) 15400a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka 15509f3d080fe0cadab0db6380c58dd4968db20287dSerhiy Storchaka def assertIsNotInterned(self, s): 15609f3d080fe0cadab0db6380c58dd4968db20287dSerhiy Storchaka if isinterned(s): 15709f3d080fe0cadab0db6380c58dd4968db20287dSerhiy Storchaka self.fail('String %r is interned' % (s,)) 15809f3d080fe0cadab0db6380c58dd4968db20287dSerhiy Storchaka 15900a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka @cpython_only 16000a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka def test_interned_string(self): 16100a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka co = compile('res = "str_value"', '?', 'exec') 16200a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka v = self.find_const(co.co_consts, 'str_value') 16300a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka self.assertIsInterned(v) 16400a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka 16500a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka @cpython_only 16600a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka def test_interned_string_in_tuple(self): 16700a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka co = compile('res = ("str_value",)', '?', 'exec') 16800a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka v = self.find_const(co.co_consts, ('str_value',)) 16900a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka self.assertIsInterned(v[0]) 17000a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka 17100a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka @cpython_only 17200a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka def test_interned_string_in_frozenset(self): 17300a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka co = compile('res = a in {"str_value"}', '?', 'exec') 17400a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka v = self.find_const(co.co_consts, frozenset(('str_value',))) 17500a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka self.assertIsInterned(tuple(v)[0]) 17600a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka 17700a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka @cpython_only 17800a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka def test_interned_string_default(self): 17900a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka def f(a='str_value'): 18000a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka return a 18100a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka self.assertIsInterned(f()) 18200a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka 18309f3d080fe0cadab0db6380c58dd4968db20287dSerhiy Storchaka @cpython_only 18409f3d080fe0cadab0db6380c58dd4968db20287dSerhiy Storchaka def test_interned_string_with_null(self): 18509f3d080fe0cadab0db6380c58dd4968db20287dSerhiy Storchaka co = compile(r'res = "str\0value!"', '?', 'exec') 18609f3d080fe0cadab0db6380c58dd4968db20287dSerhiy Storchaka v = self.find_const(co.co_consts, 'str\0value!') 18709f3d080fe0cadab0db6380c58dd4968db20287dSerhiy Storchaka self.assertIsNotInterned(v) 18809f3d080fe0cadab0db6380c58dd4968db20287dSerhiy Storchaka 1897b82b40a47498bea476746d6e69f2de4434810d9Alexandre Vassalotti 1904222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winterclass CodeWeakRefTest(unittest.TestCase): 1914222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter 1924222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter def test_basic(self): 1934222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter # Create a code object in a clean environment so that we know we have 1944222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter # the only reference to it left. 1954222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter namespace = {} 1964222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter exec("def f(): pass", globals(), namespace) 1974222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter f = namespace["f"] 1984222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter del namespace 1994222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter 2004222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter self.called = False 2014222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter def callback(code): 2024222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter self.called = True 2034222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter 2044222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter # f is now the last reference to the function, and through it, the code 2054222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter # object. While we hold it, check that we can create a weakref and 2064222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter # deref it. Then delete it, and check that the callback gets called and 2074222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter # the reference dies. 2084222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter coderef = weakref.ref(f.__code__, callback) 2094222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter self.assertTrue(bool(coderef())) 2104222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter del f 2114222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter self.assertFalse(bool(coderef())) 2124222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter self.assertTrue(self.called) 2134222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter 2144222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winter 2153e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hyltondef test_main(verbose=None): 2163e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton from test import test_code 2173e0055f8c65c407e74ce476b8e2b1fb889723514Jeremy Hylton run_doctest(test_code, verbose) 21800a0fc1144d928515ff8abd0de7bb6ad072fcbdbSerhiy Storchaka run_unittest(CodeTest, CodeConstsTest, CodeWeakRefTest) 219ad9d48d865706a76e86b8929be5f981971206657Benjamin Peterson 220ad9d48d865706a76e86b8929be5f981971206657Benjamin Peterson 2214222e9c07cc9a223ac756f8cc1c1cd2f9212765eCollin Winterif __name__ == "__main__": 222ad9d48d865706a76e86b8929be5f981971206657Benjamin Peterson test_main() 223