Skip to content

✨ add StrictMerge option and improve list-limit handling in decoder tests#70

Merged
techouse merged 9 commits into
mainfrom
fix/upstream-v2
May 28, 2026
Merged

✨ add StrictMerge option and improve list-limit handling in decoder tests#70
techouse merged 9 commits into
mainfrom
fix/upstream-v2

Conversation

@techouse
Copy link
Copy Markdown
Owner

@techouse techouse commented May 28, 2026

This pull request primarily updates the qs npm package dependency to version 6.15.2 and significantly expands and refines the test suite for the QsNet decoding logic. The test changes focus on stricter and more accurate handling of array/list limits, merging strategies, and edge cases such as comma-separated values and bracket notation. These improvements help ensure the decoder's behavior closely matches the intended and documented behavior, especially in complex or ambiguous scenarios.

Dependency Update:

  • Upgraded the qs npm package from version 6.15.1 to 6.15.2 in both package.json and pnpm-lock.yaml, ensuring the latest bug fixes and features from the upstream library are included. [1] [2] [3] [4]

Decode Options and Merge Behavior:

  • Added and tested the StrictMerge option in DecodeOptions, with new tests verifying both the default and legacy (false) behaviors for merging object and primitive values under the same key. [1] [2] [3] [4] [5] [6]
  • Improved handling and tests for duplicate keys, ensuring bracket notation always combines values appropriately regardless of the Duplicates setting.

Array/List Limit Handling:

  • Refined tests to ensure that explicit and implicit array indices respect the ListLimit option, including correct conversion to maps when limits are exceeded and proper exception throwing when ThrowOnLimitExceeded is set. [1] [2] [3] [4] [5]

Comma-Separated Value Handling:

  • Overhauled tests for comma-separated values, ensuring that when the sum of values exceeds the list limit, the decoder now converts the result to a map (overflow map) instead of truncating, and all values are preserved. This behavior is now consistently tested across different scenarios, including bracketed keys and nested lists. [1] [2] [3] [4] [5] [6] [7] [8]

Edge Case and Encoding Tests:

  • Added new tests to ensure correct decoding of percent-encoded bracket characters and that literal percent sequences are not incorrectly decoded, improving robustness for unusual but valid inputs.

These changes enhance the reliability and predictability of the decoder, especially in edge cases and under strict option settings.

Summary by CodeRabbit

  • New Features

    • Added StrictMerge option (defaults to wrapping conflicts); bracket-array keys always combine; refined ListLimit semantics; encoder uses configured delimiter when charset sentinel present.
  • Bug Fixes

    • Preserve percent-encoded bracket text when decoding; improved comma-list null handling and overflow preservation; stricter list-index/overflow behavior.
  • Tests

    • Expanded coverage for list limits, comma-split overflow, duplicate/merge behaviors, encoding round-trips.
  • Documentation

    • Clarified StrictMerge, ListLimit, and bracket-array decoding behavior.
  • Chores

    • Bumped qs dependency to ^6.15.2.

Review Change Stack

@techouse techouse requested a review from Copilot May 28, 2026 09:26
@techouse techouse added the enhancement New feature or request label May 28, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 28, 2026

📝 Walkthrough

Walkthrough

Adds StrictMerge, converts overflowed lists into index-keyed overflow maps, tightens ListLimit boundaries (indices >= limit become map entries or throw), forces bracket-array ([]) keys to always combine, uses configured delimiter in Encode, and updates tests/docs plus a minor package.json bump.

Changes

List Overflow Handling, StrictMerge, and Bracket-Array Semantics

Layer / File(s) Summary
DecodeOptions model: StrictMerge property
QsNet/Models/DecodeOptions.cs
New init-only StrictMerge property (default true) controls whether object/primitive merge conflicts are wrapped into a list; CopyWith accepts strictMerge and wires it through.
Merge and overflow utilities
QsNet/Internal/Utils.cs
Utils.Merge produces a combined two-element list for computed-key dictionary conflicts when StrictMerge is enabled. New MarkListOverflow converts positional lists into overflow-marked index-keyed dictionaries.
Decoder list parsing and bracket-array handling
QsNet/Internal/Decoder.cs
ParseListValue gains enforceListLimit and marks overflow via MarkListOverflow when appropriate. ParseQueryStringValues detects bracket-array keys ([]), converts IDictionary parse results into decoded dictionaries with overflow marking, and forces combine semantics for [] keys. ParseObject treats explicit numeric indices as list entries only when idx < ListLimit; at/above limit it either throws (when enabled) or converts to overflow map.
Qs API: Decode and Encode integration
QsNet/Qs.cs
Qs.Decode routes bracket-array keys into combine-with-limit behavior rather than honoring First/Last-only semantics; Qs.Encode uses opts.Delimiter (not &) when inserting the first body part after a charset sentinel.
Test coverage updates
QsNet.Tests/DecodeOptionsTests.cs, QsNet.Tests/DecodeTests.cs, QsNet.Tests/EncodeTests.cs, QsNet.Tests/UtilsTests.cs
Tests updated/added for StrictMerge wiring, list-limit boundary conversions, bracket-notation duplicate combining, comma-split overflow becoming overflow-maps, bracket-single inner-list exemption, encoded-bracket regressions, and encoder delimiter behavior.
Documentation and dependencies
README.md, docs/docs/decoding.md, QsNet.Comparison/js/package.json
Documentation clarifies bracket-array combine behavior, StrictMerge default/legacy behavior, and ListLimit index handling; JS package.json updates qs to ^6.15.2.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • techouse/qs-net#44: Modifies the same list-limit and overflow machinery in Decoder.cs and Utils.cs, updating tests for overflow-map handling.
  • techouse/qs-net#55: Changes list/array-key ([]) decoding logic in Decoder.cs, touching the same parse paths.
  • techouse/qs-net#13: Touches ParseQueryStringValues/ParseListValue internals related to comma-split parsing and list-limit enforcement.

Suggested labels

test

"I'm a rabbit in the code forest, hopping through arrays,
I wrap conflicts with care and save overflowed days,
Bracket-arrays now gather, commas keep every part,
Delimiters follow settings, tests and docs play their part,
Hooray for tidy parsing—thump, thump, a happy heart!"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.97% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description check ✅ Passed The PR description is comprehensive and well-structured, covering dependency updates, decode options, array/list handling, comma-separated values, and edge cases with relevant links and context.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title mentions adding StrictMerge and improving list-limit handling in decoder tests, which are core features demonstrated across multiple test files and decoder implementation changes in this PR.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/upstream-v2

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 28, 2026

Codecov Report

❌ Patch coverage is 95.65217% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 99.30%. Comparing base (7c24f3e) to head (8e9752f).

Files with missing lines Patch % Lines
QsNet/Internal/Decoder.cs 94.44% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #70      +/-   ##
==========================================
- Coverage   99.38%   99.30%   -0.09%     
==========================================
  Files          20       20              
  Lines        2130     2161      +31     
  Branches      542      552      +10     
==========================================
+ Hits         2117     2146      +29     
- Misses         13       15       +2     
Flag Coverage Δ
unittests 99.30% <95.65%> (-0.09%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@codacy-production
Copy link
Copy Markdown

codacy-production Bot commented May 28, 2026

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics -12 complexity · 0 duplication

Metric Results
Complexity -12
Duplication 0

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
QsNet.Tests/DecodeTests.cs (1)

2668-2668: ⚡ Quick win

Rename new/updated tests to Should... format for suite consistency.

Several new/modified test method names use Decode_* rather than the required Should... naming pattern.

As per coding guidelines, “Name tests in Should... form (e.g., ShouldDecodeNestedObjects).”

Also applies to: 2690-2690, 2718-2718, 2959-2959, 4747-4747, 4772-4772, 4798-4798, 4824-4824, 4866-4866, 4898-4898, 5566-5566, 5588-5588

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@QsNet.Tests/DecodeTests.cs` at line 2668, Rename the test method
Decode_Duplicates_BracketNotationAlwaysCombines to follow the suite's
"Should..." naming convention (e.g.,
ShouldCombineDuplicatesWhenUsingBracketNotation) and update any
references/usages accordingly; also apply the same rename pattern to the other
listed tests (the ones at the indicated ranges) so their names start with
"Should" and describe expected behavior (for example, Decode_* -> Should...
form) to keep the test suite consistent.
QsNet.Tests/EncodeTests.cs (1)

5914-5981: ⚡ Quick win

Rename new test methods to Should... form for suite consistency.

The newly added test method names use Encode_...; this breaks the test naming convention used in this project.

As per coding guidelines, "Name tests in Should... form (e.g., ShouldDecodeNestedObjects); group with nested classes when scenarios grow".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@QsNet.Tests/EncodeTests.cs` around lines 5914 - 5981, Rename the four new
test methods to follow the project's "Should..." naming convention while leaving
their bodies and [Fact] attributes unchanged: change
Encode_StrictNullHandling_FormatsRfc1738BareKey ->
Should_FormatRfc1738BareKeyWhenStrictNullHandling,
Encode_FilterIterable_SkipsNullEntries ->
Should_SkipNullEntriesWhenFilterIterable,
Encode_CommaEncodeValuesOnly_HandlesNullEntriesLikeQs ->
Should_HandleNullEntriesLikeQsWhenCommaEncodeValuesOnly, and
Encode_RoundTripsKeysContainingPercentEncodedBracketText ->
Should_RoundTripKeysContainingPercentEncodedBracketText; update only the method
names in the test class so references (if any) compile and behavior is
identical.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@QsNet.Tests/DecodeTests.cs`:
- Line 2668: Rename the test method
Decode_Duplicates_BracketNotationAlwaysCombines to follow the suite's
"Should..." naming convention (e.g.,
ShouldCombineDuplicatesWhenUsingBracketNotation) and update any
references/usages accordingly; also apply the same rename pattern to the other
listed tests (the ones at the indicated ranges) so their names start with
"Should" and describe expected behavior (for example, Decode_* -> Should...
form) to keep the test suite consistent.

In `@QsNet.Tests/EncodeTests.cs`:
- Around line 5914-5981: Rename the four new test methods to follow the
project's "Should..." naming convention while leaving their bodies and [Fact]
attributes unchanged: change Encode_StrictNullHandling_FormatsRfc1738BareKey ->
Should_FormatRfc1738BareKeyWhenStrictNullHandling,
Encode_FilterIterable_SkipsNullEntries ->
Should_SkipNullEntriesWhenFilterIterable,
Encode_CommaEncodeValuesOnly_HandlesNullEntriesLikeQs ->
Should_HandleNullEntriesLikeQsWhenCommaEncodeValuesOnly, and
Encode_RoundTripsKeysContainingPercentEncodedBracketText ->
Should_RoundTripKeysContainingPercentEncodedBracketText; update only the method
names in the test class so references (if any) compile and behavior is
identical.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2035c00e-c65f-4f61-832e-3087921cdf43

📥 Commits

Reviewing files that changed from the base of the PR and between 7c24f3e and 983056d.

⛔ Files ignored due to path filters (1)
  • QsNet.Comparison/js/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (11)
  • QsNet.Comparison/js/package.json
  • QsNet.Tests/DecodeOptionsTests.cs
  • QsNet.Tests/DecodeTests.cs
  • QsNet.Tests/EncodeTests.cs
  • QsNet.Tests/UtilsTests.cs
  • QsNet/Internal/Decoder.cs
  • QsNet/Internal/Utils.cs
  • QsNet/Models/DecodeOptions.cs
  • QsNet/Qs.cs
  • README.md
  • docs/docs/decoding.md

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates QsNet’s decode/encode behavior and documentation/tests to better match upstream qs behavior, including new decode semantics around merge conflicts, list limits, and bracket-array duplicate handling, plus a qs JS comparison dependency bump.

Changes:

  • Added DecodeOptions.StrictMerge (default true) and updated merge behavior/tests/docs for object/primitive conflicts.
  • Updated decode behavior/tests so foo[] bracket-array duplicates always combine, and refined ListLimit semantics (explicit indices and comma-splitting overflow behavior).
  • Updated encoding output when CharsetSentinel=true to use the configured delimiter (not always &), and bumped qs (JS comparison) to 6.15.2.

Reviewed changes

Copilot reviewed 11 out of 12 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
README.md Documents bracket-array duplicate combining, StrictMerge, and clarified ListLimit semantics.
QsNet/Qs.cs Applies bracket-array duplicate combining to enumerable input bucketing; fixes charset-sentinel/body delimiter joining.
QsNet/Models/DecodeOptions.cs Introduces StrictMerge option and threads it through CopyWith; clarifies ListLimit doc.
QsNet/Internal/Utils.cs Implements StrictMerge merge behavior; adds list-overflow helpers and overflow-aware combining logic.
QsNet/Internal/Decoder.cs Adjusts comma parsing + list-limit enforcement; propagates overflow maps through decoding; explicit-index limit semantics.
QsNet.Tests/UtilsTests.cs Updates merge tests to cover legacy behavior via StrictMerge=false.
QsNet.Tests/EncodeTests.cs Updates delimiter/sentinel expectation and adds additional encode parity/edge-case tests.
QsNet.Tests/DecodeTests.cs Expands decode tests for StrictMerge, bracket-array duplicates, list-limit edges, and comma overflow behavior.
QsNet.Tests/DecodeOptionsTests.cs Extends CopyWith tests to include StrictMerge.
QsNet.Comparison/js/pnpm-lock.yaml Updates locked qs version to 6.15.2.
QsNet.Comparison/js/package.json Bumps qs dependency to ^6.15.2.
docs/docs/decoding.md Mirrors README updates for bracket-array duplicates, StrictMerge, and ListLimit semantics.
Files not reviewed (1)
  • QsNet.Comparison/js/pnpm-lock.yaml: Language not supported

Comment thread QsNet/Internal/Utils.cs Outdated
Comment thread QsNet/Internal/Decoder.cs
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 28, 2026

Actionable comments posted: 0

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 12 changed files in this pull request and generated 2 comments.

Files not reviewed (1)
  • QsNet.Comparison/js/pnpm-lock.yaml: Language not supported

Comment thread QsNet/Internal/Decoder.cs
Comment thread QsNet/Internal/Decoder.cs
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 28, 2026

Actionable comments posted: 0

@techouse techouse changed the title ✨ upstream parity ✨ add StrictMerge option and improve list-limit handling in decoder tests May 28, 2026
@techouse techouse merged commit 1a1d948 into main May 28, 2026
14 of 16 checks passed
@techouse techouse deleted the fix/upstream-v2 branch May 28, 2026 16:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants