From f4166d52893d6c34b41579e167a78194d364948e Mon Sep 17 00:00:00 2001 From: Mark Florisson Date: Sat, 8 Jan 2011 23:05:16 +0100 Subject: [PATCH] Debugger: Disable optimization for test cases manually as they don't use distutils.core.setup() --- Cython/Debugger/Tests/TestLibCython.py | 11 ++ .../Debugger/Tests/test_libcython_in_gdb.py | 176 ++++++++++-------- 2 files changed, 111 insertions(+), 76 deletions(-) diff --git a/Cython/Debugger/Tests/TestLibCython.py b/Cython/Debugger/Tests/TestLibCython.py index ba0b772e..8bc123a0 100644 --- a/Cython/Debugger/Tests/TestLibCython.py +++ b/Cython/Debugger/Tests/TestLibCython.py @@ -16,6 +16,7 @@ from distutils import ccompiler import runtests import Cython.Distutils.extension +import Cython.Distutils.build_ext from Cython.Debugger import Cygdb as cygdb root = os.path.dirname(os.path.abspath(__file__)) @@ -24,6 +25,10 @@ cfuncs_file = os.path.join(root, 'cfuncs.c') with open(codefile) as f: source_to_lineno = dict((line.strip(), i + 1) for i, line in enumerate(f)) +# Cython.Distutils.__init__ imports build_ext from build_ext which means we +# can't access the module anymore. Get it from sys.modules instead. +build_ext = sys.modules['Cython.Distutils.build_ext'] + class DebuggerTestCase(unittest.TestCase): def setUp(self): @@ -52,6 +57,9 @@ class DebuggerTestCase(unittest.TestCase): module='codefile', ) + optimization_disabler = build_ext.Optimization() + optimization_disabler.disable_optimization() + cython_compile_testcase = runtests.CythonCompileTestCase( workdir=self.tempdir, # we clean up everything (not only compiled files) @@ -77,6 +85,8 @@ class DebuggerTestCase(unittest.TestCase): **opts ) + optimization_disabler.restore_state() + # ext = Cython.Distutils.extension.Extension( # 'codefile', # ['codefile.pyx'], @@ -95,6 +105,7 @@ class DebuggerTestCase(unittest.TestCase): class GdbDebuggerTestCase(DebuggerTestCase): + def setUp(self): super(GdbDebuggerTestCase, self).setUp() diff --git a/Cython/Debugger/Tests/test_libcython_in_gdb.py b/Cython/Debugger/Tests/test_libcython_in_gdb.py index 8fe1cb6e..5775969a 100644 --- a/Cython/Debugger/Tests/test_libcython_in_gdb.py +++ b/Cython/Debugger/Tests/test_libcython_in_gdb.py @@ -14,6 +14,7 @@ import warnings import unittest import textwrap import tempfile +import functools import traceback import itertools from test import test_support @@ -28,12 +29,35 @@ from Cython.Debugger.Tests import TestLibCython as test_libcython sys.argv = ['gdb'] +def print_on_call_decorator(func): + @functools.wraps(func) + def wrapper(self, *args, **kwargs): + _debug(type(self).__name__, func.__name__) + + try: + return func(self, *args, **kwargs) + except Exception, e: + _debug("An exception occurred:", traceback.format_exc(e)) + raise + + return wrapper + +class TraceMethodCallMeta(type): + + def __init__(self, name, bases, dict): + for func_name, func in dict.iteritems(): + if inspect.isfunction(func): + setattr(self, func_name, print_on_call_decorator(func)) + + class DebugTestCase(unittest.TestCase): """ - Base class for test cases. On teardown it kills the inferior and unsets + Base class for test cases. On teardown it kills the inferior and unsets all breakpoints. """ - + + __metaclass__ = TraceMethodCallMeta + def __init__(self, name): super(DebugTestCase, self).__init__(name) self.cy = libcython.cy @@ -43,17 +67,17 @@ class DebugTestCase(unittest.TestCase): 'codefile.ham'] self.eggs_func = libcython.cy.functions_by_qualified_name[ 'codefile.eggs'] - + def read_var(self, varname, cast_to=None): result = gdb.parse_and_eval('$cy_cvalue("%s")' % varname) if cast_to: result = cast_to(result) - + return result - + def local_info(self): return gdb.execute('info locals', to_string=True) - + def lineno_equals(self, source_line=None, lineno=None): if source_line is not None: lineno = test_libcython.source_to_lineno[source_line] @@ -71,19 +95,19 @@ class DebugTestCase(unittest.TestCase): gdb.execute('kill inferior 1', to_string=True) except RuntimeError: pass - + gdb.execute('set args -c "import codefile"') - + class TestDebugInformationClasses(DebugTestCase): - + def test_CythonModule(self): "test that debug information was parsed properly into data structures" self.assertEqual(self.module.name, 'codefile') - global_vars = ('c_var', 'python_var', '__name__', + global_vars = ('c_var', 'python_var', '__name__', '__builtins__', '__doc__', '__file__') assert set(global_vars).issubset(self.module.globals) - + def test_CythonVariable(self): module_globals = self.module.globals c_var = module_globals['c_var'] @@ -91,32 +115,32 @@ class TestDebugInformationClasses(DebugTestCase): self.assertEqual(c_var.type, libcython.CObject) self.assertEqual(python_var.type, libcython.PythonObject) self.assertEqual(c_var.qualified_name, 'codefile.c_var') - + def test_CythonFunction(self): self.assertEqual(self.spam_func.qualified_name, 'codefile.spam') - self.assertEqual(self.spam_meth.qualified_name, + self.assertEqual(self.spam_meth.qualified_name, 'codefile.SomeClass.spam') self.assertEqual(self.spam_func.module, self.module) - + assert self.eggs_func.pf_cname, (self.eggs_func, self.eggs_func.pf_cname) assert not self.ham_func.pf_cname assert not self.spam_func.pf_cname assert not self.spam_meth.pf_cname - + self.assertEqual(self.spam_func.type, libcython.CObject) self.assertEqual(self.ham_func.type, libcython.CObject) - + self.assertEqual(self.spam_func.arguments, ['a']) - self.assertEqual(self.spam_func.step_into_functions, + self.assertEqual(self.spam_func.step_into_functions, set(['puts', 'some_c_function'])) - + expected_lineno = test_libcython.source_to_lineno['def spam(a=0):'] self.assertEqual(self.spam_func.lineno, expected_lineno) self.assertEqual(sorted(self.spam_func.locals), list('abcd')) class TestParameters(unittest.TestCase): - + def test_parameters(self): gdb.execute('set cy_colorize_code on') assert libcython.parameters.colorize_code @@ -129,7 +153,7 @@ class TestBreak(DebugTestCase): def test_break(self): breakpoint_amount = len(gdb.breakpoints() or ()) gdb.execute('cy break codefile.spam') - + self.assertEqual(len(gdb.breakpoints()), breakpoint_amount + 1) bp = gdb.breakpoints()[-1] self.assertEqual(bp.type, gdb.BP_BREAKPOINT) @@ -152,67 +176,67 @@ class TestBreak(DebugTestCase): class TestKilled(DebugTestCase): - + def test_abort(self): gdb.execute("set args -c 'import os; os.abort()'") output = gdb.execute('cy run', to_string=True) assert 'abort' in output.lower() class DebugStepperTestCase(DebugTestCase): - + def step(self, varnames_and_values, source_line=None, lineno=None): gdb.execute(self.command) for varname, value in varnames_and_values: self.assertEqual(self.read_var(varname), value, self.local_info()) - + self.lineno_equals(source_line, lineno) class TestStep(DebugStepperTestCase): """ - Test stepping. Stepping happens in the code found in + Test stepping. Stepping happens in the code found in Cython/Debugger/Tests/codefile. """ - + def test_cython_step(self): gdb.execute('cy break codefile.spam') - + gdb.execute('run', to_string=True) self.lineno_equals('def spam(a=0):') - + gdb.execute('cy step', to_string=True) self.lineno_equals('b = c = d = 0') - + self.command = 'cy step' self.step([('b', 0)], source_line='b = 1') self.step([('b', 1), ('c', 0)], source_line='c = 2') self.step([('c', 2)], source_line='int(10)') self.step([], source_line='puts("spam")') - + gdb.execute('cont', to_string=True) self.assertEqual(len(gdb.inferiors()), 1) self.assertEqual(gdb.inferiors()[0].pid, 0) - + def test_c_step(self): self.break_and_run('some_c_function()') gdb.execute('cy step', to_string=True) self.assertEqual(gdb.selected_frame().name(), 'some_c_function') - + def test_python_step(self): self.break_and_run('os.path.join("foo", "bar")') - + result = gdb.execute('cy step', to_string=True) - + curframe = gdb.selected_frame() self.assertEqual(curframe.name(), 'PyEval_EvalFrameEx') - + pyframe = libpython.Frame(curframe).get_pyop() self.assertEqual(str(pyframe.co_name), 'join') assert re.match(r'\d+ def join\(', result), result class TestNext(DebugStepperTestCase): - + def test_cython_next(self): self.break_and_run('c = 2') @@ -229,18 +253,18 @@ class TestNext(DebugStepperTestCase): class TestLocalsGlobals(DebugTestCase): - + def test_locals(self): self.break_and_run('int(10)') - + result = gdb.execute('cy locals', to_string=True) assert 'a = 0', repr(result) assert 'b = (int) 1', result assert 'c = (int) 2' in result, repr(result) - + def test_globals(self): self.break_and_run('int(10)') - + result = gdb.execute('cy globals', to_string=True) assert '__name__ ' in result, repr(result) assert '__doc__ ' in result, repr(result) @@ -250,45 +274,45 @@ class TestLocalsGlobals(DebugTestCase): class TestBacktrace(DebugTestCase): - + def test_backtrace(self): libcython.parameters.colorize_code.value = False - + self.break_and_run('os.path.join("foo", "bar")') result = gdb.execute('cy bt', to_string=True) - + _debug(libpython.execute, libpython._execute, gdb.execute) _debug(gdb.execute('cy list', to_string=True)) _debug(repr(result)) - - assert re.search(r'\#\d+ *0x.* in spam\(\) at .*codefile\.pyx:22', + + assert re.search(r'\#\d+ *0x.* in spam\(\) at .*codefile\.pyx:22', result), result assert 'os.path.join("foo", "bar")' in result, result - + gdb.execute("cy step") - + gdb.execute('cy bt') result = gdb.execute('cy bt -a', to_string=True) assert re.search(r'\#0 *0x.* in main\(\)', result), result class TestFunctions(DebugTestCase): - + def test_functions(self): self.break_and_run('c = 2') result = gdb.execute('print $cy_cname("b")', to_string=True) assert re.search('__pyx_.*b', result), result - + result = gdb.execute('print $cy_lineno()', to_string=True) supposed_lineno = test_libcython.source_to_lineno['c = 2'] assert str(supposed_lineno) in result, (supposed_lineno, result) - + result = gdb.execute('print $cy_cvalue("b")', to_string=True) assert '= 1' in result - + class TestPrint(DebugTestCase): - + def test_print(self): self.break_and_run('c = 2') result = gdb.execute('cy print b', to_string=True) @@ -301,68 +325,68 @@ class TestUpDown(DebugTestCase): self.break_and_run('os.path.join("foo", "bar")') gdb.execute('cy step') self.assertRaises(RuntimeError, gdb.execute, 'cy down') - + result = gdb.execute('cy up', to_string=True) assert 'spam()' in result assert 'os.path.join("foo", "bar")' in result class TestExec(DebugTestCase): - + def setUp(self): super(TestExec, self).setUp() self.fd, self.tmpfilename = tempfile.mkstemp() self.tmpfile = os.fdopen(self.fd, 'r+') - + def tearDown(self): super(TestExec, self).tearDown() - + try: self.tmpfile.close() finally: os.remove(self.tmpfilename) - + def eval_command(self, command): - gdb.execute('cy exec open(%r, "w").write(str(%s))' % + gdb.execute('cy exec open(%r, "w").write(str(%s))' % (self.tmpfilename, command)) return self.tmpfile.read().strip() - + def test_cython_exec(self): self.break_and_run('os.path.join("foo", "bar")') - + # test normal behaviour self.assertEqual("[0]", self.eval_command('[a]')) - + # test multiline code result = gdb.execute(textwrap.dedent('''\ cy exec pass - + "nothing" end ''')) result = self.tmpfile.read().rstrip() self.assertEqual('', result) - + def test_python_exec(self): self.break_and_run('os.path.join("foo", "bar")') gdb.execute('cy step') - + gdb.execute('cy exec some_random_var = 14') self.assertEqual('14', self.eval_command('some_random_var')) class TestClosure(DebugTestCase): - + def test_cython_closure(self): self.break_and_run('def inner():') - + # Allow the Cython-generated code to initialize the scope variable gdb.execute('cy step') - + self.assertEqual(str(self.read_var('a')), '1') print_result = gdb.execute('cy print a', to_string=True).strip() self.assertEqual(print_result, 'a = 1') - + def test_cython_closure_no_closing_variables(self): self.break_and_run('def inner2():') self.assertEqual(gdb.execute('cy locals', to_string=True), '') @@ -374,7 +398,7 @@ if _do_debug: def _debug(*messages): if _do_debug: - messages = itertools.chain([sys._getframe(1).f_code.co_name, ':'], + messages = itertools.chain([sys._getframe(1).f_code.co_name, ':'], messages) _debug_file.write(' '.join(str(msg) for msg in messages) + '\n') @@ -391,13 +415,13 @@ def run_unittest_in_module(modulename): else: m = __import__(modulename, fromlist=['']) tests = inspect.getmembers(m, inspect.isclass) - + # test_support.run_unittest(tests) - + test_loader = unittest.TestLoader() suite = unittest.TestSuite( [test_loader.loadTestsFromTestCase(cls) for name, cls in tests]) - + result = unittest.TextTestRunner(verbosity=1).run(suite) return result.wasSuccessful() @@ -410,15 +434,15 @@ def runtests(): success_libcython = run_unittest_in_module(__name__) success_libpython = run_unittest_in_module(test_libpython_in_gdb.__name__) - + if not success_libcython or not success_libpython: sys.exit(1) - + def main(version, trace_code=False): - global inferior_python_version - + global inferior_python_version + inferior_python_version = version - + if trace_code: tracer = trace.Trace(count=False, trace=True, outfile=sys.stderr, ignoredirs=[sys.prefix, sys.exec_prefix]) -- 2.26.2