1
0
Files
h8-536-decoder/tests/test_emulator_state_search.py
2026-05-26 10:48:39 +10:00

121 lines
4.1 KiB
Python

import io
import json
import tempfile
import unittest
from pathlib import Path
from unittest.mock import patch
from h8536.emulator.state_search import (
SearchCase,
SearchResult,
StatePatch,
build_cases,
classify_display,
main,
parse_address,
parse_matrix_patch,
parse_single_patch,
target_matches,
)
class EmulatorStateSearchTest(unittest.TestCase):
def test_parse_patch_accepts_hex_address_and_value(self):
patch = parse_single_patch("F730=0x41", size=1)
self.assertEqual(patch, StatePatch(1, 0xF730, 0x41, "user"))
self.assertEqual(patch.label(), "byte:H'F730=0x41")
def test_parse_matrix_patch_expands_values(self):
patches = parse_matrix_patch("E000=0x4080,0x8080", size=2)
self.assertEqual(patches, [
StatePatch(2, 0xE000, 0x4080, "user"),
StatePatch(2, 0xE000, 0x8080, "user"),
])
def test_parse_address_accepts_h_quote(self):
self.assertEqual(parse_address("H'F970"), 0xF970)
def test_connect_queue_preset_builds_small_rom_driven_matrix(self):
parser = __import__("h8536.emulator.state_search", fromlist=["build_arg_parser"]).build_arg_parser()
args = parser.parse_args(["--preset", "connect-queue"])
cases = build_cases(args)
self.assertEqual(len(cases), 25)
first = cases[0]
self.assertEqual(first.pc, 0x2806)
self.assertIn(StatePatch(2, 0xF970, 0x0000, "preset"), first.patches)
self.assertIn(StatePatch(2, 0xE000, 0x0000, "preset"), first.patches)
def test_custom_matrix_combines_fixed_and_matrix_patches(self):
parser = __import__("h8536.emulator.state_search", fromlist=["build_arg_parser"]).build_arg_parser()
args = parser.parse_args([
"--preset",
"custom",
"--pc",
"0x2CB9",
"--byte",
"F730=0",
"--matrix-word",
"E000=0x4080,0x8080",
])
cases = build_cases(args)
self.assertEqual(len(cases), 2)
self.assertEqual(cases[0], SearchCase((StatePatch(1, 0xF730, 0, "user"), StatePatch(2, 0xE000, 0x4080, "user")), 0x2CB9))
def test_classify_display(self):
self.assertEqual(classify_display(" CONNECT: OK | "), "ok")
self.assertEqual(classify_display(" CONNECT:DXC-637 | "), "dxc")
self.assertEqual(classify_display(" CONNECT:NOT ACT | "), "not-act")
def test_target_matching(self):
self.assertTrue(target_matches("ok", "ok"))
self.assertTrue(target_matches("dxc", "any-connect"))
self.assertTrue(target_matches("ok", "changed"))
self.assertFalse(target_matches("not-act", "changed"))
def test_cli_dry_run_lists_cases(self):
stdout = io.StringIO()
rc = main(["--dry-run", "--preset", "connect-branch", "--limit", "2"], stdout=stdout)
self.assertEqual(rc, 0)
output = stdout.getvalue()
self.assertIn("preset=connect-branch cases=2", output)
self.assertIn("case[0] pc=H'2CB9", output)
def test_cli_json_output_uses_results_from_run_search(self):
fake_result = SearchResult(
case_index=0,
patches=(StatePatch(2, 0xE000, 0x8080, "preset"),),
pc=0x2CB9,
steps=10,
stopped_reason="stop_pc",
final_pc=0xFFFF,
display=" CONNECT: OK | ",
line0=" CONNECT: OK ",
outcome="ok",
f730=0x81,
e000=0x8080,
f9b4=0,
f9b9=0,
)
with tempfile.TemporaryDirectory() as tmpdir:
path = Path(tmpdir) / "out.json"
stdout = io.StringIO()
with patch("h8536.emulator.state_search.run_search", return_value=[fake_result]):
rc = main(["--preset", "custom", "--word", "E000=0x8080", "--json-out", str(path)], stdout=stdout)
payload = json.loads(path.read_text(encoding="utf-8"))
self.assertEqual(rc, 0)
self.assertIn("hits=1", stdout.getvalue())
self.assertEqual(payload["hits"][0]["outcome"], "ok")
if __name__ == "__main__":
unittest.main()