#!/usr/bin/env python3 """End-to-end UI test for the shell: compile-error jump + Ctrl-K-D quit. Compiler correctness is covered by matrix/run_compile_tests.sh (fast, no pty). This test covers the *shell* behaviour that only exists interactively: 1. W loads a work file (LoadWorkFile ends with a Pause: needs a filler key) 2. C reports a TP3 error (error number + relative text position) 3. ESC opens the editor with the cursor ON the error position (TP3 kcwait: waitesc ; BX:=txerrpos ; DEC BX ; JMP editor2) 4. Ctrl-K D returns to the main menu 5. Q exits the shell cleanly with status 0 (a bare HALT aborts with SIGABRT under gm2 -fiso) Fixture: uierror.pas has a deliberate *syntax* error (a missing operand after '+'), reported as error 41 at pos 331 = line 9, column 12 (1-based). A syntax error is used deliberately rather than, say, a missing library feature: those come and go as the compiler grows, and a UI test whose expectations drift with it stops being a test. Usage: uitest.py [fixture.pas] """ import os import sys sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from ptyharness import CTRL_K, SHELL_DIR, Screen, drain, reap, send, spawn, status_str, visible FIXTURE = sys.argv[1] if len(sys.argv) > 1 else os.path.join( os.path.dirname(os.path.abspath(__file__)), "fixtures", "uierror.pas") EXPECT_ERR = "41" EXPECT_LINE = 9 EXPECT_COL = 12 def main(): pid, fd = spawn() checks = [] try: drain(fd, quiet=0.6) send(fd, b"w") send(fd, FIXTURE.encode()) send(fd, b"\r", quiet=0.8) send(fd, b" ", quiet=0.5) # clears LoadWorkFile's Pause comp = visible(send(fd, b"c", quiet=1.5)) checks.append(("compile reports a TP3 error", "TP3-style error" in comp)) checks.append(("error number is %s (not the 0 from the old " "self-assignment)" % EXPECT_ERR, ("error %s " % EXPECT_ERR) in comp)) checks.append(("compile did not claim success", "Compiled OK" not in comp)) ed = send(fd, b"\x1b", quiet=1.0) # accept the error jump scr = Screen() scr.feed(ed) text = scr.text() row = scr.row_with("x := 1 +") checks.append(("editor opened", "Line %d" % EXPECT_LINE in text)) checks.append(("cursor on the faulty line (that row carries the bad stmt)", row is not None)) checks.append(("status line reports Line %d" % EXPECT_LINE, ("Line %d" % EXPECT_LINE) in text.split("\n")[0])) checks.append(("status line reports Col %d" % EXPECT_COL, ("Col %d" % EXPECT_COL) in text.split("\n")[0])) checks.append(("cursor is on that row", row is not None and row == scr.r)) send(fd, CTRL_K, quiet=0.4) after = visible(send(fd, b"d", quiet=0.6)) checks.append(("Ctrl-K D returned to the main menu", "Main file" in after)) send(fd, b"q", quiet=0.6) finally: status = reap(fd, pid) checks.append(("shell exited cleanly (status 0)", os.WIFEXITED(status) and os.WEXITSTATUS(status) == 0)) print("UI TEST: %s" % os.path.basename(FIXTURE)) print("-" * 60) ok = True for name, passed in checks: print("%-58s %s" % (name, "PASS" if passed else "FAIL")) ok = ok and passed print("-" * 60) print("child: %s" % status_str(status)) print("RESULT: %s" % ("ALL PASS" if ok else "FAILURES PRESENT")) return 0 if ok else 1 if __name__ == "__main__": sys.exit(main())