1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.juneau.bean.swagger;
18
19 import static org.apache.juneau.TestUtils.*;
20 import static org.apache.juneau.bean.swagger.SwaggerBuilder.*;
21 import static org.junit.jupiter.api.Assertions.*;
22
23 import org.apache.juneau.*;
24 import org.apache.juneau.collections.*;
25 import org.junit.jupiter.api.*;
26
27
28
29
30 class Swagger_Test extends TestBase {
31
32 @Nested class A_basicTests extends TestBase {
33
34 private static final BeanTester<Swagger> TESTER =
35 testBean(
36 bean()
37 .setBasePath("a")
38 .setConsumes(MediaType.of("b"))
39 .setDefinitions(map("c1", JsonMap.of("type", "c2")))
40 .setExternalDocs(externalDocumentation("d"))
41 .setHost("e")
42 .setInfo(info("f1", "f2"))
43 .setParameters(map("g1", parameterInfo("g2", "g3")))
44 .setPaths(map("h1", operationMap().append("get", operation().setSummary("h2"))))
45 .setProduces(MediaType.of("i"))
46 .setResponses(map("j1", responseInfo().setDescription("j2")))
47 .setSchemes("k")
48 .setSecurity(list(map("l1", list("l2"))))
49 .setSecurityDefinitions(map("m1", securityScheme().setType("m2")))
50 .setSwagger("n")
51 .setTags(tag().setName("o"))
52 )
53 .props("basePath,consumes,definitions{c1{type}},externalDocs{url},host,info{title,version},parameters{g1{in,name}},paths{h1{get{summary}}},produces,responses{j1{description}},schemes,security{0{l1}},securityDefinitions{m1{type}},swagger,tags{0{name}}")
54 .vals("a,[b],{{c2}},{d},e,{f1,f2},{{g2,g3}},{{{h2}}},[i],{{j2}},[k],{{[l2]}},{{m2}},n,{{o}}")
55 .json("{basePath:'a',consumes:['b'],definitions:{c1:{type:'c2'}},externalDocs:{url:'d'},host:'e',info:{title:'f1',version:'f2'},parameters:{g1:{'in':'g2',name:'g3'}},paths:{h1:{get:{summary:'h2'}}},produces:['i'],responses:{j1:{description:'j2'}},schemes:['k'],security:[{l1:['l2']}],securityDefinitions:{m1:{type:'m2'}},swagger:'n',tags:[{name:'o'}]}")
56 .string("{'basePath':'a','consumes':['b'],'definitions':{'c1':{'type':'c2'}},'externalDocs':{'url':'d'},'host':'e','info':{'title':'f1','version':'f2'},'parameters':{'g1':{'in':'g2','name':'g3'}},'paths':{'h1':{'get':{'summary':'h2'}}},'produces':['i'],'responses':{'j1':{'description':'j2'}},'schemes':['k'],'security':[{'l1':['l2']}],'securityDefinitions':{'m1':{'type':'m2'}},'swagger':'n','tags':[{'name':'o'}]}".replace('\'', '"'))
57 ;
58
59 @Test void a01_gettersAndSetters() {
60 TESTER.assertGettersAndSetters();
61 }
62
63 @Test void a02_copy() {
64 TESTER.assertCopy();
65 }
66
67 @Test void a03_toJson() {
68 TESTER.assertToJson();
69 }
70
71 @Test void a04_fromJson() {
72 TESTER.assertFromJson();
73 }
74
75 @Test void a05_roundTrip() {
76 TESTER.assertRoundTrip();
77 }
78
79 @Test void a06_toString() {
80 TESTER.assertToString();
81 }
82
83 @Test void a07_keySet() {
84 assertList(TESTER.bean().keySet(), "basePath", "consumes", "definitions", "externalDocs", "host", "info", "parameters", "paths", "produces", "responses", "schemes", "security", "securityDefinitions", "swagger", "tags");
85 }
86
87 @Test void a08_otherGettersAndSetters() {
88
89 var x = bean()
90 .addPath("a1", "get", operation().setSummary("a2"))
91 .addPath("b1", "get", operation().addResponse("200", responseInfo("b2")).setParameters(parameterInfo("b3", "b4")))
92 .addParameter("c1", parameterInfo("c2", "c3"));
93
94 assertBean(x.getPath("a1"), "get{summary}", "{a2}");
95 assertBean(x.getOperation("a1", "get"), "summary", "a2");
96 assertBean(x.getResponseInfo("b1", "get", "200"), "description", "b2");
97 assertBean(x.getResponseInfo("b1", "get", 200), "description", "b2");
98 assertBean(x.getParameterInfo("b1", "get", "b3", "b4"), "in,name", "b3,b4");
99
100
101 x = bean()
102 .setConsumes(MediaType.of("e1"), MediaType.of("e2"))
103 .setProduces(MediaType.of("f1"), MediaType.of("f2"))
104 .setSchemes("g1", "g2");
105
106 assertBean(x, "consumes,produces,schemes", "[e1,e2],[f1,f2],[g1,g2]");
107 }
108
109 @Test void a09_nullParameters() {
110 var x = bean();
111
112 assertThrows(IllegalArgumentException.class, ()->x.getPath(null));
113 assertThrows(IllegalArgumentException.class, ()->x.getOperation(null, "a"));
114 assertThrows(IllegalArgumentException.class, ()->x.getOperation("a", null));
115 assertThrows(IllegalArgumentException.class, ()->x.getResponseInfo(null, "a", "a"));
116 assertThrows(IllegalArgumentException.class, ()->x.getResponseInfo("a", null, "a"));
117 assertThrows(IllegalArgumentException.class, ()->x.getResponseInfo("a", "a", null));
118 assertThrows(IllegalArgumentException.class, ()->x.getParameterInfo(null, "a", "a", "a"));
119 assertThrows(IllegalArgumentException.class, ()->x.getParameterInfo("a", null, "a", "a"));
120 assertThrows(IllegalArgumentException.class, ()->x.getParameterInfo("a", "a", null, "a"));
121 assertThrows(IllegalArgumentException.class, ()->x.get(null, String.class));
122 assertThrows(IllegalArgumentException.class, ()->x.set(null, "value"));
123 assertThrows(IllegalArgumentException.class, ()->x.addDefinition(null, JsonMap.of("a", "b")));
124 assertThrows(IllegalArgumentException.class, ()->x.addDefinition("a", null));
125 assertThrows(IllegalArgumentException.class, ()->x.addParameter(null, parameterInfo("a", "b")));
126 assertThrows(IllegalArgumentException.class, ()->x.addParameter("a", null));
127 assertThrows(IllegalArgumentException.class, ()->x.addPath(null, "get", operation()));
128 assertThrows(IllegalArgumentException.class, ()->x.addPath("a", null, operation()));
129 assertThrows(IllegalArgumentException.class, ()->x.addPath("a", "get", null));
130 assertThrows(IllegalArgumentException.class, ()->x.addResponse(null, responseInfo()));
131 assertThrows(IllegalArgumentException.class, ()->x.addResponse("a", null));
132 assertThrows(IllegalArgumentException.class, ()->x.addSecurity(null, "a"));
133 assertThrows(IllegalArgumentException.class, ()->x.addSecurityDefinition(null, securityScheme()));
134 assertThrows(IllegalArgumentException.class, ()->x.addSecurityDefinition("a", null));
135 }
136
137 @Test void a10_collectionSetters() {
138
139 var x = bean()
140 .setConsumes(list(
141 MediaType.of("a1"),
142 MediaType.of("a2")
143 ))
144 .setProduces(list(
145 MediaType.of("b1"),
146 MediaType.of("b2")
147 ))
148 .setSchemes(list("c1", "c2"))
149 .setTags(list(tag().setName("d1"), tag().setName("d2")))
150 .setSecurity(list(
151 map("e1", list("e2")),
152 map("e3", list("e4"))
153 ));
154
155 assertBean(x,
156 "consumes,produces,schemes,tags{0{name},1{name}},security{0{e1},1{e3}}",
157 "[a1,a2],[b1,b2],[c1,c2],{{d1},{d2}},{{[e2]},{[e4]}}"
158 );
159 }
160
161 @Test void a11_varargAdders() {
162
163 var x = bean()
164 .addConsumes(MediaType.of("a1"))
165 .addConsumes(MediaType.of("a2"))
166 .addProduces(MediaType.of("b1"))
167 .addProduces(MediaType.of("b2"))
168 .addSchemes("c1")
169 .addSchemes("c2")
170 .addTags(tag().setName("d1"))
171 .addTags(tag().setName("d2"));
172
173 assertBean(x,
174 "consumes,produces,schemes,tags{0{name},1{name}}",
175 "[a1,a2],[b1,b2],[c1,c2],{{d1},{d2}}"
176 );
177 }
178
179 @Test void a12_collectionAdders() {
180
181 var x = bean()
182 .addConsumes(list(MediaType.of("a1")))
183 .addConsumes(list(MediaType.of("a2")))
184 .addProduces(list(MediaType.of("b1")))
185 .addProduces(list(MediaType.of("b2")))
186 .addSchemes(list("c1"))
187 .addSchemes(list("c2"))
188 .addSecurity(list(map("d1",list("d2"))))
189 .addSecurity(list(map("d3",list("d4"))))
190 .addTags(list(tag().setName("e1")))
191 .addTags(list(tag().setName("e2")));
192
193 assertBean(x,
194 "consumes,produces,schemes,security,tags{0{name},1{name}}",
195 "[a1,a2],[b1,b2],[c1,c2],[{d1=[d2]},{d3=[d4]}],{{e1},{e2}}"
196 );
197 }
198
199 @Test void a13_asMap() {
200 assertBean(
201 bean()
202 .setBasePath("a")
203 .setHost("b")
204 .set("x1", "x1a")
205 .asMap(),
206 "basePath,host,swagger,x1",
207 "a,b,2.0,x1a"
208 );
209 }
210
211 @Test void a14_extraKeys() {
212 var x = bean().set("x1", "x1a").set("x2", "x2a");
213 assertList(x.extraKeys(), "x1", "x2");
214 assertEmpty(bean().extraKeys());
215 }
216
217 @Test void a15_addResponse() {
218
219 var x = bean()
220 .addResponse("200", responseInfo().setDescription("a"))
221 .addResponse("404", responseInfo().setDescription("b"));
222
223 assertBean(x,
224 "responses{200{description},404{description}}",
225 "{{a},{b}}"
226 );
227 }
228
229 @Test void a16_addSecurity() {
230
231 var x = bean()
232 .addSecurity("scheme1", "a", "b")
233 .addSecurity("scheme2", "c");
234
235 assertBean(x,
236 "security{0{scheme1},1{scheme2}}",
237 "{{[a,b]},{[c]}}"
238 );
239 }
240
241 @Test void a17_addSecurityDefinition() {
242
243 var x = bean()
244 .addSecurityDefinition("def1", securityScheme().setType("a"))
245 .addSecurityDefinition("def2", securityScheme().setType("b"));
246
247 assertBean(x,
248 "securityDefinitions{def1{type},def2{type}}",
249 "{{a},{b}}"
250 );
251 }
252
253 @Test void a18_getOperationNullPath() {
254 var a = swagger()
255 .addPath("/existing", "get", operation().setSummary("test"));
256
257
258 assertNull(a.getOperation("/nonexistent", "get"));
259
260
261 assertNull(a.getResponseInfo("/nonexistent", "get", "200"));
262
263
264 assertNull(a.getResponseInfo("/test", "post", "200"));
265
266
267 assertNull(a.getParameterInfo("/nonexistent", "get", "query", "param"));
268
269
270 assertNull(a.getParameterInfo("/test", "post", "query", "param"));
271 }
272
273 @Test void a19_getMethodWithInvalidProperty() {
274 var a = swagger();
275
276
277 assertNull(a.get("invalidProperty", String.class));
278 }
279
280 @Test void a20_strictMode() {
281 assertThrows(RuntimeException.class, () -> bean().strict().set("foo", "bar"));
282 assertDoesNotThrow(() -> bean().set("foo", "bar"));
283
284 assertFalse(bean().isStrict());
285 assertTrue(bean().strict().isStrict());
286 assertFalse(bean().strict(false).isStrict());
287 }
288
289 @Test void a21_asJson() {
290 var x = swagger().setHost("a");
291 var json = x.asJson();
292 assertTrue(json.contains("a"));
293 }
294 }
295
296 @Nested class B_emptyTests extends TestBase {
297
298 private static final BeanTester<Swagger> TESTER =
299 testBean(bean())
300 .props("basePath,host,swagger,info,tags,schemes,consumes,produces,paths,definitions,parameters,responses,securityDefinitions,security,externalDocs")
301 .vals("<null>,<null>,2.0,<null>,<null>,<null>,<null>,<null>,<null>,<null>,<null>,<null>,<null>,<null>,<null>")
302 .json("{swagger:'2.0'}")
303 .string("{\"swagger\":\"2.0\"}")
304 ;
305
306 @Test void b01_gettersAndSetters() {
307 TESTER.assertGettersAndSetters();
308 }
309
310 @Test void b02_copy() {
311 TESTER.assertCopy();
312 }
313
314 @Test void b03_toJson() {
315 TESTER.assertToJson();
316 }
317
318 @Test void b04_fromJson() {
319 TESTER.assertFromJson();
320 }
321
322 @Test void b05_roundTrip() {
323 TESTER.assertRoundTrip();
324 }
325
326 @Test void b06_toString() {
327 TESTER.assertToString();
328 }
329
330 @Test void b07_keySet() {
331 assertList(TESTER.bean().keySet(), "swagger");
332 assertList(TESTER.bean().setSwagger(null).keySet());
333 }
334 }
335
336 @Nested class C_extraProperties extends TestBase {
337
338 private static final BeanTester<Swagger> TESTER =
339 testBean(
340 bean()
341 .set("basePath", "a")
342 .set("consumes", list(MediaType.of("b")))
343 .set("definitions", map("c1", JsonMap.of("type", "c2")))
344 .set("externalDocs", externalDocumentation("d"))
345 .set("host", "e")
346 .set("info", info("f1", "f2"))
347 .set("parameters", map("g1", parameterInfo("g2", "g3")))
348 .set("paths", map("h1", operationMap().append("get", operation().setSummary("h2"))))
349 .set("produces", list(MediaType.of("i")))
350 .set("responses", map("j1", responseInfo().setDescription("j2")))
351 .set("schemes", list("k"))
352 .set("security", list(map("l1", list("l2"))))
353 .set("securityDefinitions", map("m1", securityScheme().setType("m2")))
354 .set("swagger", "n")
355 .set("tags", list(tag().setName("o")))
356 .set("x1", "x1a")
357 .set("x2", null)
358 )
359 .props("basePath,consumes,definitions{c1{type}},externalDocs{url},host,info{title,version},parameters{g1{in,name}},paths{h1{get{summary}}},produces,responses{j1{description}},schemes,security{0{l1}},securityDefinitions{m1{type}},swagger,tags{0{name}},x1,x2")
360 .vals("a,[b],{{c2}},{d},e,{f1,f2},{{g2,g3}},{{{h2}}},[i],{{j2}},[k],{{[l2]}},{{m2}},n,{{o}},x1a,<null>")
361 .json("{basePath:'a',consumes:['b'],definitions:{c1:{type:'c2'}},externalDocs:{url:'d'},host:'e',info:{title:'f1',version:'f2'},parameters:{g1:{'in':'g2',name:'g3'}},paths:{h1:{get:{summary:'h2'}}},produces:['i'],responses:{j1:{description:'j2'}},schemes:['k'],security:[{l1:['l2']}],securityDefinitions:{m1:{type:'m2'}},swagger:'n',tags:[{name:'o'}],x1:'x1a'}")
362 .string("{'basePath':'a','consumes':['b'],'definitions':{'c1':{'type':'c2'}},'externalDocs':{'url':'d'},'host':'e','info':{'title':'f1','version':'f2'},'parameters':{'g1':{'in':'g2','name':'g3'}},'paths':{'h1':{'get':{'summary':'h2'}}},'produces':['i'],'responses':{'j1':{'description':'j2'}},'schemes':['k'],'security':[{'l1':['l2']}],'securityDefinitions':{'m1':{'type':'m2'}},'swagger':'n','tags':[{'name':'o'}],'x1':'x1a'}".replace('\'', '"'))
363 ;
364
365 @Test void c01_gettersAndSetters() {
366 TESTER.assertGettersAndSetters();
367 }
368
369 @Test void c02_copy() {
370 TESTER.assertCopy();
371 }
372
373 @Test void c03_toJson() {
374 TESTER.assertToJson();
375 }
376
377 @Test void c04_fromJson() {
378 TESTER.assertFromJson();
379 }
380
381 @Test void c05_roundTrip() {
382 TESTER.assertRoundTrip();
383 }
384
385 @Test void c06_toString() {
386 TESTER.assertToString();
387 }
388
389 @Test void c07_keySet() {
390 assertList(TESTER.bean().keySet(), "basePath", "consumes", "definitions", "externalDocs", "host", "info", "parameters", "paths", "produces", "responses", "schemes", "security", "securityDefinitions", "swagger", "tags", "x1", "x2");
391 }
392
393 @Test void c08_get() {
394 assertMapped(
395 TESTER.bean(), (obj,prop) -> obj.get(prop, Object.class),
396 "basePath,consumes,definitions{c1{type}},externalDocs{url},host,info{title,version},parameters{g1{in,name}},paths{h1{get{summary}}},produces,responses{j1{description}},schemes,security{0{l1}},securityDefinitions{m1{type}},swagger,tags{0{name}},x1,x2",
397 "a,[b],{{c2}},{d},e,{f1,f2},{{g2,g3}},{{{h2}}},[i],{{j2}},[k],{{[l2]}},{{m2}},n,{{o}},x1a,<null>"
398 );
399 }
400
401 @Test void c09_getTypes() {
402 assertMapped(
403 TESTER.bean(), (obj,prop) -> simpleClassNameOf(obj.get(prop, Object.class)),
404 "basePath,consumes,definitions,externalDocs,host,info,parameters,paths,produces,responses,schemes,security,securityDefinitions,swagger,tags,x1,x2",
405 "String,LinkedHashSet,LinkedHashMap,ExternalDocumentation,String,Info,LinkedHashMap,TreeMap,LinkedHashSet,LinkedHashMap,LinkedHashSet,ArrayList,LinkedHashMap,String,LinkedHashSet,String,<null>"
406 );
407 }
408
409 @Test void c10_nullPropertyValue() {
410 assertThrows(IllegalArgumentException.class, ()->bean().get(null));
411 assertThrows(IllegalArgumentException.class, ()->bean().get(null, String.class));
412 assertThrows(IllegalArgumentException.class, ()->bean().set(null, "a"));
413 }
414 }
415
416 @Nested class D_refs extends TestBase {
417
418
419 @Test void d01_findRef() {
420 var x = swagger().addDefinition("a1", JsonMap.of("type", "a2"));
421 assertBean(
422 x.findRef("#/definitions/a1", JsonMap.class),
423 "type",
424 "a2"
425 );
426
427 assertNull(x.findRef("#/definitions/notfound", JsonMap.class));
428
429 assertThrows(IllegalArgumentException.class, () -> x.findRef(null, JsonMap.class));
430 assertThrows(IllegalArgumentException.class, () -> x.findRef("a", null));
431 assertThrows(IllegalArgumentException.class, () -> x.findRef("", JsonMap.class));
432 assertThrowsWithMessage(BasicRuntimeException.class, "Unsupported reference: 'invalid'", () -> x.findRef("invalid", JsonMap.class));
433 }
434
435 @Test void d02_findRefInvalidType() {
436
437 var x = swagger()
438 .addDefinition("Pet", JsonMap.of("type", "object"))
439 .addResponse("Error", responseInfo().setDescription("Error response"))
440 .addParameter("petId", parameterInfo("path", "id"));
441
442
443 assertThrows(Exception.class, () -> x.findRef("#/definitions/Pet", Integer.class));
444
445
446 assertThrows(Exception.class, () -> x.findRef("#/responses/Error", Integer.class));
447
448
449 assertThrows(Exception.class, () -> x.findRef("#/parameters/petId", Integer.class));
450 }
451
452 }
453
454
455
456
457
458 private static Swagger bean() {
459 return swagger();
460 }
461
462 }