Skip to content

Commit fb9c473

Browse files
mromaszewiczclaude
andcommitted
fix: apply collision strategies in global phases to prevent oscillation
When multiple content types map to the same short suffix (e.g., application/json, application/merge-patch+json, and application/json-patch+json all mapping to "JSON"), the per-group strategy cascade caused an infinite oscillation: context suffix appended "RequestBody", then content type suffix appended "JSON", then context suffix fired again because the name no longer ended in "RequestBody", ad infinitum. Fix by restructuring resolveCollisions to apply each strategy as a global phase: exhaust one strategy across ALL colliding groups (re-checking for new collisions after each pass) before advancing to the next strategy. This ensures numeric fallback is reached when earlier strategies cannot disambiguate. Also fix resolvedNameForComponent to accept an optional content type for exact matching, so each media type variant of a requestBody or response gets its own resolved name instead of all variants receiving whichever name the map iterator returns first. Adds Pattern H test case (TMF622 scenario from PR #2213): a component that exists in both schemas and requestBodies where the requestBody has 3 content types that all collapse to the "JSON" short name. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 67b8ec9 commit fb9c473

File tree

6 files changed

+491
-23
lines changed

6 files changed

+491
-23
lines changed

internal/test/name_conflict_resolution/name_conflict_resolution.gen.go

Lines changed: 260 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/test/name_conflict_resolution/name_conflict_resolution_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,61 @@ func TestSchemaMatchesOpResponse(t *testing.T) {
136136
assert.Equal(t, "healthy", *wrapper.JSON200.Status)
137137
}
138138

139+
// TestMultipleJsonContentTypes verifies Pattern H: schema "Order" collides with
140+
// requestBody "Order" which has 3 content types that all contain "json":
141+
// - application/json
142+
// - application/merge-patch+json
143+
// - application/json-patch+json
144+
//
145+
// All three map to the same "JSON" short name via contentTypeSuffix(), which
146+
// would trigger an infinite oscillation between context suffix ("RequestBody")
147+
// and content type suffix ("JSON") strategies if applied per-group. The global
148+
// phase approach lets numeric fallback break the cycle.
149+
//
150+
// Expected types:
151+
// - Order struct (schema keeps bare name)
152+
// - OrderRequestBodyJSON struct (application/json requestBody)
153+
// - OrderRequestBodyJSON2 []struct (application/json-patch+json, numeric fallback)
154+
// - OrderRequestBodyJSON3 struct (application/merge-patch+json, numeric fallback)
155+
//
156+
// Covers: PR #2213 (TMF622 scenario)
157+
func TestMultipleJsonContentTypes(t *testing.T) {
158+
// Schema type keeps bare name "Order"
159+
order := Order{
160+
Id: ptr("order-1"),
161+
Product: ptr("Widget"),
162+
}
163+
assert.Equal(t, "order-1", *order.Id)
164+
assert.Equal(t, "Widget", *order.Product)
165+
166+
// The 3 requestBody content types should each get a unique name.
167+
// They all collide on "OrderRequestBodyJSON", so numeric fallback kicks in.
168+
// The type names below are compile-time assertions that all 3 exist and are distinct.
169+
170+
// application/json requestBody
171+
jsonBody := OrderRequestBodyJSON{
172+
Id: ptr("order-2"),
173+
Product: ptr("Gadget"),
174+
}
175+
assert.Equal(t, "order-2", *jsonBody.Id)
176+
177+
// application/json-patch+json requestBody (numeric fallback, array type alias)
178+
var jsonPatch OrderRequestBodyJSON2
179+
assert.Nil(t, jsonPatch)
180+
181+
// application/merge-patch+json requestBody (numeric fallback)
182+
mergePatch := OrderRequestBodyJSON3{
183+
Product: ptr("Gadget-patched"),
184+
}
185+
assert.Equal(t, "Gadget-patched", *mergePatch.Product)
186+
187+
// CreateOrder wrapper should not collide
188+
var wrapper CreateOrderResponse
189+
assert.Nil(t, wrapper.JSON200)
190+
wrapper.JSON200 = &order
191+
assert.Equal(t, "order-1", *wrapper.JSON200.Id)
192+
}
193+
139194
// TestRequestBodyVsSchema verifies that "Pet" in schemas and requestBodies
140195
// resolves correctly: the schema keeps bare name "Pet", the requestBody
141196
// gets "PetRequestBody".

0 commit comments

Comments
 (0)