Skip to content

V10.1.1/fix semver - #33

Closed
gimlichael wants to merge 4 commits into
mainfrom
v10.1.1/fix-semver
Closed

V10.1.1/fix semver#33
gimlichael wants to merge 4 commits into
mainfrom
v10.1.1/fix-semver

Conversation

@gimlichael

Copy link
Copy Markdown
Member

This pull request introduces enhanced support for semantic API versioning, improves compatibility with standard API versions, and adds comprehensive functional tests to ensure correct routing and negotiation based on various version formats. It also includes minor documentation and configuration updates.

Semantic API Versioning Improvements:

  • Updated SemanticApiVersion to improve compatibility with standard ApiVersion by adding the IsCompatibleWithStandardApiVersion method and refining the logic in GetHashCode and Equals to handle standard and semantic versions more robustly. [1] [2] [3]

  • Enhanced SemanticApiVersionParser to correctly parse numeric and dotted version formats, supporting both short and full semantic version strings.

Functional Testing Enhancements:

  • Added a new functional test project Codebelt.Extensions.Asp.Versioning.FunctionalTests with tests for semantic version compatibility and non-production scenarios, ensuring correct routing, negotiation, and status codes for various HTTP methods and version formats. [1] [2] [3]

Documentation and Configuration Updates:

  • Updated .docfx/toc.yml and .docfx/docfx.json to fix links and adjust file exclusions for documentation generation. [1] [2]

  • Added the new functional test project to the solution file Codebelt.Extensions.Asp.Versioning.slnx.

aicia-bot added 4 commits July 7, 2026 18:09
Extended SemanticApiVersion to support equality and hashing with standard ApiVersion when patch version is zero and no prerelease or build metadata is present. Updated SemanticApiVersionParser to accept shorthand semantic version formats (major only, or major.minor) in addition to full major.minor.patch format.
Added comprehensive unit test coverage for SemanticApiVersion compatibility with standard ApiVersion. Tests verify equality, hash code consistency, and parser support for shorthand semantic version formats (major only and major.minor).
Introduced Codebelt.Extensions.Asp.Versioning.FunctionalTests project with end-to-end test scenarios covering production and non-production compatibility use cases. Tests verify semantic version behavior across real middleware and application context. Updated solution file to include the new test project.
Updated namespace documentation and DocFX publishing configuration to reflect semantic version compatibility feature. Clarified behavior of SemanticApiVersion equality and comparison semantics. Updated site navigation and doc build metadata.
@gimlichael gimlichael self-assigned this Jul 7, 2026
@greptile-apps

greptile-apps Bot commented Jul 7, 2026

Copy link
Copy Markdown

Greptile Summary

This PR improves SemanticApiVersion compatibility with standard ApiVersion by allowing short version strings ("1", "1.2") to be parsed and treated as equivalent to their standard counterparts, and adds a comprehensive functional test suite covering routing, negotiation, and status-code behavior across all HTTP methods.

  • SemanticApiVersionParser now accepts 1- and 2-segment inputs ("1" → 1.0.0, "1.2" → 1.2.0), enabling API clients to send abbreviated version strings without breaking routing.
  • SemanticApiVersion gains IsCompatibleWithStandardApiVersion() which makes a patch-zero, release-only semantic version hash- and equality-compatible with the equivalent ApiVersion, and the Equals(object) override was broadened from is SemanticApiVersion to is ApiVersion to allow cross-type comparison.
  • SemanticApiVersionNonProduction passes typeof(SemanticApiVersionProduction) to the base constructor instead of typeof(SemanticApiVersionNonProduction), a copy-paste error that will likely scope the managed test host incorrectly and cause those tests to run against the wrong application configuration.

Confidence Score: 3/5

The core library changes are well-reasoned and backed by new unit tests, but the NonProduction functional test class has a constructor that references the wrong type and will run its tests against the wrong host setup.

The typeof(SemanticApiVersionProduction) copy-paste in SemanticApiVersionNonProduction's constructor means those test cases are effectively testing the production host rather than the non-production one, providing no coverage guarantee for the scenarios they were written for. The SemanticApiVersion equality change is architecturally sound but leans on the Asp.Versioning library's virtual dispatch behavior for cross-type symmetry.

test/Codebelt.Extensions.Asp.Versioning.FunctionalTests/SemanticApiVersionNonProduction.cs — wrong type argument in base constructor call

Important Files Changed

Filename Overview
src/Codebelt.Extensions.Asp.Versioning/SemanticApiVersion.cs Adds IsCompatibleWithStandardApiVersion(), updates GetHashCode() and Equals() to treat patch-zero release versions as equal to standard ApiVersion; equality symmetry relies on Asp.Versioning library dispatch behavior
src/Codebelt.Extensions.Asp.Versioning/SemanticApiVersionParser.cs Extended TryReadCore to accept 1- and 2-segment version strings ("1" → 1.0.0, "1.2" → 1.2.0); logic is correct and tests cover the new cases
test/Codebelt.Extensions.Asp.Versioning.FunctionalTests/SemanticApiVersionNonProduction.cs New functional test class for non-production semantic versions, but the base constructor passes typeof(SemanticApiVersionProduction) instead of typeof(SemanticApiVersionNonProduction), likely scoping the test host incorrectly
test/Codebelt.Extensions.Asp.Versioning.FunctionalTests/SemanticApiVersionProduction.cs New functional test class covering routing, version negotiation, and unsupported version handling for production semantic versions across all standard HTTP methods; looks correct
test/Codebelt.Extensions.Asp.Versioning.FunctionalTests/SemanticApiVersionCompatibility.cs New functional test verifying that short semantic format versions ("1", "1.0", "1.0.0") route identically to their ApiVersion counterparts; well-structured theory data and assertions
test/Codebelt.Extensions.Asp.Versioning.Tests/SemanticApiVersionTest.cs Adds unit tests for cross-type equality, parser short-format support, and updated invalid-input cases; changes are consistent with the SemanticApiVersion and parser updates

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["SemanticApiVersion.Equals(ApiVersion other)"] --> B{other is SemanticApiVersion?}
    B -- Yes --> C["Compare Major, Minor, Patch,\nPrerelease, BuildMetadata\n(full SemVer identity)"]
    B -- No --> D{other is null?}
    D -- Yes --> E["return false"]
    D -- No --> F{IsCompatibleWithStandardApiVersion?\nPatch==0 && no Prerelease && no BuildMetadata}
    F -- No --> G["return false"]
    F -- Yes --> H{Major & Minor match? Status empty?}
    H -- Yes --> I["return true (equal to standard ApiVersion)"]
    H -- No --> J["return false"]
    K["SemanticApiVersionParser.TryReadCore(text)"] --> Q{Dots found?}
    Q -- No dot --> R["major only, minor=0, patch=0"]
    Q -- One dot --> S["major.minor, patch=0"]
    Q -- Two dots --> T["major.minor.patch (original)"]
    Q -- More than two --> U["return false"]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A["SemanticApiVersion.Equals(ApiVersion other)"] --> B{other is SemanticApiVersion?}
    B -- Yes --> C["Compare Major, Minor, Patch,\nPrerelease, BuildMetadata\n(full SemVer identity)"]
    B -- No --> D{other is null?}
    D -- Yes --> E["return false"]
    D -- No --> F{IsCompatibleWithStandardApiVersion?\nPatch==0 && no Prerelease && no BuildMetadata}
    F -- No --> G["return false"]
    F -- Yes --> H{Major & Minor match? Status empty?}
    H -- Yes --> I["return true (equal to standard ApiVersion)"]
    H -- No --> J["return false"]
    K["SemanticApiVersionParser.TryReadCore(text)"] --> Q{Dots found?}
    Q -- No dot --> R["major only, minor=0, patch=0"]
    Q -- One dot --> S["major.minor, patch=0"]
    Q -- Two dots --> T["major.minor.patch (original)"]
    Q -- More than two --> U["return false"]
Loading

Comments Outside Diff (1)

  1. src/Codebelt.Extensions.Asp.Versioning/SemanticApiVersion.cs, line 107-163 (link)

    P2 Cross-type equality symmetry depends on library internals

    SemanticApiVersion.Equals(ApiVersion other) now returns true when comparing a compatible semantic version (e.g. SemanticApiVersion(1, 0, 0)) to a standard ApiVersion(1, 0). For the Equals contract to hold, standard.Equals(semantic) must return the same result. That dispatch goes through ApiVersion.Equals(ApiVersion other) (the base class method on the standard receiver), which has no knowledge of PatchVersion. If the library's ApiVersion.Equals only compares MajorVersion, MinorVersion, and Status, then ApiVersion(1, 2).Equals(SemanticApiVersion(1, 2, 3)) would return true even though SemanticApiVersion(1, 2, 3).Equals(ApiVersion(1, 2)) returns false — violating the symmetry contract and breaking collections or dictionaries that rely on it. The new unit tests (Assert.False(standard.Equals(semantic))) implicitly validate this, but their correctness hinges on the library's virtual dispatch behavior. If a future library upgrade changes that behavior, this contract will silently break.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: src/Codebelt.Extensions.Asp.Versioning/SemanticApiVersion.cs
    Line: 107-163
    
    Comment:
    **Cross-type equality symmetry depends on library internals**
    
    `SemanticApiVersion.Equals(ApiVersion other)` now returns `true` when comparing a compatible semantic version (e.g. `SemanticApiVersion(1, 0, 0)`) to a standard `ApiVersion(1, 0)`. For the `Equals` contract to hold, `standard.Equals(semantic)` must return the same result. That dispatch goes through `ApiVersion.Equals(ApiVersion other)` (the base class method on the `standard` receiver), which has no knowledge of `PatchVersion`. If the library's `ApiVersion.Equals` only compares `MajorVersion`, `MinorVersion`, and `Status`, then `ApiVersion(1, 2).Equals(SemanticApiVersion(1, 2, 3))` would return `true` even though `SemanticApiVersion(1, 2, 3).Equals(ApiVersion(1, 2))` returns `false` — violating the symmetry contract and breaking collections or dictionaries that rely on it. The new unit tests (`Assert.False(standard.Equals(semantic))`) implicitly validate this, but their correctness hinges on the library's virtual dispatch behavior. If a future library upgrade changes that behavior, this contract will silently break.
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
test/Codebelt.Extensions.Asp.Versioning.FunctionalTests/SemanticApiVersionNonProduction.cs:37-39
**Wrong type reference in base constructor call**

The constructor passes `typeof(SemanticApiVersionProduction)` instead of `typeof(SemanticApiVersionNonProduction)`. If `MinimalWebHostTest` uses this type to key or scope the managed test host instance (as the name `ManagedWebMinimalHostFixture` suggests), both classes will share the same host scope — meaning `SemanticApiVersionNonProduction` will get a host configured with the routes and settings from `SemanticApiVersionProduction` rather than its own. This would cause every `SemanticApiVersionNonProduction` test to run against the wrong application configuration.

```suggestion
    public SemanticApiVersionNonProduction(ManagedWebMinimalHostFixture hostFixture, ITestOutputHelper output) : base(hostFixture, output, typeof(SemanticApiVersionNonProduction))
    {
    }
```

### Issue 2 of 2
src/Codebelt.Extensions.Asp.Versioning/SemanticApiVersion.cs:107-163
**Cross-type equality symmetry depends on library internals**

`SemanticApiVersion.Equals(ApiVersion other)` now returns `true` when comparing a compatible semantic version (e.g. `SemanticApiVersion(1, 0, 0)`) to a standard `ApiVersion(1, 0)`. For the `Equals` contract to hold, `standard.Equals(semantic)` must return the same result. That dispatch goes through `ApiVersion.Equals(ApiVersion other)` (the base class method on the `standard` receiver), which has no knowledge of `PatchVersion`. If the library's `ApiVersion.Equals` only compares `MajorVersion`, `MinorVersion`, and `Status`, then `ApiVersion(1, 2).Equals(SemanticApiVersion(1, 2, 3))` would return `true` even though `SemanticApiVersion(1, 2, 3).Equals(ApiVersion(1, 2))` returns `false` — violating the symmetry contract and breaking collections or dictionaries that rely on it. The new unit tests (`Assert.False(standard.Equals(semantic))`) implicitly validate this, but their correctness hinges on the library's virtual dispatch behavior. If a future library upgrade changes that behavior, this contract will silently break.

Reviews (1): Last reviewed commit: "📝 update api documentation for semantic..." | Re-trigger Greptile

@codecov

codecov Bot commented Jul 7, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.24%. Comparing base (cf312b0) to head (901cd96).

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #33      +/-   ##
==========================================
- Coverage   99.60%   99.24%   -0.36%     
==========================================
  Files          10       10              
  Lines         510      533      +23     
  Branches       82       89       +7     
==========================================
+ Hits          508      529      +21     
- Misses          2        4       +2     

☔ View full report in Codecov by Harness.
📢 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.

Comment on lines +37 to +39
public SemanticApiVersionNonProduction(ManagedWebMinimalHostFixture hostFixture, ITestOutputHelper output) : base(hostFixture, output, typeof(SemanticApiVersionProduction))
{
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Wrong type reference in base constructor call

The constructor passes typeof(SemanticApiVersionProduction) instead of typeof(SemanticApiVersionNonProduction). If MinimalWebHostTest uses this type to key or scope the managed test host instance (as the name ManagedWebMinimalHostFixture suggests), both classes will share the same host scope — meaning SemanticApiVersionNonProduction will get a host configured with the routes and settings from SemanticApiVersionProduction rather than its own. This would cause every SemanticApiVersionNonProduction test to run against the wrong application configuration.

Suggested change
public SemanticApiVersionNonProduction(ManagedWebMinimalHostFixture hostFixture, ITestOutputHelper output) : base(hostFixture, output, typeof(SemanticApiVersionProduction))
{
}
public SemanticApiVersionNonProduction(ManagedWebMinimalHostFixture hostFixture, ITestOutputHelper output) : base(hostFixture, output, typeof(SemanticApiVersionNonProduction))
{
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: test/Codebelt.Extensions.Asp.Versioning.FunctionalTests/SemanticApiVersionNonProduction.cs
Line: 37-39

Comment:
**Wrong type reference in base constructor call**

The constructor passes `typeof(SemanticApiVersionProduction)` instead of `typeof(SemanticApiVersionNonProduction)`. If `MinimalWebHostTest` uses this type to key or scope the managed test host instance (as the name `ManagedWebMinimalHostFixture` suggests), both classes will share the same host scope — meaning `SemanticApiVersionNonProduction` will get a host configured with the routes and settings from `SemanticApiVersionProduction` rather than its own. This would cause every `SemanticApiVersionNonProduction` test to run against the wrong application configuration.

```suggestion
    public SemanticApiVersionNonProduction(ManagedWebMinimalHostFixture hostFixture, ITestOutputHelper output) : base(hostFixture, output, typeof(SemanticApiVersionNonProduction))
    {
    }
```

How can I resolve this? If you propose a fix, please make it concise.

@gimlichael gimlichael closed this Jul 7, 2026
@gimlichael
gimlichael deleted the v10.1.1/fix-semver branch July 7, 2026 16:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants