1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.juneau.bean.openapi3;
18
19 import static org.apache.juneau.TestUtils.*;
20 import static org.apache.juneau.bean.openapi3.OpenApiBuilder.*;
21 import static org.junit.jupiter.api.Assertions.*;
22
23 import java.net.*;
24
25 import org.apache.juneau.*;
26 import org.junit.jupiter.api.*;
27
28
29
30
31 class OpenApi_Test extends TestBase {
32
33 @Nested class A_basicTests extends TestBase {
34
35 private static final BeanTester<OpenApi> TESTER =
36 testBean(
37 bean()
38 .setComponents(components().setSchemas(map("a1", schemaInfo().setType("a2"))))
39 .setExternalDocs(externalDocumentation().setUrl(URI.create("b")))
40 .setInfo(info().setTitle("c1").setVersion("c2"))
41 .setOpenapi("3.0.0")
42 .setPaths(map("d1", pathItem().setGet(operation().setSummary("d2"))))
43 .setSecurity(list(securityRequirement().setRequirements(map("e1",list("e2")))))
44 .setServers(list(server().setUrl(URI.create("f"))))
45 .setTags(list(tag().setName("g")))
46 )
47 .props("components{schemas{a1{type}}},externalDocs{url},info{title,version},openapi,paths{d1{get{summary}}},security{0{requirements{e1}}},servers{0{url}},tags{0{name}}")
48 .vals("{{{a2}}},{b},{c1,c2},3.0.0,{{{d2}}},{{{[e2]}}},{{f}},{{g}}")
49 .json("{components:{schemas:{a1:{type:'a2'}}},externalDocs:{url:'b'},info:{title:'c1',version:'c2'},openapi:'3.0.0',paths:{d1:{get:{summary:'d2'}}},security:[{requirements:{e1:['e2']}}],servers:[{url:'f'}],tags:[{name:'g'}]}")
50 .string("{'components':{'schemas':{'a1':{'type':'a2'}}},'externalDocs':{'url':'b'},'info':{'title':'c1','version':'c2'},'openapi':'3.0.0','paths':{'d1':{'get':{'summary':'d2'}}},'security':[{'requirements':{'e1':['e2']}}],'servers':[{'url':'f'}],'tags':[{'name':'g'}]}".replace('\'','"'))
51 ;
52
53 @Test void a01_gettersAndSetters() {
54 TESTER.assertGettersAndSetters();
55 }
56
57 @Test void a02_copy() {
58 TESTER.assertCopy();
59 }
60
61 @Test void a03_toJson() {
62 TESTER.assertToJson();
63 }
64
65 @Test void a04_fromJson() {
66 TESTER.assertFromJson();
67 }
68
69 @Test void a05_roundTrip() {
70 TESTER.assertRoundTrip();
71 }
72
73 @Test void a06_toString() {
74 TESTER.assertToString();
75 }
76
77 @Test void a07_keySet() {
78 assertList(TESTER.bean().keySet(), "components", "externalDocs", "info", "openapi", "paths", "security", "servers", "tags");
79 }
80
81 @Test void a08_nullParameters() {
82 var x = bean();
83 assertThrows(IllegalArgumentException.class, () -> x.get(null, String.class));
84 assertThrows(IllegalArgumentException.class, () -> x.set(null, "value"));
85 }
86
87 @Test void a09_addMethods() {
88 assertBean(
89 bean()
90 .addPath("/test", pathItem().setGet(operation().setSummary("a"))),
91 "paths{/test{get{summary}}}",
92 "{{{a}}}"
93 );
94
95
96 var x1 = bean()
97 .addTags(tag("b1"), tag("b2"))
98 .addTags(list(tag("b3")));
99 assertBean(x1, "tags{#{name}}", "{[{b1},{b2},{b3}]}");
100
101
102 var x2 = bean()
103 .addServers(server().setUrl(URI.create("http://c1.com")), server().setUrl(URI.create("http://c2.com")))
104 .addServers(list(server().setUrl(URI.create("http://c3.com"))));
105 assertBean(x2, "servers{#{url}}", "{[{http://c1.com},{http://c2.com},{http://c3.com}]}");
106
107
108 var x3 = bean()
109 .addSecurity(securityRequirement().setRequirements(map("d1", list("d2"))))
110 .addSecurity(list(securityRequirement().setRequirements(map("d3", list("d4")))));
111 assertBean(x3, "security{#{requirements}}", "{[{{d1=[d2]}},{{d3=[d4]}}]}");
112 }
113
114 @Test void a09b_setTagsVarargs() {
115
116 var x = bean().setTags(tag("t1"), tag("t2"), tag("t3"));
117 assertBean(x, "tags{#{name}}", "{[{t1},{t2},{t3}]}");
118 }
119
120 @Test void a10_asMap() {
121 assertBean(
122 bean()
123 .setInfo(info().setTitle("a1").setVersion("a2"))
124 .set("x1", "x1a")
125 .asMap(),
126 "info{title,version},openapi,x1",
127 "{a1,a2},3.0.0,x1a"
128 );
129 }
130
131 @Test void a11_extraKeys() {
132 var x = bean().set("x1", "x1a").set("x2", "x2a");
133 assertList(x.extraKeys(), "x1", "x2");
134 assertEmpty(bean().extraKeys());
135 }
136
137 @Test void a12_strictMode() {
138 assertThrows(RuntimeException.class, () -> bean().strict().set("foo", "bar"));
139 assertDoesNotThrow(() -> bean().set("foo", "bar"));
140
141 assertFalse(bean().isStrict());
142 assertTrue(bean().strict().isStrict());
143 assertFalse(bean().strict(false).isStrict());
144 }
145
146 @Test void a13_collectionSetters() {
147 var x = bean()
148 .setSecurity(list(securityRequirement().setRequirements(map("a1", list("a2"))), securityRequirement().setRequirements(map("b1", list("b2")))))
149 .setServers(list(server().setUrl(URI.create("http://example1.com")), server().setUrl(URI.create("http://example2.com"))))
150 .setTags(list(tag().setName("c1"), tag().setName("c2")));
151
152 assertBean(x,
153 "security{#{requirements}},servers{#{url}},tags{#{name}}",
154 "{[{{a1=[a2]}},{{b1=[b2]}}]},{[{http://example1.com},{http://example2.com}]},{[{c1},{c2}]}"
155 );
156 }
157
158 @Test void a14_addPath() {
159
160 var x = bean()
161 .addPath("/test", pathItem().setGet(operation().setSummary("Test operation")))
162 .addPath("/test2", pathItem().setPost(operation().setSummary("Test POST operation")));
163
164 assertBean(x,
165 "paths{/test{get{summary}},/test2{post{summary}}}",
166 "{{{Test operation}},{{Test POST operation}}}"
167 );
168
169
170 assertThrows(IllegalArgumentException.class, () -> x.addPath(null, pathItem()));
171 assertThrows(IllegalArgumentException.class, () -> x.addPath("/test", null));
172 }
173 }
174
175 @Nested class B_emptyTests extends TestBase {
176
177 private static final BeanTester<OpenApi> TESTER =
178 testBean(bean())
179 .props("openapi,info,externalDocs,servers,tags,paths,components,security")
180 .vals("3.0.0,<null>,<null>,<null>,<null>,<null>,<null>,<null>")
181 .json("{openapi:'3.0.0'}")
182 .string("{\"openapi\":\"3.0.0\"}")
183 ;
184
185 @Test void b01_gettersAndSetters() {
186 TESTER.assertGettersAndSetters();
187 }
188
189 @Test void b02_copy() {
190 TESTER.assertCopy();
191 }
192
193 @Test void b03_toJson() {
194 TESTER.assertToJson();
195 }
196
197 @Test void b04_fromJson() {
198 TESTER.assertFromJson();
199 }
200
201 @Test void b05_roundTrip() {
202 TESTER.assertRoundTrip();
203 }
204
205 @Test void b06_toString() {
206 TESTER.assertToString();
207 }
208
209 @Test void b07_keySet() {
210 assertList(TESTER.bean().keySet(), "openapi");
211 }
212
213 @Test void b08_keySet_infoNull() {
214
215 var x = bean().setOpenapi("3.0.0");
216 assertList(x.keySet(), "openapi");
217 assertFalse(x.keySet().contains("info"));
218 }
219 }
220
221 @Nested class C_extraProperties extends TestBase {
222 private static final BeanTester<OpenApi> TESTER =
223 testBean(
224 bean()
225 .set("components", components().setSchemas(map("a1", schemaInfo("a2"))))
226 .set("externalDocs", externalDocumentation().setUrl(URI.create("b")))
227 .set("info", info().setTitle("c").setVersion("d"))
228 .set("openapi", "e")
229 .set("paths", map("f1", pathItem().setGet(operation().setSummary("f2"))))
230 .set("security", list(securityRequirement().setRequirements(map("g1",list("g2")))))
231 .set("servers", list(server().setUrl(URI.create("h"))))
232 .set("tags", list(tag("i")))
233 .set("x1", "x1a")
234 .set("x2", null)
235 )
236 .props("components{schemas{a1{type}}},externalDocs{url},info{title,version},openapi,paths{f1{get{summary}}},security{#{requirements{g1{#{toString}}}}},servers{#{url}},tags{#{name}},x1,x2")
237 .vals("{{{a2}}},{b},{c,d},e,{{{f2}}},{[{{{[{g2}]}}}]},{[{h}]},{[{i}]},x1a,<null>")
238 .json("{components:{schemas:{a1:{type:'a2'}}},externalDocs:{url:'b'},info:{title:'c',version:'d'},openapi:'e',paths:{f1:{get:{summary:'f2'}}},security:[{requirements:{g1:['g2']}}],servers:[{url:'h'}],tags:[{name:'i'}],x1:'x1a'}")
239 .string("{'components':{'schemas':{'a1':{'type':'a2'}}},'externalDocs':{'url':'b'},'info':{'title':'c','version':'d'},'openapi':'e','paths':{'f1':{'get':{'summary':'f2'}}},'security':[{'requirements':{'g1':['g2']}}],'servers':[{'url':'h'}],'tags':[{'name':'i'}],'x1':'x1a'}".replace('\'', '"'))
240 ;
241
242 @Test void c01_gettersAndSetters() {
243 TESTER.assertGettersAndSetters();
244 }
245
246 @Test void c02_copy() {
247 TESTER.assertCopy();
248 }
249
250 @Test void c03_toJson() {
251 TESTER.assertToJson();
252 }
253
254 @Test void c04_fromJson() {
255 TESTER.assertFromJson();
256 }
257
258 @Test void c05_roundTrip() {
259 TESTER.assertRoundTrip();
260 }
261
262 @Test void c06_toString() {
263 TESTER.assertToString();
264 }
265
266 @Test void c07_keySet() {
267 assertList(TESTER.bean().keySet(), "components", "externalDocs", "info", "openapi", "paths", "security", "servers", "tags", "x1", "x2");
268 }
269
270 @Test void c08_get() {
271 assertMapped(
272 TESTER.bean(), (obj,prop) -> obj.get(prop, Object.class),
273 "components{schemas{a1{type}}},externalDocs{url},info{title,version},openapi,paths{f1{get{summary}}},security{#{requirements{g1{#{toString}}}}},servers{#{url}},tags{#{name}},x1,x2",
274 "{{{a2}}},{b},{c,d},e,{{{f2}}},{[{{{[{g2}]}}}]},{[{h}]},{[{i}]},x1a,<null>"
275 );
276 }
277
278 @Test void c09_getTypes() {
279 assertMapped(
280 TESTER.bean(), (obj,prop) -> simpleClassNameOf(obj.get(prop, Object.class)),
281 "components,externalDocs,info,openapi,paths,security,servers,tags,x1,x2",
282 "Components,ExternalDocumentation,Info,String,TreeMap,ArrayList,ArrayList,ArrayList,String,<null>"
283 );
284 }
285
286 @Test void c10_nullPropertyValue() {
287 assertThrows(IllegalArgumentException.class, ()->bean().get(null));
288 assertThrows(IllegalArgumentException.class, ()->bean().get(null, String.class));
289 assertThrows(IllegalArgumentException.class, ()->bean().set(null, "a"));
290 }
291 }
292
293 @Nested class D_utilityMethods extends TestBase {
294
295 @Test void d01_findRef() {
296 var x = openApi()
297 .setComponents(components().setSchemas(map("a1", schemaInfo().setType("a2"))));
298
299 assertBean(
300 x.findRef("#/components/schemas/a1", SchemaInfo.class),
301 "type",
302 "a2"
303 );
304
305 assertNull(x.findRef("#/components/schemas/notfound", SchemaInfo.class));
306
307 assertThrows(IllegalArgumentException.class, () -> x.findRef(null, SchemaInfo.class));
308 assertThrows(IllegalArgumentException.class, () -> x.findRef("a", null));
309 assertThrows(IllegalArgumentException.class, () -> x.findRef("", SchemaInfo.class));
310 assertThrowsWithMessage(BasicRuntimeException.class, "Unsupported reference: 'invalid'", () -> x.findRef("invalid", SchemaInfo.class));
311 }
312 }
313
314
315
316
317
318 private static OpenApi bean() {
319 return openApi();
320 }
321 }