Skip to content

Commit a024d91

Browse files
thcedclaude
andcommitted
test: Add polymorphic-body integration coverage for oneOf
Replace stub /anyOf and /allOf fixture routes with a real /shapes endpoint that uses oneOf to discriminate between circle and square request bodies. Adds an integration test verifying both valid branches return 200 and that bodies matching zero branches return 400 application/problem+json with the oneOf keyword in the body. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent a1bc0c0 commit a024d91

4 files changed

Lines changed: 165 additions & 12 deletions

File tree

src/test/java/com/retailsvc/http/OpenApiServerIT.java

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,4 +402,92 @@ void getPathParams_shouldReturnInternalErrorOnMissingHandler() {
402402
}
403403
}
404404
}
405+
406+
@Nested
407+
class Shapes {
408+
409+
String path = "/shapes";
410+
411+
@Test
412+
void postShape_validCircleReturns200() {
413+
try (var server =
414+
newServer(Map.of("post-shape", new com.retailsvc.http.start.PolymorphicHandler()));
415+
var client = httpClient()) {
416+
var body = "{\"kind\":\"circle\",\"radius\":2.5}";
417+
var request = newRequest(server, path, "POST", ofString(body));
418+
419+
var response = client.send(request, BodyHandlers.ofString());
420+
421+
assertThat(response.statusCode()).isEqualTo(200);
422+
assertThat(response.body()).contains("\"ok\":true");
423+
} catch (IOException e) {
424+
fail(e);
425+
} catch (InterruptedException e) {
426+
Thread.currentThread().interrupt();
427+
fail(e);
428+
}
429+
}
430+
431+
@Test
432+
void postShape_validSquareReturns200() {
433+
try (var server =
434+
newServer(Map.of("post-shape", new com.retailsvc.http.start.PolymorphicHandler()));
435+
var client = httpClient()) {
436+
var body = "{\"kind\":\"square\",\"side\":3}";
437+
var request = newRequest(server, path, "POST", ofString(body));
438+
439+
var response = client.send(request, BodyHandlers.ofString());
440+
441+
assertThat(response.statusCode()).isEqualTo(200);
442+
} catch (IOException e) {
443+
fail(e);
444+
} catch (InterruptedException e) {
445+
Thread.currentThread().interrupt();
446+
fail(e);
447+
}
448+
}
449+
450+
@Test
451+
void postShape_unknownKindReturns400() {
452+
// matches zero branches: "kind" is neither "circle" nor "square".
453+
try (var server =
454+
newServer(Map.of("post-shape", new com.retailsvc.http.start.PolymorphicHandler()));
455+
var client = httpClient()) {
456+
var body = "{\"kind\":\"triangle\",\"side\":3}";
457+
var request = newRequest(server, path, "POST", ofString(body));
458+
459+
var response = client.send(request, BodyHandlers.ofString());
460+
461+
assertThat(response.statusCode()).isEqualTo(400);
462+
assertThat(response.headers().firstValue("Content-Type").orElse(""))
463+
.contains("application/problem+json");
464+
assertThat(response.body()).contains("oneOf");
465+
} catch (IOException e) {
466+
fail(e);
467+
} catch (InterruptedException e) {
468+
Thread.currentThread().interrupt();
469+
fail(e);
470+
}
471+
}
472+
473+
@Test
474+
void postShape_missingDiscriminatorReturns400() {
475+
// omitting "kind" makes both branches fail "required".
476+
try (var server =
477+
newServer(Map.of("post-shape", new com.retailsvc.http.start.PolymorphicHandler()));
478+
var client = httpClient()) {
479+
var body = "{\"radius\":2.5}";
480+
var request = newRequest(server, path, "POST", ofString(body));
481+
482+
var response = client.send(request, BodyHandlers.ofString());
483+
484+
assertThat(response.statusCode()).isEqualTo(400);
485+
} catch (IOException e) {
486+
fail(e);
487+
} catch (InterruptedException e) {
488+
Thread.currentThread().interrupt();
489+
fail(e);
490+
}
491+
}
492+
}
405493
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.retailsvc.http.start;
2+
3+
import com.sun.net.httpserver.HttpExchange;
4+
import com.sun.net.httpserver.HttpHandler;
5+
import java.io.IOException;
6+
import java.nio.charset.StandardCharsets;
7+
8+
public class PolymorphicHandler implements HttpHandler {
9+
10+
@Override
11+
public void handle(HttpExchange exchange) throws IOException {
12+
byte[] body = "{\"ok\":true}".getBytes(StandardCharsets.UTF_8);
13+
exchange.getResponseHeaders().add("Content-Type", "application/json");
14+
exchange.sendResponseHeaders(200, body.length);
15+
try (var out = exchange.getResponseBody()) {
16+
out.write(body);
17+
}
18+
}
19+
}

src/test/resources/openapi.json

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -170,14 +170,37 @@
170170
}
171171
}
172172
},
173-
"/anyOf": {
173+
"/shapes": {
174174
"post": {
175-
176-
}
177-
},
178-
"/allOf": {
179-
"post": {
180-
175+
"operationId": "post-shape",
176+
"requestBody": {
177+
"required": true,
178+
"content": {
179+
"application/json": {
180+
"schema": {
181+
"oneOf": [
182+
{
183+
"type": "object",
184+
"required": ["kind", "radius"],
185+
"properties": {
186+
"kind": { "type": "string", "enum": ["circle"] },
187+
"radius": { "type": "number" }
188+
}
189+
},
190+
{
191+
"type": "object",
192+
"required": ["kind", "side"],
193+
"properties": {
194+
"kind": { "type": "string", "enum": ["square"] },
195+
"side": { "type": "number" }
196+
}
197+
}
198+
]
199+
}
200+
}
201+
}
202+
},
203+
"responses": { "200": { "description": "OK" } }
181204
}
182205
}
183206
},

src/test/resources/openapi.yaml

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,11 +109,34 @@ paths:
109109
"200":
110110
description: OK
111111

112-
/anyOf:
113-
post: {}
114-
115-
/allOf:
116-
post: {}
112+
/shapes:
113+
post:
114+
operationId: post-shape
115+
requestBody:
116+
required: true
117+
content:
118+
application/json:
119+
schema:
120+
oneOf:
121+
- type: object
122+
required: [kind, radius]
123+
properties:
124+
kind:
125+
type: string
126+
enum: [circle]
127+
radius:
128+
type: number
129+
- type: object
130+
required: [kind, side]
131+
properties:
132+
kind:
133+
type: string
134+
enum: [square]
135+
side:
136+
type: number
137+
responses:
138+
"200":
139+
description: OK
117140

118141
components:
119142
parameters:

0 commit comments

Comments
 (0)