Index: third_party/cython/src/Cython/Debugger/Tests/TestLibCython.py |
diff --git a/third_party/cython/src/Cython/Debugger/Tests/TestLibCython.py b/third_party/cython/src/Cython/Debugger/Tests/TestLibCython.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..2f91096b4d0f7cc6206a8f95b12f785ad42f9c94 |
--- /dev/null |
+++ b/third_party/cython/src/Cython/Debugger/Tests/TestLibCython.py |
@@ -0,0 +1,285 @@ |
+ |
+import os |
+import re |
+import sys |
+import shutil |
+import warnings |
+import textwrap |
+import unittest |
+import tempfile |
+import subprocess |
+#import distutils.core |
+#from distutils import sysconfig |
+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__)) |
+codefile = os.path.join(root, 'codefile') |
+cfuncs_file = os.path.join(root, 'cfuncs.c') |
+ |
+f = open(codefile) |
+try: |
+ source_to_lineno = dict([ (line.strip(), i + 1) for i, line in enumerate(f) ]) |
+finally: |
+ f.close() |
+ |
+# 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'] |
+ |
+ |
+have_gdb = None |
+def test_gdb(): |
+ global have_gdb |
+ if have_gdb is not None: |
+ return have_gdb |
+ |
+ try: |
+ p = subprocess.Popen(['gdb', '-v'], stdout=subprocess.PIPE) |
+ have_gdb = True |
+ except OSError: |
+ # gdb was not installed |
+ have_gdb = False |
+ else: |
+ gdb_version = p.stdout.read().decode('ascii', 'ignore') |
+ p.wait() |
+ p.stdout.close() |
+ |
+ if have_gdb: |
+ # Based on Lib/test/test_gdb.py |
+ regex = "^GNU gdb [^\d]*(\d+)\.(\d+)" |
+ gdb_version_number = list(map(int, re.search(regex, gdb_version).groups())) |
+ |
+ if gdb_version_number >= [7, 2]: |
+ python_version_script = tempfile.NamedTemporaryFile(mode='w+') |
+ try: |
+ python_version_script.write( |
+ 'python import sys; print("%s %s" % sys.version_info[:2])') |
+ python_version_script.flush() |
+ p = subprocess.Popen(['gdb', '-batch', '-x', python_version_script.name], |
+ stdout=subprocess.PIPE) |
+ try: |
+ python_version = p.stdout.read().decode('ascii') |
+ p.wait() |
+ finally: |
+ p.stdout.close() |
+ try: |
+ python_version_number = list(map(int, python_version.split())) |
+ except ValueError: |
+ have_gdb = False |
+ finally: |
+ python_version_script.close() |
+ |
+ # Be Python 3 compatible |
+ if (not have_gdb |
+ or gdb_version_number < [7, 2] |
+ or python_version_number < [2, 6]): |
+ warnings.warn( |
+ 'Skipping gdb tests, need gdb >= 7.2 with Python >= 2.6') |
+ have_gdb = False |
+ |
+ return have_gdb |
+ |
+ |
+class DebuggerTestCase(unittest.TestCase): |
+ |
+ def setUp(self): |
+ """ |
+ Run gdb and have cygdb import the debug information from the code |
+ defined in TestParseTreeTransforms's setUp method |
+ """ |
+ if not test_gdb(): |
+ return |
+ |
+ self.tempdir = tempfile.mkdtemp() |
+ self.destfile = os.path.join(self.tempdir, 'codefile.pyx') |
+ self.debug_dest = os.path.join(self.tempdir, |
+ 'cython_debug', |
+ 'cython_debug_info_codefile') |
+ self.cfuncs_destfile = os.path.join(self.tempdir, 'cfuncs') |
+ |
+ self.cwd = os.getcwd() |
+ try: |
+ os.chdir(self.tempdir) |
+ |
+ shutil.copy(codefile, self.destfile) |
+ shutil.copy(cfuncs_file, self.cfuncs_destfile + '.c') |
+ |
+ compiler = ccompiler.new_compiler() |
+ compiler.compile(['cfuncs.c'], debug=True, extra_postargs=['-fPIC']) |
+ |
+ opts = dict( |
+ test_directory=self.tempdir, |
+ module='codefile', |
+ ) |
+ |
+ optimization_disabler = build_ext.Optimization() |
+ |
+ cython_compile_testcase = runtests.CythonCompileTestCase( |
+ workdir=self.tempdir, |
+ # we clean up everything (not only compiled files) |
+ cleanup_workdir=False, |
+ tags=runtests.parse_tags(codefile), |
+ **opts |
+ ) |
+ |
+ |
+ new_stderr = open(os.devnull, 'w') |
+ |
+ stderr = sys.stderr |
+ sys.stderr = new_stderr |
+ |
+ optimization_disabler.disable_optimization() |
+ try: |
+ cython_compile_testcase.run_cython( |
+ targetdir=self.tempdir, |
+ incdir=None, |
+ annotate=False, |
+ extra_compile_options={ |
+ 'gdb_debug':True, |
+ 'output_dir':self.tempdir, |
+ }, |
+ **opts |
+ ) |
+ |
+ cython_compile_testcase.run_distutils( |
+ incdir=None, |
+ workdir=self.tempdir, |
+ extra_extension_args={'extra_objects':['cfuncs.o']}, |
+ **opts |
+ ) |
+ finally: |
+ optimization_disabler.restore_state() |
+ sys.stderr = stderr |
+ new_stderr.close() |
+ |
+ # ext = Cython.Distutils.extension.Extension( |
+ # 'codefile', |
+ # ['codefile.pyx'], |
+ # cython_gdb=True, |
+ # extra_objects=['cfuncs.o']) |
+ # |
+ # distutils.core.setup( |
+ # script_args=['build_ext', '--inplace'], |
+ # ext_modules=[ext], |
+ # cmdclass=dict(build_ext=Cython.Distutils.build_ext) |
+ # ) |
+ |
+ except: |
+ os.chdir(self.cwd) |
+ raise |
+ |
+ def tearDown(self): |
+ if not test_gdb(): |
+ return |
+ os.chdir(self.cwd) |
+ shutil.rmtree(self.tempdir) |
+ |
+ |
+class GdbDebuggerTestCase(DebuggerTestCase): |
+ |
+ def setUp(self): |
+ if not test_gdb(): |
+ return |
+ |
+ super(GdbDebuggerTestCase, self).setUp() |
+ |
+ prefix_code = textwrap.dedent('''\ |
+ python |
+ |
+ 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(version=%r) |
+ |
+ end |
+ ''' % (sys.version_info[:2],)) |
+ |
+ self.gdb_command_file = cygdb.make_command_file(self.tempdir, |
+ prefix_code) |
+ |
+ f = open(self.gdb_command_file, 'a') |
+ try: |
+ f.write(code) |
+ finally: |
+ f.close() |
+ |
+ args = ['gdb', '-batch', '-x', self.gdb_command_file, '-n', '--args', |
+ sys.executable, '-c', 'import codefile'] |
+ |
+ paths = [] |
+ path = os.environ.get('PYTHONPATH') |
+ if path: |
+ paths.append(path) |
+ paths.append(os.path.dirname(os.path.dirname( |
+ os.path.abspath(Cython.__file__)))) |
+ env = dict(os.environ, PYTHONPATH=os.pathsep.join(paths)) |
+ |
+ self.p = subprocess.Popen( |
+ args, |
+ stdout=open(os.devnull, 'w'), |
+ stderr=subprocess.PIPE, |
+ env=env) |
+ |
+ def tearDown(self): |
+ if not test_gdb(): |
+ return |
+ |
+ try: |
+ super(GdbDebuggerTestCase, self).tearDown() |
+ if self.p: |
+ try: self.p.stdout.close() |
+ except: pass |
+ try: self.p.stderr.close() |
+ except: pass |
+ self.p.wait() |
+ finally: |
+ os.remove(self.gdb_command_file) |
+ |
+ |
+class TestAll(GdbDebuggerTestCase): |
+ |
+ def test_all(self): |
+ if not test_gdb(): |
+ return |
+ |
+ out, err = self.p.communicate() |
+ err = err.decode('UTF-8') |
+ |
+ exit_status = self.p.returncode |
+ |
+ if exit_status == 1: |
+ sys.stderr.write(err) |
+ elif exit_status >= 2: |
+ border = u'*' * 30 |
+ start = u'%s v INSIDE GDB v %s' % (border, border) |
+ end = u'%s ^ INSIDE GDB ^ %s' % (border, border) |
+ errmsg = u'\n%s\n%s%s' % (start, err, end) |
+ |
+ sys.stderr.write(errmsg) |
+ |
+ |
+if __name__ == '__main__': |
+ unittest.main() |