Обвязка для быстрых тестов plain-C логики: секунды вместо прогона в MAME, без образа диска. ucsim_z80 идёт в комплекте нашего SDCC — новых зависимостей нет. ПОЧЕМУ ПОД Z80, А НЕ ХОСТОВЫМ GCC. У SDCC z80 int 16 бит, у хоста 32, и расходится это НЕ в объявлениях, а в выражениях: integer promotion повышает операнды до int независимо от того, объявлены они как uint8_t или uint16_t. Перевод кода на фиксированные типы разницу не убирает — убирает только исполнение с z80-семантикой. Побочно проверяется кодогенерация SDCC и модули с inline-asm, которых хостовая сборка не видит в принципе. Устройство: crt0_ucsim.s (SP, зануление, main, halt), tcheck.* (итог в структуру в ОЗУ), run_ucsim.py (гоняет ucsim, дампит tc_result, печатает отчёт), host-tests.mk (общие правила). Вывода через printf нет: тестовый бинарь линкуется без Sprinter-libc. Через ucsim-simif не идём — номера его команд плавают между версиями, halt + dump работают везде. Наборы лежат РЯДОМ с проверяемым кодом, обвязка общая: testkit/t_selftest.c — самопроверка (sizeof(int)==2) applications/PoP/roomtest/tests-host/ — движок PoP Первый содержательный набор — t_geom: сверяет рукописный asm-LCG из pop_geom.c с наивной 32-битной формулой на 128 шагах. Заявка «бит-в-бит как в SDLPoP» до сих пор держалась на комментарии. Тест проверен мутацией: порча эталонной константы даёт красный. Планы дальнейшего покрытия: docs/host-tests-plan.md — libc и libbgi (не начато) applications/PoP/docs/host_tests_plan.md — движок PoP Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
8.2 KiB
План: модульные тесты libc и libbgi под ucsim_z80
Статус: не начато, задача на будущее. Обвязка уже готова и обкатана —
testkit/ (см. testkit/README.md); первый потребитель —
applications/PoP/roomtest/tests-host/. Этот документ — про то, как накрыть
тем же способом основной продукт репозитория.
Что это НЕ заменяет
В tests/ уже лежат 62 каталога — это интеграционные тесты: одна фича =
одна программа, которая пакуется на дискету и гоняется в MAME
(docs/mame-autotest.md). Они проверяют, что API работает на живой машине:
ESTEX, BIOS, диск, экран, тайминги.
Модульные тесты их не отменяют, а дополняют с другой стороны:
tests/ (MAME) |
tests-host (ucsim) |
|
|---|---|---|
| что проверяет | работает ли на машине | верна ли логика |
| граничные случаи | 1–2 на фичу | десятки, дёшево |
| время прогона | десятки секунд | миллисекунды |
| ловит | железо, тайминги, банки | арифметику, краевые условия, регрессии |
Правило разделения то же, что уже записано для PoP: что можно проверить без железа — проверять в ucsim, MAME оставить железу.
Три группы модулей
1. Чистая логика — тестируется как есть, швов не нужно
Здесь можно начинать в тот же день, когда задачу возьмут в работу.
libc:
time/—_tm_is_leap,_tm_mdays,_tm_month_days,_tm_year_days,mktime,gmtime,localtime,asctime,ctime. Классическая календарная арифметика: високосные годы, границы месяцев, переходы через год, круговой прогонmktime(gmtime(t)) == t. Идеальный первый набор — много краевых случаев и ноль зависимостей.stdio/—dec_print,hex8/16/32,_scanf_core,sscanf. Формат и разбор: ширина, знак, переполнение, мусор на входе.string/,stdlib/—strlwr,strupr,max,min.
libbgi/common (115 модулей, почти всё mode-agnostic):
_bgi_isqrt,_bgi_trig— сверить с эталонной формулой на всём диапазоне, ровно как сделано для LCG вt_geomу PoP;_bgi_lineseg,_bgi_styled_line,_bgi_poly_edge,_bgi_arc_draw— геометрия и отсечение: линия целиком вне окна, по диагонали через угол, вырожденная в точку;_spr_ysort— порядок сортировки спрайтов;_bgi_hspan,_bgi_fill_span— заливка: краевые span'ы, нулевая ширина.
2. Нужны швы — но швы дешёвые
Фейковый ESTEX и BIOS прямо в тестовом crt0. Оба вызываются через
rst #0x10 и rst #0x08, то есть через фиксированные векторы в первых
байтах памяти. В тестовом бинаре эти адреса наши: можно положить туда
обработчик, который эмулирует крошечную файловую систему в ОЗУ и текстовый
экран в буфере. Это открывает:
file/(32 модуля) иio/(21) —fopen/fread/fwrite/fseek, буферизация (docs/file-buffering-design.md), поведение на EOF и ошибках,errno;conio/(38) — вывод в буфер вместо экрана, проверка атрибутов, скроллинга, границ окна.
Отдельно ценно: гарды, которые обязаны быть в обеих сборках. _fd_guard
(девятый OPEN вешает DSS) — это ровно тот случай, где нужен тест, а не
вера в комментарий: открыть восемь, убедиться, что девятый вернул ошибку и
не дошёл до ESTEX.
Кадровый буфер в ОЗУ для libbgi. Если рисующие ядра умеют писать в обычный буфер, а не только в видеопамять, растеризацию можно проверять снимком: нарисовать фигуру, сравнить с эталонным массивом. Начинать с маленьких (8×8, 16×16) — эталон читаемый прямо в исходнике.
3. Только MAME
Банки и W-окна, EMM, реальный ESTEX/DSS, клавиатурный трамплин и IM2,
CBL-звук (cbl/), мышь (mouse/), mem/ (это банки и страницы, а не
куча), тайминги и бюджет кадра, ускоритель.
Обе сборки: fast и safe
Библиотеки собираются в двух вариантах (-D*_NOCHECK вырезает
валидацию параметров). Наборы стоит гонять против обоих:
- в safe — что валидация ловит мусорные аргументы и ставит
errno; - в fast — что вырезание валидации не поменяло поведение на корректных входах.
Это дешёвая параметризация Makefile (тот же набор, два OBJS_*), и она
пресекает целый класс расхождений между вариантами.
Фазы
- Календарь и формат.
time/,stdio/. Нулевые швы, максимальная плотность краевых случаев. Цель — обкатать поток работы на libc. - Геометрия libbgi.
common/: isqrt, тригонометрия, отсечение линий, рёбра полигонов. Тоже без швов. - Фейковые ESTEX/BIOS в crt0. Открывает
file/,io/,conio/и гарды. Самый крупный кусок работы и самая большая отдача. - Растр libbgi по снимкам — если окажется, что ядра можно нацелить на буфер в ОЗУ без правок продукта; иначе отложить.
- Параметризация fast/safe — после того, как наборов станет заметно.
Критерии
- Тест не считается написанным, пока не проверен мутацией: сломать проверяемое место, убедиться, что набор краснеет. Пустые тесты хуже отсутствующих.
- Каждый закрытый баг libc/libbgi получает регрессионный кейс, если он ловится без железа.
make host-testsостаётся быстрым: если суммарно перевалит за несколько секунд, делить на быстрый и полный прогон.
Организация
Наборы кладутся рядом с кодом, обвязка общая:
libc/tests-host/ наборы по областям: t_time.c, t_stdio.c, …
libbgi/tests-host/ t_geom.c, t_raster.c, …
Каждому — Makefile на пять строк (TESTKIT, ENGINE_DIR, OBJS_*,
include), и добавить каталог в HOST_TEST_DIRS корневого Makefile.
Подробности — testkit/README.md.