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.http.part;
18  
19  import static org.apache.juneau.TestUtils.*;
20  import static org.apache.juneau.http.HttpParts.*;
21  import static org.junit.jupiter.api.Assertions.*;
22  
23  import java.util.*;
24  import java.util.concurrent.atomic.*;
25  
26  import org.apache.http.*;
27  import org.apache.juneau.*;
28  import org.apache.juneau.http.annotation.*;
29  import org.apache.juneau.httppart.*;
30  import org.apache.juneau.oapi.*;
31  import org.junit.jupiter.api.*;
32  
33  /**
34   * Tests: {@link PartList}, {@link PartList.Builder}, {@link BasicPartIterator}
35   */
36  class PartList_Test extends TestBase {
37  
38  	private static final NameValuePair
39  		FOO_1 = part("Foo","1"),
40  		FOO_2 = part("Foo","2"),
41  		FOO_3 = part("Foo","3"),
42  		FOO_4 = part("Foo","4"),
43  		FOO_5 = part("Foo","5"),
44  		FOO_6 = part("Foo","6"),
45  		FOO_7 = part("Foo","7"),
46  		BAR_1 = part("Bar","1"),
47  		BAR_2 = part("Bar","2"),
48  
49  		X_x = part("X", "x");
50  
51  	@Query("a")
52  	public static class APart extends BasicStringPart {
53  		public static final APart X = new APart("x"), Y = new APart("y"), Z = new APart("z");
54  		public APart(Object value) {
55  			super("a", s(value));
56  		}
57  	}
58  
59  	@FormData("b")
60  	public static class BPart extends BasicStringPart {
61  		public static final BPart X = new BPart("x"), Y = new BPart("y"), Z = new BPart("z");
62  		public BPart(Object value) {
63  			super("b", s(value));
64  		}
65  	}
66  
67  	@Path("c")
68  	public static class CPart extends BasicStringPart {
69  		public static final CPart X = new CPart("x");
70  		public CPart(Object value) {
71  			super("c", s(value));
72  		}
73  	}
74  
75  	@Test void a01_basic() {
76  		var x = PartList.create();
77  
78  		assertEquals("", s(x));
79  		x.append(FOO_1);
80  		assertEquals("Foo=1", s(x));
81  		x.append(FOO_2);
82  		assertEquals("Foo=1&Foo=2", s(x));
83  		x.append(PartList.of().getAll());
84  		assertEquals("Foo=1&Foo=2", s(x));
85  		x.append(PartList.of(FOO_3).getAll());
86  		assertEquals("Foo=1&Foo=2&Foo=3", s(x));
87  		x.append(PartList.of(FOO_4, FOO_5).getAll());
88  		assertEquals("Foo=1&Foo=2&Foo=3&Foo=4&Foo=5", s(x));
89  		x.append(PartList.of(FOO_6, FOO_7).getAll());
90  		assertEquals("Foo=1&Foo=2&Foo=3&Foo=4&Foo=5&Foo=6&Foo=7", s(x));
91  		x.append((NameValuePair)null);
92  		assertEquals("Foo=1&Foo=2&Foo=3&Foo=4&Foo=5&Foo=6&Foo=7", s(x));
93  		x.append((List<NameValuePair>)null);
94  		assertEquals("Foo=1&Foo=2&Foo=3&Foo=4&Foo=5&Foo=6&Foo=7", s(x));
95  
96  		assertEquals("", s(new PartList.Void()));
97  	}
98  
99  	@Test void a02_creators() {
100 		var x = partList(FOO_1, FOO_2, null);
101 
102 		assertEquals("Foo=1&Foo=2", s(x));
103 
104 		x = partList(alist(FOO_1, FOO_2, null));
105 		assertEquals("Foo=1&Foo=2", s(x));
106 
107 		x = partList("Foo","1","Foo","2");
108 		assertEquals("Foo=1&Foo=2", s(x));
109 
110 		assertThrowsWithMessage(IllegalArgumentException.class, "Odd number of parameters passed into PartList.ofPairs()", ()->partList("Foo"));
111 
112 		x = PartList.of((List<NameValuePair>)null);
113 		assertEquals("", s(x));
114 
115 		x = PartList.of(Collections.emptyList());
116 		assertEquals("", s(x));
117 
118 		x = PartList.of(alist(FOO_1));
119 		assertEquals("Foo=1", s(x));
120 
121 		x = PartList.of((NameValuePair[])null);
122 		assertEquals("", s(x));
123 
124 		x = PartList.of();
125 		assertEquals("", s(x));
126 
127 		x = PartList.of(FOO_1);
128 		assertEquals("Foo=1", s(x));
129 
130 		x = PartList.ofPairs((String[])null);
131 		assertEquals("", s(x));
132 
133 		x = PartList.ofPairs();
134 		assertEquals("", s(x));
135 	}
136 
137 	@Test void a03_addMethods() {
138 		var pname = "PartSupplierTest.x";
139 
140 		var x = PartList.create().resolving();
141 		System.setProperty(pname, "y");
142 
143 		x.append("X1","bar");
144 		x.append("X2","$S{"+pname+"}");
145 		x.append("X3","bar");
146 		x.append("X4",()->"$S{"+pname+"}");
147 		x.append(new SerializedPart("X5","bar",HttpPartType.QUERY,openApiSession(),null,false));
148 
149 		assertEquals("X1=bar&X2=y&X3=bar&X4=y&X5=bar", s(x));
150 
151 		System.setProperty(pname, "z");
152 
153 		assertEquals("X1=bar&X2=z&X3=bar&X4=z&X5=bar", s(x));
154 
155 		System.clearProperty(pname);
156 	}
157 
158 	@Test void a04_toArrayMethods() {
159 		var x = PartList
160 			.create()
161 			.append("X1","1")
162 			.append(partList("X2","2").getAll());
163 		assertEquals("X1=1&X2=2", s(x));
164 	}
165 
166 	@Test void a05_copy() {
167 		var x = PartList.of(FOO_1).copy();
168 		assertEquals("Foo=1", s(x));
169 	}
170 
171 	@Test void a06_getCondensed() {
172 		var x = PartList.of(FOO_1);
173 		assertEmpty(x.get((String)null));
174 		assertString("Foo=1", x.get("Foo"));
175 		assertEmpty(x.get("Bar"));
176 		x = PartList.of(FOO_1, FOO_2, FOO_3, X_x);
177 		assertString("Foo=1,2,3", x.get("Foo"));
178 		assertEmpty(x.get("Bar"));
179 	}
180 
181 	@Query("Foo")
182 	static class Foo extends BasicStringPart {
183 		public Foo(Object value) {
184 			super("Foo", s(value));
185 		}
186 	}
187 
188 	@Test void a07_getCondensed_asType() {
189 		var x = PartList.of(FOO_1);
190 		assertEmpty(x.get(null, APart.class));
191 		assertString("a=1", x.get("Foo", APart.class));
192 		assertEmpty(x.get("Bar", APart.class));
193 		x = PartList.of(FOO_1, FOO_2, FOO_3, X_x);
194 		assertString("a=1,2,3", x.get("Foo", APart.class));
195 		assertEmpty(x.get("Bar", APart.class));
196 		assertString("Foo=1,2,3", x.get(Foo.class));
197 		var x2 = x;
198 		assertThrowsWithMessage(IllegalArgumentException.class, "Part name could not be found on bean type 'java.lang.String'", ()->x2.get(String.class));
199 	}
200 
201 	@Test void a08_get() {
202 		var x = PartList.of(FOO_1, FOO_2, X_x);
203 		assertEmpty(x.getAll(null));
204 		assertList(x.getAll("Foo"), "Foo=1", "Foo=2");
205 		assertEmpty(x.getAll("FOO"));
206 		assertEmpty(x.getAll("Bar"));
207 	}
208 
209 	@Test void a09_getFirst() {
210 		var x = PartList.of(FOO_1, FOO_2, X_x);
211 		assertEmpty(x.getFirst(null));
212 		assertString("Foo=1", x.getFirst("Foo"));
213 		assertEmpty(x.getFirst("FOO"));
214 		assertEmpty(x.getFirst("Bar"));
215 	}
216 
217 	@Test void a10_getLast() {
218 		var x = PartList.of(FOO_1, FOO_2, X_x);
219 		assertEmpty(x.getLast(null));
220 		assertString("Foo=2", x.getLast("Foo"));
221 		assertEmpty(x.getLast("FOO"));
222 		assertEmpty(x.getLast("Bar"));
223 	}
224 
225 	@Test void a11_contains() {
226 		var x = PartList.of(FOO_1, FOO_2, X_x);
227 		assertFalse(x.contains(null));
228 		assertTrue(x.contains("Foo"));
229 		assertFalse(x.contains("FOO"));
230 		assertFalse(x.contains("Bar"));
231 	}
232 
233 	@Test void a12_partIterator_all() {
234 		var x = PartList.of();
235 		assertFalse(x.partIterator().hasNext());
236 		x = PartList.of(FOO_1);
237 		assertTrue(x.partIterator().hasNext());
238 	}
239 
240 	@Test void a13_partIterator_single() {
241 		var x = PartList.of();
242 		assertFalse(x.partIterator("Foo").hasNext());
243 		x = PartList.of(FOO_1);
244 		assertTrue(x.partIterator("Foo").hasNext());
245 		assertFalse(x.partIterator("FOO").hasNext());
246 	}
247 
248 	@Test void a14_forEach_all() {
249 		var x = PartList.of();
250 
251 		var i1 = new AtomicInteger();
252 		x.forEach(h -> i1.incrementAndGet());
253 		assertEquals(0, i1.get());
254 
255 		x = PartList.of(FOO_1, FOO_2);
256 		var i2 = new AtomicInteger();
257 		x.forEach(h -> i2.incrementAndGet());
258 		assertEquals(2, i2.get());
259 	}
260 
261 	@Test void a15_forEach_single() {
262 		var x = PartList.of();
263 
264 		var i1 = new AtomicInteger();
265 		x.forEach("Foo", h -> i1.incrementAndGet());
266 		assertEquals(0, i1.get());
267 
268 		x = PartList.of(FOO_1, FOO_2, X_x);
269 		var i2 = new AtomicInteger();
270 		x.forEach("Foo", h -> i2.incrementAndGet());
271 		assertEquals(2, i2.get());
272 	}
273 
274 	@Test void a16_stream_all() {
275 		var x = PartList.of();
276 
277 		var i1 = new AtomicInteger();
278 		x.stream().forEach(h -> i1.incrementAndGet());
279 		assertEquals(0, i1.get());
280 
281 		x = PartList.of(FOO_1, FOO_2);
282 		var i2 = new AtomicInteger();
283 		x.stream().forEach(h -> i2.incrementAndGet());
284 		assertEquals(2, i2.get());
285 	}
286 
287 	@Test void a17_stream_single() {
288 		var x = PartList.of();
289 
290 		var i1 = new AtomicInteger();
291 		x.stream("Foo").forEach(h -> i1.incrementAndGet());
292 		assertEquals(0, i1.get());
293 
294 		x = PartList.of(FOO_1, FOO_2, X_x);
295 		var i2 = new AtomicInteger();
296 		x.stream("Foo").forEach(h -> i2.incrementAndGet());
297 		assertEquals(2, i2.get());
298 	}
299 
300 	@Test void a18_caseSensitive() {
301 		var x1 = PartList.create().append(FOO_1, FOO_2, X_x);
302 		assertList(x1.getAll("Foo"), "Foo=1", "Foo=2");
303 		assertEmpty(x1.getAll("FOO"));
304 
305 		var x2 = x1.copy().caseInsensitive(true);
306 		assertList(x2.getAll("Foo"), "Foo=1", "Foo=2");
307 		assertList(x2.getAll("FOO"), "Foo=1", "Foo=2");
308 	}
309 
310 	@Test void a19_size() {
311 		var x = PartList.of(FOO_1);
312 		assertEquals(1, x.size());
313 	}
314 
315 	//-----------------------------------------------------------------------------------------------------------------
316 	// Builder methods
317 	//-----------------------------------------------------------------------------------------------------------------
318 
319 	@Test void b01_builder_clear() {
320 		var x = PartList.create();
321 		x.append(FOO_1);
322 		x.clear();
323 		assertEquals("", s(x));
324 	}
325 
326 	@Test void b02_builder_append() {
327 		var x1 = PartList.create().append(FOO_1);
328 		var x2 = PartList
329 			.create()
330 			.append()
331 			.append((PartList)null)
332 			.append((NameValuePair)null)
333 			.append((NameValuePair[])null)
334 			.append(x1)
335 			.append(FOO_2, FOO_3)
336 			.append("Bar", "b1")
337 			.append("Bar", ()->"b2")
338 			.append((List<NameValuePair>)null)
339 			.append(alist(FOO_4));
340 		assertEquals("Foo=1&Foo=2&Foo=3&Bar=b1&Bar=b2&Foo=4", s(x2));
341 	}
342 
343 	@Test void b03_builder_prepend() {
344 		var x1 = PartList.create().append(FOO_1);
345 		var x2 = PartList
346 			.create()
347 			.prepend()
348 			.prepend((PartList)null)
349 			.prepend((NameValuePair)null)
350 			.prepend((NameValuePair[])null)
351 			.prepend(x1)
352 			.prepend(FOO_2, FOO_3)
353 			.prepend("Bar", "b1")
354 			.prepend("Bar", ()->"b2")
355 			.prepend((List<NameValuePair>)null)
356 			.prepend(alist(FOO_4));
357 		assertEquals("Foo=4&Bar=b2&Bar=b1&Foo=2&Foo=3&Foo=1", s(x2));
358 	}
359 
360 	@Test void b04_builder_remove() {
361 		var x = PartList
362 			.create()
363 			.append(FOO_1,FOO_2,FOO_3,FOO_4,FOO_5,FOO_6,FOO_7)
364 			.remove((PartList)null)
365 			.remove((NameValuePair)null)
366 			.remove(PartList.of(FOO_1))
367 			.remove(FOO_2)
368 			.remove(FOO_3, FOO_4)
369 			.remove(alist(FOO_5));
370 		assertEquals("Foo=6&Foo=7", s(x));
371 
372 		x = PartList.create().append(FOO_1,FOO_2).remove((String[])null).remove("Bar","Foo");
373 		assertEquals("", s(x));
374 	}
375 
376 	@Test void b05_builder_set() {
377 		var x = PartList
378 			.create()
379 			.append(FOO_1,FOO_2)
380 			.set(FOO_3)
381 			.set(BAR_1)
382 			.set((NameValuePair)null)
383 			.set((PartList)null);
384 		assertEquals("Foo=3&Bar=1", s(x));
385 
386 		x = PartList
387 			.create()
388 			.append(BAR_1,FOO_1,FOO_2,BAR_2)
389 			.set(FOO_3);
390 		assertEquals("Bar=1&Foo=3&Bar=2", s(x));
391 
392 		x = PartList
393 			.create()
394 			.append(BAR_1,FOO_1,FOO_2,BAR_2)
395 			.set((NameValuePair[])null)
396 			.set(null,FOO_3,FOO_4,FOO_5);
397 		assertEquals("Bar=1&Bar=2&Foo=3&Foo=4&Foo=5", s(x));
398 
399 		x = PartList
400 			.create()
401 			.append(BAR_1,FOO_1,FOO_2,BAR_2)
402 			.set((List<NameValuePair>)null)
403 			.set(alist(null,FOO_3,FOO_4,FOO_5));
404 		assertEquals("Bar=1&Bar=2&Foo=3&Foo=4&Foo=5", s(x));
405 
406 		x = PartList
407 			.create()
408 			.append(BAR_1,FOO_1,FOO_2,BAR_2)
409 			.caseInsensitive(true)
410 			.set("FOO", "x");
411 		assertEquals("Bar=1&FOO=x&Bar=2", s(x));
412 
413 		x = PartList
414 			.create()
415 			.append(BAR_1,FOO_1,FOO_2,BAR_2)
416 			.caseInsensitive(true)
417 			.set("FOO", ()->"x");
418 		assertEquals("Bar=1&FOO=x&Bar=2", s(x));
419 
420 		x = PartList
421 			.create()
422 			.append(BAR_1,FOO_1,FOO_2,BAR_2)
423 			.set("FOO", ()->"x");
424 		assertEquals("Bar=1&Foo=1&Foo=2&Bar=2&FOO=x", s(x));
425 
426 		x = PartList
427 			.create()
428 			.append(BAR_1,FOO_1,FOO_2,BAR_2)
429 			.set(PartList.of(FOO_3,FOO_4));
430 		assertEquals("Bar=1&Bar=2&Foo=3&Foo=4", s(x));
431 	}
432 
433 	//-----------------------------------------------------------------------------------------------------------------
434 	// BasicPartIterator
435 	//-----------------------------------------------------------------------------------------------------------------
436 
437 	@Test void c01_iterators() {
438 		var x = PartList.of(APart.X, BPart.X);
439 
440 		var i1 = x.partIterator();
441 		assertString("a=x", i1.next());
442 		assertString("b=x", i1.next());
443 		assertThrowsWithMessage(NoSuchElementException.class, "Iteration already finished.", i1::next);
444 
445 		var i2 = x.partIterator();
446 		assertString("a=x", i2.next());
447 		assertString("b=x", i2.next());
448 		assertThrowsWithMessage(NoSuchElementException.class, "Iteration already finished.", i2::next);
449 
450 		var i3 = x.partIterator("a");
451 		assertString("a=x", i3.next());
452 		assertThrowsWithMessage(NoSuchElementException.class, "Iteration already finished.", i3::next);
453 
454 		var i4 = x.partIterator("A");
455 		assertThrowsWithMessage(NoSuchElementException.class, "Iteration already finished.", i4::next);
456 
457 		var x2 = PartList.create().append(APart.X,BPart.X).caseInsensitive(true);
458 
459 		var i5 = x2.partIterator("A");
460 		assertString("a=x", i5.next());
461 		assertThrowsWithMessage(NoSuchElementException.class, "Iteration already finished.", i5::next);
462 
463 		assertThrowsWithMessage(UnsupportedOperationException.class, "Not supported.", i5::remove);
464 	}
465 
466 	//-----------------------------------------------------------------------------------------------------------------
467 	// Default headers
468 	//-----------------------------------------------------------------------------------------------------------------
469 
470 	@Test void d01_defaultParts() {
471 		var x1 = PartList.create().setDefault(APart.X);
472 		assertEquals("a=x", s(x1));
473 
474 		var x2 = PartList.create().set(APart.X).setDefault(APart.Y);
475 		assertEquals("a=x", s(x2));
476 
477 		var x3 = PartList.create().set(BPart.X,APart.X,BPart.Y).setDefault(APart.Y);
478 		assertEquals("b=x&a=x&b=y", s(x3));
479 
480 		var x4 = PartList.create().set(BPart.X,BPart.Y).setDefault(APart.X);
481 		assertEquals("b=x&b=y&a=x", s(x4));
482 
483 		var x5 = PartList.create().set(BPart.X,BPart.Y).setDefault(APart.X).setDefault(BPart.X);
484 		assertEquals("b=x&b=y&a=x", s(x5));
485 
486 		var x7 = PartList.create().setDefault(APart.X).setDefault(APart.Y);
487 		assertEquals("a=x", s(x7));
488 
489 		var x8 = PartList.create().setDefault(APart.X,APart.Y).setDefault(APart.Z);
490 		assertEquals("a=x", s(x8));
491 
492 		var x9 = PartList
493 			.create()
494 			.setDefault((NameValuePair)null)
495 			.setDefault((PartList)null)
496 			.setDefault((NameValuePair[])null)
497 			.setDefault((List<NameValuePair>)null);
498 		assertEquals("", s(x9));
499 
500 		var x10 = PartList.create().setDefault("a","x");
501 		assertEquals("a=x", s(x10));
502 
503 		var x11 = PartList.create().setDefault("a",()->"x");
504 		assertEquals("a=x", s(x11));
505 
506 		var x12 = PartList.create().set(BPart.X,BPart.Y).setDefault(alist(APart.X,BPart.Z,null));
507 		assertEquals("b=x&b=y&a=x", s(x12));
508 
509 		var x13 = PartList.create().set(BPart.X,BPart.Y).setDefault(PartList.of(APart.X,BPart.Z,null));
510 		assertEquals("b=x&b=y&a=x", s(x13));
511 
512 		var x14 = PartList.create().set(BPart.X,BPart.Y)
513 			.setDefault(alist(APart.X,BPart.X,null))
514 			.setDefault(alist(APart.Y,BPart.Y,null))
515 			.setDefault(alist(CPart.X));
516 		assertEquals("b=x&b=y&a=x&c=x", s(x14));
517 	}
518 
519 	//-----------------------------------------------------------------------------------------------------------------
520 	// Utility methods
521 	//-----------------------------------------------------------------------------------------------------------------
522 
523 	private static NameValuePair part(String name, Object val) {
524 		return basicPart(name, val);
525 	}
526 
527 	private static HttpPartSerializerSession openApiSession() {
528 		return OpenApiSerializer.DEFAULT.getPartSession();
529 	}
530 }