test(consumers): make the parser routing tests actually test the routing - #656
Conversation
Ten tests in CompositeMessageParserTests and ProtobufMessageParserTests were named for a routing decision but asserted only `consumedBytes >= 0`, and several hid their one real assertion behind `if (messages.Any())`. They could not fail, so the suite reported routing coverage the project did not have. Each now pins which parser ran, how many messages came out and of what type, and what consumedBytes exactly equals. Two recording parsers share one ordered call log so the tests can assert the routing ORDER rather than merely that a parser was reached. WithNullBytes_ShouldDetectAsBinary was named for the opposite of what the classifier does: "Hello\0World" is 90.9% printable ASCII, and printable ratio is weighed before null density on purpose, so it routes to text. Renamed rather than pinned as binary. closes #653 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
/agentic_review |
PR Summary by QodoFix parser routing tests to assert actual parser selection and consumption
AI Description
Diagram
High-Level Assessment
Files changed (2)
|
Code Review by Qodo🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)
Great, no issues found!Qodo reviewed your code and found no material issues that require reviewTip of the day💡 Did you know, you can switch off images and animations for a plain-text comment |
|
Qodo-clean, CI green — ready for review. Independently re-verified on head |
What was wrong
Ten tests across
CompositeMessageParserTestsandProtobufMessageParserTestscarried the names of routing tests —ShouldUseProtobufParser,ShouldDetectAsBinary,WithMultipleMessages_ShouldParseFirst— but their only assertion wasAssert.True(consumedBytes >= 0). Nothing in them said which parser had run, which is the entire behaviour they were named for. A change that routed every buffer to the wrong parser would have left all ten green. One was a strict tautology (Assert.True(binaryMessages.Count() >= 0)—Enumerable.Count()cannot be negative), and five hid their only real assertion behindif (messages.Any()), so they asserted nothing whenever the parser returned empty — which, for the buffers they used, was always. Three of them ran on an empty byte array despite being named for valid protobuf. The suite was reporting coverage of the parser routing that the project did not actually have.How it was fixed
Each test now pins the real behaviour: which parser was consulted and in what order, how many messages came out, of what concrete type and with what decoded field values, and what
consumedBytesexactly equals. Two recording parsers write into one shared ordered call log, so a test can assert the routing order (["protobuf", "text"]) rather than merely that a parser was reached — and can prove the negative, that the second parser was never consulted when the first answered. Everyif (messages.Any())guard is gone. The buffers that were fake "mock protobuf" bytes (not valid length-delimited frames at all, which is why nothing ever parsed) are now real frames built withWriteDelimitedTo.Two things a reviewer should push back on if they disagree:
WithNullBytes_ShouldDetectAsBinarywas named for the opposite of what the code does."Hello\0World"is 90.9% printable ASCII and 9.1% null, andDetectMessageTypeweighs printable ratio before null density on purpose (the 10% null threshold isn't even met). It routes to text. That is deliberate and documented in the classifier — the genuinely binary case it guards against is the 40%-null / 24%-printableSYSInfoPB?reply from issue Make serial-discovery protobuf parsing resilient to non-protobuf noise (so the probe needn't disable echo) #268 — so I renamed the test toWithOneNullByteInPrintableData_ShouldDetectAsTextrather than pin a behaviour the code doesn't have. This is not a bug report; no parser bug was found. If you'd rather the classifier did treat any null byte as binary, that's a separate design change and this test would need to move with it.ReturnsCorrectMessageTypeis a tenth test, not in issue The composite/protobuf parser tests named for routing behavior assert almost nothing #653's list of nine. It sits in the same file with the identical defect (empty buffer,if (messages.Any()),consumedBytes >= 0). Leaving it would have shipped a file that still contained the exact pattern this PR claims to remove.Mutation evidence — every rewritten test was confirmed able to fail
Each mutation was applied to production code, the tests run, then reverted. Verified red:
CompositeMessageParser.ParseMessagesWithBinaryData_ShouldUseProtobufParser,WithOneNullByteInPrintableData_ShouldDetectAsText,WithNullTextParser_UsesDefaultLineParser,WithNullProtobufParser_UsesDefaultProtobufParser,WhenPreferredParserFindsNothing_FallsBackWithFullBufferTryParseadoptsMath.Max(consumedBytes, parserConsumed)instead of only adopting on a produced messageWithMixedScenariosrows truncated protobuf frame, binary with nullscurrentIndex += messageLength(drop the length prefix from the advance)WithValidProtobuf_ShouldReturnMessage,WithMultipleMessages_ShouldParseAll,ReturnsCorrectMessageType,ReturnsDifferentMessageTypes,WithNullProtobufParser_UsesDefaultProtobufParserWithNullBytes_ResyncsAndPreservesTrailingPrefix(and only that one)breakafter the first parsed frameWithMultipleMessages_ShouldParseAllTextPrintableRatio0.8 → 0.95WithOneNullByteInPrintableData_ShouldDetectAsTextLineBasedMessageParserreportsconsumedByteswithout the line endingReturnsDifferentMessageTypes,WithNullTextParser_UsesDefaultLineParser,WithMixedScenariosrows SCPI command, SCPI queryLineBasedMessageParserswallows an unterminated tail as a lineWithMixedScenariosrows lone non-printable byte, truncated protobuf frame, binary with nullsThe one input I could not make failable is the empty buffer, because
CompositeMessageParserreturns before routing — so I dropped it from the theory rather than keep a row no mutation can kill; the existingWithEmptyData_ShouldReturnEmptyalready pins that contract exactly. There is a comment in the theory data saying so.Verification
Test-only change; no production code is modified. Full suite green on both frameworks: net9.0 Core 3838 passed / 2 skipped, net10.0 Core 3838 passed / 2 skipped, Mcp 217 passed, 0 failed, 0 warnings. Line coverage 88.48%. Bench validation does not apply — nothing here touches the device, and the board was never acquired.
The diff also drops trailing whitespace from four adjacent tests I did not otherwise change, a side effect of rewriting the file.
closes #653
Not merging — for review.