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