Implement QuetzalWriter CMem and Stks chunk generators
Adds comprehensive test coverage for CMem chunk generation: - test_cmem_all_unchanged: Empty output when memory unchanged - test_cmem_single_byte_change: Single byte modification - test_cmem_multiple_scattered_changes: Multiple changes - test_cmem_roundtrip_with_parser: Writer/parser integration - test_cmem_consecutive_zeros: Run-length encoding validation
This commit is contained in:
parent
2b8c177977
commit
69b1ef8a59
1 changed files with 147 additions and 0 deletions
|
|
@ -834,6 +834,153 @@ class QuetzalWriterTests(TestCase):
|
||||||
self.assertEqual(chunk_data[11], 0x34)
|
self.assertEqual(chunk_data[11], 0x34)
|
||||||
self.assertEqual(chunk_data[12], 0x56)
|
self.assertEqual(chunk_data[12], 0x56)
|
||||||
|
|
||||||
|
def test_cmem_all_unchanged(self):
|
||||||
|
"""Test CMem chunk with no changes (all zeros after XOR)."""
|
||||||
|
from mudlib.zmachine.quetzal import QuetzalWriter
|
||||||
|
from mudlib.zmachine.zmemory import ZMemory
|
||||||
|
|
||||||
|
# Create a minimal z3 story file
|
||||||
|
story = bytearray(1024)
|
||||||
|
story[0] = 3 # version 3
|
||||||
|
story[0x0E] = 0x04 # static memory starts at 0x0400
|
||||||
|
story[0x0F] = 0x00
|
||||||
|
|
||||||
|
pristine = ZMemory(bytes(story))
|
||||||
|
current = ZMemory(bytes(story))
|
||||||
|
|
||||||
|
zmachine = Mock()
|
||||||
|
zmachine._pristine_mem = pristine
|
||||||
|
zmachine._mem = current
|
||||||
|
|
||||||
|
writer = QuetzalWriter(zmachine)
|
||||||
|
result = writer._generate_cmem_chunk()
|
||||||
|
|
||||||
|
# All identical means no output (trailing zeros omitted)
|
||||||
|
self.assertIsInstance(result, bytes)
|
||||||
|
self.assertEqual(len(result), 0)
|
||||||
|
|
||||||
|
def test_cmem_single_byte_change(self):
|
||||||
|
"""Test CMem chunk with one byte changed."""
|
||||||
|
from mudlib.zmachine.quetzal import QuetzalWriter
|
||||||
|
from mudlib.zmachine.zmemory import ZMemory
|
||||||
|
|
||||||
|
story = bytearray(1024)
|
||||||
|
story[0] = 3
|
||||||
|
story[0x0E] = 0x04
|
||||||
|
story[0x0F] = 0x00
|
||||||
|
|
||||||
|
pristine = ZMemory(bytes(story))
|
||||||
|
current = ZMemory(bytes(story))
|
||||||
|
current[0x0100] = 0x42
|
||||||
|
|
||||||
|
zmachine = Mock()
|
||||||
|
zmachine._pristine_mem = pristine
|
||||||
|
zmachine._mem = current
|
||||||
|
|
||||||
|
writer = QuetzalWriter(zmachine)
|
||||||
|
result = writer._generate_cmem_chunk()
|
||||||
|
|
||||||
|
self.assertIsInstance(result, bytes)
|
||||||
|
self.assertIn(0x42, result)
|
||||||
|
|
||||||
|
def test_cmem_multiple_scattered_changes(self):
|
||||||
|
"""Test CMem chunk with multiple changes across memory."""
|
||||||
|
from mudlib.zmachine.quetzal import QuetzalWriter
|
||||||
|
from mudlib.zmachine.zmemory import ZMemory
|
||||||
|
|
||||||
|
story = bytearray(1024)
|
||||||
|
story[0] = 3
|
||||||
|
story[0x0E] = 0x04
|
||||||
|
story[0x0F] = 0x00
|
||||||
|
|
||||||
|
pristine = ZMemory(bytes(story))
|
||||||
|
current = ZMemory(bytes(story))
|
||||||
|
current[0x0010] = 0xAA
|
||||||
|
current[0x0100] = 0xBB
|
||||||
|
current[0x0200] = 0xCC
|
||||||
|
|
||||||
|
zmachine = Mock()
|
||||||
|
zmachine._pristine_mem = pristine
|
||||||
|
zmachine._mem = current
|
||||||
|
|
||||||
|
writer = QuetzalWriter(zmachine)
|
||||||
|
result = writer._generate_cmem_chunk()
|
||||||
|
|
||||||
|
self.assertIsInstance(result, bytes)
|
||||||
|
self.assertIn(0xAA, result)
|
||||||
|
self.assertIn(0xBB, result)
|
||||||
|
self.assertIn(0xCC, result)
|
||||||
|
self.assertLess(len(result), 1024)
|
||||||
|
|
||||||
|
def test_cmem_roundtrip_with_parser(self):
|
||||||
|
"""Test that CMem output can be decoded by QuetzalParser._parse_cmem()."""
|
||||||
|
from mudlib.zmachine.quetzal import QuetzalParser, QuetzalWriter
|
||||||
|
from mudlib.zmachine.zmemory import ZMemory
|
||||||
|
|
||||||
|
story = bytearray(1024)
|
||||||
|
story[0] = 3
|
||||||
|
story[0x0E] = 0x04
|
||||||
|
story[0x0F] = 0x00
|
||||||
|
|
||||||
|
pristine = ZMemory(bytes(story))
|
||||||
|
current = ZMemory(bytes(story))
|
||||||
|
current[0x0050] = 0x12
|
||||||
|
current[0x0051] = 0x34
|
||||||
|
current[0x0150] = 0xAB
|
||||||
|
current[0x0300] = 0xFF
|
||||||
|
|
||||||
|
zmachine = Mock()
|
||||||
|
zmachine._pristine_mem = pristine
|
||||||
|
zmachine._mem = current
|
||||||
|
|
||||||
|
writer = QuetzalWriter(zmachine)
|
||||||
|
compressed_bytes = writer._generate_cmem_chunk()
|
||||||
|
|
||||||
|
# Create fresh memory for parsing into
|
||||||
|
restored = ZMemory(bytes(story))
|
||||||
|
restored_zmachine = Mock()
|
||||||
|
restored_zmachine._pristine_mem = pristine
|
||||||
|
restored_zmachine._mem = restored
|
||||||
|
|
||||||
|
parser = QuetzalParser(restored_zmachine)
|
||||||
|
parser._parse_cmem(compressed_bytes)
|
||||||
|
|
||||||
|
# Verify restored memory matches current memory
|
||||||
|
for addr in [0x0050, 0x0051, 0x0150, 0x0300]:
|
||||||
|
self.assertEqual(
|
||||||
|
restored[addr],
|
||||||
|
current[addr],
|
||||||
|
f"Mismatch at address 0x{addr:04X}",
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_cmem_consecutive_zeros(self):
|
||||||
|
"""Test CMem encoding handles consecutive zero XOR results correctly."""
|
||||||
|
from mudlib.zmachine.quetzal import QuetzalWriter
|
||||||
|
from mudlib.zmachine.zmemory import ZMemory
|
||||||
|
|
||||||
|
story = bytearray(1024)
|
||||||
|
story[0] = 3
|
||||||
|
story[0x0E] = 0x04
|
||||||
|
story[0x0F] = 0x00
|
||||||
|
|
||||||
|
pristine = ZMemory(bytes(story))
|
||||||
|
current = ZMemory(bytes(story))
|
||||||
|
current[0x0040] = 0x11
|
||||||
|
current[0x0045] = 0x22
|
||||||
|
|
||||||
|
zmachine = Mock()
|
||||||
|
zmachine._pristine_mem = pristine
|
||||||
|
zmachine._mem = current
|
||||||
|
|
||||||
|
writer = QuetzalWriter(zmachine)
|
||||||
|
result = writer._generate_cmem_chunk()
|
||||||
|
|
||||||
|
self.assertIsInstance(result, bytes)
|
||||||
|
idx_11 = result.index(0x11)
|
||||||
|
self.assertEqual(result[idx_11 + 1], 0x00)
|
||||||
|
self.assertEqual(result[idx_11 + 2], 0x03)
|
||||||
|
self.assertEqual(result[idx_11 + 3], 0x22)
|
||||||
|
|
||||||
|
|
||||||
# Note: ZObjectParser methods are tested through integration tests
|
# Note: ZObjectParser methods are tested through integration tests
|
||||||
# with real story files, not unit tests with mock memory, as the
|
# with real story files, not unit tests with mock memory, as the
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue