# -*- coding: UTF-8 -*- """ Test libpython.py. This is already partly tested by test_libcython_in_gdb and Lib/test/test_gdb.py in the Python source. These tests are run in gdb and called from test_libcython_in_gdb.main() """ import os import sys import gdb from Cython.Debugger import libcython from Cython.Debugger import libpython from . import test_libcython_in_gdb from .test_libcython_in_gdb import _debug, inferior_python_version class TestPrettyPrinters(test_libcython_in_gdb.DebugTestCase): """ Test whether types of Python objects are correctly inferred and that the right libpython.PySomeTypeObjectPtr classes are instantiated. Also test whether values are appropriately formatted (don't be too laborious as Lib/test/test_gdb.py already covers this extensively). Don't take care of decreffing newly allocated objects as a new interpreter is started for every test anyway. """ def setUp(self): super(TestPrettyPrinters, self).setUp() self.break_and_run('b = c = d = 0') def get_pyobject(self, code): value = gdb.parse_and_eval(code) assert libpython.pointervalue(value) != 0 return value def pyobject_fromcode(self, code, gdbvar=None): if gdbvar is not None: d = {'varname':gdbvar, 'code':code} gdb.execute('set $%(varname)s = %(code)s' % d) code = '$' + gdbvar return libpython.PyObjectPtr.from_pyobject_ptr(self.get_pyobject(code)) def get_repr(self, pyobject): return pyobject.get_truncated_repr(libpython.MAX_OUTPUT_LEN) def alloc_bytestring(self, string, gdbvar=None): if inferior_python_version < (3, 0): funcname = 'PyString_FromStringAndSize' else: funcname = 'PyBytes_FromStringAndSize' assert b'"' not in string # ensure double quotes code = '(PyObject *) %s("%s", %d)' % (funcname, string.decode('iso8859-1'), len(string)) return self.pyobject_fromcode(code, gdbvar=gdbvar) def alloc_unicodestring(self, string, gdbvar=None): postfix = libpython.get_inferior_unicode_postfix() funcname = 'PyUnicode%s_DecodeUnicodeEscape' % (postfix,) data = string.encode("unicode_escape").decode('iso8859-1') return self.pyobject_fromcode( '(PyObject *) %s("%s", %d, "strict")' % ( funcname, data.replace('"', r'\"').replace('\\', r'\\'), len(data)), gdbvar=gdbvar) def test_bytestring(self): bytestring = self.alloc_bytestring(b"spam") if inferior_python_version < (3, 0): bytestring_class = libpython.PyStringObjectPtr expected = repr(b"spam") else: bytestring_class = libpython.PyBytesObjectPtr expected = "b'spam'" self.assertEqual(type(bytestring), bytestring_class) self.assertEqual(self.get_repr(bytestring), expected) def test_unicode(self): unicode_string = self.alloc_unicodestring(u"spam ἄλφα") expected = u"'spam ἄλφα'" if inferior_python_version < (3, 0): expected = 'u' + expected self.assertEqual(type(unicode_string), libpython.PyUnicodeObjectPtr) self.assertEqual(self.get_repr(unicode_string), expected) def test_int(self): if inferior_python_version < (3, 0): intval = self.pyobject_fromcode('PyInt_FromLong(100)') self.assertEqual(type(intval), libpython.PyIntObjectPtr) self.assertEqual(self.get_repr(intval), '100') def test_long(self): longval = self.pyobject_fromcode('PyLong_FromLong(200)', gdbvar='longval') assert gdb.parse_and_eval('$longval->ob_type == &PyLong_Type') self.assertEqual(type(longval), libpython.PyLongObjectPtr) self.assertEqual(self.get_repr(longval), '200') def test_frame_type(self): frame = self.pyobject_fromcode('PyEval_GetFrame()') self.assertEqual(type(frame), libpython.PyFrameObjectPtr)