[pypy-commit] pypy default: refactor the code and start to write tests
antocuni
noreply at buildbot.pypy.org
Thu Aug 4 17:02:49 CEST 2011
Author: Antonio Cuni <anto.cuni at gmail.com>
Branch:
Changeset: r46274:6acca3ec3ace
Date: 2011-08-04 16:49 +0200
http://bitbucket.org/pypy/pypy/changeset/6acca3ec3ace/
Log: refactor the code and start to write tests
diff --git a/pypy/tool/gdb_pypy.py b/pypy/tool/gdb_pypy.py
--- a/pypy/tool/gdb_pypy.py
+++ b/pypy/tool/gdb_pypy.py
@@ -10,9 +10,48 @@
import sys
import os.path
-import gdb
-class RPyType (gdb.Command):
+try:
+ # when running inside gdb
+ from gdb import Command
+except ImportError:
+ # whenn running outside gdb: mock class for testing
+ class Command(object):
+ def __init__(self, name, command_class):
+ pass
+
+
+def find_field_with_suffix(val, suffix):
+ """
+ Return ``val[field]``, where ``field`` is the only one whose name ends
+ with ``suffix``. If there is no such field, or more than one, raise KeyError.
+ """
+ names = []
+ for field in val.type.fields():
+ if field.name.endswith(suffix):
+ names.append(field.name)
+ #
+ if len(names) == 1:
+ return val[names[0]]
+ elif len(names) == 0:
+ raise KeyError, "cannot find field *%s" % suffix
+ else:
+ raise KeyError, "too many matching fields: %s" % ', '.join(names)
+
+def lookup(val, suffix):
+ """
+ Lookup a field which ends with ``suffix`` following the rpython struct
+ inheritance hierarchy (i.e., looking both at ``val`` and
+ ``val['*_super']``, recursively.
+ """
+ try:
+ return find_field_with_suffix(val, suffix)
+ except KeyError:
+ baseobj = find_field_with_suffix(val, '_super')
+ return lookup(baseobj, suffix)
+
+
+class RPyType(Command):
"""
Prints the RPython type of the expression (remember to dereference it!)
It assumes to find ``typeids.txt`` in the current directory.
@@ -24,8 +63,12 @@
prog2typeids = {}
- def __init__(self):
- gdb.Command.__init__(self, "rpy_type", gdb.COMMAND_NONE)
+ def __init__(self, gdb=None):
+ # dependency injection, for tests
+ if gdb is None:
+ import gdb
+ self.gdb = gdb
+ Command.__init__(self, "rpy_type", self.gdb.COMMAND_NONE)
# some magic code to automatically reload the python file while developing
def invoke(self, arg, from_tty):
@@ -36,8 +79,8 @@
self.do_invoke(arg, from_tty)
def do_invoke(self, arg, from_tty):
- obj = gdb.parse_and_eval(arg)
- hdr = self.get_gc_header(obj)
+ obj = self.gdb.parse_and_eval(arg)
+ hdr = lookup(obj, '_gcheader')
tid = hdr['h_tid']
offset = tid & 0xFFFFFFFF # 64bit only
offset = int(offset) # convert from gdb.Value to python int
@@ -48,7 +91,7 @@
print 'Cannot find the type with offset %d' % offset
def get_typeids(self):
- progspace = gdb.current_progspace()
+ progspace = self.gdb.current_progspace()
try:
return self.prog2typeids[progspace]
except KeyError:
@@ -68,26 +111,12 @@
for line in open('typeids.txt'):
member, descr = map(str.strip, line.split(None, 1))
expr = "((char*)(&pypy_g_typeinfo.%s)) - (char*)&pypy_g_typeinfo" % member
- offset = int(gdb.parse_and_eval(expr))
+ offset = int(self.gdb.parse_and_eval(expr))
typeids[offset] = descr
return typeids
- def get_first_field_if(self, obj, suffix):
- ctype = obj.type
- field = ctype.fields()[0]
- if field.name.endswith(suffix):
- return obj[field.name]
- return None
-
- def get_super(self, obj):
- return self.get_first_field_if(obj, '_super')
-
- def get_gc_header(self, obj):
- while True:
- sup = self.get_super(obj)
- if sup is None:
- break
- obj = sup
- return self.get_first_field_if(obj, '_gcheader')
-
-RPyType() # side effects
+try:
+ import gdb
+ RPyType() # side effects
+except ImportError:
+ pass
diff --git a/pypy/tool/test/test_gdb_pypy.py b/pypy/tool/test/test_gdb_pypy.py
new file mode 100644
--- /dev/null
+++ b/pypy/tool/test/test_gdb_pypy.py
@@ -0,0 +1,62 @@
+import py
+from pypy.tool import gdb_pypy
+
+class Mock(object):
+ def __init__(self, **attrs):
+ self.__dict__.update(attrs)
+
+class Field(Mock):
+ pass
+
+class Struct(object):
+ def __init__(self, fieldnames):
+ self._fields = [Field(name=name) for name in fieldnames]
+
+ def fields(self):
+ return self._fields[:]
+
+class Value(dict):
+ def __init__(self, *args, **kwds):
+ dict.__init__(self, *args, **kwds)
+ self.type = Struct(self.keys())
+ for key, val in self.iteritems():
+ if isinstance(val, dict):
+ self[key] = Value(val)
+
+def test_mock_objects():
+ d = {'a': 1,
+ 'b': 2,
+ 'super': {
+ 'c': 3,
+ }
+ }
+ val = Value(d)
+ assert val['a'] == 1
+ assert val['b'] == 2
+ assert isinstance(val['super'], Value)
+ assert val['super']['c'] == 3
+ fields = val.type.fields()
+ names = [f.name for f in fields]
+ assert sorted(names) == ['a', 'b', 'super']
+
+def test_find_field_with_suffix():
+ obj = Value(x_foo = 1,
+ y_bar = 2,
+ z_foobar = 3)
+ assert gdb_pypy.find_field_with_suffix(obj, 'foo') == 1
+ assert gdb_pypy.find_field_with_suffix(obj, 'foobar') == 3
+ py.test.raises(KeyError, "gdb_pypy.find_field_with_suffix(obj, 'bar')")
+ py.test.raises(KeyError, "gdb_pypy.find_field_with_suffix(obj, 'xxx')")
+
+def test_lookup():
+ d = {'r_super': {
+ '_gcheader': {
+ 'h_tid': 123,
+ }
+ },
+ 'r_foo': 42,
+ }
+ obj = Value(d)
+ assert gdb_pypy.lookup(obj, 'foo') == 42
+ hdr = gdb_pypy.lookup(obj, 'gcheader')
+ assert hdr['h_tid'] == 123
More information about the pypy-commit
mailing list