From 0dada80e65cd08a95a718d926c31569803f1bedf Mon Sep 17 00:00:00 2001 From: Sebastian Jeong Date: Sun, 16 Aug 2026 21:54:22 +0900 Subject: [PATCH] test: unify registry and capture Watcom diagnostics --- src/ferrolang_vm/dosboxx.py | 22 ++++- src/ferrolang_vm/registry.py | 120 +++++++++++++++++++++++++ src/ferrolang_vm/registry_m1_m3.py | 69 -------------- src/ferrolang_vm/registry_m4_m6.py | 49 ---------- src/ferrolang_vm/suite.py | 9 +- tools/tests/test_milestones_dosboxx.py | 11 ++- 6 files changed, 149 insertions(+), 131 deletions(-) create mode 100644 src/ferrolang_vm/registry.py delete mode 100644 src/ferrolang_vm/registry_m1_m3.py delete mode 100644 src/ferrolang_vm/registry_m4_m6.py diff --git a/src/ferrolang_vm/dosboxx.py b/src/ferrolang_vm/dosboxx.py index 1deb9c6..581f14c 100644 --- a/src/ferrolang_vm/dosboxx.py +++ b/src/ferrolang_vm/dosboxx.py @@ -140,19 +140,29 @@ def _batch(cases: list[Case], *, show_dos: bool, trace_dos: bool) -> str: for index, case in enumerate(cases): key = f"C{index:03d}" command = case.command + # Watcom writes diagnostics into the current directory. Isolate each + # case so a later pytest item never sees stale diagnostics. + lines.extend([ + "if exist *.ERR del *.ERR > NUL", + f"if exist RESULTS\\{key}.ERR del RESULTS\\{key}.ERR > NUL", + ]) if not trace_dos: command += f" > RESULTS\\{key}.LOG" lines.append(command) if case.expect_success: lines.extend([ - f"if errorlevel 1 goto {key}F", f"echo PASS>RESULTS\\{key}.RES", - f"goto {key}D", f":{key}F", f"echo FAIL>RESULTS\\{key}.RES", f":{key}D", + f"if errorlevel 1 goto {key}E", f"echo PASS>RESULTS\\{key}.RES", + f"goto {key}C", f":{key}E", f"echo FAIL>RESULTS\\{key}.RES", ]) else: lines.extend([ - f"if errorlevel 1 goto {key}P", f"echo FAIL>RESULTS\\{key}.RES", - f"goto {key}D", f":{key}P", f"echo PASS>RESULTS\\{key}.RES", f":{key}D", + f"if errorlevel 1 goto {key}E", f"echo FAIL>RESULTS\\{key}.RES", + f"goto {key}C", f":{key}E", f"echo PASS>RESULTS\\{key}.RES", ]) + lines.extend([ + f":{key}C", f"if exist *.ERR type *.ERR > RESULTS\\{key}.ERR", + f"if not exist RESULTS\\{key}.ERR type NUL > RESULTS\\{key}.ERR", + ]) lines.extend([ "goto FINISH", ":BUILDFAIL", "echo FAIL>RESULTS\\BUILD.RES", ":FINISH", "echo DONE>RUN.OK", *(["pause"] if show_dos else []), "exit", "", @@ -190,6 +200,10 @@ class SuiteRun: console = self.root / "CONSOLE.LOG" return console.read_text(encoding="utf-8", errors="replace") if console.is_file() else "" + def err(self, case: Case) -> str: + path = self.fec / "RESULTS" / f"{self._key(case)}.ERR" + return path.read_text(encoding="utf-8", errors="replace") if path.is_file() else "" + def cleanup(self) -> None: if not self.keep: shutil.rmtree(self.root, ignore_errors=True) diff --git a/src/ferrolang_vm/registry.py b/src/ferrolang_vm/registry.py new file mode 100644 index 0000000..5ef627e --- /dev/null +++ b/src/ferrolang_vm/registry.py @@ -0,0 +1,120 @@ +"""Explicit M1--M3 commands and expectations from TEST-DOS.BAT.""" +from __future__ import annotations + +from .suite import Case + + +def _c(milestone: int, name: str, command: str, ok: bool = True) -> Case: + return Case(f"m{milestone}-{name}", milestone, command, ok) + + +CASES: list[Case] = [] +for _name in ("basic", "literals", "keybuilt", "v012form"): + CASES.append(_c(1, f"{_name}-parse", f"FEC.EXE --dump-ast TESTS\\PASS\\{_name.upper()}.FE")) +for _name in ("core", "fmt", "io", "list", "map", "mem", "str", "sys"): + CASES.append(_c(1, f"std-{_name}-parse", f"FEC.EXE --dump-ast STD\\{_name.upper()}.FE")) +for _name in ("misssemi", "unclcomm", "logical"): + CASES.append(_c(1, f"{_name}-reject", f"FEC.EXE --dump-ast TESTS\\FAIL\\{_name.upper()}.FE", False)) + +for _name in ("hello", "scopes"): + _upper = _name.upper() + CASES.extend([ + _c(2, f"{_name}-emit", f"FEC.EXE --target=bits32 --emit-c TESTS\\M2\\{_upper}.FE -o TESTS\\M2\\{_upper}.C"), + _c(2, f"{_name}-build", f"WCL386 -q -za -bt=dos -fe=TESTS\\M2\\{_upper}.EXE TESTS\\M2\\{_upper}.C"), + _c(2, f"{_name}-run", f"TESTS\\M2\\{_upper}.EXE"), + ]) +CASES.extend([ + _c(2, "castwhil-emit", "FEC.EXE --target=bits16 --emit-c TESTS\\M2\\CASTWHIL.FE -o TESTS\\M2\\CAST16.C"), + _c(2, "castwhil-build", "WCL -q -za -bt=dos -fe=TESTS\\M2\\CAST16.EXE TESTS\\M2\\CAST16.C"), + _c(2, "castwhil-run", "TESTS\\M2\\CAST16.EXE"), +]) +_m2_outputs = { + "bad-cond": "BAD-CO", "bad-cast": "BAD-CA", "bad-asgn": "BAD-AS", + "bad-unk": "BAD-UN", "bad-ari": "BAD-AR", "bad-type": "BAD-TY", + "bad-ret": "BAD-RE", "bad-unit": "BAD-UI", "bad-void": "BAD-VO", +} +for _name, _output in _m2_outputs.items(): + CASES.append(_c(2, f"{_name}-reject", "FEC.EXE --target=bits32 --emit-c " + f"TESTS\\M2\\{_name.upper()}.FE -o TESTS\\M2\\{_output}.C", False)) + +def _m3_runtime(name: str) -> list[Case]: + upper = name.upper() + return [ + _c(3, f"{name}-emit", f"FEC.EXE --target=bits32 --emit-c TESTS\\M3\\{upper}.FE -o TESTS\\M3\\{upper}.C"), + _c(3, f"{name}-build", f"WCL386 -q -za -bt=dos -fe=TESTS\\M3\\{upper}.EXE TESTS\\M3\\{upper}.C"), + _c(3, f"{name}-run", f"TESTS\\M3\\{upper}.EXE"), + ] + + +for _name in ("struct", "enum", "array", "mutable"): + CASES.extend(_m3_runtime(_name)) +for _name in ("bad-mlet", "bad-shwr"): + CASES.append(_c(3, f"{_name}-reject", "FEC.EXE --target=bits32 --emit-c " + f"TESTS\\M3\\{_name.upper()}.FE -o TESTS\\M3\\{_name.upper()}.C", False)) +for _name in ("str", "for", "nested", "char", "arrayctx"): + CASES.extend(_m3_runtime(_name)) +for _name in ("bounds", "slcbound"): + _upper = _name.upper() + CASES.extend([ + _c(3, f"{_name}-emit", f"FEC.EXE --target=bits32 --emit-c TESTS\\M3\\{_upper}.FE -o TESTS\\M3\\{_upper}.C"), + _c(3, f"{_name}-build", f"WCL386 -q -za -bt=dos -fe=TESTS\\M3\\{_upper}.EXE TESTS\\M3\\{_upper}.C"), + _c(3, f"{_name}-trap", f"TESTS\\M3\\{_upper}.EXE", False), + ]) +CASES.extend([ + _c(3, "bounds-no-checks-emit", "FEC.EXE --target=bits32 --no-checks --emit-c TESTS\\M3\\BOUNDS.FE -o TESTS\\M3\\BOUNDS-N.C"), + _c(3, "bounds-no-checks-build", "WCL386 -q -za -bt=dos -fe=TESTS\\M3\\BOUNDS-N.EXE TESTS\\M3\\BOUNDS-N.C"), +]) +for _name in ("badfld", "badmat", "badarr", "badcycle", "badstr", "badchar", "badfield", "badindex"): + CASES.append(_c(3, f"{_name}-reject", "FEC.EXE --target=bits32 --emit-c " + f"TESTS\\M3\\{_name.upper()}.FE -o TESTS\\M3\\{_name.upper()}.C", False)) + +"""Explicit M4--M5 cases from TEST-DOS.BAT and M6 fixture expectations. + +Only commands and their expected status live here; the ``.fe`` fixtures stay +under ``fec/tests`` and are copied by the runner. +""" +def _c(milestone: int, name: str, command: str, ok: bool) -> Case: + return Case(f"m{milestone}-{name}", milestone, command, ok) + + +CASES.extend([ + _c(4, "format", "FEC.EXE --target=bits32 --emit-c TESTS\\M4\\FORMAT.FE -o TESTS\\M4\\FORMAT.C", True), + _c(4, "format-build", "WCL386 -q -za -wx -wcd=202 -bt=dos -fe=TESTS\\M4\\FORMAT.EXE TESTS\\M4\\FORMAT.C", True), + _c(4, "format-run", "TESTS\\M4\\FORMAT.EXE", True), + _c(4, "try-fpr", "FEC.EXE --target=bits32 --emit-c TESTS\\M4\\TRY-FPR.FE -o TESTS\\M4\\TRY-FPR.C", True), + _c(4, "try-fpr-build", "WCL386 -q -za -wx -wcd=202 -bt=dos -fe=TESTS\\M4\\TRY-FPR.EXE TESTS\\M4\\TRY-FPR.C", True), + _c(4, "try-fpr-run", "TESTS\\M4\\TRY-FPR.EXE", True), + _c(4, "prop", "FEC.EXE --target=bits32 --emit-c TESTS\\M4\\PROP.FE -o TESTS\\M4\\PROP.C", True), + _c(4, "prop-build", "WCL386 -q -za -wx -wcd=202 -bt=dos -fe=TESTS\\M4\\PROP.EXE TESTS\\M4\\PROPTEST.C", True), + _c(4, "prop-run", "TESTS\\M4\\PROP.EXE", True), +]) + +_m4_outputs = {"bad-type": "BAD-TYP", "bad-writ": "BAD-WRI"} +for _name in ("bad-ari", "bad-verb", "bad-run", "bad-type", "bad-try", "bad-writ", "bad-bufw", "bad-many", "bad-open", "bad-cls"): + _output = _m4_outputs.get(_name, _name.upper()) + CASES.append(_c(4, _name, "FEC.EXE --target=bits32 --emit-c " + f"TESTS\\M4\\{_name.upper()}.FE -o TESTS\\M4\\{_output}.C", False)) + +for _name in ("defer", "owned"): + CASES.append(_c(5, _name, "FEC.EXE --target=bits32 --emit-c " + f"TESTS\\M5\\{_name.upper()}.FE -o TESTS\\M5\\{_name.upper()}.C", True)) +for _name in ("bad-move", "bad-dest", "bad-drop", "bad-dbl", "bad-cond", "bad-proj", "bad-clos", "bad-loop"): + _output = "BAD-DES" if _name == "bad-dest" else _name.upper() + CASES.append(_c(5, _name, "FEC.EXE --target=bits32 --emit-c " + f"TESTS\\M5\\{_name.upper()}.FE -o TESTS\\M5\\{_output}.C", False)) +CASES += [ + _c(5, "runtime", "FEC.EXE --target=bits32 --emit-c TESTS\\M5\\RUNTIME.FE -o TESTS\\M5\\RUNT-G.C", True), + _c(5, "runtime-build", "WCL386 -q -za -bt=dos -dmalloc=m5_malloc -dfree=m5_free -fe=TESTS\\M5\\RUNTIME.EXE TESTS\\M5\\RUNT-G.C TESTS\\M5\\RUNTIME.C", True), + _c(5, "runtime-run", "TESTS\\M5\\RUNTIME.EXE", True), +] + +for _name in ("badarg", "badbinit", "badbrmov", "baddefer", "badfld", "badglob", "badgmut", "badinv", "badlocsl", "badloop", "badmove", "badmut", "badmut2", "badptr", "badret", "badrfld", "badridx", "badscop", "badself", "badshwr", "badslfld", "badtwo", "badup", "badweak"): + CASES.append(_c(6, _name, f"FEC.EXE --check TESTS\\M6\\{_name.upper()}.FE", False)) +for _name in ("okbranch", "okdefer", "okglobcp", "oklast", "okr8free", "okr8join", "okr8meth", "okr8stat", "okrebor", "okrtlast", "okshare", "okslreb", "okstatic", "oktemp", "oktrim", "okwcall"): + CASES.append(_c(6, _name, f"FEC.EXE --target=bits32 --emit-c -o OUT\\{_name.upper()}.C TESTS\\M6\\{_name.upper()}.FE", True)) + + +def all_cases(*, through: int = 6, only: int | None = None) -> list[Case]: + if only is not None: + return [case for case in CASES if case.milestone == only] + return [case for case in CASES if case.milestone <= through] diff --git a/src/ferrolang_vm/registry_m1_m3.py b/src/ferrolang_vm/registry_m1_m3.py deleted file mode 100644 index a9623ab..0000000 --- a/src/ferrolang_vm/registry_m1_m3.py +++ /dev/null @@ -1,69 +0,0 @@ -"""Explicit M1--M3 commands and expectations from TEST-DOS.BAT.""" -from __future__ import annotations - -from .suite import Case - - -def _c(milestone: int, name: str, command: str, ok: bool = True) -> Case: - return Case(f"m{milestone}-{name}", milestone, command, ok) - - -M1_M3_CASES: list[Case] = [] -for _name in ("basic", "literals", "keybuilt", "v012form"): - M1_M3_CASES.append(_c(1, f"{_name}-parse", f"FEC.EXE --dump-ast TESTS\\PASS\\{_name.upper()}.FE")) -for _name in ("core", "fmt", "io", "list", "map", "mem", "str", "sys"): - M1_M3_CASES.append(_c(1, f"std-{_name}-parse", f"FEC.EXE --dump-ast STD\\{_name.upper()}.FE")) -for _name in ("misssemi", "unclcomm", "logical"): - M1_M3_CASES.append(_c(1, f"{_name}-reject", f"FEC.EXE --dump-ast TESTS\\FAIL\\{_name.upper()}.FE", False)) - -for _name in ("hello", "scopes"): - _upper = _name.upper() - M1_M3_CASES.extend([ - _c(2, f"{_name}-emit", f"FEC.EXE --target=bits32 --emit-c TESTS\\M2\\{_upper}.FE -o TESTS\\M2\\{_upper}.C"), - _c(2, f"{_name}-build", f"WCL386 -q -za -bt=dos -fe=TESTS\\M2\\{_upper}.EXE TESTS\\M2\\{_upper}.C"), - _c(2, f"{_name}-run", f"TESTS\\M2\\{_upper}.EXE"), - ]) -M1_M3_CASES.extend([ - _c(2, "castwhil-emit", "FEC.EXE --target=bits16 --emit-c TESTS\\M2\\CASTWHIL.FE -o TESTS\\M2\\CAST16.C"), - _c(2, "castwhil-build", "WCL -q -za -bt=dos -fe=TESTS\\M2\\CAST16.EXE TESTS\\M2\\CAST16.C"), - _c(2, "castwhil-run", "TESTS\\M2\\CAST16.EXE"), -]) -_m2_outputs = { - "bad-cond": "BAD-CO", "bad-cast": "BAD-CA", "bad-asgn": "BAD-AS", - "bad-unk": "BAD-UN", "bad-ari": "BAD-AR", "bad-type": "BAD-TY", - "bad-ret": "BAD-RE", "bad-unit": "BAD-UI", "bad-void": "BAD-VO", -} -for _name, _output in _m2_outputs.items(): - M1_M3_CASES.append(_c(2, f"{_name}-reject", "FEC.EXE --target=bits32 --emit-c " - f"TESTS\\M2\\{_name.upper()}.FE -o TESTS\\M2\\{_output}.C", False)) - -def _m3_runtime(name: str) -> list[Case]: - upper = name.upper() - return [ - _c(3, f"{name}-emit", f"FEC.EXE --target=bits32 --emit-c TESTS\\M3\\{upper}.FE -o TESTS\\M3\\{upper}.C"), - _c(3, f"{name}-build", f"WCL386 -q -za -bt=dos -fe=TESTS\\M3\\{upper}.EXE TESTS\\M3\\{upper}.C"), - _c(3, f"{name}-run", f"TESTS\\M3\\{upper}.EXE"), - ] - - -for _name in ("struct", "enum", "array", "mutable"): - M1_M3_CASES.extend(_m3_runtime(_name)) -for _name in ("bad-mlet", "bad-shwr"): - M1_M3_CASES.append(_c(3, f"{_name}-reject", "FEC.EXE --target=bits32 --emit-c " - f"TESTS\\M3\\{_name.upper()}.FE -o TESTS\\M3\\{_name.upper()}.C", False)) -for _name in ("str", "for", "nested", "char", "arrayctx"): - M1_M3_CASES.extend(_m3_runtime(_name)) -for _name in ("bounds", "slcbound"): - _upper = _name.upper() - M1_M3_CASES.extend([ - _c(3, f"{_name}-emit", f"FEC.EXE --target=bits32 --emit-c TESTS\\M3\\{_upper}.FE -o TESTS\\M3\\{_upper}.C"), - _c(3, f"{_name}-build", f"WCL386 -q -za -bt=dos -fe=TESTS\\M3\\{_upper}.EXE TESTS\\M3\\{_upper}.C"), - _c(3, f"{_name}-trap", f"TESTS\\M3\\{_upper}.EXE", False), - ]) -M1_M3_CASES.extend([ - _c(3, "bounds-no-checks-emit", "FEC.EXE --target=bits32 --no-checks --emit-c TESTS\\M3\\BOUNDS.FE -o TESTS\\M3\\BOUNDS-N.C"), - _c(3, "bounds-no-checks-build", "WCL386 -q -za -bt=dos -fe=TESTS\\M3\\BOUNDS-N.EXE TESTS\\M3\\BOUNDS-N.C"), -]) -for _name in ("badfld", "badmat", "badarr", "badcycle", "badstr", "badchar", "badfield", "badindex"): - M1_M3_CASES.append(_c(3, f"{_name}-reject", "FEC.EXE --target=bits32 --emit-c " - f"TESTS\\M3\\{_name.upper()}.FE -o TESTS\\M3\\{_name.upper()}.C", False)) diff --git a/src/ferrolang_vm/registry_m4_m6.py b/src/ferrolang_vm/registry_m4_m6.py deleted file mode 100644 index 48b23e0..0000000 --- a/src/ferrolang_vm/registry_m4_m6.py +++ /dev/null @@ -1,49 +0,0 @@ -"""Explicit M4--M5 cases from TEST-DOS.BAT and M6 fixture expectations. - -Only commands and their expected status live here; the ``.fe`` fixtures stay -under ``fec/tests`` and are copied by the runner. -""" -from __future__ import annotations - -from .suite import Case - - -def _c(milestone: int, name: str, command: str, ok: bool) -> Case: - return Case(f"m{milestone}-{name}", milestone, command, ok) - - -M4_M6_CASES: list[Case] = [ - _c(4, "format", "FEC.EXE --target=bits32 --emit-c TESTS\\M4\\FORMAT.FE -o TESTS\\M4\\FORMAT.C", True), - _c(4, "format-build", "WCL386 -q -za -wx -wcd=202 -bt=dos -fe=TESTS\\M4\\FORMAT.EXE TESTS\\M4\\FORMAT.C", True), - _c(4, "format-run", "TESTS\\M4\\FORMAT.EXE", True), - _c(4, "try-fpr", "FEC.EXE --target=bits32 --emit-c TESTS\\M4\\TRY-FPR.FE -o TESTS\\M4\\TRY-FPR.C", True), - _c(4, "try-fpr-build", "WCL386 -q -za -wx -wcd=202 -bt=dos -fe=TESTS\\M4\\TRY-FPR.EXE TESTS\\M4\\TRY-FPR.C", True), - _c(4, "try-fpr-run", "TESTS\\M4\\TRY-FPR.EXE", True), - _c(4, "prop", "FEC.EXE --target=bits32 --emit-c TESTS\\M4\\PROP.FE -o TESTS\\M4\\PROP.C", True), - _c(4, "prop-build", "WCL386 -q -za -wx -wcd=202 -bt=dos -fe=TESTS\\M4\\PROP.EXE TESTS\\M4\\PROPTEST.C", True), - _c(4, "prop-run", "TESTS\\M4\\PROP.EXE", True), -] - -_m4_outputs = {"bad-type": "BAD-TYP", "bad-writ": "BAD-WRI"} -for _name in ("bad-ari", "bad-verb", "bad-run", "bad-type", "bad-try", "bad-writ", "bad-bufw", "bad-many", "bad-open", "bad-cls"): - _output = _m4_outputs.get(_name, _name.upper()) - M4_M6_CASES.append(_c(4, _name, "FEC.EXE --target=bits32 --emit-c " - f"TESTS\\M4\\{_name.upper()}.FE -o TESTS\\M4\\{_output}.C", False)) - -for _name in ("defer", "owned"): - M4_M6_CASES.append(_c(5, _name, "FEC.EXE --target=bits32 --emit-c " - f"TESTS\\M5\\{_name.upper()}.FE -o TESTS\\M5\\{_name.upper()}.C", True)) -for _name in ("bad-move", "bad-dest", "bad-drop", "bad-dbl", "bad-cond", "bad-proj", "bad-clos", "bad-loop"): - _output = "BAD-DES" if _name == "bad-dest" else _name.upper() - M4_M6_CASES.append(_c(5, _name, "FEC.EXE --target=bits32 --emit-c " - f"TESTS\\M5\\{_name.upper()}.FE -o TESTS\\M5\\{_output}.C", False)) -M4_M6_CASES += [ - _c(5, "runtime", "FEC.EXE --target=bits32 --emit-c TESTS\\M5\\RUNTIME.FE -o TESTS\\M5\\RUNT-G.C", True), - _c(5, "runtime-build", "WCL386 -q -za -bt=dos -dmalloc=m5_malloc -dfree=m5_free -fe=TESTS\\M5\\RUNTIME.EXE TESTS\\M5\\RUNT-G.C TESTS\\M5\\RUNTIME.C", True), - _c(5, "runtime-run", "TESTS\\M5\\RUNTIME.EXE", True), -] - -for _name in ("badarg", "badbinit", "badbrmov", "baddefer", "badfld", "badglob", "badgmut", "badinv", "badlocsl", "badloop", "badmove", "badmut", "badmut2", "badptr", "badret", "badrfld", "badridx", "badscop", "badself", "badshwr", "badslfld", "badtwo", "badup", "badweak"): - M4_M6_CASES.append(_c(6, _name, f"FEC.EXE --check TESTS\\M6\\{_name.upper()}.FE", False)) -for _name in ("okbranch", "okdefer", "okglobcp", "oklast", "okr8free", "okr8join", "okr8meth", "okr8stat", "okrebor", "okrtlast", "okshare", "okslreb", "okstatic", "oktemp", "oktrim", "okwcall"): - M4_M6_CASES.append(_c(6, _name, f"FEC.EXE --target=bits32 --emit-c -o OUT\\{_name.upper()}.C TESTS\\M6\\{_name.upper()}.FE", True)) diff --git a/src/ferrolang_vm/suite.py b/src/ferrolang_vm/suite.py index 7072f51..b402d4e 100644 --- a/src/ferrolang_vm/suite.py +++ b/src/ferrolang_vm/suite.py @@ -13,10 +13,5 @@ class Case: def all_cases(*, through: int = 6, only: int | None = None) -> list[Case]: - from .registry_m1_m3 import M1_M3_CASES - from .registry_m4_m6 import M4_M6_CASES - - cases = [*M1_M3_CASES, *M4_M6_CASES] - if only is not None: - return [case for case in cases if case.milestone == only] - return [case for case in cases if case.milestone <= through] + from .registry import all_cases as _all_cases + return _all_cases(through=through, only=only) diff --git a/tools/tests/test_milestones_dosboxx.py b/tools/tests/test_milestones_dosboxx.py index c6bc2fd..a1c0ea1 100644 --- a/tools/tests/test_milestones_dosboxx.py +++ b/tools/tests/test_milestones_dosboxx.py @@ -1,6 +1,7 @@ from __future__ import annotations import os +import warnings import pytest @@ -48,7 +49,13 @@ def test_compiler_build(suite_run: SuiteRun) -> None: def test_milestone_case(case: Case, suite_run: SuiteRun) -> None: if suite_run.result() != "PASS": pytest.skip("compiler build failed") - assert suite_run.result(case) == "PASS", ( + 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)}" + f"{suite_run.log(case)}\n{err}" )