Skip to content

test(quic): expand frame.cpp coverage (parser error paths, varint boundaries, malformed input) #1011

Description

@kcenon

What

Expand unit test coverage for src/protocols/quic/frame.cpp (currently 1203 lines — the single largest untested translation unit remaining under EPIC #953). Existing tests tests/test_quic_frame.cpp (641 lines, 37 cases) and tests/unit/quic_frame_types_test.cpp (1038 lines, 94 cases) exercise frame-type enums and happy-path build/parse round-trips, but do not exhaustively cover parser error branches, varint boundary conditions, truncated input, or malformed wire formats.

This is a Step 2 narrow-scoped test expansion under EPIC #953.

Why

  • frame.cpp implements QUIC's binary framing layer (RFC 9000 §19). A mis-parsed frame length or varint overflow corrupts every subsequent frame in the packet.
  • EPIC Expand unit test coverage from 40% to 80% #953 baseline (2026-04-13, pre-BUILD_WITH_*) reported 15.0% line coverage on this file. The file has grown from 600 to 1203 lines since then, so the real branch-coverage gap is substantially larger.
  • frame_parser::parse_* returns Result<T> on malformed input. The error branches (truncated buffers, invalid varints, out-of-range enum values, reserved/unknown frame types) are currently unverified — a silent miss here would produce undefined behavior on the receive path.
  • This is the largest single remaining file by line count in the EPIC Expand unit test coverage from 40% to 80% #953 worst-coverage list.

Where

  • Source: src/protocols/quic/frame.cpp
  • Header: src/internal/protocols/quic/frame.h
  • New test: tests/unit/quic_frame_coverage_test.cpp
  • CMake registration: tests/CMakeLists.txt via add_network_test(...)

How

Test surface (per public API in frame.h)

  • frame_parser::peek_type — empty buffer, single-byte and multi-byte varint, reserved/unknown type values
  • frame_parser::parse — dispatch across all frame types including unknown type ID (must return error, not crash)
  • frame_parser::parse_all — multi-frame buffer, partial frame at the end (must reject), empty buffer (returns empty list)
  • frame_parser::parse_padding — all-zero-byte runs of various lengths; verify count matches
  • frame_parser::parse_ping — zero-byte payload (only type consumed)
  • frame_parser::parse_ack — with/without ECN, zero ACK ranges, maximum ACK range count, truncated at each varint boundary; largest_ack < first_ack_range (invalid)
  • frame_parser::parse_reset_stream, parse_stop_sending — truncated at each field boundary
  • frame_parser::parse_crypto, parse_new_token, parse_stream — length prefix mismatched vs remaining bytes; LEN flag on/off and OFF flag on/off combinations (stream)
  • frame_parser::parse_max_data, parse_max_stream_data, parse_max_streams (bidi + uni) — varint boundary values (0, 2^62-1)
  • frame_parser::parse_data_blocked, parse_stream_data_blocked, parse_streams_blocked — truncated input
  • frame_parser::parse_new_connection_id — zero-length conn-id (invalid), max-length (20 bytes), stateless_reset_token short/long
  • frame_parser::parse_retire_connection_id — single varint, truncated
  • frame_parser::parse_path_challenge, parse_path_response — require exactly 8 bytes; reject truncated
  • frame_parser::parse_connection_close — transport vs application variant, zero-length reason phrase, reason phrase length mismatch
  • frame_parser::parse_handshake_done — zero-byte payload
  • frame_builder::append_varint, append_bytes — accessible via full build/parse round-trips
  • frame_builder::build + every build_* — round-trip with extreme values (0, 1-byte, 2-byte, 4-byte, 8-byte varint lengths)
  • Round-trip property: for every build_*(input), parse(build_*(input)) returns equivalent frame

Acceptance Criteria

  • tests/unit/quic_frame_coverage_test.cpp added and registered in tests/CMakeLists.txt
  • network_quic_frame_coverage_test builds and all tests pass on local build
  • Tests do not require any network I/O or external QUIC peer
  • Tests use only the public API of frame_parser and frame_builder (no private/friend access)
  • All tests pass on Ubuntu/macOS/Windows CI when run via release pipeline
  • No regression in existing test_quic_frame.cpp or quic_frame_types_test.cpp cases

Out of scope

  • QUIC fuzzing (separate effort, belongs to a fuzz harness, not unit tests)
  • Live QUIC handshake / transport integration coverage
  • Re-baselining EPIC Expand unit test coverage from 40% to 80% #953 file-level coverage numbers (separate measurement task)

Dependencies

Metadata

Metadata

Assignees

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions