1#!/usr/bin/env python3
2from pathlib import Path
3import struct
4import subprocess
5import tempfile
6
7source = Path(__file__).resolve().parent
8for arch in ['x86', 'x86_64', 'aarch64']:
9 subprocess.run(['python3', str(source / 'build.py'), '--arch', arch], check=True)
10 data = (source / 'build' / ('snowglobe-guest-' + arch + '.exe')).read_bytes()
11 pe = struct.unpack_from('<I', data, 60)[0]
12 assert data[pe:pe + 4] == b'PE\0\0'
13 machine, sections, _, _, _, optional_size = struct.unpack_from('<HHIIIH', data, pe + 4)
14 optional = pe + 24
15 assert machine == {'x86': 0x14c, 'x86_64': 0x8664, 'aarch64': 0xaa64}[arch]
16 assert struct.unpack_from('<HH', data, optional + 48) == ((10, 0) if arch == 'aarch64' else (6, 1))
17 table = optional + optional_size
18 def offset(rva):
19 for index in range(sections):
20 size, start, raw_size, raw = struct.unpack_from('<IIII', data, table + 40 * index + 8)
21 if start <= rva < start + max(size, raw_size): return raw + rva - start
22 raise AssertionError('unmapped PE address')
23 directory = optional + (96 if arch == 'x86' else 112)
24 imports = offset(struct.unpack_from('<I', data, directory + 8)[0])
25 libraries = set()
26 while any(data[imports:imports + 20]):
27 name = offset(struct.unpack_from('<I', data, imports + 12)[0])
28 libraries.add(data[name:data.index(0, name)].decode().lower())
29 imports += 20
30 assert libraries == {'kernel32.dll', 'user32.dll', 'gdi32.dll'}, libraries
31 print(arch, len(data), 'bytes; system DLLs only; minimum subsystem verified')
32with tempfile.TemporaryDirectory() as temporary:
33 binary = Path(temporary) / 'cursor-tests'
34 subprocess.run(['cc', '-std=c99', '-Wall', '-Wextra', '-Werror', '-ffreestanding', '-fsanitize=address,undefined', '-I', str(source / 'build'), str(source / 'cursor.c'), str(source / 'tests.c'), '-o', str(binary)], check=True)
35 subprocess.run([str(binary)], check=True)
36print('cursor alpha, inversion, dirty rectangles, and bounds passed')