nanobrush / tests /test_mb3dat.py
nmarshall's picture
formats: map dat converter
543c8e8
Raw History Blame Contribute Delete
4.64 kB
"""Small independent byte fixtures for the E02 inspector's validation boundaries."""
import struct
import unittest
from inspect_mb3dat import InvalidDAT, inspect
from analyze_converter import cases, dat, i32, methods, vecs, TRIPLE
class DATInspectorTests(unittest.TestCase):
def test_two_distinct_header_layouts(self):
for version, size in [(201501280, 21), (201512200, 23)]:
data = dat(version)
self.assertEqual(len(data), size)
result = inspect(data)
self.assertEqual(result['version'], version)
self.assertEqual(result['consumed_bytes'], size)
self.assertEqual(result['brushes'], [])
def test_origin_and_direction_vectors(self):
d = inspect(dat(201512200, b'\0\1' + vecs(TRIPLE), 1))
p = d['brushes'][0]['planes'][0]
self.assertEqual(p['offset'], 21)
self.assertEqual(p['p0'], [1, 2, 3])
self.assertEqual(p['u'], [4, 5, 6])
self.assertEqual(p['v'], [7, 8, 9])
def test_sparse_strings_and_binary_duplicate(self):
body = b'\0\1\0first\0\0last\0\xff' + vecs(TRIPLE)
d = inspect(dat(201512200, body, 1, tables=b'\1name\0\0'))
self.assertEqual(d['string_properties'], ['name'])
self.assertEqual(d['brushes'][0]['planes'][0]['strings'], {'0': 'last'})
def test_uv_wire_order_is_not_text_tuple_order(self):
body = b'\0\1\0' + struct.pack('<10f', *range(1, 11)) + b'\xff' + vecs(TRIPLE)
d = inspect(dat(201512200, body, 1, tables=b'\0\1uv\0'))
self.assertEqual(d['brushes'][0]['planes'][0]['uv']['0'], list(range(1, 11)))
def test_width_three_uses_four_bytes(self):
data = dat(201512200, tables=i32(0) + i32(0), widths=30)
self.assertEqual(inspect(data)['consumed_bytes'], 29)
def test_legacy_signed_16_count_is_rejected(self):
with self.assertRaisesRegex(InvalidDAT, 'invalid/excessive count -32768'):
inspect(dat(201501280, b'\1\0\x80', 1))
def test_computed_contour(self):
body = b'\0\1' + vecs(TRIPLE) + b'\1' + vecs([(9, 8, 7)])
d = inspect(dat(201512200, body, 1, computed=True))
self.assertEqual(d['brushes'][0]['planes'][0]['polygon'], [[9, 8, 7]])
def test_patch_implicit_grid_size(self):
body = b'\0\3\3\2\2' + vecs([(1, 2, 3)] * 9) + vecs([(4, 5, 6)] * 9) + vecs([(0, 1, 0)] * 9)
d = inspect(dat(201512200, patch_records=body, patch_count=1, computed=True))
self.assertEqual(len(d['patches'][0]['points']), 9)
self.assertEqual(d['patches'][0]['normals'][8], [0, 1, 0])
def test_all_prefix_truncations_rejected(self):
data = dat(201512200, b'\0\1' + vecs(TRIPLE), 1)
for length in range(len(data)):
with self.subTest(length=length), self.assertRaises(InvalidDAT):
inspect(data[:length])
def test_unterminated_string_and_bad_index_rejected(self):
with self.assertRaisesRegex(InvalidDAT, 'unterminated'):
inspect(b'Mb3World' + i32(201512200) + b'\0\1no-terminator')
with self.assertRaisesRegex(InvalidDAT, 'index 1 out of range'):
inspect(dat(201512200, b'\0\1\1bad\0\xff' + vecs(TRIPLE), 1, tables=b'\1p\0\0'))
def test_allocation_limit_and_count_overflow(self):
with self.assertRaises(InvalidDAT):
inspect(dat(201512200, brush_count=2**31 - 1))
with self.assertRaises(InvalidDAT):
inspect(dat(201512200, patch_records=b'\x0a' + i32(65536) * 4, patch_count=1))
def test_trailing_bytes_reported(self):
self.assertEqual(inspect(dat(201512200) + b'extra')['trailing_bytes'], 5)
def test_wrong_magic_and_unknown_version(self):
for data in [b'NOTWORLD' + dat(201512200)[8:], b'Mb3World' + i32(1) + b'\0' * 20]:
with self.assertRaises(InvalidDAT):
inspect(data)
class ResearchHarnessTests(unittest.TestCase):
def test_unique_case_names_and_chained_inputs(self):
for version in [201501280, 201512200]:
seen = set()
for case in cases(version):
self.assertNotIn(case['name'], seen)
if 'from_case' in case:
self.assertIn(case['from_case'], seen)
seen.add(case['name'])
def test_il_anchor_index(self):
il = '.method public static void Sample () cil managed\n{\n// Method begins at RVA 0x2050\n// Code size: 7 (0x7)\n} // end of method Example::Sample\n'
self.assertEqual(methods(il), [{'name': 'Example::Sample', 'rva': '0x2050', 'il_bytes': 7, 'il_line': 1}])
if __name__ == '__main__':
unittest.main()