feat(typedef): add implementation task decomposition (12 tasks, 7 generations)

Break the alknet-typedef architecture specs into atomic, dependency-ordered
implementation tasks covering crate init, error types, schema layer, data
access, both layout modes (aligned static + packed sequential), TUnion
dispatch, jsonschema custom keyword validators, TypedefEngine integration,
comprehensive tests, and a final review checkpoint.

Validated: 12 tasks, 0 cycles, 7 parallel generations.
This commit is contained in:
deepseek-v4-pro committed 2026-07-21 09:36:30 +00:00
1 parent dd232c3d47
commit db100f9849
12 files changed
+1996

No files matched your search

+192
View File
@@ -0,0 +1,192 @@
---
id: typedef/tests
name: "Write comprehensive tests for alknet-typedef: unit tests, integration tests, and POC round-trip tests"
status: pending
depends_on: [typedef/engine]
scope: moderate
risk: low
impact: component
level: implementation
---
## Description
Write comprehensive tests for the `alknet-typedef` crate. Tests should cover all
17 `TypeDef:*` kinds, both layout modes, endianness, TUnion dispatch, validation,
and error paths. Include the POC-verified round-trip tests that validate
byte-identical output against known-good serialization.
### Test categories
#### 1. Schema layer tests (`tests/schema_tests.rs` or `#[cfg(test)] mod tests` in `schema.rs`)
- `get_typedef_kind()` correctly identifies all 17 kinds
- `type_size()` returns correct sizes for all fixed-size types
- `type_size()` returns `None` for variable-length types
- `natural_alignment()` returns correct alignment
- `Endian::from_schema()` defaults to Little, parses "big" correctly
- `parse_encoding()` handles `true`, `{ "encoding": "length-prefixed" }`, `{ "encoding": "offset-indirect" }`
- `parse_align()` returns `None` when absent, correct value when present
- `parse_max_length()` returns `None` when absent, correct value when present
- `parse_discriminator()` handles byte-offset and field-name discriminators
- `normalize_refs()` rewrites bare-name refs, leaves full paths unchanged, handles nested objects
#### 2. Data access tests (`tests/data_access_tests.rs`)
- Fixed-size read/write round-trip for all types: `i8`, `i16`, `i32`, `u8`, `u16`, `u32`, `u64`, `f32`, `f64`, `bool`, `enum`
- Endianness: little-endian and big-endian produce correct byte order
- `read_bool`: `0x00` → false, `0x01` → true, other values → error
- `read_string`: correct length-prefixed read, UTF-8 validation, buffer-too-short error
- `read_bytes`: correct length-prefixed read, buffer-too-short error
- `write_string` / `write_bytes`: correct length prefix + data written, returns bytes written
- `read_string_indirect` / `read_bytes_indirect`: correct offset-indirect read
- Buffer bounds checking: all functions return `TypedefError::Access` for too-short buffers
- Field path in error messages is correct
#### 3. OffsetMap tests (aligned static mode) (`tests/offset_map_tests.rs`)
- Simple struct: `{ u8, u32, f32 }` → correct offsets with natural alignment (0, 4, 8)
- Nested struct: `{ header: { version: u32, magic: u32 }, payload: bytes }` → correct dotted paths
- `TArray` of fixed-size elements: correct stride and element offsets
- `TArray` with fixed count (`minItems == maxItems`): correct total size
- `TArray` with variable count: length-prefixed encoding
- Variable-length types (inline length-prefixing): 4-byte length prefix at known offset
- Variable-length types (`maxLength`): reserved bytes at fixed offset
- Variable-length types (offset-indirect): 8-byte `{offset, length}` struct
- `TUnion` with byte-offset discriminator: discriminator at offset, variant at offset + disc_size
- `TUnion` with field-name discriminator: discriminator is a regular field
- Struct-level `"align"` annotation: rounds up total size
- Field-level `"align"` annotation: overrides struct default
- `OffsetMap::get()` returns correct `ByteRange` for dotted paths
- `OffsetMap::total_size()` is correct
- `OffsetMap::iter()` returns all fields
#### 4. LayoutBuilder tests (packed sequential mode, write-side) (`tests/layout_builder_tests.rs`)
- Simple struct: `{ u8, u32, string }` → packed offsets (0, 1, 5) with no padding
- Variable-length fields shift subsequent fields based on actual sizes
- Nested struct: correct dotted paths with packed offsets
- `TArray` of fixed-size elements: correct stride (element size, no padding)
- `TUnion` with byte-offset discriminator: correct discriminator and variant positions
- Missing variable-length field size → `TypedefError::Offset`
#### 5. SequentialReader tests (packed sequential mode, read-side) (`tests/sequential_reader_tests.rs`)
- Read fields sequentially: correct values and position advancement
- Variable-length fields: reads length prefix, skips data, advances correctly
- `read_next()` returns `None` when all fields read
- `read_field()` walks through preceding fields
- `reset()` resets position
- Nested struct: returns `FieldValue::Struct { start, end }`
- `TUnion`: returns `FieldValue::Union { ... }`
- `TArray`: returns `FieldValue::Array { count, element_start, element_stride }`
- Endianness respected for multi-byte reads
#### 6. TUnion dispatch tests (`tests/tunion_tests.rs`)
- Byte-offset discriminator: reads u8 at offset 0, returns correct key and variant offset
- Byte-offset discriminator with u16 and u32 types
- Field-name discriminator: reads string field, returns correct key
- Field-name discriminator with u8 and enum field types
- `resolve_variant()`: resolves `$ref` pointers, returns error for unknown keys
- `discriminator_size()`: correct for each discriminator type
#### 7. Validation tests (`tests/validation_tests.rs`)
- `build_validator()` returns a working validator
- Each `TypeDef:*` kind's validator rejects invalid values
- `Float32Validator`: rejects NaN, Infinity
- `Int8Validator`: rejects 128, -129
- `Uint8Validator`: rejects -1, 256
- `StringValidator`: rejects non-string, respects `maxLength`
- `TimestampValidator`: rejects non-RFC 3339 strings
- `StructValidator`: validates nested fields
- `UnionValidator`: validates discriminator membership
- `ArrayValidator`: validates element types and length bounds
#### 8. TypedefEngine integration tests (`tests/engine_tests.rs`)
- `compile()` in aligned mode produces a working engine
- `compile()` in packed mode produces a working engine
- `compile()` normalizes `$ref` values
- `compile()` returns error for invalid schemas
- `endian()` and `mode()` accessors
- `offset_map()`, `layout_builder()`, `sequential_reader()` accessors
- `validate_json()` and `is_valid_json()` work correctly
- `read_field()` and `write_field()` in aligned mode
#### 9. POC round-trip tests (`tests/poc_roundtrip_tests.rs`)
Replicate the key POC tests from `/workspace/alknet-typedef-poc/`:
- **Fixed-size round-trip**: Write u8, u16, u32, u64, f32, f64, bool, enum to a buffer
at computed offsets; read back; verify values match.
- **String round-trip**: Write a length-prefixed string; read back; verify.
- **Nested struct round-trip**: Write a struct with nested fields; read back; verify.
- **Endianness round-trip**: Write in big-endian; read back in big-endian; verify.
- **SFTP packet round-trip** (if SFTP schemas are available): Write an SFTP Read/Write/Status
packet; verify byte-identical output against known-good serialization.
#### 10. Error path tests
- Buffer too short for every read function
- Invalid UTF-8 in `read_string`
- Invalid boolean byte value
- Missing required schema keywords
- Unknown `TypeDef:*` kind
- Malformed discriminator annotation
- Unknown discriminator value
- Missing variable-length field size in `LayoutBuilder::build()`
### Test organization
Tests can be organized as:
- Unit tests in `#[cfg(test)] mod tests` blocks within each source file (for
module-internal functions).
- Integration tests in `tests/` directory (for public API tests that exercise
multiple modules).
### What this does NOT include
- Tests for arrays of variable-length-element structs (deferred, OQ-069)
- WASM-specific tests (deferred, OQ-070)
- Performance benchmarks
## Acceptance Criteria
- [ ] Schema layer tests: all `schema.rs` public functions tested
- [ ] Data access tests: all read/write functions tested with round-trip, endianness, and error paths
- [ ] OffsetMap tests: aligned static layout with alignment, nesting, arrays, unions, variable-length types
- [ ] LayoutBuilder tests: packed sequential layout with variable-length shifting
- [ ] SequentialReader tests: sequential field reading with position tracking
- [ ] TUnion tests: both discriminator kinds, variant resolution
- [ ] Validation tests: all 17 custom keyword validators tested
- [ ] Engine tests: compile, accessors, convenience methods
- [ ] POC round-trip tests: fixed-size, string, nested struct, endianness
- [ ] Error path tests: buffer-too-short, invalid UTF-8, malformed schemas
- [ ] All tests pass: `cargo test -p alknet-typedef`
- [ ] No `unwrap()` in test code that would mask failures (use `?` or `assert!(matches!(...))`)
- [ ] `cargo clippy -p alknet-typedef --all-targets` succeeds with no warnings
- [ ] `cargo build --workspace` still succeeds
- [ ] `cargo test --workspace` still succeeds (old tests untouched)
## References
- docs/research/alknet-typedef/findings.md — POC results (26 tests passing)
- /workspace/alknet-typedef-poc/src/lib.rs — POC test reference
- docs/architecture/crates/typedef/README.md — design principles
- All preceding task files in tasks/typedef/
## Notes
> This is the testing task — it validates the entire crate. The POC had 26 tests
> passing; this task should cover at least that many scenarios plus additional
> error-path tests. Tests should be organized by module/concern. The SFTP round-trip
> test is a stretch goal — it requires SFTP packet schemas which may not be in the
> repo yet. If SFTP schemas aren't available, test with hand-crafted schemas that
> exercise the same patterns (byte-offset TUnion, big-endian, mixed fixed/variable
> fields).
## Summary
> To be filled on completion