Files
doslang-mirror/tools/tests/test_milestones_dosboxx.py
T
coolguyandClaude Opus 5 c25312135d refactor: rebuild the milestone registry as a table
registry.py was literally `cat registry_m1_m3.py registry_m4_m6.py`, which
left a duplicate `_c` definition and a stray module-level docstring at the
seam. Replace the hand-rolled append loops with five builders -- _emit, _wcl,
_triple, _rejects, _dump_ast -- and express the cases as one ordered list.

The irregularities are now parameters instead of one-off code, each with the
reason recorded:

- _triple(stem=) for M2 castwhil emitting CAST16
- _triple(build_source=) for M4 prop, which emits PROP.C but compiles
  PROPTEST.C because that file #includes it
- _triple(run_suffix="trap", run_ok=False) for the M3 bounds cases
- _triple(emit_suffix=None) for M4, whose ids lack the -emit suffix
- _emit(output_first=True) for M6, which passes -o before the input

The three scattered 8.3 output-name mappings collapse into one _OUT83 table
keyed by (milestone, name). The key needs both: bad-type is BAD-TY in M2 but
BAD-TYP in M4, and bad-cond is BAD-CO in M2 but unshortened in M5. Values are
carried over verbatim -- the shortenings are inconsistent and several were
never required, but that is a separate decision.

suite.py keeps only Case and drops the all_cases forwarder, so the
registry -> suite -> registry cycle is gone along with the function-scoped
import that worked around it. dosboxx.py still imports Case from suite and is
untouched.

Verified behaviour-preserving by snapshotting (id, milestone, command,
expect_success) for all 150 cases in order before and after: diff is empty.
pytest collects the same 151 items.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BScg8CF1sAAM2zVHAu5zvW
2026-08-16 22:11:13 +09:00

63 lines
1.9 KiB
Python

from __future__ import annotations
import os
import warnings
import pytest
from ferrolang_vm.dosboxx import SuiteRun, run_suite
from ferrolang_vm.registry import all_cases
from ferrolang_vm.suite import Case
def _number(name: str) -> int:
if not name.startswith("m") or not name[1:].isdigit():
raise ValueError(f"invalid milestone: {name}")
value = int(name[1:])
if value not in range(1, 7):
raise ValueError(f"unsupported milestone: {name}")
return value
ONLY = os.environ.get("FERRO_TEST_ONLY")
CASES = all_cases(
through=_number(os.environ.get("FERRO_TEST_THROUGH", "m6")),
only=_number(ONLY) if ONLY else None,
)
@pytest.fixture(scope="session")
def suite_run() -> SuiteRun:
run = run_suite(
CASES,
keep=os.environ.get("FERRO_TEST_KEEP_FAILED") == "1",
show_dos=os.environ.get("FERRO_TEST_SHOW_DOS") == "1",
trace_dos=os.environ.get("FERRO_TEST_TRACE_DOS") == "1",
)
yield run
if os.environ.get("FERRO_TEST_DOS_LOG") == "1":
console = run.root / "CONSOLE.LOG"
if console.is_file():
print(console.read_text(encoding="utf-8", errors="replace"))
run.cleanup()
def test_compiler_build(suite_run: SuiteRun) -> None:
assert suite_run.result() == "PASS", suite_run.log()
@pytest.mark.parametrize("case", CASES, ids=lambda case: case.id)
def test_milestone_case(case: Case, suite_run: SuiteRun) -> None:
if suite_run.result() != "PASS":
pytest.skip("compiler build failed")
result = suite_run.result(case)
err = suite_run.err(case)
if result == "PASS" and err:
warning_lines = [line for line in err.splitlines() if "warning" in line.lower()]
if warning_lines:
warnings.warn("\n".join(warning_lines), stacklevel=1)
assert result == "PASS", (
f"DOS command: {case.command}\nExpected success: {case.expect_success}\n"
f"{suite_run.log(case)}\n{err}"
)