View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
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 java.util.*;
24  
25  import org.apache.juneau.*;
26  import org.apache.juneau.collections.*;
27  import org.junit.jupiter.api.*;
28  
29  /**
30   * Testcase for {@link Items}.
31   */
32  class Items_Test extends TestBase {
33  
34  	@Nested class A_basicTests extends TestBase {
35  
36  		private static final BeanTester<Items> TESTER =
37  			testBean(
38  				bean()
39  					.setCollectionFormat("a")
40  					.setDefault("b")
41  					.setEnum("c")
42  					.setExclusiveMaximum(true)
43  					.setExclusiveMinimum(true)
44  					.setFormat("d")
45  					.setItems(items().setType("e"))
46  					.setMaximum(1)
47  					.setMaxItems(2)
48  					.setMaxLength(3)
49  					.setMinimum(4)
50  					.setMinItems(5)
51  					.setMinLength(6)
52  					.setMultipleOf(7)
53  					.setPattern("f")
54  					.setRef("g")
55  					.setType("h")
56  					.setUniqueItems(true)
57  			)
58  			.props("collectionFormat,default,enum,exclusiveMaximum,exclusiveMinimum,format,items{type},maximum,maxItems,maxLength,minimum,minItems,minLength,multipleOf,pattern,ref,type,uniqueItems")
59  			.vals("a,b,[c],true,true,d,{e},1,2,3,4,5,6,7,f,g,h,true")
60  			.json("{'$ref':'g',collectionFormat:'a','default':'b','enum':['c'],exclusiveMaximum:true,exclusiveMinimum:true,format:'d',items:{type:'e'},maxItems:2,maxLength:3,maximum:1,minItems:5,minLength:6,minimum:4,multipleOf:7,pattern:'f',type:'h',uniqueItems:true}")
61  			.string("{'$ref':'g','collectionFormat':'a','default':'b','enum':['c'],'exclusiveMaximum':true,'exclusiveMinimum':true,'format':'d','items':{'type':'e'},'maxItems':2,'maxLength':3,'maximum':1,'minItems':5,'minLength':6,'minimum':4,'multipleOf':7,'pattern':'f','type':'h','uniqueItems':true}".replace('\'', '"'))
62  		;
63  
64  		@Test void a01_gettersAndSetters() {
65  			TESTER.assertGettersAndSetters();
66  		}
67  
68  		@Test void a02_copy() {
69  			TESTER.assertCopy();
70  		}
71  
72  		@Test void a03_toJson() {
73  			TESTER.assertToJson();
74  		}
75  
76  		@Test void a04_fromJson() {
77  			TESTER.assertFromJson();
78  		}
79  
80  		@Test void a05_roundTrip() {
81  			TESTER.assertRoundTrip();
82  		}
83  
84  		@Test void a06_toString() {
85  			TESTER.assertToString();
86  		}
87  
88  		@Test void a07_keySet() {
89  			assertList(TESTER.bean().keySet(), "$ref", "collectionFormat", "default", "enum", "exclusiveMaximum", "exclusiveMinimum", "format", "items", "maxItems", "maxLength", "maximum", "minItems", "minLength", "minimum", "multipleOf", "pattern", "type", "uniqueItems");
90  		}
91  
92  		@Test void a08_nullParameters() {
93  			var x = bean();
94  			assertThrows(IllegalArgumentException.class, () -> x.get(null, String.class));
95  			assertThrows(IllegalArgumentException.class, () -> x.set(null, "value"));
96  		}
97  
98  		@Test void a09_addMethods() {
99  			var x = bean().addEnum("a1");
100 			assertNotNull(x);
101 			assertNotNull(x.getEnum());
102 		}
103 
104 		@Test void a10_asMap() {
105 			assertBean(
106 				bean()
107 					.setFormat("a")
108 					.setType("b")
109 					.set("x1", "x1a")
110 					.asMap(),
111 				"format,type,x1",
112 				"a,b,x1a"
113 			);
114 		}
115 
116 		@Test void a11_extraKeys() {
117 			var x = bean().set("x1", "x1a").set("x2", "x2a");
118 			assertList(x.extraKeys(), "x1", "x2");
119 			assertEmpty(bean().extraKeys());
120 		}
121 
122 		@Test void a12_strictMode() {
123 			assertThrows(RuntimeException.class, () -> bean().strict().set("foo", "bar"));
124 			assertDoesNotThrow(() -> bean().set("foo", "bar"));
125 
126 			assertFalse(bean().isStrict());
127 			assertTrue(bean().strict().isStrict());
128 			assertFalse(bean().strict(false).isStrict());
129 
130 			var x = bean().strict();
131 			var y = bean(); // not strict
132 
133 			assertThrowsWithMessage(RuntimeException.class, "Invalid value passed in to setCollectionFormat(String).  Value='invalid', valid values=['csv','ssv','tsv','pipes','multi']", () -> x.setCollectionFormat("invalid"));
134 			assertDoesNotThrow(() -> x.setCollectionFormat("csv"));
135 			assertDoesNotThrow(() -> x.setCollectionFormat("ssv"));
136 			assertDoesNotThrow(() -> x.setCollectionFormat("tsv"));
137 			assertDoesNotThrow(() -> x.setCollectionFormat("pipes"));
138 			assertDoesNotThrow(() -> x.setCollectionFormat("multi"));
139 			assertDoesNotThrow(() -> y.setCollectionFormat("invalid"));
140 
141 			assertThrowsWithMessage(RuntimeException.class, "Invalid value passed in to setType(String).  Value='invalid', valid values=['string','number','integer','boolean','array']", () -> x.setType("invalid"));
142 			assertDoesNotThrow(() -> x.setType("string"));
143 			assertDoesNotThrow(() -> x.setType("number"));
144 			assertDoesNotThrow(() -> x.setType("integer"));
145 			assertDoesNotThrow(() -> x.setType("boolean"));
146 			assertDoesNotThrow(() -> x.setType("array"));
147 			assertDoesNotThrow(() -> y.setType("invalid"));
148 		}
149 	}
150 
151 	@Nested class B_emptyTests extends TestBase {
152 
153 		private static final BeanTester<Items> TESTER =
154 			testBean(bean())
155 			.props("format,type,collectionFormat,default,maximum,exclusiveMaximum,minimum,exclusiveMinimum,maxLength,minLength,pattern,maxItems,minItems,uniqueItems,enum,multipleOf,items")
156 			.vals("<null>,<null>,<null>,<null>,<null>,<null>,<null>,<null>,<null>,<null>,<null>,<null>,<null>,<null>,<null>,<null>,<null>")
157 			.json("{}")
158 			.string("{}")
159 		;
160 
161 		@Test void b01_gettersAndSetters() {
162 			TESTER.assertGettersAndSetters();
163 		}
164 
165 		@Test void b02_copy() {
166 			TESTER.assertCopy();
167 		}
168 
169 		@Test void b03_toJson() {
170 			TESTER.assertToJson();
171 		}
172 
173 		@Test void b04_fromJson() {
174 			TESTER.assertFromJson();
175 		}
176 
177 		@Test void b05_roundTrip() {
178 			TESTER.assertRoundTrip();
179 		}
180 
181 		@Test void b06_toString() {
182 			TESTER.assertToString();
183 		}
184 
185 		@Test void b07_keySet() {
186 			assertEmpty(TESTER.bean().keySet());
187 		}
188 	}
189 
190 	@Nested class C_extraProperties extends TestBase {
191 
192 		private static final BeanTester<Items> TESTER =
193 			testBean(
194 				bean()
195 					.set("collectionFormat", "a")
196 					.set("default", "b")
197 					.set("enum", set("c"))
198 					.set("exclusiveMaximum", true)
199 					.set("exclusiveMinimum", true)
200 					.set("format", "d")
201 					.set("items", items().setType("e"))
202 					.set("maximum", 1)
203 					.set("maxItems", 2)
204 					.set("maxLength", 3)
205 					.set("minimum", 4)
206 					.set("minItems", 5)
207 					.set("minLength", 6)
208 					.set("multipleOf", 7)
209 					.set("pattern", "f")
210 					.set("$ref", "g")
211 					.set("type", "h")
212 					.set("uniqueItems", true)
213 					.set("x1", "x1a")
214 					.set("x2", null)
215 			)
216 			.props("collectionFormat,default,enum,exclusiveMaximum,exclusiveMinimum,format,items{type},maximum,maxItems,maxLength,minimum,minItems,minLength,multipleOf,pattern,ref,type,uniqueItems,x1,x2")
217 			.vals("a,b,[c],true,true,d,{e},1,2,3,4,5,6,7,f,g,h,true,x1a,<null>")
218 			.json("{'$ref':'g',collectionFormat:'a','default':'b','enum':['c'],exclusiveMaximum:true,exclusiveMinimum:true,format:'d',items:{type:'e'},maxItems:2,maxLength:3,maximum:1,minItems:5,minLength:6,minimum:4,multipleOf:7,pattern:'f',type:'h',uniqueItems:true,x1:'x1a'}")
219 			.string("{'$ref':'g','collectionFormat':'a','default':'b','enum':['c'],'exclusiveMaximum':true,'exclusiveMinimum':true,'format':'d','items':{'type':'e'},'maxItems':2,'maxLength':3,'maximum':1,'minItems':5,'minLength':6,'minimum':4,'multipleOf':7,'pattern':'f','type':'h','uniqueItems':true,'x1':'x1a'}".replace('\'', '"'))
220 		;
221 
222 		@Test void c01_gettersAndSetters() {
223 			TESTER.assertGettersAndSetters();
224 		}
225 
226 		@Test void c02_copy() {
227 			TESTER.assertCopy();
228 		}
229 
230 		@Test void c03_toJson() {
231 			TESTER.assertToJson();
232 		}
233 
234 		@Test void c04_fromJson() {
235 			TESTER.assertFromJson();
236 		}
237 
238 		@Test void c05_roundTrip() {
239 			TESTER.assertRoundTrip();
240 		}
241 
242 		@Test void c06_toString() {
243 			TESTER.assertToString();
244 		}
245 
246 		@Test void c07_keySet() {
247 			assertList(TESTER.bean().keySet(), "$ref", "collectionFormat", "default", "enum", "exclusiveMaximum", "exclusiveMinimum", "format", "items", "maxItems", "maxLength", "maximum", "minItems", "minLength", "minimum", "multipleOf", "pattern", "type", "uniqueItems", "x1", "x2");
248 		}
249 
250 		@Test void c08_get() {
251 			assertMapped(
252 				TESTER.bean(), (obj,prop) -> obj.get(prop, Object.class),
253 				"collectionFormat,default,enum,exclusiveMaximum,exclusiveMinimum,format,items{type},maximum,maxItems,maxLength,minimum,minItems,minLength,multipleOf,pattern,$ref,type,uniqueItems,x1,x2",
254 				"a,b,[c],true,true,d,{e},1,2,3,4,5,6,7,f,g,h,true,x1a,<null>"
255 			);
256 		}
257 
258 		@Test void c09_getTypes() {
259 			assertMapped(
260 				TESTER.bean(), (obj,prop) -> simpleClassNameOf(obj.get(prop, Object.class)),
261 				"collectionFormat,default,enum,exclusiveMaximum,exclusiveMinimum,format,items,maximum,maxItems,maxLength,minimum,minItems,minLength,multipleOf,pattern,$ref,type,uniqueItems,x1,x2",
262 				"String,String,LinkedHashSet,Boolean,Boolean,String,Items,Integer,Integer,Integer,Integer,Integer,Integer,Integer,String,String,String,Boolean,String,<null>"
263 			);
264 		}
265 
266 		@Test void c10_nullPropertyValue() {
267 			assertThrows(IllegalArgumentException.class, ()->bean().get(null));
268 			assertThrows(IllegalArgumentException.class, ()->bean().get(null, String.class));
269 			assertThrows(IllegalArgumentException.class, ()->bean().set(null, "a"));
270 		}
271 	}
272 
273 	@Nested class D_refs extends TestBase {
274 
275 		@Test void d01_resolveRefs_basic() {
276 			var swagger = swagger()
277 				.addDefinition("MyItem", JsonMap.of("type", "string"));
278 
279 			assertBean(
280 				items().setRef("#/definitions/MyItem").resolveRefs(swagger, new ArrayDeque<>(), 10),
281 				"type",
282 				"string"
283 			);
284 		}
285 
286 		@Test void d02_resolveRefs_nestedItems() {
287 			var swagger = swagger()
288 				.addDefinition("MyItem", JsonMap.of("type", "string"))
289 				.addDefinition("MyArray", JsonMap.of("type", "array", "items", JsonMap.of("$ref", "#/definitions/MyItem")));
290 
291 			assertBean(
292 				items().setRef("#/definitions/MyArray").resolveRefs(swagger, new ArrayDeque<>(), 10),
293 				"type,items{type}",
294 				"array,{string}"
295 			);
296 		}
297 
298 		@Test void d03_resolveRefs_maxDepth() {
299 			var swagger = swagger()
300 				.addDefinition("MyItem", JsonMap.of("type", "string"))
301 				.addDefinition("MyArray", JsonMap.of("type", "array", "items", JsonMap.of("$ref", "#/definitions/MyItem")));
302 
303 			assertBean(
304 				items().setRef("#/definitions/MyArray").resolveRefs(swagger, new ArrayDeque<>(), 1),
305 				"type,items{ref}",
306 				"array,{#/definitions/MyItem}"
307 			);
308 		}
309 
310 		@Test void d04_resolveRefs_noRefNoItems() {
311 			// Test resolveRefs when both ref and items are null (covers the missing branch)
312 			var swagger = swagger();
313 			var items = items()
314 				.setType("string")
315 				.setFormat("text");
316 
317 			var result = items.resolveRefs(swagger, new ArrayDeque<>(), 10);
318 
319 			// Should return the same object unchanged
320 			assertSame(items, result);
321 			assertEquals("string", result.getType());
322 			assertEquals("text", result.getFormat());
323 		}
324 	}
325 
326 	//---------------------------------------------------------------------------------------------
327 	// Helper methods
328 	//---------------------------------------------------------------------------------------------
329 
330 	private static Items bean() {
331 		return items();
332 	}
333 
334 }