import unittest from collections import Counter from h8536.emulator.memory import MemoryAccess from h8536.emulator.rx_divergence import ( DivergenceContext, STATE_BUFFERS, bench_signature_line, classify_hits, format_interesting_writes, format_pc_hits, format_state_changes, label_frame, parse_frame, write_label, ) class EmulatorRxDivergenceTest(unittest.TestCase): def test_reuses_probe_frame_parser_and_labels_bench_signature(self): frame = parse_frame("04 00 00 80 80") self.assertEqual(frame, bytes.fromhex("04000080805E")) self.assertIn("bench_cmd0_echo_80", label_frame(frame)) self.assertIn("bench_connect_ok", bench_signature_line()) def test_pc_hit_summary_makes_dispatch_outcome_visible(self): hits = Counter({0xBC69: 1, 0xBA26: 2}) summary = classify_hits(hits) self.assertTrue(summary["cmd0_reached_BC69"]) self.assertFalse(summary["cmd1_reached_BCD7"]) self.assertFalse(summary["retry_echo"]) self.assertFalse(summary["cmd7_replay"]) def test_formats_watched_pc_hits_in_trace_order(self): context = DivergenceContext() for pc in (0xBC0F, 0xBC69, 0xBC69): context.record_pc(pc) lines = format_pc_hits(context) self.assertIn("H'BC0F:faa2_split=1", lines) self.assertIn("H'BC69:cmd0_set_value=2", lines) self.assertIn("first=H'BC0F,H'BC69,H'BC69", lines) def test_filters_required_write_addresses(self): accesses = [ MemoryAccess(0xF860, 1, 0x12, "write", "on_chip_ram"), MemoryAccess(0xE001, 1, 0x34, "write", "external"), MemoryAccess(0xE002, 1, 0x56, "write", "external"), MemoryAccess(0xFEDD, 1, 0x78, "write", "register"), ] lines = format_interesting_writes(accesses) self.assertEqual(len(lines), 2) self.assertIn("rx_validation_F860_F865", lines[0]) self.assertIn("primary_table_E000", lines[1]) self.assertEqual(write_label(0xFAA6), "serial_latches_FAA2_FAA6") self.assertIsNone(write_label(0xE002)) def test_state_changes_formats_bytes_and_ints_compactly(self): lines = format_state_changes( {"FAA2_session_flags": 0, "F860_F865_rx_validation": b"\x00" * 6}, {"FAA2_session_flags": 0x80, "F860_F865_rx_validation": bytes.fromhex("010203040506")}, ) self.assertIn("FAA2_session_flags:00->80", lines) self.assertIn("F860_F865_rx_validation:00 00 00 00 00 00->01 02 03 04 05 06", lines) def test_snapshots_visible_40a0_candidate_table_slots(self): self.assertEqual(STATE_BUFFERS["E880_E881_current_0040"], (0xE880, 2)) self.assertEqual(STATE_BUFFERS["E900_E901_current_0080"], (0xE900, 2)) self.assertEqual(STATE_BUFFERS["E980_E981_current_00C0"], (0xE980, 2)) if __name__ == "__main__": unittest.main()