calc_smoke.py 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. #!/usr/bin/env python3
  2. """Boot the compiled CALC.COM and quit it through its own command menu.
  3. The compile ladder proves the front-end reaches the final '.'. This proves the
  4. linked image is a runnable program: it is loaded above the boot sector, prints
  5. the MicroCalc welcome/grid, accepts a numeric formula in cell A1, reaches the
  6. command menu, accepts `/Q' and exits 0. The first cell-entry path used to
  7. restart CALC (a nested procedure fell through into its enclosing body); feeding
  8. one formula here keeps that regression visible.
  9. The loader is the high-image variant of bootcom.s (LOAD_SEG=0x1000, input at
  10. 0x9800); the ordinary fixture harness uses the same default now, while
  11. rt_exec.py keeps the original low loader for its own driver image.
  12. """
  13. import os
  14. import shutil
  15. import subprocess
  16. import sys
  17. import tempfile
  18. HERE = os.path.dirname(os.path.abspath(__file__))
  19. SHELL = os.path.dirname(HERE)
  20. RES = os.path.join(os.path.dirname(SHELL), "Resources", "TP3")
  21. sys.path.insert(0, HERE)
  22. import run_com_exec as r # noqa: E402
  23. def main():
  24. td = tempfile.mkdtemp(prefix="tpcalc-")
  25. try:
  26. for name in ("CALC.PAS", "CALC.INC"):
  27. shutil.copy(os.path.join(RES, name), os.path.join(td, name))
  28. exe = r.ensure_comtest()
  29. src = os.path.join(td, "CALC.PAS")
  30. p = subprocess.run([exe], cwd=td, input=(src + "\n").encode(),
  31. capture_output=True)
  32. coms = [os.path.join(td, n) for n in os.listdir(td)
  33. if n.upper().endswith(".COM")]
  34. if p.returncode != 0 or not coms:
  35. sys.exit("comtest did not produce CALC.COM:\n%s"
  36. % p.stdout.decode(errors="replace"))
  37. com = open(coms[0], "rb").read()
  38. if len(com) > r.COM_MAX:
  39. sys.exit("CALC.COM is %d bytes, past the loader's %d"
  40. % (len(com), r.COM_MAX))
  41. boot = r.build_boot_sector(no_keypress=True)
  42. img = os.path.join(td, "calc.img")
  43. open(img, "wb").write(r.build_floppy(boot, com, b"\r1+2\r/Q"))
  44. out, rc, note = r.run_qemu(img)
  45. code = r.exit_code_of(rc)
  46. text = out.decode("latin-1")
  47. missing = [s for s in ("Welcome to MicroCalc", "AutoCalc: ON",
  48. "3.00", "Update, Quit") if s not in text]
  49. if code != 0 or missing:
  50. sys.exit("CALC did not start/quit cleanly: exit=%r note=%s missing=%r\n%s"
  51. % (code, note, missing, r.visible_output(out[:2000])))
  52. print(" CALC.COM PASS com=%d bytes, exit=0, cell-entry/formula/menu"
  53. % len(com))
  54. return 0
  55. finally:
  56. shutil.rmtree(td, ignore_errors=True)
  57. if __name__ == "__main__":
  58. sys.exit(main())