193 lines
7.8 KiB
Python
193 lines
7.8 KiB
Python
#!/usr/bin/env python3
|
||
import subprocess
|
||
import sys
|
||
import os
|
||
import re
|
||
from pathlib import Path
|
||
|
||
SCRIPT_DIR = Path(__file__).parent.absolute()
|
||
PROJECT_ROOT = SCRIPT_DIR.parent.parent
|
||
SOURCE_REL = SCRIPT_DIR / "тест_бнд.квс"
|
||
|
||
def clean():
|
||
files = [
|
||
"тест_бнд.elf",
|
||
"тест_бнд.csv",
|
||
"тест_бнд.аст",
|
||
"тест_бнд.токены",
|
||
"тест_бнд.константа",
|
||
"тест_бнд_pass4.log"
|
||
]
|
||
for f in files:
|
||
f_path = SCRIPT_DIR / f
|
||
if f_path.exists():
|
||
f_path.unlink()
|
||
|
||
def build():
|
||
os.chdir(PROJECT_ROOT)
|
||
build = subprocess.run(["python3", "квс_сборка.py", str(SOURCE_REL)],
|
||
capture_output=True, text=True)
|
||
if build.returncode != 0:
|
||
print(f"❌ Ошибка сборки: {build.returncode}", file=sys.stderr)
|
||
print(build.stderr, file=sys.stderr)
|
||
return False
|
||
return True
|
||
|
||
def test_file_size():
|
||
"""Проверка: файл должен быть маленьким (BSS не в файле)"""
|
||
print("DEBUG: Проверка размера файла", file=sys.stderr)
|
||
elf_path = SCRIPT_DIR / "тест_бнд.elf"
|
||
size = elf_path.stat().st_size
|
||
|
||
max_size = 100 * 1024 # 100 КБ
|
||
if size >= max_size:
|
||
print(f"❌ Размер файла {size} байт (ожидалось < {max_size})", file=sys.stderr)
|
||
return False
|
||
|
||
print(f"DEBUG: Размер файла {size} байт (OK)", file=sys.stderr)
|
||
return True
|
||
|
||
def test_bss_section():
|
||
"""Проверка секции .bss через readelf -S"""
|
||
print("DEBUG: Проверка секции .bss", file=sys.stderr)
|
||
os.chdir(SCRIPT_DIR)
|
||
|
||
result = subprocess.run(["readelf", "-S", "тест_бнд.elf"],
|
||
capture_output=True, text=True)
|
||
|
||
lines = result.stdout.split('\n')
|
||
expected_size = 1048576 # 1 МБ = 0x100000
|
||
|
||
for i, line in enumerate(lines):
|
||
if '.bss' in line and 'NOBITS' in line:
|
||
if i + 1 < len(lines):
|
||
size_line = lines[i + 1].strip()
|
||
match = re.search(r'^([0-9a-fA-F]+)', size_line)
|
||
if match:
|
||
size = int(match.group(1), 16)
|
||
if size == expected_size:
|
||
print(f"DEBUG: Размер .bss = {size} (OK)", file=sys.stderr)
|
||
return True
|
||
else:
|
||
print(f"❌ Размер .bss = {size} (ожидался {expected_size})", file=sys.stderr)
|
||
return False
|
||
|
||
print("❌ Секция .bss не найдена или имеет неверный формат", file=sys.stderr)
|
||
return False
|
||
|
||
def test_load_segment():
|
||
"""Проверка сегмента LOAD с BSS"""
|
||
print("DEBUG: Проверка сегмента LOAD", file=sys.stderr)
|
||
os.chdir(SCRIPT_DIR)
|
||
|
||
result = subprocess.run(["readelf", "-l", "тест_бнд.elf"],
|
||
capture_output=True, text=True)
|
||
|
||
print("DEBUG: Вывод readelf -l:", file=sys.stderr)
|
||
print(result.stdout, file=sys.stderr)
|
||
|
||
lines = result.stdout.split('\n')
|
||
expected_min = 1048576
|
||
|
||
# Поиск LOAD сегмента с RW
|
||
for i, line in enumerate(lines):
|
||
print(f"DEBUG: Строка {i}: {repr(line)}", file=sys.stderr)
|
||
if 'LOAD' in line and 'RW' in line:
|
||
print(f"DEBUG: Найден LOAD RW на строке {i}: {line}", file=sys.stderr)
|
||
# Ищем в следующих строках p_memsz
|
||
for j in range(i + 1, min(i + 5, len(lines))):
|
||
print(f"DEBUG: Строка {j}: {repr(lines[j])}", file=sys.stderr)
|
||
# Формат: 0x0000000000000001 0x0000000000101000 RW 0x1000
|
||
matches = re.findall(r'0x([0-9a-fA-F]+)', lines[j])
|
||
print(f"DEBUG: Найдено hex: {matches}", file=sys.stderr)
|
||
if len(matches) >= 2:
|
||
filesz = int(matches[0], 16)
|
||
memsz = int(matches[1], 16)
|
||
print(f"DEBUG: p_filesz = {filesz}, p_memsz = {memsz}", file=sys.stderr)
|
||
if memsz >= expected_min:
|
||
print(f"DEBUG: p_memsz = {memsz} (OK)", file=sys.stderr)
|
||
return True
|
||
else:
|
||
print(f"❌ p_memsz = {memsz} (ожидалось >= {expected_min})", file=sys.stderr)
|
||
return False
|
||
break
|
||
else:
|
||
# Альтернативный поиск: ищем по соответствию с .bss
|
||
print("DEBUG: LOAD RW не найден, ищем по соответствию с .bss", file=sys.stderr)
|
||
in_mapping = False
|
||
for i, line in enumerate(lines):
|
||
if 'Соответствие раздел-сегмент' in line:
|
||
in_mapping = True
|
||
print(f"DEBUG: Найдено 'Соответствие раздел-сегмент' на строке {i}", file=sys.stderr)
|
||
continue
|
||
if in_mapping and '.bss' in line:
|
||
print(f"DEBUG: Найдена строка с .bss: {line}", file=sys.stderr)
|
||
# Находим номер сегмента
|
||
seg_match = re.search(r'(\d+)', line)
|
||
if seg_match:
|
||
seg_num = int(seg_match.group(1))
|
||
print(f"DEBUG: Сегмент {seg_num} содержит .bss", file=sys.stderr)
|
||
# Теперь ищем этот сегмент в заголовках
|
||
for k, l in enumerate(lines):
|
||
if f'LOAD' in l and k < i:
|
||
print(f"DEBUG: Найден LOAD на строке {k}: {l}", file=sys.stderr)
|
||
# Проверяем его размер
|
||
for m in range(k + 1, min(k + 5, len(lines))):
|
||
matches = re.findall(r'0x([0-9a-fA-F]+)', lines[m])
|
||
if len(matches) >= 2:
|
||
memsz = int(matches[1], 16)
|
||
if memsz >= expected_min:
|
||
print(f"DEBUG: p_memsz = {memsz} (OK)", file=sys.stderr)
|
||
return True
|
||
break
|
||
|
||
print("❌ Не найден LOAD сегмент с BSS", file=sys.stderr)
|
||
return False
|
||
|
||
def test_execution():
|
||
"""Проверка: программа должна выполниться и вернуть 0"""
|
||
print("DEBUG: Проверка выполнения", file=sys.stderr)
|
||
os.chdir(SCRIPT_DIR)
|
||
|
||
elf_path = SCRIPT_DIR / "тест_бнд.elf"
|
||
run = subprocess.run([str(elf_path)], capture_output=True, text=True)
|
||
|
||
if run.returncode != 0:
|
||
print(f"❌ Код возврата {run.returncode} (ожидался 0)", file=sys.stderr)
|
||
return False
|
||
|
||
print("DEBUG: Выполнение успешно", file=sys.stderr)
|
||
return True
|
||
|
||
def main():
|
||
print("DEBUG: Начало теста тест_бнд", file=sys.stderr)
|
||
|
||
if not build():
|
||
clean()
|
||
sys.exit(1)
|
||
|
||
tests = [
|
||
("Размер файла", test_file_size),
|
||
("Секция .bss", test_bss_section),
|
||
("Сегмент LOAD", test_load_segment),
|
||
("Выполнение", test_execution),
|
||
]
|
||
|
||
all_passed = True
|
||
for name, test_func in tests:
|
||
if not test_func():
|
||
print(f"❌ Провалена проверка: {name}", file=sys.stderr)
|
||
all_passed = False
|
||
break
|
||
|
||
clean()
|
||
|
||
if all_passed:
|
||
print("✅", file=sys.stderr)
|
||
sys.exit(0)
|
||
else:
|
||
print("❌", file=sys.stderr)
|
||
sys.exit(1)
|
||
|
||
if __name__ == "__main__":
|
||
main() |