tests: move common helpers to top-level

This commit is contained in:
Omar Sandoval 2019-07-23 15:41:30 -07:00
parent 62ff4e1dba
commit b5b024ecac
3 changed files with 150 additions and 135 deletions

View File

@ -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)

View File

@ -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):

View File

@ -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.