2026-06-09 22:43:10 +03:00
|
|
|
|
#!/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)
|
2026-06-20 05:20:34 +03:00
|
|
|
|
build = subprocess.run(["python3", "квс_сборка.py", str(SOURCE_REL)],
|
2026-06-09 22:43:10 +03:00
|
|
|
|
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()
|