test(quic): expand branch coverage for quic_socket.cpp#1057
Merged
Conversation
Adds tests/unit/quic_socket_branch_test.cpp with 53 hermetic test cases exercising public-API surfaces of src/internal/quic_socket.cpp that remained uncovered after Issue #989. Targets the #953 acceptance bar of line >= 70% / branch >= 60%. Coverage includes: short-lived construction loops for both client and server roles; default invariants for state, role, is_connected, is_handshake_complete, remote_endpoint, remote_connection_id; local_connection_id RFC 9000 length bounds and pairwise uniqueness across 16 sockets; callback registration with default-constructed, replaced, and shared_ptr-captured handlers for all four callback types; mutable and const socket() accessor reachability; role-guard rejection in connect/accept (server-cannot-connect with and without SNI, client-cannot-accept with empty and missing PEM paths, repeated rejection idempotency); close() idempotency on idle/draining/closed including triple-close, application-error-code branch with max-uint64 and 1024-character reason; send_stream_data not-connected guard; create_stream not-connected guard for client/server bidi/uni; close_stream not_found early-return for nine unknown ids; start_receive/stop_receive flag transitions; move construction and move assignment with populated callbacks; self-move-assignment via reference; concurrent state-query polling and concurrent callback replacement under shared_ptr lifetime; multi-instance independent state; destructor cleanup paths. Honest scope: the impl-level methods that physically exchange QUIC packets with a peer (do_receive, handle_packet, process_frame and its dispatch branches, process_crypto_frame, process_stream_frame, process_ack_frame, process_connection_close_frame, process_handshake_done_frame, send_pending_packets populated path, send_packet encryption + async_send_to dispatch, queue_crypto_data populated state, determine_encryption_level per-packet-type dispatch, on_retransmit_timeout) require a live UDP/QUIC peer and remain uncovered without a transport fixture. The connect()/accept() success paths past TLS init also need a peer or PEM files on disk. Closes #1051 Part of #953
Contributor
Coverage Report
Coverage DetailsFull HTML report is available as a build artifact. |
This was referenced Apr 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Summary
Adds
tests/unit/quic_socket_branch_test.cppwith 53 hermetic test cases exercising public-API surfaces ofsrc/internal/quic_socket.cpp. Targets the #953 acceptance bar of line >= 70% / branch >= 60% by covering every reachable surface that does not require a live UDP/QUIC peer.Change Type
Why
Related Issues
Motivation
src/internal/quic_socket.cppsits among the lowest-coverage files in the network_system source tree per the 2026-04-26 measurement ondevelop @ 05c1b7bb(line 43.7%, branch 21.3%). The uncovered region concentrates in error and boundary paths -- exactly the surfaces that regress during the ongoingResult<T>migration and API stabilization. Bringing this file over the 70% line / 60% branch bar contributes directly to the #953 acceptance criteria.Where
Files Changed
tests/unit/quic_socket_branch_test.cpp(new, 718 lines, 53 tests)tests/CMakeLists.txt(registration)CHANGELOG.md,docs/CHANGELOG.md(Unreleased / Added entries)How
Implementation Highlights
The test file complements
quic_socket_construction_test.cpp(Issue #989) and groups tests under a singleQuicSocketBranchTestfixture that owns anasio::io_context. Coverage groups:quic_role::clientandquic_role::server(16 iterations each)state()/role()/is_connected()/is_handshake_complete()/remote_endpoint()/remote_connection_id()(the latter two exercise the seldom-exercised query path before any connect/accept)local_connection_id()RFC 9000 length bounds (0..20) and pairwise uniqueness across 16 socketsstream_data,connected,error,close) with default-constructed (empty)std::function, multi-replacement (3-deep), andshared_ptr-captured state lambdassocket()accessor reachabilityconnect()rejected with and without SNI, clientaccept()rejected with empty and missing PEM paths, 3-iteration repeated server-connect rejection idempotencyclose()idempotency: idle close, application error code (is_application_error=truebranch),std::numeric_limits<uint64_t>::max()error code, 1024-character reason, empty reason, triple-closesend_stream_data()not-connected guard for empty / populated / 64 KiB payloads with and without FINcreate_stream()not-connected guard for client-bidi / client-uni / server-bidi / server-uniclose_stream()not_foundearly-return for nine separate unknown stream ids includingnumeric_limits<uint64_t>::max()stop_receive()before any start, repeated idempotency, and start-then-stop sequencethis != &otherguard)state/is_connected/is_handshake_completeand forrole/local_connection_idand forremote_connection_idis_connectedreader threadclose(), withoutclose(), and afterstart_receive()(timer cancellation, async-receive cancellation)Honest scope statement
The impl-level methods that physically exchange QUIC packets with a peer remain reachable only with a UDP transport fixture and a TLS-1.3 peer. Specifically the private surfaces:
do_receive()(async UDP receive completion)handle_packet()(header parsing, header unprotection, payload decryption, frame parsing dispatch)process_frame()and itsstd::visitdispatch branches for every variant in theprotocols::quic::framevariantprocess_crypto_frame()(TLS handshake state machine including client/server transition toconnected)process_stream_frame()(stream-data callback delivery)process_ack_frame()(placeholder)process_connection_close_frame()(peer-driven draining)process_handshake_done_frame()(client-side handshake completion)send_pending_packets()populated-queue success path with non-empty crypto / stream queuessend_packet()encryption +async_send_todispatch including initial / handshake / short-header builder branches and thekeys_result.is_err()failure-branch complementqueue_crypto_data()populated-state append branch's complementdetermine_encryption_level()per-packet-type dispatch (initial / zero_rtt / handshake / default / short header)on_retransmit_timeout()handlerall require a live UDP peer that speaks the QUIC wire format end-to-end. Driving them would require either a mock UDP peer that speaks the QUIC wire format end-to-end or a friend-declared injection point inside
quic_socket. Theconnect()andaccept()success paths past TLS init also require a peer that completes the TLS handshake, or real PEM cert / key files on disk foraccept().Testing Done
QuicSocketBranchTest)Breaking Changes
None -- test-only additions.