mirror of
https://github.com/JakeHillion/drgn.git
synced 2024-12-23 01:33:06 +00:00
tests: move common helpers to top-level
This commit is contained in:
parent
62ff4e1dba
commit
b5b024ecac
@ -1,10 +1,19 @@
|
||||
import functools
|
||||
from typing import NamedTuple, Optional
|
||||
import unittest
|
||||
|
||||
from drgn import (
|
||||
int_type,
|
||||
float_type,
|
||||
struct_type,
|
||||
union_type,
|
||||
Architecture,
|
||||
FindObjectFlags,
|
||||
Object,
|
||||
Program,
|
||||
TypeKind,
|
||||
enum_type,
|
||||
float_type,
|
||||
int_type,
|
||||
struct_type,
|
||||
typedef_type,
|
||||
union_type,
|
||||
)
|
||||
|
||||
|
||||
@ -23,3 +32,123 @@ option_type = union_type('option', 4, (
|
||||
color_type = enum_type('color', int_type('unsigned int', 4, False),
|
||||
(('RED', 0), ('GREEN', 1), ('BLUE', 2)))
|
||||
pid_type = typedef_type('pid_t', int_type('int', 4, True))
|
||||
|
||||
|
||||
MOCK_32BIT_ARCH = Architecture.IS_LITTLE_ENDIAN
|
||||
MOCK_ARCH = Architecture.IS_64_BIT | Architecture.IS_LITTLE_ENDIAN
|
||||
|
||||
|
||||
class MockMemorySegment(NamedTuple):
|
||||
buf: bytes
|
||||
virt_addr: Optional[int] = None
|
||||
phys_addr: Optional[int] = None
|
||||
|
||||
|
||||
def mock_memory_read(data, address, count, offset, physical):
|
||||
return data[offset:offset + count]
|
||||
|
||||
|
||||
def mock_program(arch=MOCK_ARCH, *, segments=None, types=None, symbols=None):
|
||||
def mock_find_type(kind, name, filename):
|
||||
if filename:
|
||||
return None
|
||||
for type in types:
|
||||
if type.kind == kind:
|
||||
try:
|
||||
type_name = type.name
|
||||
except AttributeError:
|
||||
try:
|
||||
type_name = type.tag
|
||||
except AttributeError:
|
||||
continue
|
||||
if type_name == name:
|
||||
return type
|
||||
return None
|
||||
|
||||
def mock_symbol_find(name, flags, filename):
|
||||
if filename:
|
||||
return None
|
||||
for sym_name, sym in symbols:
|
||||
if sym_name == name:
|
||||
if sym.value is not None or sym.is_enumerator:
|
||||
if flags & FindObjectFlags.CONSTANT:
|
||||
break
|
||||
elif sym.type.kind == TypeKind.FUNCTION:
|
||||
if flags & FindObjectFlags.FUNCTION:
|
||||
break
|
||||
elif flags & FindObjectFlags.VARIABLE:
|
||||
break
|
||||
else:
|
||||
return None
|
||||
return sym
|
||||
|
||||
prog = Program(arch)
|
||||
if segments is not None:
|
||||
for segment in segments:
|
||||
if segment.virt_addr is not None:
|
||||
prog.add_memory_segment(
|
||||
segment.virt_addr, len(segment.buf),
|
||||
functools.partial(mock_memory_read, segment.buf))
|
||||
if segment.phys_addr is not None:
|
||||
prog.add_memory_segment(
|
||||
segment.phys_addr, len(segment.buf),
|
||||
functools.partial(mock_memory_read, segment.buf), True)
|
||||
if types is not None:
|
||||
prog.add_type_finder(mock_find_type)
|
||||
if symbols is not None:
|
||||
prog.add_symbol_finder(mock_symbol_find)
|
||||
return prog
|
||||
|
||||
|
||||
class ObjectTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.prog = mock_program()
|
||||
# For testing, we want to compare the raw objects rather than using the
|
||||
# language's equality operator.
|
||||
def object_equality_func(a, b, msg=None):
|
||||
if a.prog_ is not b.prog_:
|
||||
raise self.failureException(msg or 'objects have different program')
|
||||
if a.type_ != b.type_:
|
||||
raise self.failureException(msg or f'object types differ: {a.type_!r} != {b.type_!r}')
|
||||
if a.address_ != b.address_:
|
||||
a_address = 'None' if a.address_ is None else hex(a.address_)
|
||||
b_address = 'None' if b.address_ is None else hex(b.address_)
|
||||
raise self.failureException(msg or f'object addresses differ: {a_address} != {b_address}')
|
||||
if a.byteorder_ != b.byteorder_:
|
||||
raise self.failureException(msg or f'object byteorders differ: {a.byteorder_} != {b.byteorder_}')
|
||||
if a.bit_offset_ != b.bit_offset_:
|
||||
raise self.failureException(msg or f'object bit offsets differ: {a.bit_offset_} != {b.bit_offset_}')
|
||||
if a.bit_field_size_ != b.bit_field_size_:
|
||||
raise self.failureException(msg or f'object bit field sizes differ: {a.bit_field_size_} != {b.bit_field_size_}')
|
||||
exc_a = exc_b = False
|
||||
try:
|
||||
value_a = a.value_()
|
||||
except Exception:
|
||||
exc_a = True
|
||||
try:
|
||||
value_b = b.value_()
|
||||
except Exception:
|
||||
exc_b = True
|
||||
if exc_a and not exc_b:
|
||||
raise self.failureException(msg or f'exception raised while reading {a!r}')
|
||||
if not exc_a and exc_b:
|
||||
raise self.failureException(msg or f'exception raised while reading {b!r}')
|
||||
if not exc_a and value_a != value_b:
|
||||
raise self.failureException(msg or f'object values differ: {value_a!r} != {value_b!r}')
|
||||
self.addTypeEqualityFunc(Object, object_equality_func)
|
||||
|
||||
def bool(self, value):
|
||||
return Object(self.prog, '_Bool', value=value)
|
||||
|
||||
def int(self, value):
|
||||
return Object(self.prog, 'int', value=value)
|
||||
|
||||
def unsigned_int(self, value):
|
||||
return Object(self.prog, 'unsigned int', value=value)
|
||||
|
||||
def long(self, value):
|
||||
return Object(self.prog, 'long', value=value)
|
||||
|
||||
def double(self, value):
|
||||
return Object(self.prog, 'double', value=value)
|
||||
|
@ -1,88 +1,35 @@
|
||||
import math
|
||||
import operator
|
||||
import struct
|
||||
import unittest
|
||||
|
||||
from drgn import (
|
||||
FaultError,
|
||||
Object,
|
||||
Qualifiers,
|
||||
Type,
|
||||
array_type,
|
||||
cast,
|
||||
container_of,
|
||||
enum_type,
|
||||
FaultError,
|
||||
float_type,
|
||||
function_type,
|
||||
int_type,
|
||||
Object,
|
||||
pointer_type,
|
||||
Qualifiers,
|
||||
reinterpret,
|
||||
struct_type,
|
||||
Type,
|
||||
typedef_type,
|
||||
union_type,
|
||||
void_type,
|
||||
)
|
||||
from tests import (
|
||||
MockMemorySegment,
|
||||
ObjectTestCase,
|
||||
color_type,
|
||||
line_segment_type,
|
||||
mock_program,
|
||||
option_type,
|
||||
point_type,
|
||||
)
|
||||
from tests.test_program import MockMemorySegment, mock_program
|
||||
|
||||
|
||||
class ObjectTestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.prog = mock_program()
|
||||
# For testing, we want to compare the raw objects rather than using the
|
||||
# language's equality operator.
|
||||
def object_equality_func(a, b, msg=None):
|
||||
if a.prog_ is not b.prog_:
|
||||
raise self.failureException(msg or 'objects have different program')
|
||||
if a.type_ != b.type_:
|
||||
raise self.failureException(msg or f'object types differ: {a.type_!r} != {b.type_!r}')
|
||||
if a.address_ != b.address_:
|
||||
a_address = 'None' if a.address_ is None else hex(a.address_)
|
||||
b_address = 'None' if b.address_ is None else hex(b.address_)
|
||||
raise self.failureException(msg or f'object addresses differ: {a_address} != {b_address}')
|
||||
if a.byteorder_ != b.byteorder_:
|
||||
raise self.failureException(msg or f'object byteorders differ: {a.byteorder_} != {b.byteorder_}')
|
||||
if a.bit_offset_ != b.bit_offset_:
|
||||
raise self.failureException(msg or f'object bit offsets differ: {a.bit_offset_} != {b.bit_offset_}')
|
||||
if a.bit_field_size_ != b.bit_field_size_:
|
||||
raise self.failureException(msg or f'object bit field sizes differ: {a.bit_field_size_} != {b.bit_field_size_}')
|
||||
exc_a = exc_b = False
|
||||
try:
|
||||
value_a = a.value_()
|
||||
except Exception:
|
||||
exc_a = True
|
||||
try:
|
||||
value_b = b.value_()
|
||||
except Exception:
|
||||
exc_b = True
|
||||
if exc_a and not exc_b:
|
||||
raise self.failureException(msg or f'exception raised while reading {a!r}')
|
||||
if not exc_a and exc_b:
|
||||
raise self.failureException(msg or f'exception raised while reading {b!r}')
|
||||
if not exc_a and value_a != value_b:
|
||||
raise self.failureException(msg or f'object values differ: {value_a!r} != {value_b!r}')
|
||||
self.addTypeEqualityFunc(Object, object_equality_func)
|
||||
|
||||
def bool(self, value):
|
||||
return Object(self.prog, '_Bool', value=value)
|
||||
|
||||
def int(self, value):
|
||||
return Object(self.prog, 'int', value=value)
|
||||
|
||||
def unsigned_int(self, value):
|
||||
return Object(self.prog, 'unsigned int', value=value)
|
||||
|
||||
def long(self, value):
|
||||
return Object(self.prog, 'long', value=value)
|
||||
|
||||
def double(self, value):
|
||||
return Object(self.prog, 'double', value=value)
|
||||
|
||||
|
||||
class TestInit(ObjectTestCase):
|
||||
|
@ -1,22 +1,18 @@
|
||||
import ctypes
|
||||
import functools
|
||||
import itertools
|
||||
import os
|
||||
import tempfile
|
||||
from typing import NamedTuple, Optional
|
||||
import unittest
|
||||
import unittest.mock
|
||||
|
||||
from drgn import (
|
||||
Architecture,
|
||||
FaultError,
|
||||
FileFormatError,
|
||||
FindObjectFlags,
|
||||
Program,
|
||||
ProgramFlags,
|
||||
Qualifiers,
|
||||
Symbol,
|
||||
TypeKind,
|
||||
array_type,
|
||||
bool_type,
|
||||
float_type,
|
||||
@ -26,81 +22,24 @@ from drgn import (
|
||||
typedef_type,
|
||||
void_type,
|
||||
)
|
||||
from tests import color_type, option_type, pid_type, point_type
|
||||
from tests import (
|
||||
MOCK_32BIT_ARCH,
|
||||
MOCK_ARCH,
|
||||
MockMemorySegment,
|
||||
color_type,
|
||||
mock_program,
|
||||
option_type,
|
||||
pid_type,
|
||||
point_type,
|
||||
)
|
||||
from tests.elf import ET, PT
|
||||
from tests.elfwriter import ElfSection, create_elf_file
|
||||
|
||||
|
||||
MOCK_32BIT_ARCH = Architecture.IS_LITTLE_ENDIAN
|
||||
MOCK_ARCH = Architecture.IS_64_BIT | Architecture.IS_LITTLE_ENDIAN
|
||||
|
||||
|
||||
class MockMemorySegment(NamedTuple):
|
||||
buf: bytes
|
||||
virt_addr: Optional[int] = None
|
||||
phys_addr: Optional[int] = None
|
||||
|
||||
|
||||
def mock_memory_read(data, address, count, offset, physical):
|
||||
return data[offset:offset + count]
|
||||
|
||||
|
||||
def zero_memory_read(address, count, offset, physical):
|
||||
return bytes(count)
|
||||
|
||||
|
||||
def mock_program(arch=MOCK_ARCH, *, segments=None, types=None, symbols=None):
|
||||
def mock_find_type(kind, name, filename):
|
||||
if filename:
|
||||
return None
|
||||
for type in types:
|
||||
if type.kind == kind:
|
||||
try:
|
||||
type_name = type.name
|
||||
except AttributeError:
|
||||
try:
|
||||
type_name = type.tag
|
||||
except AttributeError:
|
||||
continue
|
||||
if type_name == name:
|
||||
return type
|
||||
return None
|
||||
|
||||
def mock_symbol_find(name, flags, filename):
|
||||
if filename:
|
||||
return None
|
||||
for sym_name, sym in symbols:
|
||||
if sym_name == name:
|
||||
if sym.value is not None or sym.is_enumerator:
|
||||
if flags & FindObjectFlags.CONSTANT:
|
||||
break
|
||||
elif sym.type.kind == TypeKind.FUNCTION:
|
||||
if flags & FindObjectFlags.FUNCTION:
|
||||
break
|
||||
elif flags & FindObjectFlags.VARIABLE:
|
||||
break
|
||||
else:
|
||||
return None
|
||||
return sym
|
||||
|
||||
prog = Program(arch)
|
||||
if segments is not None:
|
||||
for segment in segments:
|
||||
if segment.virt_addr is not None:
|
||||
prog.add_memory_segment(
|
||||
segment.virt_addr, len(segment.buf),
|
||||
functools.partial(mock_memory_read, segment.buf))
|
||||
if segment.phys_addr is not None:
|
||||
prog.add_memory_segment(
|
||||
segment.phys_addr, len(segment.buf),
|
||||
functools.partial(mock_memory_read, segment.buf), True)
|
||||
if types is not None:
|
||||
prog.add_type_finder(mock_find_type)
|
||||
if symbols is not None:
|
||||
prog.add_symbol_finder(mock_symbol_find)
|
||||
return prog
|
||||
|
||||
|
||||
class TestProgram(unittest.TestCase):
|
||||
def test_set_pid(self):
|
||||
# Debug the running Python interpreter itself.
|
||||
|
Loading…
Reference in New Issue
Block a user