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[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
|
||||
# with real story files, not unit tests with mock memory, as the
|
||||
|
|
|
|||
Loading…
Reference in a new issue