Files

114 lines
4.5 KiB
Python

#!/usr/bin/env python3
"""Unabhängige Soll-Gegenproben; Produktcode und bestehende Tests bleiben unverändert."""
from pathlib import Path
import os
import subprocess
import tempfile
ROOT = next(p for p in Path(__file__).resolve().parents
if (p / "Cargo.toml").is_file() and (p / "openspec").is_dir())
TBC = ROOT / "target/debug/tbc"
def run(*args, **kwargs):
return subprocess.run(args, capture_output=True, text=True, timeout=60, **kwargs)
def main():
subprocess.run(["cargo", "build", "-p", "tb-cli"], cwd=ROOT, check=True)
failed = []
def check(name, ok, evidence):
print(f"{'PASS' if ok else 'FAIL'} {name}: {evidence}")
if not ok:
failed.append(name)
with tempfile.TemporaryDirectory(prefix="tb-review-") as tmp:
tmp = Path(tmp)
for name, source in [("PSET", "PSET (1,1),2"),
("PALETTE", "DIM a%(15)\nPALETTE USING a%(0)")]:
path = tmp / "graphics.bas"
path.write_text(source + "\n")
out = run(str(TBC), "check", str(path))
check(name + " Non-Feature", out.returncode != 0 and
"Feature unavailable" in out.stderr and name in out.stderr,
out.stderr.strip())
path = tmp / "parent.frm"
path.write_text('''VERSION 1.00
Begin Form Form1
Begin Frame Group
Index = 0
End
Begin Frame Group
Index = 1
Begin TextBox Probe
End
End
End
DIM p AS CONTROL
p=Probe.Parent
Form1.Hide
PRINT p.Index
END
''')
out = run(str(TBC), "run", str(path))
check("Indizierter Parent aus FRM", out.returncode == 0 and out.stdout.strip() == "1",
f"Soll=1, Ist={out.stdout!r}, {out.stderr}")
build = run(str(TBC), "build", str(path))
assert build.returncode == 0, build.stderr
path.unlink()
out = run(str(TBC), "run", str(path.with_suffix(".tbc")))
check("Indizierter Parent aus TBC ohne Quelle", out.returncode == 0 and out.stdout.strip() == "1",
f"Soll=1, Ist={out.stdout!r}, {out.stderr}")
# Kopie im Temp-Verzeichnis erlaubt Zugriff auf den privaten Prüfer.
# Einzige Mutation: TIMEZONEKNOWN zeigt auf die gültige TIMER-Bindung.
source = (ROOT / "crates/tb-cli/tests/inventar.rs").read_text()
source = source.replace('include_str!("../../../tests/support/inventar-quellen.tsv")',
f'include_str!("{ROOT}/tests/support/inventar-quellen.tsv")')
source += r'''
#[test]
fn review_falsches_laufzeitziel_muss_abgewiesen_werden() {
let e=inventar().into_iter().find(|e|e.name=="TIMEZONEKNOWN").unwrap();
let (src,catalog)=probe_source(&e);
let mut module=tb_vm::compile_source_with_forms("FORM1",&src,&catalog).unwrap();
let mut changed=false;
for i in module.procs.iter_mut().flat_map(|p|&mut p.code) {
if let tb_vm::bytecode::Instr::CallBuiltin(id,_) = i {
if *id==tb_runtime::builtins::ids::TIMEZONEKNOWN {
*id=tb_runtime::builtins::ids::TIMER;
changed=true;
}
}
}
assert!(changed);
let result=pruefe_kompilat(&e,Ok(module),|id|tb_runtime::builtins::builtin_table().get(id as usize).is_some());
assert!(result.is_err(),"TIMEZONEKNOWN mit TIMER-Ziel wird akzeptiert: {result:?}");
}
'''
probe = tmp / "inventar.rs"
probe.write_text(source)
# Cargo resolves a coherent dependency graph; selecting rlibs by mtime
# can mix feature variants after a workspace test run.
source = source.replace('env!("CARGO_MANIFEST_DIR")', f'"{ROOT}/crates/tb-cli"')
probe.write_text(source)
manifest = '[package]\nname = "tb-review-probes"\nversion = "0.0.0"\nedition = "2021"\n[workspace]\n'
manifest += '[[test]]\nname = "inventar"\npath = "inventar.rs"\n[dependencies]\n'
for name in ["tb-vm", "tb-frontend", "tb-runtime"]:
manifest += f'{name} = {{ path = "{ROOT}/crates/{name}" }}\n'
(tmp / "Cargo.toml").write_text(manifest)
env = os.environ.copy()
env["CARGO_BIN_EXE_tbc"] = str(TBC)
out = run("cargo", "test", "--manifest-path", str(tmp / "Cargo.toml"),
"--offline", "--target-dir", str(ROOT / "target/review-probes"),
"--test", "inventar", "review_falsches", "--", "--nocapture", env=env)
check("Inventar erkennt falsches Laufzeitziel", out.returncode == 0,
out.stdout + out.stderr)
print(f"{len(failed)} fehlgeschlagene Soll-Gegenproben")
return bool(failed)
if __name__ == "__main__":
raise SystemExit(main())