The Test Ladder
Every compatibility fix should climb from a small DOS repro to the broader runs it can affect. The ladder keeps LainDOS caller-driven instead of collecting untested DOS stubs.
How to choose the next test
Begin with the narrowest proof that would have failed before the change. If the fix touches a DOS APIDOS APIThe program-facing DOS service contract, mostly reached through INT 21h in LainDOS., write a tiny program. If it touches shell, loader, or FAT state, add a scenario runner. If the bug only appears in a game, keep the media local and add a smoke that proves the visible path.
Layers
These live under tests/programs/. They set up segment registers, call INT 21hINT 21hThe main DOS API interrupt. Programs select services such as open, read, EXEC, and exit with AH. or a narrow hardware path, print PASS:/FAIL: markers, and exit with AH=4Ch so QEMUQEMUThe default fast emulator for automated LainDOS builds, tests, monitor probes, and game smoke runs. serial output can be checked automatically.
tests/programs/irqmask.asmtests/programs/execparam.asmtests/programs/findnext.asmMost scripts use build_nasmNASMNetwide Assembler, the assembler used for LainDOS boot, kernel, shell, and focused test programs._test_image, run_serial_image, and check_markers from scripts/testlib.py. The image is disposable and always contains the current boot sector and kernel.
scripts/test_irqmask.pyscripts/test_execparam.pyscripts/run_tests.pyThese cover command dispatch, EXEC parent/child restoration, writable FAT behavior, directory mutation, rollback, and persistent image contents after QEMUQEMUThe default fast emulator for automated LainDOS builds, tests, monitor probes, and game smoke runs. exits.
scripts/test_shell.pyscripts/test_savewrite.pyscripts/test_dirmut.pyGame smokessmoke testA coarse end-to-end run that proves a game or workflow reaches a visible expected state without fatal markers. build generated images from local media, drive QEMUQEMUThe default fast emulator for automated LainDOS builds, tests, monitor probes, and game smoke runs. through monitor socketsmonitor socketA QEMU control channel used to send keys, capture screenshots, inspect registers, or quit scripted runs., keep host audio silent, and use serial plus framebufferframebufferThe raw pixels currently shown by VGA; smoke tests hash or inspect it when serial output cannot prove gameplay. checks to catch crashes and blank screens.
scripts/test_shell_monkey.pyscripts/test_wolf3d_smoke.pyscripts/test_shortline_smoke.pyFocused test template
The important convention is not the exact code shape; it is the serial-visible contract: one unique PASS: marker, useful FAIL: markers, and a DOS exit code.
Game smoke rules
Game smokes are integration tests, not media archival. Keep proprietary input ignored, build disposable images under build/, use QEMUQEMUThe default fast emulator for automated LainDOS builds, tests, monitor probes, and game smoke runs. monitor input for deterministic startup, and prefer framebufferframebufferThe raw pixels currently shown by VGA; smoke tests hash or inspect it when serial output cannot prove gameplay. checks when the serial log cannot prove that graphics reached gameplay.