Commit d07e7567 authored by Mark Florisson's avatar Mark Florisson

lots of tests

parent 1327c85b
...@@ -197,10 +197,12 @@ class TestDebugTransform(TestLibCython.DebuggerTestCase): ...@@ -197,10 +197,12 @@ class TestDebugTransform(TestLibCython.DebuggerTestCase):
self.assertEqual(1, len(list(spam_arguments))) self.assertEqual(1, len(list(spam_arguments)))
# test step-into functions # test step-into functions
spam_stepinto = list(spam.find('StepIntoFunctions')) step_into = spam.find('StepIntoFunctions')
spam_stepinto = [x.attrib['name'] for x in step_into]
assert spam_stepinto assert spam_stepinto
self.assertEqual(1, len(list(spam_stepinto))) self.assertEqual(2, len(spam_stepinto))
self.assertEqual('puts', list(spam_stepinto)[0].attrib['name']) assert 'puts' in spam_stepinto
assert 'some_c_function' in spam_stepinto
except: except:
print open(self.debug_dest).read() print open(self.debug_dest).read()
raise raise
......
...@@ -9,10 +9,16 @@ import tempfile ...@@ -9,10 +9,16 @@ import tempfile
import subprocess import subprocess
import distutils.core import distutils.core
from distutils import sysconfig from distutils import sysconfig
from distutils import ccompiler
import Cython.Distutils.extension import Cython.Distutils.extension
from Cython.Debugger import Cygdb as cygdb from Cython.Debugger import Cygdb as cygdb
root = os.path.dirname(os.path.abspath(__file__))
codefile = os.path.join(root, 'codefile')
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))
class DebuggerTestCase(unittest.TestCase): class DebuggerTestCase(unittest.TestCase):
...@@ -26,52 +32,26 @@ class DebuggerTestCase(unittest.TestCase): ...@@ -26,52 +32,26 @@ class DebuggerTestCase(unittest.TestCase):
self.debug_dest = os.path.join(self.tempdir, self.debug_dest = os.path.join(self.tempdir,
'cython_debug', 'cython_debug',
'cython_debug_info_codefile') 'cython_debug_info_codefile')
self.cfuncs_destfile = os.path.join(self.tempdir, 'cfuncs')
code = textwrap.dedent("""
cdef extern from "stdio.h":
int puts(char *s)
cdef int c_var = 0
python_var = 0
def spam(a=0):
cdef:
int b, c, d
b = c = d = 0
b = 1
c = 2
d = 3
int(10)
puts("spam")
cdef ham():
pass
cpdef eggs():
pass
cdef class SomeClass(object):
def spam(self):
pass
spam()
""")
self.cwd = os.getcwd() self.cwd = os.getcwd()
os.chdir(self.tempdir) os.chdir(self.tempdir)
open(self.destfile, 'w').write(code) shutil.copy(codefile, self.destfile)
shutil.copy(cfuncs_file, self.cfuncs_destfile + '.c')
compiler = ccompiler.new_compiler()
compiler.compile(['cfuncs.c'], debug=True)
ext = Cython.Distutils.extension.Extension( ext = Cython.Distutils.extension.Extension(
'codefile', 'codefile',
['codefile.pyx'], ['codefile.pyx'],
pyrex_debug=True) pyrex_debug=True,
extra_objects=['cfuncs.o'])
distutils.core.setup( distutils.core.setup(
script_args=['build_ext', '--inplace'], script_args=['build_ext', '--inplace'],
ext_modules=[ext], ext_modules=[ext],
cmdclass=dict(build_ext=Cython.Distutils.build_ext) cmdclass=dict(build_ext=Cython.Distutils.build_ext)
) )
...@@ -84,12 +64,39 @@ class GdbDebuggerTestCase(DebuggerTestCase): ...@@ -84,12 +64,39 @@ class GdbDebuggerTestCase(DebuggerTestCase):
def setUp(self): def setUp(self):
super(GdbDebuggerTestCase, self).setUp() super(GdbDebuggerTestCase, self).setUp()
self.gdb_command_file = cygdb.make_command_file(self.tempdir) prefix_code = textwrap.dedent('''\
with open(self.gdb_command_file, 'a') as f: python
f.write('python '
'from Cython.Debugger.Tests import test_libcython_in_gdb;'
'test_libcython_in_gdb.main()\n')
import os
import sys
import traceback
def excepthook(type, value, tb):
traceback.print_exception(type, value, tb)
os._exit(1)
sys.excepthook = excepthook
# Have tracebacks end up on sys.stderr (gdb replaces sys.stderr
# with an object that calls gdb.write())
sys.stderr = sys.__stderr__
end
''')
code = textwrap.dedent('''\
python
from Cython.Debugger.Tests import test_libcython_in_gdb
test_libcython_in_gdb.main()
end
''')
self.gdb_command_file = cygdb.make_command_file(self.tempdir,
prefix_code)
open(self.gdb_command_file, 'a').write(code)
args = ['gdb', '-batch', '-x', self.gdb_command_file, '-n', '--args', args = ['gdb', '-batch', '-x', self.gdb_command_file, '-n', '--args',
sys.executable, '-c', 'import codefile'] sys.executable, '-c', 'import codefile']
...@@ -100,6 +107,7 @@ class GdbDebuggerTestCase(DebuggerTestCase): ...@@ -100,6 +107,7 @@ class GdbDebuggerTestCase(DebuggerTestCase):
paths.append(os.path.dirname(os.path.dirname( paths.append(os.path.dirname(os.path.dirname(
os.path.abspath(Cython.__file__)))) os.path.abspath(Cython.__file__))))
env = dict(os.environ, PYTHONPATH=os.pathsep.join(paths)) env = dict(os.environ, PYTHONPATH=os.pathsep.join(paths))
self.p = subprocess.Popen( self.p = subprocess.Popen(
args, args,
stdout=open(os.devnull, 'w'), stdout=open(os.devnull, 'w'),
......
void
some_c_function(void)
{
int a, b, c;
a = 1;
b = 2;
}
\ No newline at end of file
cdef extern from "stdio.h":
int puts(char *s)
cdef extern:
void some_c_function()
import os
cdef int c_var = 0
python_var = 0
def spam(a=0):
cdef:
int b, c
b = c = d = 0
b = 1
c = 2
int(10)
puts("spam")
os.path.join("foo", "bar")
some_c_function()
cdef ham():
pass
cpdef eggs():
pass
cdef class SomeClass(object):
def spam(self):
pass
spam()
print "bye!"
...@@ -5,19 +5,9 @@ Note: debug information is already imported by the file generated by ...@@ -5,19 +5,9 @@ Note: debug information is already imported by the file generated by
Cython.Debugger.Cygdb.make_command_file() Cython.Debugger.Cygdb.make_command_file()
""" """
import sys
# First, fix gdb's python. Make sure to do this before importing modules
# that bind output streams as default parameters
# for some reason sys.argv is missing in gdb
sys.argv = ['gdb']
# Allow gdb to capture output, but have errors end up on stderr
# sys.stdout = sys.__stdout__
sys.stderr = sys.__stderr__
import os import os
import sys
import trace
import warnings import warnings
import unittest import unittest
import traceback import traceback
...@@ -26,6 +16,12 @@ from test import test_support ...@@ -26,6 +16,12 @@ from test import test_support
import gdb import gdb
from Cython.Debugger import libcython from Cython.Debugger import libcython
from Cython.Debugger import libpython
from Cython.Debugger.Tests import TestLibCython as test_libcython
# for some reason sys.argv is missing in gdb
sys.argv = ['gdb']
class DebugTestCase(unittest.TestCase): class DebugTestCase(unittest.TestCase):
...@@ -39,14 +35,35 @@ class DebugTestCase(unittest.TestCase): ...@@ -39,14 +35,35 @@ class DebugTestCase(unittest.TestCase):
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): def read_var(self, varname, cast_to=None):
return gdb.parse_and_eval('$cy_cname("%s")' % varname) result = gdb.parse_and_eval('$cy_cname("%s")' % varname)
if cast_to:
result = cast_to(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)
class TestDebugInformationClasses(DebugTestCase): def lineno_equals(self, source_line=None, lineno=None):
if source_line is not None:
lineno = test_libcython.source_to_lineno[source_line]
frame = gdb.selected_frame()
self.assertEqual(libcython.cy.step.lineno(frame), lineno)
def tearDown(self):
gdb.execute('delete breakpoints', to_string=True)
try:
gdb.execute('kill inferior 1', to_string=True)
except RuntimeError:
pass
def break_and_run(self, source_line):
break_lineno = test_libcython.source_to_lineno[source_line]
gdb.execute('cy break codefile:%d' % break_lineno, to_string=True)
gdb.execute('run', to_string=True)
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"
...@@ -78,9 +95,11 @@ class TestDebugInformationClasses(DebugTestCase): ...@@ -78,9 +95,11 @@ class TestDebugInformationClasses(DebugTestCase):
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, set(['puts'])) self.assertEqual(self.spam_func.step_into_functions,
set(['puts', 'some_c_function']))
self.assertEqual(self.spam_func.lineno, 8) 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')) self.assertEqual(sorted(self.spam_func.locals), list('abcd'))
...@@ -95,7 +114,8 @@ class TestParameters(unittest.TestCase): ...@@ -95,7 +114,8 @@ class TestParameters(unittest.TestCase):
class TestBreak(DebugTestCase): class TestBreak(DebugTestCase):
def test_break(self): def test_break(self):
result = gdb.execute('cy break codefile.spam', to_string=True) result = libpython._execute('cy break codefile.spam', to_string=True)
print >>sys.stderr, repr(result)
assert self.spam_func.cname in result assert self.spam_func.cname in result
self.assertEqual(len(gdb.breakpoints()), 1) self.assertEqual(len(gdb.breakpoints()), 1)
...@@ -104,48 +124,109 @@ class TestBreak(DebugTestCase): ...@@ -104,48 +124,109 @@ class TestBreak(DebugTestCase):
self.assertEqual(bp.location, self.spam_func.cname) self.assertEqual(bp.location, self.spam_func.cname)
assert bp.enabled assert bp.enabled
class TestStep(DebugTestCase): class DebugStepperTestCase(DebugTestCase):
def test_step(self): def step(self, varnames_and_values, source_line=None, lineno=None):
# Note: breakpoint for spam is still set gdb.execute(self.command, to_string=True)
gdb.execute('run') for varname, value in varnames_and_values:
self.assertEqual(self.read_var(varname), value, self.local_info())
gdb.execute('cy step', to_string=True) # b = c = d = 0 self.lineno_equals(source_line, lineno)
gdb.execute('cy step', to_string=True) # b = 1
self.assertEqual(self.read_var('b'), 1, self.local_info())
self.assertRaises(RuntimeError, self.read_var('b'))
gdb.execute('cont')
class TestNext(DebugTestCase): class TestStep(DebugStepperTestCase):
"""
Test stepping. Stepping happens in the code found in
Cython/Debugger/Tests/codefile.
"""
def test_cython_step(self):
gdb.execute('cy break codefile.spam')
libcython.parameters.step_into_c_code.value = False
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")')
self.step([], source_line='os.path.join("foo", "bar")')
gdb.execute('cont', to_string=True)
self.assertEqual(len(gdb.inferiors()), 1)
self.assertEqual(gdb.inferiors()[0].pid, 0)
def test_next(self): def test_c_step(self):
pass libcython.parameters.step_into_c_code.value = True
self.break_and_run('some_c_function()')
gdb.execute('cy step', to_string=True)
self.assertEqual(gdb.selected_frame().name(), 'some_c_function')
def main(): def test_python_step(self):
self.break_and_run('os.path.join("foo", "bar")')
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')
class TestNext(DebugStepperTestCase):
def test_cython_next(self):
libcython.parameters.step_into_c_code.value = True
self.break_and_run('c = 2')
lines = (
'int(10)',
'puts("spam")',
'os.path.join("foo", "bar")',
'some_c_function()',
)
for line in lines:
gdb.execute('cy next')
self.lineno_equals(line)
def _main():
# unittest.main(module=__import__(__name__, fromlist=['']))
try: try:
# unittest.main(module=__import__(__name__, fromlist=[''])) gdb.lookup_type('PyModuleObject')
try: except RuntimeError:
gdb.lookup_type('PyModuleObject') msg = ("Unable to run tests, Python was not compiled with "
except RuntimeError: "debugging information. Either compile python with "
msg = ("Unable to run tests, Python was not compiled with " "-g or get a debug build (configure with --with-pydebug).")
"debugging information. Either compile python with " warnings.warn(msg)
"-g or get a debug build (configure with --with-pydebug).") else:
warnings.warn(msg) tests = (
else: TestDebugInformationClasses,
tests = ( TestParameters,
TestDebugInformationClasses, TestBreak,
TestParameters, TestStep,
TestBreak, TestNext,
TestStep )
) # 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 cls in tests])
[test_loader.loadTestsFromTestCase(cls) for cls in tests])
result = unittest.TextTestRunner(verbosity=1).run(suite)
unittest.TextTestRunner(verbosity=1).run(suite) if not result.wasSuccessful():
except Exception: os._exit(1)
traceback.print_exc()
os._exit(1) def main(trace_code=False):
\ No newline at end of file if trace_code:
tracer = trace.Trace(count=False, trace=True, outfile=sys.stderr,
ignoredirs=[sys.prefix, sys.exec_prefix])
tracer.runfunc(_main)
else:
_main()
\ No newline at end of file
import unittest
from Cython import StringIOTree as stringtree
code = """
cdef int spam # line 1
cdef ham():
a = 1
b = 2
c = 3
d = 4
def eggs():
pass
cpdef bacon():
print spam
print 'scotch'
print 'tea?'
print 'or coffee?' # line 16
"""
linemap = dict(enumerate(code.splitlines()))
class TestStringIOTree(unittest.TestCase):
def setUp(self):
self.tree = stringtree.StringIOTree()
def test_markers(self):
assert not self.tree.allmarkers()
def test_insertion(self):
self.write_lines((1, 2, 3))
line_4_to_6_insertion_point = self.tree.insertion_point()
self.write_lines((7, 8))
line_9_to_13_insertion_point = self.tree.insertion_point()
self.write_lines((14, 15, 16))
line_4_insertion_point = line_4_to_6_insertion_point.insertion_point()
self.write_lines((5, 6), tree=line_4_to_6_insertion_point)
line_9_to_12_insertion_point = (
line_9_to_13_insertion_point.insertion_point())
self.write_line(13, tree=line_9_to_13_insertion_point)
self.write_line(4, tree=line_4_insertion_point)
self.write_line(9, tree=line_9_to_12_insertion_point)
line_10_insertion_point = line_9_to_12_insertion_point.insertion_point()
self.write_line(11, tree=line_9_to_12_insertion_point)
self.write_line(10, tree=line_10_insertion_point)
self.write_line(12, tree=line_9_to_12_insertion_point)
self.assertEqual(self.tree.allmarkers(), range(1, 17))
self.assertEqual(code.strip(), self.tree.getvalue().strip())
def write_lines(self, linenos, tree=None):
for lineno in linenos:
self.write_line(lineno, tree=tree)
def write_line(self, lineno, tree=None):
if tree is None:
tree = self.tree
tree.markers.append(lineno)
tree.write(linemap[lineno] + '\n')
\ No newline at end of file
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