Commit f4166d52 authored by Mark Florisson's avatar Mark Florisson

Debugger: Disable optimization for test cases manually as they don't use distutils.core.setup()

parent 8193f74a
...@@ -16,6 +16,7 @@ from distutils import ccompiler ...@@ -16,6 +16,7 @@ from distutils import ccompiler
import runtests import runtests
import Cython.Distutils.extension import Cython.Distutils.extension
import Cython.Distutils.build_ext
from Cython.Debugger import Cygdb as cygdb from Cython.Debugger import Cygdb as cygdb
root = os.path.dirname(os.path.abspath(__file__)) root = os.path.dirname(os.path.abspath(__file__))
...@@ -24,6 +25,10 @@ cfuncs_file = os.path.join(root, 'cfuncs.c') ...@@ -24,6 +25,10 @@ cfuncs_file = os.path.join(root, 'cfuncs.c')
with open(codefile) as f: with open(codefile) as f:
source_to_lineno = dict((line.strip(), i + 1) for i, line in enumerate(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): class DebuggerTestCase(unittest.TestCase):
def setUp(self): def setUp(self):
...@@ -52,6 +57,9 @@ class DebuggerTestCase(unittest.TestCase): ...@@ -52,6 +57,9 @@ class DebuggerTestCase(unittest.TestCase):
module='codefile', module='codefile',
) )
optimization_disabler = build_ext.Optimization()
optimization_disabler.disable_optimization()
cython_compile_testcase = runtests.CythonCompileTestCase( cython_compile_testcase = runtests.CythonCompileTestCase(
workdir=self.tempdir, workdir=self.tempdir,
# we clean up everything (not only compiled files) # we clean up everything (not only compiled files)
...@@ -77,6 +85,8 @@ class DebuggerTestCase(unittest.TestCase): ...@@ -77,6 +85,8 @@ class DebuggerTestCase(unittest.TestCase):
**opts **opts
) )
optimization_disabler.restore_state()
# ext = Cython.Distutils.extension.Extension( # ext = Cython.Distutils.extension.Extension(
# 'codefile', # 'codefile',
# ['codefile.pyx'], # ['codefile.pyx'],
...@@ -95,6 +105,7 @@ class DebuggerTestCase(unittest.TestCase): ...@@ -95,6 +105,7 @@ class DebuggerTestCase(unittest.TestCase):
class GdbDebuggerTestCase(DebuggerTestCase): class GdbDebuggerTestCase(DebuggerTestCase):
def setUp(self): def setUp(self):
super(GdbDebuggerTestCase, self).setUp() super(GdbDebuggerTestCase, self).setUp()
......
...@@ -14,6 +14,7 @@ import warnings ...@@ -14,6 +14,7 @@ import warnings
import unittest import unittest
import textwrap import textwrap
import tempfile import tempfile
import functools
import traceback import traceback
import itertools import itertools
from test import test_support from test import test_support
...@@ -28,12 +29,35 @@ from Cython.Debugger.Tests import TestLibCython as test_libcython ...@@ -28,12 +29,35 @@ from Cython.Debugger.Tests import TestLibCython as test_libcython
sys.argv = ['gdb'] 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): 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. all breakpoints.
""" """
__metaclass__ = TraceMethodCallMeta
def __init__(self, name): def __init__(self, name):
super(DebugTestCase, self).__init__(name) super(DebugTestCase, self).__init__(name)
self.cy = libcython.cy self.cy = libcython.cy
...@@ -43,17 +67,17 @@ class DebugTestCase(unittest.TestCase): ...@@ -43,17 +67,17 @@ class DebugTestCase(unittest.TestCase):
'codefile.ham'] 'codefile.ham']
self.eggs_func = libcython.cy.functions_by_qualified_name[ self.eggs_func = libcython.cy.functions_by_qualified_name[
'codefile.eggs'] 'codefile.eggs']
def read_var(self, varname, cast_to=None): def read_var(self, varname, cast_to=None):
result = gdb.parse_and_eval('$cy_cvalue("%s")' % varname) result = gdb.parse_and_eval('$cy_cvalue("%s")' % varname)
if cast_to: if cast_to:
result = cast_to(result) result = cast_to(result)
return result return result
def local_info(self): def local_info(self):
return gdb.execute('info locals', to_string=True) return gdb.execute('info locals', to_string=True)
def lineno_equals(self, source_line=None, lineno=None): def lineno_equals(self, source_line=None, lineno=None):
if source_line is not None: if source_line is not None:
lineno = test_libcython.source_to_lineno[source_line] lineno = test_libcython.source_to_lineno[source_line]
...@@ -71,19 +95,19 @@ class DebugTestCase(unittest.TestCase): ...@@ -71,19 +95,19 @@ class DebugTestCase(unittest.TestCase):
gdb.execute('kill inferior 1', to_string=True) gdb.execute('kill inferior 1', to_string=True)
except RuntimeError: except RuntimeError:
pass pass
gdb.execute('set args -c "import codefile"') gdb.execute('set args -c "import codefile"')
class TestDebugInformationClasses(DebugTestCase): class TestDebugInformationClasses(DebugTestCase):
def test_CythonModule(self): def test_CythonModule(self):
"test that debug information was parsed properly into data structures" "test that debug information was parsed properly into data structures"
self.assertEqual(self.module.name, 'codefile') self.assertEqual(self.module.name, 'codefile')
global_vars = ('c_var', 'python_var', '__name__', global_vars = ('c_var', 'python_var', '__name__',
'__builtins__', '__doc__', '__file__') '__builtins__', '__doc__', '__file__')
assert set(global_vars).issubset(self.module.globals) assert set(global_vars).issubset(self.module.globals)
def test_CythonVariable(self): def test_CythonVariable(self):
module_globals = self.module.globals module_globals = self.module.globals
c_var = module_globals['c_var'] c_var = module_globals['c_var']
...@@ -91,32 +115,32 @@ class TestDebugInformationClasses(DebugTestCase): ...@@ -91,32 +115,32 @@ class TestDebugInformationClasses(DebugTestCase):
self.assertEqual(c_var.type, libcython.CObject) self.assertEqual(c_var.type, libcython.CObject)
self.assertEqual(python_var.type, libcython.PythonObject) self.assertEqual(python_var.type, libcython.PythonObject)
self.assertEqual(c_var.qualified_name, 'codefile.c_var') self.assertEqual(c_var.qualified_name, 'codefile.c_var')
def test_CythonFunction(self): def test_CythonFunction(self):
self.assertEqual(self.spam_func.qualified_name, 'codefile.spam') 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') 'codefile.SomeClass.spam')
self.assertEqual(self.spam_func.module, self.module) self.assertEqual(self.spam_func.module, self.module)
assert self.eggs_func.pf_cname, (self.eggs_func, self.eggs_func.pf_cname) assert self.eggs_func.pf_cname, (self.eggs_func, self.eggs_func.pf_cname)
assert not self.ham_func.pf_cname assert not self.ham_func.pf_cname
assert not self.spam_func.pf_cname assert not self.spam_func.pf_cname
assert not self.spam_meth.pf_cname assert not self.spam_meth.pf_cname
self.assertEqual(self.spam_func.type, libcython.CObject) self.assertEqual(self.spam_func.type, libcython.CObject)
self.assertEqual(self.ham_func.type, libcython.CObject) self.assertEqual(self.ham_func.type, libcython.CObject)
self.assertEqual(self.spam_func.arguments, ['a']) 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'])) set(['puts', 'some_c_function']))
expected_lineno = test_libcython.source_to_lineno['def spam(a=0):'] expected_lineno = test_libcython.source_to_lineno['def spam(a=0):']
self.assertEqual(self.spam_func.lineno, expected_lineno) self.assertEqual(self.spam_func.lineno, expected_lineno)
self.assertEqual(sorted(self.spam_func.locals), list('abcd')) self.assertEqual(sorted(self.spam_func.locals), list('abcd'))
class TestParameters(unittest.TestCase): class TestParameters(unittest.TestCase):
def test_parameters(self): def test_parameters(self):
gdb.execute('set cy_colorize_code on') gdb.execute('set cy_colorize_code on')
assert libcython.parameters.colorize_code assert libcython.parameters.colorize_code
...@@ -129,7 +153,7 @@ class TestBreak(DebugTestCase): ...@@ -129,7 +153,7 @@ class TestBreak(DebugTestCase):
def test_break(self): def test_break(self):
breakpoint_amount = len(gdb.breakpoints() or ()) breakpoint_amount = len(gdb.breakpoints() or ())
gdb.execute('cy break codefile.spam') gdb.execute('cy break codefile.spam')
self.assertEqual(len(gdb.breakpoints()), breakpoint_amount + 1) self.assertEqual(len(gdb.breakpoints()), breakpoint_amount + 1)
bp = gdb.breakpoints()[-1] bp = gdb.breakpoints()[-1]
self.assertEqual(bp.type, gdb.BP_BREAKPOINT) self.assertEqual(bp.type, gdb.BP_BREAKPOINT)
...@@ -152,67 +176,67 @@ class TestBreak(DebugTestCase): ...@@ -152,67 +176,67 @@ class TestBreak(DebugTestCase):
class TestKilled(DebugTestCase): class TestKilled(DebugTestCase):
def test_abort(self): def test_abort(self):
gdb.execute("set args -c 'import os; os.abort()'") gdb.execute("set args -c 'import os; os.abort()'")
output = gdb.execute('cy run', to_string=True) output = gdb.execute('cy run', to_string=True)
assert 'abort' in output.lower() assert 'abort' in output.lower()
class DebugStepperTestCase(DebugTestCase): class DebugStepperTestCase(DebugTestCase):
def step(self, varnames_and_values, source_line=None, lineno=None): def step(self, varnames_and_values, source_line=None, lineno=None):
gdb.execute(self.command) gdb.execute(self.command)
for varname, value in varnames_and_values: for varname, value in varnames_and_values:
self.assertEqual(self.read_var(varname), value, self.local_info()) self.assertEqual(self.read_var(varname), value, self.local_info())
self.lineno_equals(source_line, lineno) self.lineno_equals(source_line, lineno)
class TestStep(DebugStepperTestCase): 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. Cython/Debugger/Tests/codefile.
""" """
def test_cython_step(self): def test_cython_step(self):
gdb.execute('cy break codefile.spam') gdb.execute('cy break codefile.spam')
gdb.execute('run', to_string=True) gdb.execute('run', to_string=True)
self.lineno_equals('def spam(a=0):') self.lineno_equals('def spam(a=0):')
gdb.execute('cy step', to_string=True) gdb.execute('cy step', to_string=True)
self.lineno_equals('b = c = d = 0') self.lineno_equals('b = c = d = 0')
self.command = 'cy step' self.command = 'cy step'
self.step([('b', 0)], source_line='b = 1') self.step([('b', 0)], source_line='b = 1')
self.step([('b', 1), ('c', 0)], source_line='c = 2') self.step([('b', 1), ('c', 0)], source_line='c = 2')
self.step([('c', 2)], source_line='int(10)') self.step([('c', 2)], source_line='int(10)')
self.step([], source_line='puts("spam")') self.step([], source_line='puts("spam")')
gdb.execute('cont', to_string=True) gdb.execute('cont', to_string=True)
self.assertEqual(len(gdb.inferiors()), 1) self.assertEqual(len(gdb.inferiors()), 1)
self.assertEqual(gdb.inferiors()[0].pid, 0) self.assertEqual(gdb.inferiors()[0].pid, 0)
def test_c_step(self): def test_c_step(self):
self.break_and_run('some_c_function()') self.break_and_run('some_c_function()')
gdb.execute('cy step', to_string=True) gdb.execute('cy step', to_string=True)
self.assertEqual(gdb.selected_frame().name(), 'some_c_function') self.assertEqual(gdb.selected_frame().name(), 'some_c_function')
def test_python_step(self): def test_python_step(self):
self.break_and_run('os.path.join("foo", "bar")') self.break_and_run('os.path.join("foo", "bar")')
result = gdb.execute('cy step', to_string=True) result = gdb.execute('cy step', to_string=True)
curframe = gdb.selected_frame() curframe = gdb.selected_frame()
self.assertEqual(curframe.name(), 'PyEval_EvalFrameEx') self.assertEqual(curframe.name(), 'PyEval_EvalFrameEx')
pyframe = libpython.Frame(curframe).get_pyop() pyframe = libpython.Frame(curframe).get_pyop()
self.assertEqual(str(pyframe.co_name), 'join') self.assertEqual(str(pyframe.co_name), 'join')
assert re.match(r'\d+ def join\(', result), result assert re.match(r'\d+ def join\(', result), result
class TestNext(DebugStepperTestCase): class TestNext(DebugStepperTestCase):
def test_cython_next(self): def test_cython_next(self):
self.break_and_run('c = 2') self.break_and_run('c = 2')
...@@ -229,18 +253,18 @@ class TestNext(DebugStepperTestCase): ...@@ -229,18 +253,18 @@ class TestNext(DebugStepperTestCase):
class TestLocalsGlobals(DebugTestCase): class TestLocalsGlobals(DebugTestCase):
def test_locals(self): def test_locals(self):
self.break_and_run('int(10)') self.break_and_run('int(10)')
result = gdb.execute('cy locals', to_string=True) result = gdb.execute('cy locals', to_string=True)
assert 'a = 0', repr(result) assert 'a = 0', repr(result)
assert 'b = (int) 1', result assert 'b = (int) 1', result
assert 'c = (int) 2' in result, repr(result) assert 'c = (int) 2' in result, repr(result)
def test_globals(self): def test_globals(self):
self.break_and_run('int(10)') self.break_and_run('int(10)')
result = gdb.execute('cy globals', to_string=True) result = gdb.execute('cy globals', to_string=True)
assert '__name__ ' in result, repr(result) assert '__name__ ' in result, repr(result)
assert '__doc__ ' in result, repr(result) assert '__doc__ ' in result, repr(result)
...@@ -250,45 +274,45 @@ class TestLocalsGlobals(DebugTestCase): ...@@ -250,45 +274,45 @@ class TestLocalsGlobals(DebugTestCase):
class TestBacktrace(DebugTestCase): class TestBacktrace(DebugTestCase):
def test_backtrace(self): def test_backtrace(self):
libcython.parameters.colorize_code.value = False libcython.parameters.colorize_code.value = False
self.break_and_run('os.path.join("foo", "bar")') self.break_and_run('os.path.join("foo", "bar")')
result = gdb.execute('cy bt', to_string=True) result = gdb.execute('cy bt', to_string=True)
_debug(libpython.execute, libpython._execute, gdb.execute) _debug(libpython.execute, libpython._execute, gdb.execute)
_debug(gdb.execute('cy list', to_string=True)) _debug(gdb.execute('cy list', to_string=True))
_debug(repr(result)) _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 result), result
assert 'os.path.join("foo", "bar")' in result, result assert 'os.path.join("foo", "bar")' in result, result
gdb.execute("cy step") gdb.execute("cy step")
gdb.execute('cy bt') gdb.execute('cy bt')
result = gdb.execute('cy bt -a', to_string=True) result = gdb.execute('cy bt -a', to_string=True)
assert re.search(r'\#0 *0x.* in main\(\)', result), result assert re.search(r'\#0 *0x.* in main\(\)', result), result
class TestFunctions(DebugTestCase): class TestFunctions(DebugTestCase):
def test_functions(self): def test_functions(self):
self.break_and_run('c = 2') self.break_and_run('c = 2')
result = gdb.execute('print $cy_cname("b")', to_string=True) result = gdb.execute('print $cy_cname("b")', to_string=True)
assert re.search('__pyx_.*b', result), result assert re.search('__pyx_.*b', result), result
result = gdb.execute('print $cy_lineno()', to_string=True) result = gdb.execute('print $cy_lineno()', to_string=True)
supposed_lineno = test_libcython.source_to_lineno['c = 2'] supposed_lineno = test_libcython.source_to_lineno['c = 2']
assert str(supposed_lineno) in result, (supposed_lineno, result) assert str(supposed_lineno) in result, (supposed_lineno, result)
result = gdb.execute('print $cy_cvalue("b")', to_string=True) result = gdb.execute('print $cy_cvalue("b")', to_string=True)
assert '= 1' in result assert '= 1' in result
class TestPrint(DebugTestCase): class TestPrint(DebugTestCase):
def test_print(self): def test_print(self):
self.break_and_run('c = 2') self.break_and_run('c = 2')
result = gdb.execute('cy print b', to_string=True) result = gdb.execute('cy print b', to_string=True)
...@@ -301,68 +325,68 @@ class TestUpDown(DebugTestCase): ...@@ -301,68 +325,68 @@ class TestUpDown(DebugTestCase):
self.break_and_run('os.path.join("foo", "bar")') self.break_and_run('os.path.join("foo", "bar")')
gdb.execute('cy step') gdb.execute('cy step')
self.assertRaises(RuntimeError, gdb.execute, 'cy down') self.assertRaises(RuntimeError, gdb.execute, 'cy down')
result = gdb.execute('cy up', to_string=True) result = gdb.execute('cy up', to_string=True)
assert 'spam()' in result assert 'spam()' in result
assert 'os.path.join("foo", "bar")' in result assert 'os.path.join("foo", "bar")' in result
class TestExec(DebugTestCase): class TestExec(DebugTestCase):
def setUp(self): def setUp(self):
super(TestExec, self).setUp() super(TestExec, self).setUp()
self.fd, self.tmpfilename = tempfile.mkstemp() self.fd, self.tmpfilename = tempfile.mkstemp()
self.tmpfile = os.fdopen(self.fd, 'r+') self.tmpfile = os.fdopen(self.fd, 'r+')
def tearDown(self): def tearDown(self):
super(TestExec, self).tearDown() super(TestExec, self).tearDown()
try: try:
self.tmpfile.close() self.tmpfile.close()
finally: finally:
os.remove(self.tmpfilename) os.remove(self.tmpfilename)
def eval_command(self, command): 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)) (self.tmpfilename, command))
return self.tmpfile.read().strip() return self.tmpfile.read().strip()
def test_cython_exec(self): def test_cython_exec(self):
self.break_and_run('os.path.join("foo", "bar")') self.break_and_run('os.path.join("foo", "bar")')
# test normal behaviour # test normal behaviour
self.assertEqual("[0]", self.eval_command('[a]')) self.assertEqual("[0]", self.eval_command('[a]'))
# test multiline code # test multiline code
result = gdb.execute(textwrap.dedent('''\ result = gdb.execute(textwrap.dedent('''\
cy exec cy exec
pass pass
"nothing" "nothing"
end end
''')) '''))
result = self.tmpfile.read().rstrip() result = self.tmpfile.read().rstrip()
self.assertEqual('', result) self.assertEqual('', result)
def test_python_exec(self): def test_python_exec(self):
self.break_and_run('os.path.join("foo", "bar")') self.break_and_run('os.path.join("foo", "bar")')
gdb.execute('cy step') gdb.execute('cy step')
gdb.execute('cy exec some_random_var = 14') gdb.execute('cy exec some_random_var = 14')
self.assertEqual('14', self.eval_command('some_random_var')) self.assertEqual('14', self.eval_command('some_random_var'))
class TestClosure(DebugTestCase): class TestClosure(DebugTestCase):
def test_cython_closure(self): def test_cython_closure(self):
self.break_and_run('def inner():') self.break_and_run('def inner():')
# Allow the Cython-generated code to initialize the scope variable # Allow the Cython-generated code to initialize the scope variable
gdb.execute('cy step') gdb.execute('cy step')
self.assertEqual(str(self.read_var('a')), '1') self.assertEqual(str(self.read_var('a')), '1')
print_result = gdb.execute('cy print a', to_string=True).strip() print_result = gdb.execute('cy print a', to_string=True).strip()
self.assertEqual(print_result, 'a = 1') self.assertEqual(print_result, 'a = 1')
def test_cython_closure_no_closing_variables(self): def test_cython_closure_no_closing_variables(self):
self.break_and_run('def inner2():') self.break_and_run('def inner2():')
self.assertEqual(gdb.execute('cy locals', to_string=True), '') self.assertEqual(gdb.execute('cy locals', to_string=True), '')
...@@ -374,7 +398,7 @@ if _do_debug: ...@@ -374,7 +398,7 @@ if _do_debug:
def _debug(*messages): def _debug(*messages):
if _do_debug: if _do_debug:
messages = itertools.chain([sys._getframe(1).f_code.co_name, ':'], messages = itertools.chain([sys._getframe(1).f_code.co_name, ':'],
messages) messages)
_debug_file.write(' '.join(str(msg) for msg in messages) + '\n') _debug_file.write(' '.join(str(msg) for msg in messages) + '\n')
...@@ -391,13 +415,13 @@ def run_unittest_in_module(modulename): ...@@ -391,13 +415,13 @@ def run_unittest_in_module(modulename):
else: else:
m = __import__(modulename, fromlist=['']) m = __import__(modulename, fromlist=[''])
tests = inspect.getmembers(m, inspect.isclass) tests = inspect.getmembers(m, inspect.isclass)
# test_support.run_unittest(tests) # test_support.run_unittest(tests)
test_loader = unittest.TestLoader() test_loader = unittest.TestLoader()
suite = unittest.TestSuite( suite = unittest.TestSuite(
[test_loader.loadTestsFromTestCase(cls) for name, cls in tests]) [test_loader.loadTestsFromTestCase(cls) for name, cls in tests])
result = unittest.TextTestRunner(verbosity=1).run(suite) result = unittest.TextTestRunner(verbosity=1).run(suite)
return result.wasSuccessful() return result.wasSuccessful()
...@@ -410,15 +434,15 @@ def runtests(): ...@@ -410,15 +434,15 @@ def runtests():
success_libcython = run_unittest_in_module(__name__) success_libcython = run_unittest_in_module(__name__)
success_libpython = run_unittest_in_module(test_libpython_in_gdb.__name__) success_libpython = run_unittest_in_module(test_libpython_in_gdb.__name__)
if not success_libcython or not success_libpython: if not success_libcython or not success_libpython:
sys.exit(1) sys.exit(1)
def main(version, trace_code=False): def main(version, trace_code=False):
global inferior_python_version global inferior_python_version
inferior_python_version = version inferior_python_version = version
if trace_code: if trace_code:
tracer = trace.Trace(count=False, trace=True, outfile=sys.stderr, tracer = trace.Trace(count=False, trace=True, outfile=sys.stderr,
ignoredirs=[sys.prefix, sys.exec_prefix]) ignoredirs=[sys.prefix, sys.exec_prefix])
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment