# План: модульные тесты 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_*`), и она пресекает целый класс расхождений между вариантами. ## Фазы 1. **Календарь и формат.** `time/`, `stdio/`. Нулевые швы, максимальная плотность краевых случаев. Цель — обкатать поток работы на libc. 2. **Геометрия libbgi.** `common/`: isqrt, тригонометрия, отсечение линий, рёбра полигонов. Тоже без швов. 3. **Фейковые ESTEX/BIOS в crt0.** Открывает `file/`, `io/`, `conio/` и гарды. Самый крупный кусок работы и самая большая отдача. 4. **Растр libbgi по снимкам** — если окажется, что ядра можно нацелить на буфер в ОЗУ без правок продукта; иначе отложить. 5. **Параметризация 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`.