Skip to content

fix: resolve dollar-ref chains and disambiguate component sections - #131

Open
MaxMichel2 wants to merge 1 commit into
refactor/mock-http-client-call-internalfrom
fix/openapi-ref-resolution
Open

MaxMichel2 wants to merge 1 commit into
refactor/mock-http-client-call-internalfrom
fix/openapi-ref-resolution

Conversation

@MaxMichel2

Copy link
Copy Markdown
Collaborator

Summary

Stacked on #126 (PR chain: #123 → #124 → #127 → #128 → #129 → #126 → this) — merge in order.

OpenApiParser.resolveRef keyed resolved $ref targets by a fragment's trailing name segment only, ignoring which components.<section> it actually named, and followed a $ref chain exactly one level deep (a resolved entry's own $ref, if any, was not followed further). Real specs' components sections cross-reference and chain more than this parser could handle — this is a prerequisite for #82/#84 (schema synthesis), which will need to resolve $ref chains through components.schemas the same way.

What changed

  • OpenApiParser.resolveRef (private, inside ParseContext): now takes an explicit section parameter ("parameters"/"responses"/"examples"/"headers") and validates a fragment's declared section against it — a $ref naming an unexpected section is rejected with a clear error instead of being silently resolved against whatever map the call site happened to expect, so a same-named entry in a different section can never be conflated with the one actually referenced.
  • Converted from a single lookup into a loop that keeps resolving as long as a resolved entry itself declares a $ref (via a new refOf parameter), until a non-ref entry is reached — a $ref chain is now followed to completion instead of stopping after one hop.
  • Cycle guard: a visited: MutableSet<Pair<OpenApiDocument, String>> tracks every (document, fragment) hop; revisiting one throws a clear IllegalStateException instead of looping forever.
  • Updated all four call sites (resolveParameter, and the response/example/header refs inside resolveResponseIndex/resolveHeaders) and the class-level KDoc's "Scope decisions" section to match.
  • docs/modules/networkmock-core.md's "$ref resolution" section updated — it documented the now-fixed "one level deep" limitation.

Public API

None — the openapi package stays internal (see #73's pure-seam requirement). No api.txt diff.

Tests

Added to MockConfigRepositoryTest.kt, following the existing $ref test fixtures' style:

  • `dollar-ref naming the wrong components section is rejected even if a same-named entry exists there` — a response $ref pointing at components/parameters/... instead of components/responses/..., with a same-named entry in both sections, now fails clearly instead of resolving against whichever map the call site expected.
  • `local dollar-ref chain of two hops resolves to the final non-ref entry` — A → B → literal content.
  • `cyclic dollar-ref chain fails clearly instead of hanging` — A → B → A.

Verification

.\gradlew.bat detektFull -Pandroidx.baselineprofile.skipgeneration
.\gradlew.bat testAndroidHostTest -Pandroidx.baselineprofile.skipgeneration
.\gradlew.bat :konsist:test -Pandroidx.baselineprofile.skipgeneration

All green, including a full repo-wide testAndroidHostTest run to confirm no fallout outside the networkmock modules.

🤖 Generated with GitHub Copilot

@MaxMichel2 MaxMichel2 changed the title 🐛 fix: resolve dollar-ref chains and disambiguate component sections fix: resolve dollar-ref chains and disambiguate component sections Sep 23, 2026
@MaxMichel2
MaxMichel2 added this pull request to stack #130 September 23, 2026 12:39
OpenApiParser.resolveRef previously keyed resolved components by a ref's
trailing name segment only, ignoring which components.<section> it named,
and followed a chain exactly one level deep.

This fixes both: a ref's fragment must now declare the section its call site
expects (parameters/responses/examples/headers), so a same-named entry in a
different section can never be silently conflated with the one actually
referenced; and ref chains are followed until a non-ref entry is reached,
guarded by a visited-set of (document, fragment) pairs that fails clearly on
a cycle instead of hanging.

This branch has not been deployed

No deployments
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.

1 participant