Skip to content

Commit 5f16b3a

Browse files
bbyalcinkayaclaude
andcommitted
improve comment clarity in binary parser unit tests
Explain the constructed bytecode in TestCustomSections and TestFuncCodeLengthMismatch, state the sentinel-byte contract once at class level instead of four times, explain why the shared-memory limit flags 0x02/0x03 must be rejected, note the intent behind the LEB128 boundary values, and untangle the peek_bytes test comment. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 29e0f7e commit 5f16b3a

1 file changed

Lines changed: 21 additions & 10 deletions

File tree

‎pykwasm/src/tests/unit/test_binary_parser.py‎

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ def test_f64_eof_raises(self) -> None:
8181

8282

8383
class TestIntegers:
84+
# Values chosen to cover the LEB128 encoding-length boundary (127/128 is the largest
85+
# 1-byte/smallest 2-byte unsigned value), a 3-byte encoding (624485), and the
86+
# extremes of each type's range.
8487
U32_VALUES = [0, 1, 127, 128, 300, 624485, 2**32 - 1]
8588
U64_VALUES = [0, 1, 2**32, 2**35 + 1, 2**64 - 1]
8689
I32_VALUES = [0, 1, -1, 127, -128, 2**31 - 1, -(2**31)]
@@ -155,6 +158,9 @@ def test_i64_with_max(self) -> None:
155158
assert at == wast.i64
156159
assert lim == (1, 2)
157160

161+
# 0x02/0x03 sit between the accepted flags (0x00/0x01 i32, 0x04/0x05 i64) but are the
162+
# threads proposal's shared-memory flags; the K semantics has no shared memory, so they
163+
# must be rejected rather than misread as an address type.
158164
@pytest.mark.parametrize('flag', [0x02, 0x03])
159165
def test_shared_memory_flags_rejected(self, flag: int) -> None:
160166
with pytest.raises(WasmParseError):
@@ -168,8 +174,8 @@ def test_successful_peek_does_not_advance_stream(self) -> None:
168174
assert s.tell() == 0
169175

170176
def test_partial_eof_restores_stream_position(self) -> None:
171-
# only 1 byte available, but 2 are requested: the short read must not leave the
172-
# stream advanced past the byte it couldn't help but consume while trying.
177+
# 2 bytes requested but only 1 available: the failed peek must restore the
178+
# position instead of leaving the stream advanced by the partial read.
173179
s = stream(b'\x40')
174180
with pytest.raises(WasmEOFError):
175181
peek_bytes(2, s)
@@ -187,9 +193,13 @@ def _wrap(self, *sections: bytes) -> bytes:
187193
return MAGIC + VERSION + b''.join(sections)
188194

189195
def test_custom_sections_do_not_break_stream_alignment(self) -> None:
196+
# 1 functype (0x60): params [i32 (0x7F)], results [i32 (0x7F)]
190197
type_section = section(1, uleb128(1) + bytes([0x60]) + uleb128(1) + bytes([0x7F]) + uleb128(1) + bytes([0x7F]))
198+
# 1 function with typeidx 0
191199
func_section = section(3, uleb128(1) + uleb128(0))
200+
# 1 export: name "f", kind func (0x00), funcidx 0
192201
export_section = section(7, uleb128(1) + (uleb128(len(b'f')) + b'f' + bytes([0x00]) + uleb128(0)))
202+
# 1 code entry of size 4: 0 local decls, body 'local.get 0 (0x20 0x00); end (0x0B)'
193203
code_section = section(10, uleb128(1) + (uleb128(4) + bytes([0x00, 0x20, 0x00, 0x0B])))
194204

195205
data = self._wrap(
@@ -231,12 +241,15 @@ def test_trailing_garbage_after_sections_rejected(self) -> None:
231241

232242
class TestFuncCodeLengthMismatch:
233243
def test_more_funcs_than_code_entries_rejected(self) -> None:
244+
# func section declares 1 function (typeidx 0), code section has 0 entries
234245
func_section = section(3, uleb128(1) + uleb128(0))
235246
code_section = section(10, uleb128(0))
236247
with pytest.raises(WasmParseError):
237248
parse_module(stream(MAGIC + VERSION + func_section + code_section))
238249

239250
def test_more_code_entries_than_funcs_rejected(self) -> None:
251+
# func section declares 0 functions, code section has 1 entry of size 2:
252+
# 0 local decls, body 'end (0x0B)'
240253
func_section = section(3, uleb128(0))
241254
code_section = section(10, uleb128(1) + (uleb128(2) + bytes([0x00, 0x0B])))
242255
with pytest.raises(WasmParseError):
@@ -255,8 +268,9 @@ def unwrap_instr(k: KApply) -> KApply:
255268

256269

257270
class TestInstructions:
258-
# the trailing sentinel byte proves the parser consumes exactly the memidx
259-
# operands; see the if tests below for details
271+
# Each success-case encoding ends with a 0x01 sentinel byte that is not part of the
272+
# instruction; asserting `s.read(1) == b'\x01'` after parsing proves the parser
273+
# consumed exactly the instruction's bytes (no under- or over-read).
260274
def test_memory_copy(self) -> None:
261275
# 0xFC 10 dst_memidx=0 src_memidx=0
262276
s = stream(bytes([0xFC]) + uleb128(10) + uleb128(0) + uleb128(0) + b'\x01')
@@ -308,8 +322,7 @@ def test_if_without_else(self) -> None:
308322
# 0x40 blocktype: empty (no result type)
309323
# 0x01 nop (the then-branch) — no 0x05 else opcode follows
310324
# 0x0B end: terminates the if directly
311-
# 0x01 sentinel: not part of the instruction; read back after parsing to
312-
# prove the parser consumed exactly the instruction's bytes
325+
# 0x01 sentinel
313326
s = stream(bytes([0x04, 0x40, 0x01, 0x0B]) + b'\x01')
314327
i = instr(s)
315328
expected = wast.INSTR_WITH_POS(
@@ -331,8 +344,7 @@ def test_if_with_else(self) -> None:
331344
# 0x05 else opcode
332345
# 0x00 unreachable (the else-branch)
333346
# 0x0B end: terminates the if
334-
# 0x01 sentinel: not part of the instruction; read back after parsing to
335-
# prove the parser consumed exactly the instruction's bytes
347+
# 0x01 sentinel
336348
s = stream(bytes([0x04, 0x40, 0x01, 0x05, 0x00, 0x0B]) + b'\x01')
337349
i = instr(s)
338350
expected = wast.INSTR_WITH_POS(
@@ -355,8 +367,7 @@ def test_if_without_else_nested_in_block(self) -> None:
355367
# 0x00 unreachable (the then-branch)
356368
# 0x0B end: terminates the inner if (no else branch)
357369
# 0x0B end: terminates the enclosing block
358-
# 0x01 sentinel: not part of the instruction; read back after parsing to
359-
# prove the parser consumed exactly the instruction's bytes
370+
# 0x01 sentinel
360371
s = stream(bytes([0x02, 0x40, 0x04, 0x40, 0x00, 0x0B, 0x0B]) + b'\x01')
361372
i = instr(s)
362373
expected = wast.INSTR_WITH_POS(

0 commit comments

Comments
 (0)