987 lines
44 KiB
Python
Executable file
987 lines
44 KiB
Python
Executable file
#!/usr/bin/env python3
|
||
import os
|
||
import sys
|
||
import tempfile
|
||
import shutil
|
||
import subprocess
|
||
import re
|
||
import atexit
|
||
import signal
|
||
import traceback
|
||
import glob
|
||
|
||
# Цвета для терминала
|
||
GREEN = '\033[92m'
|
||
RED = '\033[91m'
|
||
YELLOW = '\033[93m'
|
||
BLUE = '\033[94m'
|
||
RESET = '\033[0m'
|
||
BOLD = '\033[1m'
|
||
|
||
# Глобальные переменные для состояния тестов
|
||
_TESTS_PASSED = 0
|
||
_TESTS_FAILED = 0
|
||
_TESTS_TOTAL = 0
|
||
_TEST_RESULTS: list = []
|
||
|
||
def main():
|
||
# Проверяем, что передан путь к исполняемому файлу rusi
|
||
if len(sys.argv) < 2:
|
||
print("Использование: {} <путь-к-rusi>".format(sys.argv[0]), file=sys.stderr)
|
||
sys.exit(1)
|
||
|
||
rusi = sys.argv[1] # Путь к тестируемому компилятору
|
||
|
||
# Создаем временную папку для тестов
|
||
tmp = tempfile.mkdtemp(prefix='rusi-test-')
|
||
|
||
def cleanup():
|
||
# Удаляем временную папку после завершения тестов
|
||
shutil.rmtree(tmp, ignore_errors=True)
|
||
|
||
atexit.register(cleanup) # Регистрируем функцию очистки
|
||
|
||
# Обработчики сигналов для корректного завершения
|
||
signal.signal(signal.SIGINT, lambda s, f: завершить_тесты())
|
||
signal.signal(signal.SIGTERM, lambda s, f: завершить_тесты())
|
||
if hasattr(signal, 'SIGHUP'):
|
||
signal.signal(signal.SIGHUP, lambda s, f: завершить_тесты())
|
||
|
||
# Создаем пустой C-файл для тестирования
|
||
tmp_c = os.path.join(tmp, 'tmp.c')
|
||
with open(tmp_c, 'w') as f:
|
||
f.write('')
|
||
|
||
# Запускаем все тесты
|
||
try:
|
||
запустить_тесты(rusi, tmp, tmp_c)
|
||
except (AssertionError, subprocess.CalledProcessError, Exception) as e:
|
||
# При падении любого теста выводим отчет и выходим с ошибкой
|
||
вывести_отчет()
|
||
print(f"\n{RED}❌ ТЕСТЫ НЕ ПРОЙДЕНЫ: {str(e)}{RESET}")
|
||
sys.exit(1)
|
||
|
||
# Если все тесты прошли успешно
|
||
вывести_отчет()
|
||
if _TESTS_FAILED == 0:
|
||
print(f"\n{GREEN}{BOLD}🎉 ВСЕ ТЕСТЫ ПРОЙДЕНЫ УСПЕШНО!{RESET}")
|
||
sys.exit(0)
|
||
else:
|
||
print(f"\n{RED}{BOLD}❌ НЕ ПРОЙДЕНО {_TESTS_FAILED} ТЕСТОВ ИЗ {_TESTS_TOTAL}{RESET}")
|
||
sys.exit(1)
|
||
|
||
def завершить_тесты():
|
||
"""Принудительное завершение с выводом отчета"""
|
||
вывести_отчет()
|
||
sys.exit(1)
|
||
|
||
def запустить_тесты(rusi: str, tmp: str, tmp_c: str):
|
||
"""Запускает все тесты"""
|
||
global _TESTS_TOTAL
|
||
|
||
# Список всех тестов с их описаниями
|
||
тесты = [
|
||
("-o", lambda: тест_o(rusi, tmp, tmp_c)),
|
||
("--help", lambda: тест_help(rusi)),
|
||
("-S", lambda: тест_S(rusi)),
|
||
("имя выходного файла по умолчанию", lambda: тест_имя_выходного_файла(rusi, tmp)),
|
||
("несколько входных файлов", lambda: тест_несколько_входных(rusi, tmp)),
|
||
("линковщик", lambda: тест_линковщик(rusi, tmp)),
|
||
("a.out", lambda: тест_a_out(rusi, tmp)),
|
||
("-E", lambda: тест_E(rusi, tmp)),
|
||
("-E и -o", lambda: тест_E_o(rusi, tmp)),
|
||
("-I", lambda: тест_I(rusi, tmp)),
|
||
("-D", lambda: тест_D(rusi)),
|
||
("-D со значением", lambda: тест_D_значение(rusi)),
|
||
("-U", lambda: тест_U(rusi)),
|
||
("игнорируемые опции", lambda: тест_игнорируемые(rusi, tmp_c)),
|
||
("маркер BOM", lambda: тест_BOM(rusi)),
|
||
("inline", lambda: тест_inline(rusi, tmp)),
|
||
("-idirafter", lambda: тест_idirafter(rusi, tmp)),
|
||
("-fcommon (по умолчанию)", lambda: тест_fcommon_по_умолчанию(rusi)),
|
||
("-fcommon", lambda: тест_fcommon(rusi)),
|
||
("-fno-common", lambda: тест_fno_common(rusi)),
|
||
("-include", lambda: тест_include(rusi, tmp)),
|
||
("-include stdio.h", lambda: тест_include_stdio(rusi)),
|
||
("-xc", lambda: тест_xc(rusi, tmp)),
|
||
("-x assembler", lambda: тест_x_assembler(rusi, tmp)),
|
||
("-x none", lambda: тест_x_none(rusi, tmp)),
|
||
("-E без -xc", lambda: тест_E_без_xc(rusi)),
|
||
(".a", lambda: тест_a_архив(rusi, tmp)),
|
||
(".so", lambda: тест_so_библиотека(rusi, tmp)),
|
||
("хеш-таблица", lambda: тест_хеш_таблица(rusi)),
|
||
("-M", lambda: тест_M(rusi, tmp)),
|
||
("-MF", lambda: тест_MF(rusi, tmp)),
|
||
("-MP", lambda: тест_MP(rusi, tmp)),
|
||
("-MT", lambda: тест_MT(rusi, tmp)),
|
||
("-MT несколько целей", lambda: тест_MT_несколько(rusi, tmp)),
|
||
("-MD", lambda: тест_MD(rusi, tmp)),
|
||
("-MD с -MF", lambda: тест_MD_MF(rusi, tmp)),
|
||
("-fPIC", lambda: тест_fPIC(rusi, tmp)),
|
||
("#include_next", lambda: тест_include_next(rusi, tmp)),
|
||
("-static", lambda: тест_static(rusi, tmp)),
|
||
("-shared", lambda: тест_shared(rusi, tmp)),
|
||
("-L", lambda: тест_L(rusi, tmp)),
|
||
("-Wl,", lambda: тест_Wl(rusi, tmp)),
|
||
("-Xlinker", lambda: тест_Xlinker(rusi, tmp)),
|
||
# ============================================================
|
||
# НОВЫЕ ТЕСТЫ: Сборка и запуск .c файлов из папки test/
|
||
# ============================================================
|
||
("Сборка тестов .c", lambda: тест_сборка_c_файлов(rusi)),
|
||
]
|
||
|
||
_TESTS_TOTAL = len(тесты)
|
||
|
||
# Вычисляем максимальную длину названия теста для выравнивания
|
||
макс_длина = 0
|
||
for название, _ in тесты:
|
||
макс_длина = max(макс_длина, len(название))
|
||
|
||
for название, тест_функция in тесты:
|
||
выполнить_тест(название, тест_функция, макс_длина)
|
||
|
||
def выполнить_тест(название: str, тест_функция, макс_длина: int):
|
||
"""Выполняет отдельный тест - при ошибке сразу прерывает выполнение"""
|
||
global _TESTS_PASSED, _TESTS_FAILED
|
||
|
||
try:
|
||
тест_функция()
|
||
_TESTS_PASSED += 1
|
||
_TEST_RESULTS.append((название, True, None))
|
||
print(f"{GREEN}✓{RESET} {название:<{макс_длина}} ... {GREEN}ПРОЙДЕНО{RESET}")
|
||
except AssertionError as e:
|
||
_TESTS_FAILED += 1
|
||
ошибка = str(e) if str(e) else "проверка не пройдена"
|
||
_TEST_RESULTS.append((название, False, ошибка))
|
||
print(f"{RED}✗{RESET} {название:<{макс_длина}} ... {RED}НЕ ПРОЙДЕНО{RESET}: {ошибка}")
|
||
raise # Прерываем выполнение при падении теста
|
||
except subprocess.CalledProcessError as e:
|
||
_TESTS_FAILED += 1
|
||
ошибка = f"команда завершилась с кодом {e.returncode}"
|
||
_TEST_RESULTS.append((название, False, ошибка))
|
||
print(f"{RED}✗{RESET} {название:<{макс_длина}} ... {RED}НЕ ПРОЙДЕНО{RESET}: {ошибка}")
|
||
raise # Прерываем выполнение при падении теста
|
||
except Exception as e:
|
||
_TESTS_FAILED += 1
|
||
ошибка = f"{type(e).__name__}: {str(e)}"
|
||
_TEST_RESULTS.append((название, False, ошибка))
|
||
print(f"{RED}✗{RESET} {название:<{макс_длина}} ... {RED}НЕ ПРОЙДЕНО{RESET}: {ошибка}")
|
||
traceback.print_exc()
|
||
raise # Прерываем выполнение при падении теста
|
||
|
||
def вывести_отчет():
|
||
"""Выводит итоговый отчет о тестировании"""
|
||
global _TESTS_PASSED, _TESTS_FAILED, _TESTS_TOTAL
|
||
|
||
print("\n" + "=" * 60)
|
||
print(f"{BOLD}ИТОГОВЫЙ ОТЧЕТ О ТЕСТИРОВАНИИ{RESET}")
|
||
print("=" * 60)
|
||
|
||
if _TEST_RESULTS:
|
||
print("\nПОДРОБНЫЕ РЕЗУЛЬТАТЫ:")
|
||
for название, успешно, ошибка in _TEST_RESULTS:
|
||
if успешно:
|
||
статус = f"{GREEN}✓ ПРОЙДЕНО{RESET}"
|
||
else:
|
||
статус = f"{RED}✗ НЕ ПРОЙДЕНО{RESET}"
|
||
строка = f" {статус} {название}"
|
||
if not успешно and ошибка:
|
||
строка += f" ({RED}ошибка: {ошибка}{RESET})"
|
||
print(строка)
|
||
|
||
print("\n" + "-" * 60)
|
||
print(f"ВСЕГО ТЕСТОВ: {_TESTS_TOTAL}")
|
||
print(f"ПРОЙДЕНО: {GREEN}{_TESTS_PASSED}{RESET}")
|
||
print(f"НЕ ПРОЙДЕНО: {RED}{_TESTS_FAILED}{RESET}")
|
||
print("=" * 60)
|
||
|
||
def проверка_существования_файла(путь: str, сообщение: str = ""):
|
||
"""Вспомогательная функция для проверки существования файла"""
|
||
if not os.path.exists(путь):
|
||
raise AssertionError(f"файл {путь} не создан {сообщение}")
|
||
|
||
def проверка_содержимого(текст: str, паттерн, сообщение: str = ""):
|
||
"""Вспомогательная функция для проверки содержимого"""
|
||
if isinstance(паттерн, str):
|
||
if паттерн not in текст:
|
||
raise AssertionError(f"'{паттерн}' не найден в выводе {сообщение}")
|
||
else: # регулярное выражение
|
||
if not паттерн.search(текст):
|
||
raise AssertionError(f"паттерн не найден в выводе {сообщение}")
|
||
|
||
def run_rusi(rusi: str, *args, **kwargs):
|
||
"""Запускает rusi с заданными аргументами"""
|
||
cmd = [rusi] + list(args)
|
||
if 'input' in kwargs:
|
||
input_text = kwargs.pop('input')
|
||
kwargs['input'] = input_text
|
||
if 'capture_output' not in kwargs and 'stdout' not in kwargs and 'stderr' not in kwargs:
|
||
kwargs['capture_output'] = True
|
||
kwargs['text'] = True
|
||
return subprocess.run(cmd, **kwargs)
|
||
|
||
# ============================================================================
|
||
# НОВАЯ ФУНКЦИЯ: Сборка и запуск .c файлов из папки test/
|
||
# ============================================================================
|
||
|
||
def тест_сборка_c_файлов(rusi: str):
|
||
"""Собирает и запускает все .c файлы из папки test/, проверяя вывод на OK"""
|
||
|
||
# Находим все .c файлы в папке test/
|
||
test_dir = "test"
|
||
if not os.path.exists(test_dir):
|
||
raise AssertionError(f"Папка {test_dir} не найдена")
|
||
|
||
c_files = glob.glob(os.path.join(test_dir, "*.c"))
|
||
|
||
if not c_files:
|
||
raise AssertionError("В папке test/ нет .c файлов")
|
||
|
||
# Файлы, которые нужно исключить (требуют специальной линковки или не являются тестами)
|
||
исключения = [] # atomic.c теперь работает
|
||
|
||
# Файлы, которые требуют stdvv.c
|
||
stdvv = os.path.join(test_dir, "stdvv.c")
|
||
if not os.path.exists(stdvv):
|
||
stdvv = None
|
||
|
||
# Файлы, которые требуют test.c (если есть)
|
||
test_c = os.path.join(test_dir, "test.c")
|
||
if os.path.exists(test_c):
|
||
runtime = test_c
|
||
elif stdvv:
|
||
runtime = stdvv
|
||
else:
|
||
runtime = None
|
||
|
||
# Счетчики для отчета
|
||
всего_тестов = 0
|
||
пройдено_тестов = 0
|
||
пропущено_тестов = 0
|
||
|
||
# Вычисляем максимальную длину имени файла для выравнивания
|
||
макс_длина = 0
|
||
for c_file in c_files:
|
||
имя = os.path.basename(c_file)
|
||
if имя not in ["stdvv.c", "test.c", "тест.з"]:
|
||
макс_длина = max(макс_длина, len(имя))
|
||
|
||
print(f"\n{BOLD}=== ЗАПУСК СЕМАНТИЧЕСКИХ ТЕСТОВ ==={RESET}")
|
||
print()
|
||
|
||
# Проходим по всем .c файлам
|
||
for c_file in sorted(c_files):
|
||
имя_файла = os.path.basename(c_file)
|
||
имя_без_расш = os.path.splitext(имя_файла)[0]
|
||
|
||
# Пропускаем исключения
|
||
if имя_файла in исключения:
|
||
пропущено_тестов += 1
|
||
print(f"{YELLOW}⚠{RESET} {имя_файла:<{макс_длина}} ... {YELLOW}ПРОПУЩЕН{RESET} (требует специальной линковки)")
|
||
continue
|
||
|
||
# Пропускаем runtime файлы (не тесты)
|
||
if имя_файла in ["stdvv.c", "test.c", "тест.з"]:
|
||
continue
|
||
|
||
всего_тестов += 1
|
||
|
||
# Определяем, нужен ли runtime для этого теста
|
||
with open(c_file, 'r', encoding='utf-8', errors='ignore') as f:
|
||
содержимое = f.read()
|
||
нужен_runtime = 'ASSERT' in содержимое or 'ПРОВЕРИТЬ' in содержимое or 'printf' not in содержимое
|
||
|
||
# Собираем команду компиляции
|
||
выходной_файл = os.path.join(test_dir, f"test_{имя_без_расш}")
|
||
аргументы = [rusi, "-o", выходной_файл, c_file]
|
||
|
||
# Добавляем runtime если нужен
|
||
if нужен_runtime and runtime and os.path.exists(runtime):
|
||
аргументы.append(runtime)
|
||
|
||
# Собираем
|
||
try:
|
||
subprocess.run(аргументы, capture_output=True, text=True, check=True)
|
||
except subprocess.CalledProcessError as e:
|
||
raise AssertionError(f"Ошибка компиляции {имя_файла}: {e.stderr}")
|
||
|
||
# Проверяем, что исполняемый файл создан
|
||
if not os.path.exists(выходной_файл):
|
||
raise AssertionError(f"Исполняемый файл не создан для {имя_файла}")
|
||
|
||
# Запускаем и проверяем вывод
|
||
try:
|
||
результат = subprocess.run([выходной_файл], capture_output=True, text=True, timeout=5)
|
||
except subprocess.TimeoutExpired:
|
||
raise AssertionError(f"Таймаут при выполнении {имя_файла}")
|
||
|
||
# Проверяем, что программа завершилась успешно
|
||
if результат.returncode != 0:
|
||
raise AssertionError(f"{имя_файла} завершилась с кодом {результат.returncode}: {результат.stderr}")
|
||
|
||
# Проверяем, что вывод содержит OK
|
||
if "OK" not in результат.stdout:
|
||
raise AssertionError(f"{имя_файла} не вывела OK. Вывод: {результат.stdout}")
|
||
|
||
# Тест пройден!
|
||
пройдено_тестов += 1
|
||
print(f"{GREEN}✓{RESET} {имя_файла:<{макс_длина}} ... {GREEN}ПРОЙДЕНО{RESET}")
|
||
|
||
# Удаляем исполняемый файл
|
||
try:
|
||
os.unlink(выходной_файл)
|
||
except:
|
||
pass
|
||
|
||
# Выводим итоговый отчет по семантическим тестам
|
||
print()
|
||
print(f"{BOLD}=== ИТОГ СЕМАНТИЧЕСКИХ ТЕСТОВ ==={RESET}")
|
||
print(f" Всего тестов: {всего_тестов}")
|
||
print(f" {GREEN}Пройдено:{RESET} {пройдено_тестов}")
|
||
if пропущено_тестов > 0:
|
||
print(f" {YELLOW}Пропущено:{RESET} {пропущено_тестов}")
|
||
print()
|
||
|
||
# ============================================================================
|
||
# ОСТАЛЬНЫЕ ТЕСТЫ (без изменений)
|
||
# ============================================================================
|
||
|
||
def тест_o(rusi: str, tmp: str, tmp_c: str):
|
||
"""Тест опции -o"""
|
||
out_file = os.path.join(tmp, 'out')
|
||
if os.path.exists(out_file):
|
||
os.unlink(out_file)
|
||
subprocess.run([rusi, '-c', '-o', out_file, tmp_c], check=True)
|
||
проверка_существования_файла(out_file)
|
||
|
||
def тест_help(rusi: str):
|
||
"""Тест --help"""
|
||
result = subprocess.run([rusi, '--help'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
|
||
if not result.stdout.strip():
|
||
raise AssertionError("пустой вывод справки")
|
||
|
||
def тест_S(rusi: str):
|
||
"""Тест -S"""
|
||
result = subprocess.run([rusi, '-S', '-o-', '-xc', '-'],
|
||
input='int main() {}', capture_output=True, text=True)
|
||
проверка_содержимого(result.stdout, 'main:', "метка main не найдена в ассемблерном коде")
|
||
|
||
def тест_имя_выходного_файла(rusi: str, tmp: str):
|
||
"""Тест имени выходного файла по умолчанию"""
|
||
out_c = os.path.join(tmp, 'out.c')
|
||
with open(out_c, 'w') as f:
|
||
f.write('int main() {}')
|
||
|
||
out_o = os.path.join(tmp, 'out.o')
|
||
out_s = os.path.join(tmp, 'out.s')
|
||
for f in [out_o, out_s]:
|
||
if os.path.exists(f):
|
||
os.unlink(f)
|
||
|
||
old_pwd = os.getcwd()
|
||
os.chdir(tmp)
|
||
try:
|
||
subprocess.run([os.path.join(old_pwd, rusi), '-c', 'out.c'], check=True)
|
||
проверка_существования_файла(out_o)
|
||
finally:
|
||
os.chdir(old_pwd)
|
||
|
||
os.chdir(tmp)
|
||
try:
|
||
subprocess.run([os.path.join(old_pwd, rusi), '-c', '-S', 'out.c'], check=True)
|
||
проверка_существования_файла(out_s)
|
||
finally:
|
||
os.chdir(old_pwd)
|
||
|
||
def тест_несколько_входных(rusi: str, tmp: str):
|
||
"""Тест с несколькими входными файлами"""
|
||
foo_o = os.path.join(tmp, 'foo.o')
|
||
bar_o = os.path.join(tmp, 'bar.o')
|
||
for f in [foo_o, bar_o]:
|
||
if os.path.exists(f):
|
||
os.unlink(f)
|
||
|
||
foo_c = os.path.join(tmp, 'foo.c')
|
||
bar_c = os.path.join(tmp, 'bar.c')
|
||
with open(foo_c, 'w') as f:
|
||
f.write('int x;')
|
||
with open(bar_c, 'w') as f:
|
||
f.write('int y;')
|
||
|
||
old_pwd = os.getcwd()
|
||
os.chdir(tmp)
|
||
try:
|
||
subprocess.run([os.path.join(old_pwd, rusi), '-c', foo_c, bar_c], check=True)
|
||
проверка_существования_файла(foo_o)
|
||
проверка_существования_файла(bar_o)
|
||
finally:
|
||
os.chdir(old_pwd)
|
||
|
||
foo_s = os.path.join(tmp, 'foo.s')
|
||
bar_s = os.path.join(tmp, 'bar.s')
|
||
for f in [foo_s, bar_s]:
|
||
if os.path.exists(f):
|
||
os.unlink(f)
|
||
|
||
os.chdir(tmp)
|
||
try:
|
||
subprocess.run([os.path.join(old_pwd, rusi), '-c', '-S', foo_c, bar_c], check=True)
|
||
проверка_существования_файла(foo_s)
|
||
проверка_существования_файла(bar_s)
|
||
finally:
|
||
os.chdir(old_pwd)
|
||
|
||
def тест_линковщик(rusi: str, tmp: str):
|
||
"""Тест линковщика"""
|
||
foo_exe = os.path.join(tmp, 'foo')
|
||
if os.path.exists(foo_exe):
|
||
os.unlink(foo_exe)
|
||
|
||
subprocess.run([rusi, '-o', foo_exe, '-xc', '-xc', '-'],
|
||
input='int main() { return 0; }', text=True, check=True)
|
||
result = subprocess.run([foo_exe])
|
||
if result.returncode != 0:
|
||
raise AssertionError(f"программа вернула {result.returncode}, ожидалось 0")
|
||
|
||
if os.path.exists(foo_exe):
|
||
os.unlink(foo_exe)
|
||
|
||
foo_c = os.path.join(tmp, 'foo.c')
|
||
bar_c = os.path.join(tmp, 'bar.c')
|
||
with open(foo_c, 'w') as f:
|
||
f.write('int bar(); int main() { return bar(); }')
|
||
with open(bar_c, 'w') as f:
|
||
f.write('int bar() { return 42; }')
|
||
|
||
subprocess.run([rusi, '-o', foo_exe, foo_c, bar_c], check=True)
|
||
result = subprocess.run([foo_exe])
|
||
if result.returncode != 42:
|
||
raise AssertionError(f"программа вернула {result.returncode}, ожидалось 42")
|
||
|
||
def тест_a_out(rusi: str, tmp: str):
|
||
"""Тест a.out"""
|
||
a_out = os.path.join(tmp, 'a.out')
|
||
if os.path.exists(a_out):
|
||
os.unlink(a_out)
|
||
|
||
foo_c = os.path.join(tmp, 'foo.c')
|
||
with open(foo_c, 'w') as f:
|
||
f.write('int main() {}')
|
||
|
||
old_pwd = os.getcwd()
|
||
os.chdir(tmp)
|
||
try:
|
||
subprocess.run([os.path.join(old_pwd, rusi), 'foo.c'], check=True)
|
||
проверка_существования_файла(a_out)
|
||
finally:
|
||
os.chdir(old_pwd)
|
||
|
||
def тест_E(rusi: str, tmp: str):
|
||
"""Тест -E"""
|
||
out_file = os.path.join(tmp, 'out')
|
||
with open(out_file, 'w') as f:
|
||
f.write('foo')
|
||
|
||
result = subprocess.run([rusi, '-E', '-xc', '-'],
|
||
input=f'#include "{out_file}"\n', capture_output=True, text=True)
|
||
проверка_содержимого(result.stdout, 'foo', "препроцессор не вставил содержимое файла")
|
||
|
||
def тест_E_o(rusi: str, tmp: str):
|
||
"""Тест -E и -o"""
|
||
out1 = os.path.join(tmp, 'out1')
|
||
with open(out1, 'w') as f:
|
||
f.write('foo')
|
||
|
||
out2 = os.path.join(tmp, 'out2')
|
||
subprocess.run([rusi, '-E', '-o', out2, '-xc', '-'],
|
||
input=f'#include "{out1}"\n', text=True, check=True)
|
||
with open(out2) as f:
|
||
content = f.read()
|
||
проверка_содержимого(content, 'foo', "результат препроцессинга не записан в файл")
|
||
|
||
def тест_I(rusi: str, tmp: str):
|
||
"""Тест -I"""
|
||
dir_path = os.path.join(tmp, 'dir')
|
||
os.makedirs(dir_path, exist_ok=True)
|
||
i_test = os.path.join(dir_path, 'i-option-test')
|
||
with open(i_test, 'w') as f:
|
||
f.write('foo')
|
||
|
||
result = subprocess.run([rusi, f'-I{dir_path}', '-E', '-xc', '-'],
|
||
input='#include "i-option-test"\n', capture_output=True, text=True)
|
||
проверка_содержимого(result.stdout, 'foo', "файл не найден в указанной папке")
|
||
|
||
def тест_D(rusi: str):
|
||
"""Тест -D"""
|
||
result = subprocess.run([rusi, '-Dfoo', '-E', '-xc', '-'],
|
||
input='foo', capture_output=True, text=True)
|
||
проверка_содержимого(result.stdout, '1', "макрос без значения не подставлен как 1")
|
||
|
||
def тест_D_значение(rusi: str):
|
||
"""Тест -D со значением"""
|
||
result = subprocess.run([rusi, '-Dfoo=bar', '-E', '-xc', '-'],
|
||
input='foo', capture_output=True, text=True)
|
||
проверка_содержимого(result.stdout, 'bar', "макрос не подставлен с указанным значением")
|
||
|
||
def тест_U(rusi: str):
|
||
"""Тест -U"""
|
||
result = subprocess.run([rusi, '-Dfoo=bar', '-Ufoo', '-E', '-xc', '-'],
|
||
input='foo', capture_output=True, text=True)
|
||
проверка_содержимого(result.stdout, 'foo', "макрос не остался неопределенным")
|
||
|
||
def тест_игнорируемые(rusi: str, tmp_c: str):
|
||
"""Тест игнорируемых опций"""
|
||
subprocess.run([rusi, '-c', '-O', '-Wall', '-g', '-std=c11', '-ffreestanding',
|
||
'-fno-builtin', '-fno-omit-frame-pointer', '-fno-stack-protector',
|
||
'-fno-strict-aliasing', '-m64', '-mno-red-zone', '-w',
|
||
'-o', '/dev/null', tmp_c], check=True)
|
||
|
||
def тест_BOM(rusi: str):
|
||
"""Тест маркера BOM"""
|
||
result = subprocess.run([rusi, '-E', '-o-', '-xc', '-'],
|
||
input='\ufeffxyz\n', capture_output=True, text=True)
|
||
проверка_содержимого(result.stdout, re.compile(r'^xyz', re.MULTILINE), "BOM не удален")
|
||
|
||
def тест_inline(rusi: str, tmp: str):
|
||
"""Тесты inline-функций"""
|
||
inline1 = os.path.join(tmp, 'inline1.c')
|
||
inline2 = os.path.join(tmp, 'inline2.c')
|
||
inline3 = os.path.join(tmp, 'inline3.c')
|
||
|
||
# Две одинаковые inline-функции в разных файлах
|
||
with open(inline1, 'w') as f:
|
||
f.write('inline void foo() {}')
|
||
with open(inline2, 'w') as f:
|
||
f.write('inline void foo() {}')
|
||
with open(inline3, 'w') as f:
|
||
f.write('int main() { return 0; }')
|
||
|
||
subprocess.run([rusi, '-o', '/dev/null', inline1, inline2, inline3], check=True)
|
||
|
||
# extern inline
|
||
with open(inline1, 'w') as f:
|
||
f.write('extern inline void foo() {}')
|
||
with open(inline2, 'w') as f:
|
||
f.write('int foo(); int main() { foo(); }')
|
||
|
||
subprocess.run([rusi, '-o', '/dev/null', inline1, inline2], check=True)
|
||
|
||
# static inline не используется
|
||
result = subprocess.run([rusi, '-o-', '-S', '-xc', '-'],
|
||
input='static inline void f1() {}', capture_output=True, text=True)
|
||
if 'f1:' in result.stdout:
|
||
raise AssertionError("static inline функция сгенерировала код без использования")
|
||
|
||
# static inline используется
|
||
result = subprocess.run([rusi, '-o-', '-S', '-xc', '-'],
|
||
input='static inline void f1() {} void foo() { f1(); }',
|
||
capture_output=True, text=True)
|
||
проверка_содержимого(result.stdout, 'f1:', "static inline функция не сгенерировала код при использовании")
|
||
|
||
# Дополнительные проверки inline
|
||
test_input = 'static inline void f1() {} static inline void f2() { f1(); } void foo() { f1(); }'
|
||
result = subprocess.run([rusi, '-o-', '-S', '-xc', '-'],
|
||
input=test_input, capture_output=True, text=True)
|
||
проверка_содержимого(result.stdout, 'f1:', "f1 должна быть сгенерирована")
|
||
if 'f2:' in result.stdout:
|
||
raise AssertionError("f2 сгенерирована, хотя не используется")
|
||
|
||
def тест_idirafter(rusi: str, tmp: str):
|
||
"""Тест -idirafter"""
|
||
dir1 = os.path.join(tmp, 'dir1')
|
||
dir2 = os.path.join(tmp, 'dir2')
|
||
os.makedirs(dir1, exist_ok=True)
|
||
os.makedirs(dir2, exist_ok=True)
|
||
|
||
idirafter1 = os.path.join(dir1, 'idirafter')
|
||
idirafter2 = os.path.join(dir2, 'idirafter')
|
||
with open(idirafter1, 'w') as f:
|
||
f.write('foo')
|
||
with open(idirafter2, 'w') as f:
|
||
f.write('bar')
|
||
|
||
# Обычная -I ищет в первой папке
|
||
result = subprocess.run([rusi, f'-I{dir1}', f'-I{dir2}', '-E', '-xc', '-'],
|
||
input='#include "idirafter"\n', capture_output=True, text=True)
|
||
проверка_содержимого(result.stdout, 'foo', "-I не нашла файл в первой папке")
|
||
|
||
# -idirafter ищет после -I
|
||
result = subprocess.run([rusi, f'-idirafter', dir1, f'-I{dir2}', '-E', '-xc', '-'],
|
||
input='#include "idirafter"\n', capture_output=True, text=True)
|
||
проверка_содержимого(result.stdout, 'bar', "-idirafter не нашла файл после -I")
|
||
|
||
def тест_fcommon_по_умолчанию(rusi: str):
|
||
"""Тест -fcommon (по умолчанию)"""
|
||
result = subprocess.run([rusi, '-S', '-o-', '-xc', '-'],
|
||
input='int foo;', capture_output=True, text=True)
|
||
проверка_содержимого(result.stdout, '.comm foo', "директива .comm не сгенерирована")
|
||
|
||
def тест_fcommon(rusi: str):
|
||
"""Тест -fcommon"""
|
||
result = subprocess.run([rusi, '-fcommon', '-S', '-o-', '-xc', '-'],
|
||
input='int foo;', capture_output=True, text=True)
|
||
проверка_содержимого(result.stdout, '.comm foo', "директива .comm не сгенерирована с -fcommon")
|
||
|
||
def тест_fno_common(rusi: str):
|
||
"""Тест -fno-common"""
|
||
result = subprocess.run([rusi, '-fno-common', '-S', '-o-', '-xc', '-'],
|
||
input='int foo;', capture_output=True, text=True)
|
||
проверка_содержимого(result.stdout, re.compile(r'^foo:', re.MULTILINE), "foo не сгенерирована как обычная переменная")
|
||
|
||
def тест_include(rusi: str, tmp: str):
|
||
"""Тест -include"""
|
||
out_h = os.path.join(tmp, 'out.h')
|
||
with open(out_h, 'w') as f:
|
||
f.write('foo')
|
||
|
||
result = subprocess.run([rusi, '-include', out_h, '-E', '-o-', '-xc', '-'],
|
||
input='bar', capture_output=True, text=True)
|
||
проверка_содержимого(result.stdout, 'foo', "файл не включен через -include")
|
||
проверка_содержимого(result.stdout, 'bar', "входной текст отсутствует после -include")
|
||
|
||
def тест_include_stdio(rusi: str):
|
||
"""Тест -include stdio.h"""
|
||
result = subprocess.run([rusi, '-Iinclude', '-include', 'stdio.h', '-E', '-o-', '-xc', '-'],
|
||
input='NULL', capture_output=True, text=True)
|
||
проверка_содержимого(result.stdout, '0', "NULL не определен через -include stdio.h")
|
||
|
||
def тест_xc(rusi: str, tmp: str):
|
||
"""Тест -xc"""
|
||
foo_o = os.path.join(tmp, 'foo.o')
|
||
subprocess.run([rusi, '-c', '-xc', '-o', foo_o, '-'],
|
||
input='int x;', text=True, check=True)
|
||
|
||
def тест_x_assembler(rusi: str, tmp: str):
|
||
"""Тест -x assembler"""
|
||
foo_o = os.path.join(tmp, 'foo.o')
|
||
subprocess.run([rusi, '-c', '-x', 'assembler', '-o', foo_o, '-'],
|
||
input='x:', text=True, check=True)
|
||
|
||
def тест_x_none(rusi: str, tmp: str):
|
||
"""Тест -x none"""
|
||
foo_o = os.path.join(tmp, 'foo.o')
|
||
foo_c = os.path.join(tmp, 'foo.c')
|
||
with open(foo_c, 'w') as f:
|
||
f.write('int x;')
|
||
subprocess.run([rusi, '-c', '-x', 'assembler', '-x', 'none', '-o', foo_o, foo_c], check=True)
|
||
|
||
def тест_E_без_xc(rusi: str):
|
||
"""Тест -E без -xc"""
|
||
result = subprocess.run([rusi, '-E', '-'],
|
||
input='foo', capture_output=True, text=True)
|
||
проверка_содержимого(result.stdout, 'foo', "препроцессинг без -xc не прошел")
|
||
|
||
def тест_a_архив(rusi: str, tmp: str):
|
||
"""Тест работы с архивными файлами (.a)"""
|
||
foo_o = os.path.join(tmp, 'foo.o')
|
||
bar_o = os.path.join(tmp, 'bar.o')
|
||
|
||
subprocess.run([rusi, '-c', '-xc', '-o', foo_o, '-'],
|
||
input='void foo() {}', text=True, check=True)
|
||
subprocess.run([rusi, '-c', '-xc', '-o', bar_o, '-'],
|
||
input='void bar() {}', text=True, check=True)
|
||
|
||
foo_a = os.path.join(tmp, 'foo.a')
|
||
subprocess.run(['ar', 'rcs', foo_a, foo_o, bar_o], check=True)
|
||
|
||
main_c = os.path.join(tmp, 'main.c')
|
||
with open(main_c, 'w') as f:
|
||
f.write('void foo(); void bar(); int main() { foo(); bar(); }')
|
||
|
||
foo_exe = os.path.join(tmp, 'foo')
|
||
subprocess.run([rusi, '-o', foo_exe, main_c, foo_a], check=True)
|
||
|
||
def тест_so_библиотека(rusi: str, tmp: str):
|
||
"""Тест работы с динамическими библиотеками (.so)"""
|
||
foo_o = os.path.join(tmp, 'foo.o')
|
||
bar_o = os.path.join(tmp, 'bar.o')
|
||
|
||
subprocess.run(['cc', '-fPIC', '-c', '-xc', '-o', foo_o, '-'],
|
||
input='void foo() {}', text=True, check=True)
|
||
subprocess.run(['cc', '-fPIC', '-c', '-xc', '-o', bar_o, '-'],
|
||
input='void bar() {}', text=True, check=True)
|
||
|
||
foo_so = os.path.join(tmp, 'foo.so')
|
||
subprocess.run(['cc', '-shared', '-o', foo_so, foo_o, bar_o], check=True)
|
||
|
||
main_c = os.path.join(tmp, 'main.c')
|
||
with open(main_c, 'w') as f:
|
||
f.write('void foo(); void bar(); int main() { foo(); bar(); }')
|
||
|
||
foo_exe = os.path.join(tmp, 'foo')
|
||
subprocess.run([rusi, '-o', foo_exe, main_c, foo_so], check=True)
|
||
|
||
def тест_хеш_таблица(rusi: str):
|
||
"""Тест хеш-таблицы"""
|
||
subprocess.run([rusi, '-hashmap-test'], check=True)
|
||
|
||
def тест_M(rusi: str, tmp: str):
|
||
"""Тест -M"""
|
||
out_c = os.path.join(tmp, 'out.c')
|
||
with open(out_c, 'w') as f:
|
||
f.write('#include "out2.h"\n')
|
||
f.write('#include "out3.h"\n')
|
||
|
||
out2_h = os.path.join(tmp, 'out2.h')
|
||
out3_h = os.path.join(tmp, 'out3.h')
|
||
for f in [out2_h, out3_h]:
|
||
with open(f, 'w') as fh:
|
||
fh.write('')
|
||
|
||
result = subprocess.run([rusi, '-M', f'-I{tmp}', out_c],
|
||
capture_output=True, text=True)
|
||
проверка_содержимого(result.stdout, 'out.o:', "цель out.o не найдена")
|
||
проверка_содержимого(result.stdout, 'out.c', "зависимость out.c не найдена")
|
||
проверка_содержимого(result.stdout, 'out2.h', "зависимость out2.h не найдена")
|
||
проверка_содержимого(result.stdout, 'out3.h', "зависимость out3.h не найдена")
|
||
|
||
def тест_MF(rusi: str, tmp: str):
|
||
"""Тест -MF"""
|
||
out_c = os.path.join(tmp, 'out.c')
|
||
with open(out_c, 'w') as f:
|
||
f.write('#include "out2.h"\n')
|
||
f.write('#include "out3.h"\n')
|
||
|
||
out2_h = os.path.join(tmp, 'out2.h')
|
||
out3_h = os.path.join(tmp, 'out3.h')
|
||
for f in [out2_h, out3_h]:
|
||
with open(f, 'w') as fh:
|
||
fh.write('')
|
||
|
||
mf_file = os.path.join(tmp, 'mf')
|
||
subprocess.run([rusi, '-MF', mf_file, '-M', f'-I{tmp}', out_c], check=True)
|
||
with open(mf_file) as f:
|
||
content = f.read()
|
||
проверка_содержимого(content, 'out.o:', "цель out.o не найдена в MF")
|
||
проверка_содержимого(content, 'out.c', "зависимость out.c не найдена в MF")
|
||
проверка_содержимого(content, 'out2.h', "зависимость out2.h не найдена в MF")
|
||
проверка_содержимого(content, 'out3.h', "зависимость out3.h не найдена в MF")
|
||
|
||
def тест_MP(rusi: str, tmp: str):
|
||
"""Тест -MP"""
|
||
out_c = os.path.join(tmp, 'out.c')
|
||
with open(out_c, 'w') as f:
|
||
f.write('#include "out2.h"\n')
|
||
f.write('#include "out3.h"\n')
|
||
|
||
out2_h = os.path.join(tmp, 'out2.h')
|
||
out3_h = os.path.join(tmp, 'out3.h')
|
||
for f in [out2_h, out3_h]:
|
||
with open(f, 'w') as fh:
|
||
fh.write('')
|
||
|
||
mp_file = os.path.join(tmp, 'mp')
|
||
subprocess.run([rusi, '-MF', mp_file, '-MP', '-M', f'-I{tmp}', out_c], check=True)
|
||
with open(mp_file) as f:
|
||
content = f.read()
|
||
if not re.search(r'out2\.h:', content):
|
||
raise AssertionError("цель out2.h не найдена в MP")
|
||
if not re.search(r'out3\.h:', content):
|
||
raise AssertionError("цель out3.h не найдена в MP")
|
||
|
||
def тест_MT(rusi: str, tmp: str):
|
||
"""Тест -MT"""
|
||
out_c = os.path.join(tmp, 'out.c')
|
||
with open(out_c, 'w') as f:
|
||
f.write('#include "out2.h"\n')
|
||
|
||
out2_h = os.path.join(tmp, 'out2.h')
|
||
with open(out2_h, 'w') as f:
|
||
f.write('')
|
||
|
||
result = subprocess.run([rusi, '-MT', 'foo', '-M', f'-I{tmp}', out_c],
|
||
capture_output=True, text=True)
|
||
if not result.stdout.startswith('foo:'):
|
||
raise AssertionError("цель не изменена на foo")
|
||
|
||
def тест_MT_несколько(rusi: str, tmp: str):
|
||
"""Тест -MT с несколькими целями"""
|
||
out_c = os.path.join(tmp, 'out.c')
|
||
with open(out_c, 'w') as f:
|
||
f.write('#include "out2.h"\n')
|
||
|
||
out2_h = os.path.join(tmp, 'out2.h')
|
||
with open(out2_h, 'w') as f:
|
||
f.write('')
|
||
|
||
result = subprocess.run([rusi, '-MT', 'foo', '-MT', 'bar', '-M', f'-I{tmp}', out_c],
|
||
capture_output=True, text=True)
|
||
if not result.stdout.startswith('foo bar:'):
|
||
raise AssertionError("несколько целей не установлены")
|
||
|
||
def тест_MD(rusi: str, tmp: str):
|
||
"""Тест -MD"""
|
||
md2_c = os.path.join(tmp, 'md2.c')
|
||
md3_c = os.path.join(tmp, 'md3.c')
|
||
with open(md2_c, 'w') as f:
|
||
f.write('#include "out2.h"\n')
|
||
with open(md3_c, 'w') as f:
|
||
f.write('#include "out3.h"\n')
|
||
|
||
out2_h = os.path.join(tmp, 'out2.h')
|
||
out3_h = os.path.join(tmp, 'out3.h')
|
||
for f in [out2_h, out3_h]:
|
||
with open(f, 'w') as fh:
|
||
fh.write('')
|
||
|
||
old_pwd = os.getcwd()
|
||
os.chdir(tmp)
|
||
try:
|
||
subprocess.run([os.path.join(old_pwd, rusi), '-c', '-MD', '-I.', 'md2.c', 'md3.c'], check=True)
|
||
finally:
|
||
os.chdir(old_pwd)
|
||
|
||
md2_d = os.path.join(tmp, 'md2.d')
|
||
md3_d = os.path.join(tmp, 'md3.d')
|
||
with open(md2_d) as f:
|
||
content = f.read()
|
||
проверка_содержимого(content, 'md2.o:', "цель md2.o не найдена в MD")
|
||
проверка_содержимого(content, 'md2.c', "зависимость md2.c не найдена в MD")
|
||
проверка_содержимого(content, 'out2.h', "зависимость out2.h не найдена в MD")
|
||
|
||
with open(md3_d) as f:
|
||
content = f.read()
|
||
проверка_содержимого(content, 'md3.o:', "цель md3.o не найдена в MD")
|
||
проверка_содержимого(content, 'md3.c', "зависимость md3.c не найдена в MD")
|
||
проверка_содержимого(content, 'out3.h', "зависимость out3.h не найдена в MD")
|
||
|
||
def тест_MD_MF(rusi: str, tmp: str):
|
||
"""Тест -MD с -MF"""
|
||
md2_c = os.path.join(tmp, 'md2.c')
|
||
with open(md2_c, 'w') as f:
|
||
f.write('#include "out2.h"\n')
|
||
|
||
out2_h = os.path.join(tmp, 'out2.h')
|
||
with open(out2_h, 'w') as f:
|
||
f.write('')
|
||
|
||
md_mf_d = os.path.join(tmp, 'md-mf.d')
|
||
subprocess.run([rusi, '-c', '-MD', '-MF', md_mf_d, '-I.', md2_c], check=True)
|
||
with open(md_mf_d) as f:
|
||
content = f.read()
|
||
проверка_содержимого(content, 'md2.o:', "цель md2.o не найдена в MD+MF")
|
||
проверка_содержимого(content, 'md2.c', "зависимость md2.c не найдена в MD+MF")
|
||
проверка_содержимого(content, 'out2.h', "зависимость out2.h не найдена в MD+MF")
|
||
|
||
def тест_fPIC(rusi: str, tmp: str):
|
||
"""Тест -fPIC"""
|
||
foo_o = os.path.join(tmp, 'foo.o')
|
||
subprocess.run([rusi, '-fPIC', '-xc', '-c', '-o', foo_o, '-'],
|
||
input='extern int bar; int foo() { return bar; }', text=True, check=True)
|
||
|
||
foo_so = os.path.join(tmp, 'foo.so')
|
||
subprocess.run(['cc', '-shared', '-o', foo_so, foo_o], check=True)
|
||
|
||
main_c = os.path.join(tmp, 'main.c')
|
||
with open(main_c, 'w') as f:
|
||
f.write('int foo(); int bar=3; int main() { foo(); }')
|
||
|
||
foo_exe = os.path.join(tmp, 'foo')
|
||
subprocess.run([rusi, '-o', foo_exe, main_c, foo_so], check=True)
|
||
|
||
def тест_include_next(rusi: str, tmp: str):
|
||
"""Тест #include_next"""
|
||
next1 = os.path.join(tmp, 'next1')
|
||
next2 = os.path.join(tmp, 'next2')
|
||
next3 = os.path.join(tmp, 'next3')
|
||
os.makedirs(next1, exist_ok=True)
|
||
os.makedirs(next2, exist_ok=True)
|
||
os.makedirs(next3, exist_ok=True)
|
||
|
||
file_c = os.path.join(tmp, 'file.c')
|
||
with open(file_c, 'w') as f:
|
||
f.write('#include "file1.h"\n')
|
||
|
||
with open(os.path.join(next1, 'file1.h'), 'w') as f:
|
||
f.write('#include_next "file1.h"\n')
|
||
|
||
with open(os.path.join(next2, 'file1.h'), 'w') as f:
|
||
f.write('#include_next "file2.h"\n')
|
||
|
||
with open(os.path.join(next3, 'file2.h'), 'w') as f:
|
||
f.write('foo')
|
||
|
||
result = subprocess.run([rusi, f'-I{next1}', f'-I{next2}', f'-I{next3}', '-E', file_c],
|
||
capture_output=True, text=True)
|
||
проверка_содержимого(result.stdout, 'foo', "цепочка include_next не привела к foo")
|
||
|
||
def тест_static(rusi: str, tmp: str):
|
||
"""Тест -static"""
|
||
foo_c = os.path.join(tmp, 'foo.c')
|
||
bar_c = os.path.join(tmp, 'bar.c')
|
||
with open(foo_c, 'w') as f:
|
||
f.write('extern int bar; int foo() { return bar; }')
|
||
with open(bar_c, 'w') as f:
|
||
f.write('int foo(); int bar=3; int main() { foo(); }')
|
||
|
||
foo_exe = os.path.join(tmp, 'foo')
|
||
subprocess.run([rusi, '-static', '-o', foo_exe, foo_c, bar_c], check=True)
|
||
|
||
result = subprocess.run(['file', foo_exe], capture_output=True, text=True)
|
||
if 'statically linked' not in result.stdout:
|
||
raise AssertionError("файл не является статически слинкованным")
|
||
|
||
def тест_shared(rusi: str, tmp: str):
|
||
"""Тест -shared"""
|
||
foo_so = os.path.join(tmp, 'foo.so')
|
||
foo_c = os.path.join(tmp, 'foo.c')
|
||
bar_c = os.path.join(tmp, 'bar.c')
|
||
|
||
with open(foo_c, 'w') as f:
|
||
f.write('extern int bar; int foo() { return bar; }')
|
||
with open(bar_c, 'w') as f:
|
||
f.write('int foo(); int bar=3; int main() { foo(); }')
|
||
|
||
subprocess.run([rusi, '-fPIC', '-shared', '-o', foo_so, foo_c, bar_c], check=True)
|
||
|
||
def тест_L(rusi: str, tmp: str):
|
||
"""Тест -L"""
|
||
foo_c = os.path.join(tmp, 'foo.c')
|
||
with open(foo_c, 'w') as f:
|
||
f.write('extern int bar; int foo() { return bar; }')
|
||
|
||
libfoobar_so = os.path.join(tmp, 'libfoobar.so')
|
||
subprocess.run([rusi, '-fPIC', '-shared', '-o', libfoobar_so, foo_c], check=True)
|
||
|
||
bar_c = os.path.join(tmp, 'bar.c')
|
||
with open(bar_c, 'w') as f:
|
||
f.write('int foo(); int bar=3; int main() { foo(); }')
|
||
|
||
foo_exe = os.path.join(tmp, 'foo')
|
||
subprocess.run([rusi, '-o', foo_exe, bar_c, f'-L{tmp}', '-lfoobar'], check=True)
|
||
|
||
def тест_Wl(rusi: str, tmp: str):
|
||
"""Тест -Wl,"""
|
||
foo_o = os.path.join(tmp, 'foo.o')
|
||
bar_o = os.path.join(tmp, 'bar.o')
|
||
baz_o = os.path.join(tmp, 'baz.o')
|
||
|
||
subprocess.run([rusi, '-c', '-o', foo_o, '-xc', '-'],
|
||
input='int foo() {}', text=True, check=True)
|
||
subprocess.run([rusi, '-c', '-o', bar_o, '-xc', '-'],
|
||
input='int foo() {}', text=True, check=True)
|
||
subprocess.run([rusi, '-c', '-o', baz_o, '-xc', '-'],
|
||
input='int main() {}', text=True, check=True)
|
||
|
||
foo_exe = os.path.join(tmp, 'foo')
|
||
subprocess.run(['cc', '-Wl,-z,muldefs,--gc-sections', '-o', foo_exe, foo_o, bar_o, baz_o], check=True)
|
||
|
||
def тест_Xlinker(rusi: str, tmp: str):
|
||
"""Тест -Xlinker"""
|
||
foo_o = os.path.join(tmp, 'foo.o')
|
||
bar_o = os.path.join(tmp, 'bar.o')
|
||
baz_o = os.path.join(tmp, 'baz.o')
|
||
|
||
subprocess.run([rusi, '-c', '-o', foo_o, '-xc', '-'],
|
||
input='int foo() {}', text=True, check=True)
|
||
subprocess.run([rusi, '-c', '-o', bar_o, '-xc', '-'],
|
||
input='int foo() {}', text=True, check=True)
|
||
subprocess.run([rusi, '-c', '-o', baz_o, '-xc', '-'],
|
||
input='int main() {}', text=True, check=True)
|
||
|
||
foo_exe = os.path.join(tmp, 'foo')
|
||
subprocess.run(['cc', '-Xlinker', '-z', '-Xlinker', 'muldefs', '-Xlinker', '--gc-sections',
|
||
'-o', foo_exe, foo_o, bar_o, baz_o], check=True)
|
||
|
||
if __name__ == '__main__':
|
||
main() |