"""Unit tests for memory helpers and session recording.""" from __future__ import annotations import os import shutil import tempfile import unittest from greeneye.memory import Memory from greeneye.record import NullRecorder, Recorder, load_events, load_meta from greeneye.symbols import Symbol, SymbolDB class FakeClient: def __init__(self, size=0x1000): self.data = bytearray(size) for i in range(size): self.data[i] = i & 0xFF def read_mem(self, addr, size, chunk=0): return bytes(self.data[addr : addr + size]) def write_mem(self, addr, data, chunk=0): self.data[addr : addr + len(data)] = data class MemoryTests(unittest.TestCase): def setUp(self): self.mem = Memory(FakeClient()) def test_read_write_hexdump(self): self.assertEqual(self.mem.read(0x10, 4), bytes(range(0x10, 0x14))) self.mem.write(0x20, b"AB") self.assertEqual(self.mem.read(0x20, 2), b"AB") text = self.mem.hexdump(0, 16) self.assertIn("00000000", text) self.assertIn("00 01 02", text) self.assertIn("|", text) def test_search(self): self.assertEqual(self.mem.search(0, 0x40, b"\x10\x11"), [0x10]) self.assertEqual(self.mem.search_string(0, 0x40, "\x20\x21"), [0x20]) masked = self.mem.search(0, 0x100, b"\xa0", mask=b"\xf0") self.assertEqual(masked[0], 0xA0) self.mem.write(0x30, b"GREEN") self.assertEqual(self.mem.search_string(0, 0x100, "GREEN"), [0x30]) def test_snapshot_and_diff(self): before = self.mem.snapshot(0, 32, "before") self.mem.write(0x10, b"\xff") after = self.mem.snapshot(0, 32, "after") diffs = Memory.diff(before, after, base=0) self.assertEqual(len(diffs), 1) self.assertEqual(diffs[0].addr, 0x10) self.assertEqual(diffs[0].new, b"\xff") text = Memory.render_diff(diffs) self.assertIn("00000010", text) def test_hexdump_annotated(self): db = SymbolDB() db.add(Symbol(addr=0, name="block", size=0x100, source="test")) mem = Memory(FakeClient(), symbols=db) text = mem.hexdump(0, 16, annotate=True) self.assertIn("block", text) class RecorderTests(unittest.TestCase): def setUp(self): self.dir = tempfile.mkdtemp(prefix="greeneye-test-") self.recorder = Recorder(self.dir, name="unit", meta={"note": "test"}) self.recorder.event("alpha", value=1) self.recorder.event("alpha", value=2) self.recorder.snapshot("regs", 0x80000000, b"\x00" * 16) def tearDown(self): shutil.rmtree(self.dir, ignore_errors=True) def test_events_and_meta(self): self.recorder.close() events = load_events(self.dir) kinds = [e["type"] for e in events] self.assertEqual(kinds.count("alpha"), 2) self.assertIn("snapshot_saved", kinds) self.assertIn("session_end", kinds) meta = load_meta(self.dir) self.assertEqual(meta["name"], "unit") self.assertEqual(meta["note"], "test") self.assertTrue(os.path.exists(os.path.join(self.dir, "summary.md"))) summary = open(os.path.join(self.dir, "summary.md")).read() self.assertIn("unit", summary) def test_null_recorder(self): null = NullRecorder() null.event("x") null.snapshot("y", 0, b"") null.close() self.assertIsNone(null.dir) if __name__ == "__main__": unittest.main()