There is an Open Watcom install on this host (C:\WATCOM19), and its Windows build compiles the compiler's own sources in about a second. Every declaration mismatch in the unification commits was found that way; each one would otherwise have cost a DOSBox-X boot and a full compiler build to surface, with a DOS-side message that names the wrong thing. Add tools/tests/test_host_syntax.py: compile all twelve sources with the flags build-dos.bat uses (-za -wx -wcd=202) and fail on any diagnostic. It skips when Watcom is absent, so the suite still runs elsewhere. Two structural checks come with it -- that build-dos.bat, the Makefile and the test agree on the source list, and that no .c under fec/src is compiled by nothing. Both would have caught check.c and emit_c.c quietly leaving the build when the M7 wrappers included them textually. ferro-test now runs these and the 8.3 name check before starting the VM, and stops if they fail. This is not verification and does not claim to be: wcc386 targets 32-bit where the real build is 16-bit large model, so it sees syntax, types and declarations and nothing about code generation. The DOS build and the milestone suite remain the gate. It only moves the cheap failures earlier.
91 lines
4.2 KiB
Python
91 lines
4.2 KiB
Python
"""Developer test entry point backed by a disposable DOSBox-X run."""
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import os
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
from .dosboxx import DosboxError, setup
|
|
from .registry import MAX_MILESTONE, MILESTONES
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser(
|
|
prog="ferro-test",
|
|
description="Fast Ferro development tests in DOSBox-X/Open Watcom.",
|
|
)
|
|
commands = parser.add_subparsers(dest="command", required=True)
|
|
prepare = commands.add_parser("setup", help="download and verify pinned development tools")
|
|
prepare.add_argument("--accept-watcom-license", action="store_true",
|
|
help="confirm acceptance of the Sybase Open Watcom Public License")
|
|
run = commands.add_parser("run", help="build once and run milestone pytest cases")
|
|
selection = run.add_mutually_exclusive_group()
|
|
selection.add_argument("--through", choices=MILESTONES, default=f"m{MAX_MILESTONE}",
|
|
help="run cumulatively through this milestone "
|
|
f"(default: m{MAX_MILESTONE})")
|
|
selection.add_argument("--only", choices=MILESTONES,
|
|
help="run only this milestone's cases")
|
|
run.add_argument("-v", "--verbose", action="store_true", help="show every pytest case")
|
|
run.add_argument("--keep-failed", action="store_true",
|
|
help="keep the disposable DOS filesystem after failures")
|
|
run.add_argument("--show-dos", action="store_true",
|
|
help="show DOSBox-X and wait for a key before closing")
|
|
run.add_argument("--dos-log", action="store_true",
|
|
help="print the captured DOS console after the run")
|
|
run.add_argument("--trace-dos", action="store_true",
|
|
help="do not redirect case command output")
|
|
run.add_argument("-k", dest="select", metavar="EXPR",
|
|
help="run only cases whose id matches this pytest -k expression")
|
|
args, extra = parser.parse_known_args()
|
|
try:
|
|
if args.command == "setup":
|
|
dosbox, watcom = setup(accept_watcom_license=args.accept_watcom_license)
|
|
print(f"DOSBox-X: {dosbox}")
|
|
print(f"Open Watcom: {watcom}")
|
|
return 0
|
|
if args.only:
|
|
os.environ["FERRO_TEST_ONLY"] = args.only
|
|
else:
|
|
os.environ["FERRO_TEST_THROUGH"] = args.through
|
|
for enabled, name in (
|
|
(args.keep_failed, "FERRO_TEST_KEEP_FAILED"),
|
|
(args.show_dos, "FERRO_TEST_SHOW_DOS"),
|
|
(args.trace_dos, "FERRO_TEST_TRACE_DOS"),
|
|
(args.dos_log, "FERRO_TEST_DOS_LOG"),
|
|
):
|
|
if enabled:
|
|
os.environ[name] = "1"
|
|
import pytest
|
|
from .paths import ROOT
|
|
# The package can be imported from a different checkout than the one the
|
|
# shell is sitting in -- an editable install plus a git worktree is enough
|
|
# to silently build and test the wrong tree. Say which tree this is.
|
|
print(f"ferro-test: building {ROOT}", file=sys.stderr)
|
|
tests = ROOT / "tools" / "tests"
|
|
# The host gates run first and take under a second. A missing declaration
|
|
# or an 8.3-illegal name would otherwise be found only after a DOSBox-X
|
|
# boot and a full compiler build, and the DOS-side message for either is
|
|
# unhelpful. They do not replace the DOS run; they precede it.
|
|
gates = [os.fspath(tests / name) for name in
|
|
("test_host_syntax.py", "test_dos_names.py")]
|
|
if pytest.main([*gates, "-q", "--no-header"]) != 0:
|
|
print("ferro-test: host gates failed; not starting DOSBox-X",
|
|
file=sys.stderr)
|
|
return 1
|
|
test_file = os.fspath(tests / "test_milestones_dosboxx.py")
|
|
pytest_args = [test_file, "--tb=short", "-v" if args.verbose else "-q"]
|
|
if args.select:
|
|
pytest_args.extend(["-k", args.select])
|
|
if args.dos_log:
|
|
pytest_args.append("-s")
|
|
pytest_args.extend(extra)
|
|
return int(pytest.main(pytest_args))
|
|
except (DosboxError, ValueError) as exc:
|
|
print(f"ferro-test: {exc}", file=sys.stderr)
|
|
return 2
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|