Skip to content

Commit 2c73a4e

Browse files
committed
test: add test case for ExclusiveMinMax Test
(#22943)
1 parent df4a1d6 commit 2c73a4e

4 files changed

Lines changed: 525 additions & 7 deletions

File tree

.geminiignore

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# .geminiignore
2+
# This file specifies intentionally untracked files that Gemini CLI should ignore.
3+
# It uses the same pattern matching rules as .gitignore.
4+
5+
# Build artifacts
6+
target/
7+
build/
8+
*.jar
9+
*.war
10+
*.ear
11+
*.class
12+
*.log
13+
14+
# IDE and editor files
15+
.idea/
16+
.vscode/
17+
*.iml
18+
*.ipr
19+
*.iws
20+
21+
# Maven/Gradle wrapper directories
22+
.mvn/wrapper/
23+
.gradle/
24+
25+
# Node.js dependencies for website
26+
website/node_modules/
27+
website/build/
28+
29+
# Generated sources by OpenAPI Generator (usually not to be touched directly)
30+
# This includes sample outputs which are generated code for various languages.
31+
samples/
32+
33+
# Temporary files
34+
tmp/
35+
.DS_Store
36+
# Eclipse
37+
.classpath
38+
.project
39+
.settings
40+
41+
# IntelliJ IDEA
42+
.idea/
43+
*.iml
44+
*.iws
45+
*.iwp
46+
.vscode/
47+
48+
# MacOS
49+
.DS_Store
50+
51+
# ReSharper
52+
*.resharper
53+
54+
# Visual Studio
55+
.vs/
56+
*.user
57+
*.suo
58+
*.sln.docstates
59+
60+
# Other
61+
*.bak
62+
*.swp
63+
*~
64+
.#*
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
/*
2+
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.openapitools.codegen;
18+
19+
import static org.testng.Assert.assertEquals;
20+
import static org.testng.Assert.assertFalse;
21+
import static org.testng.Assert.assertNotNull;
22+
import static org.testng.Assert.assertTrue;
23+
24+
import java.util.Map;
25+
26+
import org.testng.annotations.Test;
27+
28+
import io.swagger.v3.oas.models.OpenAPI;
29+
import io.swagger.v3.oas.models.media.Schema;
30+
31+
public class ExclusiveMinMaxTest {
32+
33+
@Test
34+
public void testCodegen31ExclusiveMinMaxNumericOnly() {
35+
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_1/exclusive-min-max.yaml");
36+
37+
OpenAPINormalizer n = new OpenAPINormalizer(openAPI, Map.of("NORMALIZE_31SPEC", "true"));
38+
n.normalize();
39+
40+
DefaultCodegen config = new DefaultCodegen();
41+
config.setOpenAPI(openAPI);
42+
43+
Schema<?> schema = openAPI.getPaths().get("/x").getGet().getParameters().get(0).getSchema();
44+
45+
CodegenProperty cp = config.fromProperty("price", schema);
46+
47+
// exclusiveMinimum: 0
48+
assertEquals(cp.getMinimum(), "0");
49+
assertTrue(cp.getExclusiveMinimum());
50+
51+
// exclusiveMaximum: 10
52+
assertEquals(cp.getMaximum(), "10");
53+
assertTrue(cp.getExclusiveMaximum());
54+
}
55+
56+
@Test
57+
public void testCodegen31ExclusiveMinMaxStricterThanMinMax() {
58+
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_1/exclusive-min-max.yaml");
59+
60+
OpenAPINormalizer n = new OpenAPINormalizer(openAPI, Map.of("NORMALIZE_31SPEC", "true"));
61+
n.normalize();
62+
63+
DefaultCodegen config = new DefaultCodegen();
64+
config.setOpenAPI(openAPI);
65+
66+
Schema<?> schema = openAPI.getPaths().get("/foo").getGet().getParameters().get(0).getSchema();
67+
CodegenProperty cp = config.fromProperty("foo", schema);
68+
69+
assertEquals(cp.getMinimum(), "1");
70+
assertTrue(cp.getExclusiveMinimum());
71+
72+
assertEquals(cp.getMaximum(), "10");
73+
assertTrue(cp.getExclusiveMaximum());
74+
}
75+
76+
@Test
77+
public void testCodegen31ExclusiveMinMaxEqualToMinMax() {
78+
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_1/exclusive-min-max.yaml");
79+
80+
OpenAPINormalizer n = new OpenAPINormalizer(openAPI, Map.of("NORMALIZE_31SPEC", "true"));
81+
n.normalize();
82+
83+
DefaultCodegen config = new DefaultCodegen();
84+
config.setOpenAPI(openAPI);
85+
86+
Schema<?> schema = openAPI.getPaths().get("/bar").getGet().getParameters().get(0).getSchema();
87+
CodegenProperty cp = config.fromProperty("bar", schema);
88+
89+
// minimum: 0 + exclusiveMinimum: 0 → must remain exclusive
90+
assertEquals(cp.getMinimum(), "0");
91+
assertTrue(cp.getExclusiveMinimum());
92+
93+
// maximum: 10 + exclusiveMaximum: 10 → must remain exclusive
94+
assertEquals(cp.getMaximum(), "10");
95+
assertTrue(cp.getExclusiveMaximum());
96+
}
97+
98+
@Test
99+
public void testCodegen31ExclusiveMinMaxInclusiveStricterThanExclusiveValue() {
100+
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_1/exclusive-min-max.yaml");
101+
102+
OpenAPINormalizer n = new OpenAPINormalizer(openAPI, Map.of("NORMALIZE_31SPEC", "true"));
103+
n.normalize();
104+
105+
DefaultCodegen config = new DefaultCodegen();
106+
config.setOpenAPI(openAPI);
107+
108+
Schema<?> schema = openAPI.getPaths().get("/baz").getGet().getParameters().get(0).getSchema();
109+
CodegenProperty cp = config.fromProperty("baz", schema);
110+
111+
// minimum: 5 is stricter than exclusiveMinimum: 0 (x >= 5 dominates x > 0)
112+
assertEquals(cp.getMinimum(), "5");
113+
assertFalse(Boolean.TRUE.equals(cp.getExclusiveMinimum()));
114+
115+
// maximum: 10 is stricter than exclusiveMaximum: 11 (x <= 10 dominates x < 11)
116+
assertEquals(cp.getMaximum(), "10");
117+
assertFalse(Boolean.TRUE.equals(cp.getExclusiveMaximum()));
118+
}
119+
120+
@Test
121+
public void testCodegen31ExclusiveMinMaxBooleanExclusiveAlreadySet() {
122+
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_1/exclusive-min-max.yaml");
123+
OpenAPINormalizer n = new OpenAPINormalizer(openAPI, Map.of("NORMALIZE_31SPEC", "true"));
124+
n.normalize();
125+
126+
DefaultCodegen config = new DefaultCodegen();
127+
config.setOpenAPI(openAPI);
128+
129+
Schema<?> schema = openAPI.getPaths().get("/old").getGet().getParameters().get(0).getSchema();
130+
CodegenProperty cp = config.fromProperty("old", schema);
131+
132+
// 3.0-style boolean exclusive flags should remain intact
133+
assertEquals(cp.getMinimum(), "0");
134+
assertFalse(Boolean.TRUE.equals(cp.getExclusiveMinimum()));
135+
136+
assertEquals(cp.getMaximum(), "10");
137+
assertFalse(Boolean.TRUE.equals(cp.getExclusiveMaximum()));
138+
}
139+
140+
@Test
141+
public void testCodegenModelWithAllOfOas30() {
142+
// Load OAS 3.0 spec (using standard boolean syntax)
143+
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/exclusive-min-max.yaml");
144+
145+
// Normalize (should not affect existing 3.0 boolean flags)
146+
OpenAPINormalizer n = new OpenAPINormalizer(openAPI, Map.of());
147+
n.normalize();
148+
149+
final Schema<?> priceDto3Schema = openAPI.getComponents().getSchemas().get("PriceDto3");
150+
final CodegenConfig config = new DefaultCodegen();
151+
config.setOpenAPI(openAPI);
152+
final CodegenModel cm = config.fromModel("PriceDto3", priceDto3Schema);
153+
154+
final CodegenProperty historyPrice2Prop = cm
155+
.getVars()
156+
.stream()
157+
.filter(p -> "historyPrice2".equals(p.baseName))
158+
.findFirst()
159+
.orElse(null);
160+
161+
assertNotNull(historyPrice2Prop, "OAS 3.0: PriceDto3 should contain historyPrice2");
162+
163+
// Verify that under OAS 3.0, allOf composition correctly preserves the
164+
// exclusiveMinimum flag
165+
assertEquals(historyPrice2Prop.getMinimum(), "3001");
166+
assertTrue(historyPrice2Prop.getExclusiveMinimum(), "OAS 3.0: historyPrice2 exclusiveMinimum should be true");
167+
}
168+
169+
@Test
170+
public void testCodegenModelWithAllOfNormalization() {
171+
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_1/exclusive-min-max.yaml");
172+
173+
// 1. Run normalization
174+
OpenAPINormalizer n = new OpenAPINormalizer(openAPI, Map.of("NORMALIZE_31SPEC", "true"));
175+
n.normalize();
176+
177+
// 2. Simulate Codegen processing PriceDto3 (which uses allOf to reference
178+
// PriceDto2)
179+
final Schema<?> priceDto3Schema = openAPI.getComponents().getSchemas().get("PriceDto3");
180+
final CodegenConfig config = new DefaultCodegen();
181+
config.setOpenAPI(openAPI);
182+
final CodegenModel cm = config.fromModel("PriceDto3", priceDto3Schema);
183+
184+
// 3. Check historyPrice2 property inherited from PriceDto2
185+
final CodegenProperty historyPrice2Prop = cm
186+
.getVars()
187+
.stream()
188+
.filter(p -> "historyPrice2".equals(p.baseName))
189+
.findFirst()
190+
.orElse(null);
191+
192+
assertNotNull(historyPrice2Prop, "PriceDto3 should contain inherited historyPrice2 property from PriceDto2");
193+
194+
// Verify that CodegenProperty received normalized values and flags
195+
assertEquals(historyPrice2Prop.getMinimum(), "3101", "historyPrice2 minimum should be 3101");
196+
assertTrue(historyPrice2Prop.getExclusiveMinimum(), "historyPrice2 exclusiveMinimum should be true");
197+
}
198+
199+
}
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
openapi: 3.0.0
2+
info:
3+
title: ExclusiveMinMax Test OAS 3.0
4+
version: 1.0.0
5+
paths:
6+
/savePrice:
7+
post:
8+
summary: ''
9+
operationId: postPrice
10+
responses:
11+
'200':
12+
description: OK
13+
requestBody:
14+
content:
15+
application/json:
16+
schema:
17+
type: object
18+
properties:
19+
price:
20+
type: number
21+
minimum: 0
22+
exclusiveMinimum: true
23+
maximum: 10
24+
exclusiveMaximum: true
25+
sellingPrice:
26+
type: number
27+
minimum: 0
28+
maximum: 10
29+
historys:
30+
type: array
31+
items:
32+
type: object
33+
properties:
34+
historyPrice0:
35+
type: number
36+
minimum: 0
37+
exclusiveMinimum: true
38+
maximum: 10
39+
exclusiveMaximum: true
40+
historySellingPrice0:
41+
type: number
42+
minimum: 0
43+
maximum: 10
44+
required:
45+
- historyPrice0
46+
- historySellingPrice0
47+
required:
48+
- price
49+
- sellingPrice
50+
description: ''
51+
put:
52+
summary: ''
53+
operationId: putPrice
54+
responses:
55+
'200':
56+
description: OK
57+
requestBody:
58+
content:
59+
application/json:
60+
schema:
61+
$ref: '#/components/schemas/PriceDto1'
62+
components:
63+
schemas:
64+
PriceDto1:
65+
title: PriceDto1
66+
type: object
67+
properties:
68+
price:
69+
type: number
70+
minimum: 0
71+
exclusiveMinimum: true
72+
maximum: 10
73+
exclusiveMaximum: true
74+
sellingPrice:
75+
type: number
76+
minimum: 0
77+
maximum: 10
78+
historys:
79+
type: array
80+
items:
81+
type: object
82+
properties:
83+
historyPrice1:
84+
type: number
85+
minimum: 0
86+
exclusiveMinimum: true
87+
maximum: 10
88+
exclusiveMaximum: true
89+
historySellingPrice1:
90+
type: number
91+
minimum: 0
92+
maximum: 10
93+
required:
94+
- historyPrice1
95+
- historySellingPrice1
96+
historys2:
97+
type: array
98+
items:
99+
$ref: '#/components/schemas/PriceDto2'
100+
historys3:
101+
type: array
102+
items:
103+
$ref: '#/components/schemas/PriceDto3'
104+
required:
105+
- price
106+
- sellingPrice
107+
PriceDto2:
108+
title: PriceDto2
109+
type: object
110+
properties:
111+
historyPrice2:
112+
type: number
113+
minimum: 3001
114+
exclusiveMinimum: true
115+
maximum: 3002
116+
exclusiveMaximum: true
117+
historySellingPrice2:
118+
type: number
119+
minimum: 3003
120+
maximum: 3004
121+
required:
122+
- historyPrice2
123+
- historySellingPrice2
124+
PriceDto3:
125+
title: PriceDto3
126+
allOf:
127+
- type: object
128+
properties:
129+
id:
130+
type: string
131+
- $ref: '#/components/schemas/PriceDto2'

0 commit comments

Comments
 (0)