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:
Jared Miller 2026-02-10 09:53:12 -05:00
parent 2b8c177977
commit 69b1ef8a59
Signed by: shmup
GPG key ID: 22B5C6D66A38B06C

View file

@ -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