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.commons.collections;
18  
19  import static org.apache.juneau.commons.lang.TriState.*;
20  import static org.apache.juneau.commons.utils.CollectionUtils.*;
21  import static org.apache.juneau.junit.bct.BctAssertions.*;
22  import static org.junit.jupiter.api.Assertions.*;
23  
24  import java.util.*;
25  
26  import org.apache.juneau.*;
27  import org.apache.juneau.junit.bct.annotations.*;
28  import org.junit.jupiter.api.*;
29  
30  class Sets_Test extends TestBase {
31  
32  	//-----------------------------------------------------------------------------------------------------------------
33  	// Basic tests
34  	//-----------------------------------------------------------------------------------------------------------------
35  
36  	@Test
37  	void a01_create() {
38  		var b = Sets.create(String.class);
39  		assertNotNull(b);
40  	}
41  
42  	@Test
43  	void a02_addSingle() {
44  		var set = Sets.create(String.class)
45  			.add("a")
46  			.build();
47  
48  		assertList(set, "a");
49  	}
50  
51  	@Test
52  	void a03_addMultiple() {
53  		var set = Sets.create(String.class)
54  			.add("a", "b", "c")
55  			.build();
56  
57  		assertList(set, "a", "b", "c");
58  	}
59  
60  	@Test
61  	void a04_addAll() {
62  		var existing = l("x", "y", "z");
63  		var set = Sets.create(String.class)
64  			.ordered()
65  			.add("a")
66  			.addAll(existing)
67  			.add("b")
68  			.build();
69  
70  		assertList(set, "a", "x", "y", "z", "b");
71  	}
72  
73  	@Test
74  	void a05_addAllNull() {
75  		var set = Sets.create(String.class)
76  			.add("a")
77  			.addAll(null)
78  			.add("b")
79  			.build();
80  
81  		assertList(set, "a", "b");
82  	}
83  
84  	//-----------------------------------------------------------------------------------------------------------------
85  	// Deduplication
86  	//-----------------------------------------------------------------------------------------------------------------
87  
88  	@Test
89  	void b01_duplicates() {
90  		var set = Sets.create(String.class)
91  			.add("a", "b", "a", "c", "b", "a")
92  			.build();
93  
94  		assertList(set, "a", "b", "c");  // Duplicates removed
95  	}
96  
97  	@Test
98  	void b02_addAllWithDuplicates() {
99  		var existing = l("a", "b", "c");
100 		var set = Sets.create(String.class)
101 			.add("a", "b")  // a and b already in next collection
102 			.addAll(existing)
103 			.add("c", "d")  // c already exists
104 			.build();
105 
106 		assertSize(4, set);  // a, b, c, d (no duplicates)
107 	}
108 
109 	//-----------------------------------------------------------------------------------------------------------------
110 	// Conditional adding
111 	//-----------------------------------------------------------------------------------------------------------------
112 
113 	@Test
114 	void c01_addIf_true() {
115 		var set = Sets.create(String.class)
116 			.add("a")
117 			.addIf(true, "b")
118 			.add("c")
119 			.build();
120 
121 		assertSize(3, set);
122 		assertTrue(set.contains("b"));
123 	}
124 
125 	@Test
126 	void c02_addIf_false() {
127 		var set = Sets.create(String.class)
128 			.add("a")
129 			.addIf(false, "b")
130 			.add("c")
131 			.build();
132 
133 		assertSize(2, set);
134 		assertTrue(set.contains("a"));
135 		assertFalse(set.contains("b"));
136 		assertTrue(set.contains("c"));
137 	}
138 
139 	//-----------------------------------------------------------------------------------------------------------------
140 	// Sorting
141 	//-----------------------------------------------------------------------------------------------------------------
142 
143 	@Test
144 	void d01_sorted_naturalOrder() {
145 		var set = Sets.create(String.class)
146 			.add("c", "a", "b")
147 			.sorted()
148 			.build();
149 
150 		assertList(set, "a", "b", "c");
151 		assertTrue(set instanceof TreeSet);
152 	}
153 
154 	@Test
155 	void d02_sorted_customComparator() {
156 		var set = Sets.create(String.class)
157 			.add("a", "bb", "ccc")
158 			.sorted(Comparator.comparing(String::length))
159 			.build();
160 
161 		assertList(set, "a", "bb", "ccc");
162 	}
163 
164 	@Test
165 	void d03_sorted_integers() {
166 		var set = Sets.create(Integer.class)
167 			.add(5, 2, 8, 1, 9)
168 			.sorted()
169 			.build();
170 
171 		assertList(set, 1, 2, 5, 8, 9);
172 	}
173 
174 	//-----------------------------------------------------------------------------------------------------------------
175 	// Sparse mode
176 	//-----------------------------------------------------------------------------------------------------------------
177 
178 	@Test
179 	void e01_sparse_empty() {
180 		var set = Sets.create(String.class)
181 			.sparse()
182 			.build();
183 
184 		assertNull(set);
185 	}
186 
187 	@Test
188 	void e02_sparse_notEmpty() {
189 		var set = Sets.create(String.class)
190 			.add("a")
191 			.sparse()
192 			.build();
193 
194 		assertNotNull(set);
195 		assertSize(1, set);
196 	}
197 
198 	@Test
199 	void e03_notSparse_empty() {
200 		var set = Sets.create(String.class)
201 			.build();
202 
203 		assertNotNull(set);
204 		assertEmpty(set);
205 	}
206 
207 	//-----------------------------------------------------------------------------------------------------------------
208 	// Unmodifiable
209 	//-----------------------------------------------------------------------------------------------------------------
210 
211 	@Test
212 	void f01_unmodifiable() {
213 		var set = Sets.create(String.class)
214 			.add("a", "b", "c")
215 			.unmodifiable()
216 			.build();
217 
218 		assertSize(3, set);
219 		assertThrows(UnsupportedOperationException.class, () -> set.add("d"));
220 	}
221 
222 	@Test
223 	void f02_modifiable() {
224 		var set = Sets.create(String.class)
225 			.add("a", "b", "c")
226 			.build();
227 
228 		set.add("d");
229 		assertSize(4, set);
230 	}
231 
232 	//-----------------------------------------------------------------------------------------------------------------
233 	// Copy mode
234 	//-----------------------------------------------------------------------------------------------------------------
235 
236 	//-----------------------------------------------------------------------------------------------------------------
237 	// Element type
238 	//-----------------------------------------------------------------------------------------------------------------
239 
240 	@Test
241 	void h01_elementType() {
242 		var b = new Sets<>(String.class);
243 		b.elementType(String.class);
244 
245 		var set = b.add("a", "b").build();
246 		assertSize(2, set);
247 	}
248 
249 	//-----------------------------------------------------------------------------------------------------------------
250 	// Complex scenarios
251 	//-----------------------------------------------------------------------------------------------------------------
252 
253 	@Test
254 	void i01_multipleOperations() {
255 		var existing = l("x", "y");
256 		var set = Sets.create(String.class)
257 			.add("a")
258 			.addAll(existing)
259 			.addIf(true, "b")
260 			.addIf(false, "skip")
261 			.add("c", "d", "a")  // "a" is duplicate
262 			.sorted()
263 			.build();
264 
265 		// Should be sorted, no "skip", no duplicate "a"
266 		assertList(set, "a", "b", "c", "d", "x", "y");
267 	}
268 
269 	@Test
270 	void i02_sortedAndUnmodifiable() {
271 		var set = Sets.create(Integer.class)
272 			.add(3, 1, 2)
273 			.sorted()
274 			.unmodifiable()
275 			.build();
276 
277 		assertList(set, 1, 2, 3);
278 		assertThrows(UnsupportedOperationException.class, () -> set.add(4));
279 	}
280 
281 	@Test
282 	void i03_sparseAndSorted() {
283 		var set1 = Sets.create(String.class)
284 			.add("c", "a", "b")
285 			.sorted()
286 			.sparse()
287 			.build();
288 
289 		assertNotNull(set1);
290 		assertList(set1, "a", "b", "c");
291 
292 		var set2 = Sets.create(String.class)
293 			.sorted()
294 			.sparse()
295 			.build();
296 
297 		assertNull(set2);
298 	}
299 
300 	//-----------------------------------------------------------------------------------------------------------------
301 	// Edge cases
302 	//-----------------------------------------------------------------------------------------------------------------
303 
304 	@Test
305 	void j01_buildEmptySet() {
306 		var set = Sets.create(String.class)
307 			.build();
308 
309 		assertNotNull(set);
310 		assertEmpty(set);
311 	}
312 
313 	@Test
314 	void j02_addNullElement() {
315 		var set = Sets.create(String.class)
316 			.ordered()
317 			.add("a")
318 			.add((String)null)
319 			.add("b")
320 			.build();
321 
322 		assertList(set, "a", "<null>", "b");
323 	}
324 
325 
326 	//-----------------------------------------------------------------------------------------------------------------
327 	// AddAll edge cases
328 	//-----------------------------------------------------------------------------------------------------------------
329 
330 	@Test
331 	void k01_addAll_whenSetIsNull() {
332 		// Test addAll when set is null (should create new LinkedHashSet from collection)
333 		var existing = l("a", "b", "c");
334 		var set = Sets.create(String.class)
335 			.addAll(existing)
336 			.build();
337 
338 		assertList(set, "a", "b", "c");
339 	}
340 
341 	//-----------------------------------------------------------------------------------------------------------------
342 	// ElementFunction
343 	//-----------------------------------------------------------------------------------------------------------------
344 
345 	@Test
346 	void l01_elementFunction_withFunction() {
347 		var set = Sets.create(Integer.class)
348 			.elementFunction(o -> {
349 				if (o instanceof String) {
350 					return Integer.parseInt((String)o);
351 				}
352 				return null;
353 			})
354 			.addAny("1", "2", "3")
355 			.build();
356 
357 		assertList(set, 1, 2, 3);
358 	}
359 
360 	@Test
361 	void l02_elementFunction_withConverter() {
362 		var converter = new org.apache.juneau.commons.conversion.Converter() {
363 			@Override
364 			public <T> T convertTo(Class<T> type, Object o) {
365 				if (type == Integer.class && o instanceof String) {
366 					return type.cast(Integer.parseInt((String)o));
367 				}
368 				return null;
369 			}
370 		};
371 
372 		var set = Sets.create(Integer.class)
373 			.elementFunction(o -> converter.convertTo(Integer.class, o))
374 			.addAny("1", "2", "3")
375 			.build();
376 
377 		assertList(set, 1, 2, 3);
378 	}
379 
380 	@Test
381 	void l03_elementFunction_multipleConverters() {
382 		var converter1 = new org.apache.juneau.commons.conversion.Converter() {
383 			@Override
384 			public <T> T convertTo(Class<T> type, Object o) {
385 				return null;  // Doesn't handle this
386 			}
387 		};
388 
389 		var converter2 = new org.apache.juneau.commons.conversion.Converter() {
390 			@Override
391 			public <T> T convertTo(Class<T> type, Object o) {
392 				if (type == Integer.class && o instanceof String) {
393 					return type.cast(Integer.parseInt((String)o));
394 				}
395 				return null;
396 			}
397 		};
398 
399 		var set = Sets.create(Integer.class)
400 			.elementFunction(o -> {
401 				Integer result = converter1.convertTo(Integer.class, o);
402 				if (result != null) return result;
403 				return converter2.convertTo(Integer.class, o);
404 			})
405 			.addAny("1", "2")
406 			.build();
407 
408 		assertList(set, 1, 2);
409 	}
410 
411 	//-----------------------------------------------------------------------------------------------------------------
412 	// AddAny
413 	//-----------------------------------------------------------------------------------------------------------------
414 
415 	@Test
416 	void m01_addAny_withDirectValues() {
417 		var set = Sets.create(String.class)
418 			.addAny("a", "b", "c")
419 			.build();
420 
421 		assertList(set, "a", "b", "c");
422 	}
423 
424 	@Test
425 	void m02_addAny_withCollection() {
426 		var collection = l("a", "b", "c");
427 		var set = Sets.create(String.class)
428 			.addAny(collection)
429 			.build();
430 
431 		assertList(set, "a", "b", "c");
432 	}
433 
434 	@Test
435 	void m03_addAny_withArray() {
436 		var array = new String[]{"a", "b", "c"};
437 		var set = Sets.create(String.class)
438 			.addAny((Object)array)
439 			.build();
440 
441 		assertList(set, "a", "b", "c");
442 	}
443 
444 	@Test
445 	void m04_addAny_withNestedCollection() {
446 		var nested = l(l("a", "b"), l("c", "d"));
447 		var set = Sets.create(String.class)
448 			.addAny(nested)
449 			.build();
450 
451 		assertList(set, "a", "b", "c", "d");
452 	}
453 
454 	@Test
455 	void m05_addAny_withNestedArray() {
456 		var nested = new Object[]{new String[]{"a", "b"}, new String[]{"c", "d"}};
457 		var set = Sets.create(String.class)
458 			.addAny(nested)
459 			.build();
460 
461 		assertList(set, "a", "b", "c", "d");
462 	}
463 
464 	@Test
465 	void m06_addAny_withNullValues() {
466 		var set = Sets.create(String.class)
467 			.addAny("a", null, "b", null, "c")
468 			.build();
469 
470 		assertList(set, "a", "b", "c");
471 	}
472 
473 	@Test
474 	void m07_addAny_withTypeConversion() {
475 		var set = Sets.create(Integer.class)
476 			.elementFunction(o -> {
477 				if (o instanceof String) {
478 					return Integer.parseInt((String)o);
479 				}
480 				return null;
481 			})
482 			.addAny("1", "2", "3")
483 			.build();
484 
485 		assertList(set, 1, 2, 3);
486 	}
487 
488 	@Test
489 	void m08_addAny_withFunctionToCollection() {
490 		// This test verifies that addAny can handle collections directly.
491 		// Since elementFunction is for converting to the element type, not to collections,
492 		// we test that addAny works with collections directly.
493 		var set = Sets.create(String.class)
494 			.addAny(l("a", "b", "c"))
495 			.build();
496 
497 		assertList(set, "a", "b", "c");
498 	}
499 
500 	@Test
501 	void m09_addAny_noElementType() {
502 		assertThrows(IllegalArgumentException.class, () -> new Sets<String>(null));
503 	}
504 
505 	@Test
506 	void m10_addAny_noElementFunction_throwsException() {
507 		// Test line 698: convertElement returns null when elementFunction is null and element can't be converted
508 		// This causes line 242 to throw an exception
509 		// When elementFunction is null and we try to add a non-matching type, it should throw
510 		assertThrows(RuntimeException.class, () -> {
511 			Sets.create(Integer.class)
512 				.addAny("not-an-integer")
513 				.build();
514 		});
515 	}
516 
517 	@Test
518 	void m11_addAny_elementFunctionReturnsNull() {
519 		// ElementFunction exists but returns null (can't convert)
520 		// Should throw RuntimeException when elementFunction can't convert
521 		assertThrows(RuntimeException.class, () -> {
522 			Sets.create(Integer.class)
523 				.elementFunction(o -> null)  // Can't convert
524 				.addAny("not-an-integer")
525 				.build();
526 		});
527 	}
528 
529 	@Test
530 	void m12_addAny_withNullArray() {
531 		var set = Sets.create(String.class)
532 			.addAny((Object[])null)
533 			.build();
534 
535 		assertEmpty(set);
536 	}
537 
538 	//-----------------------------------------------------------------------------------------------------------------
539 	// AddJson
540 	//-----------------------------------------------------------------------------------------------------------------
541 
542 	@Test
543 	void n01_addJson() {
544 		// addJson is a wrapper around addAny, so it should work similarly
545 		// Note: This will depend on converters being able to parse JSON strings
546 		// For now, we'll test that it calls addAny correctly
547 		var set = Sets.create(String.class)
548 			.addJson("a", "b", "c")
549 			.build();
550 
551 		// Since there's no JSON parser converter by default, these are treated as strings
552 		assertList(set, "a", "b", "c");
553 	}
554 
555 	//-----------------------------------------------------------------------------------------------------------------
556 	// Build edge cases
557 	//-----------------------------------------------------------------------------------------------------------------
558 
559 	@Test
560 	void o01_build_sparseWithNullSet() {
561 		var set = Sets.create(String.class)
562 			.sparse()
563 			.build();
564 
565 		assertNull(set);
566 	}
567 
568 
569 	@Test
570 	void o03_build_notSparseWithNullSet() {
571 		var set = Sets.create(String.class)
572 			.build();
573 
574 		assertNotNull(set);
575 		assertEmpty(set);
576 	}
577 
578 	@Test
579 	void o04_build_sortedWithNullSet() {
580 		var set = Sets.create(String.class)
581 			.sorted()
582 			.build();
583 
584 		assertNotNull(set);
585 		assertTrue(set instanceof TreeSet);
586 		assertEmpty(set);
587 	}
588 
589 	@Test
590 	void o05_build_unmodifiableWithNullSet() {
591 		var set = Sets.create(String.class)
592 			.unmodifiable()
593 			.build();
594 
595 		assertNotNull(set);
596 		assertThrows(UnsupportedOperationException.class, () -> set.add("a"));
597 	}
598 
599 	//-----------------------------------------------------------------------------------------------------------------
600 	// BuildFluent
601 	//-----------------------------------------------------------------------------------------------------------------
602 
603 	@Test
604 	void p01_buildFluent_returnsFluentSet() {
605 		var set = Sets.create(String.class)
606 			.add("a", "b", "c")
607 			.buildFluent();
608 
609 		assertNotNull(set);
610 		assertSize(3, set);
611 		assertList(set, "a", "b", "c");
612 	}
613 
614 	@Test
615 	void p02_buildFluent_sparseEmpty() {
616 		var set = Sets.create(String.class)
617 			.sparse()
618 			.buildFluent();
619 
620 		assertNull(set);
621 	}
622 
623 	@Test
624 	void p03_buildFluent_withSorted() {
625 		var set = Sets.create(String.class)
626 			.add("c", "a", "b")
627 			.sorted()
628 			.buildFluent();
629 
630 		assertNotNull(set);
631 		assertList(set, "a", "b", "c");
632 	}
633 
634 	@Test
635 	void p04_buildFluent_withUnmodifiable() {
636 		var set = Sets.create(String.class)
637 			.add("a", "b", "c")
638 			.unmodifiable()
639 			.buildFluent();
640 
641 		assertNotNull(set);
642 		assertSize(3, set);
643 		assertThrows(UnsupportedOperationException.class, () -> set.add("d"));
644 	}
645 
646 	@Test
647 	void p05_buildFluent_fluentMethods() {
648 		var set = Sets.create(String.class)
649 			.add("a", "b")
650 			.buildFluent();
651 
652 		assertNotNull(set);
653 		// Test that FluentSet methods work
654 		set.a("c").aa(l("d", "e"));
655 		assertList(set, "a", "b", "c", "d", "e");
656 	}
657 
658 	//-----------------------------------------------------------------------------------------------------------------
659 	// buildFiltered
660 	//-----------------------------------------------------------------------------------------------------------------
661 
662 	@Test
663 	void q01_buildFiltered_returnsFilteredSet() {
664 		var set = Sets.create(String.class)
665 			.add("a", "b", "c")
666 			.buildFiltered();
667 
668 		assertNotNull(set);
669 		assertSize(3, set);
670 		assertList(set, "a", "b", "c");
671 	}
672 
673 	@Test
674 	void q02_buildFiltered_sparseEmpty() {
675 		var set = Sets.create(String.class)
676 			.sparse()
677 			.buildFiltered();
678 
679 		assertNull(set);
680 	}
681 
682 	@Test
683 	void q03_buildFiltered_withFiltering() {
684 		var set = Sets.create(Integer.class)
685 			.filtered(v -> v != null && v > 0)
686 			.add(5, -1, 10, 0)
687 			.buildFiltered();
688 
689 		assertNotNull(set);
690 		assertList(set, 5, 10);
691 	}
692 
693 	//-----------------------------------------------------------------------------------------------------------------
694 	// concurrent
695 	//-----------------------------------------------------------------------------------------------------------------
696 
697 	@Test
698 	void r01_concurrent_createsSynchronizedSet() {
699 		var set = Sets.create(String.class)
700 			.add("a", "b", "c")
701 			.concurrent()
702 			.build();
703 
704 		assertNotNull(set);
705 		assertSize(3, set);
706 	}
707 
708 	@Test
709 	void r02_concurrent_withSorted() {
710 		var set = Sets.create(String.class)
711 			.add("c", "a", "b")
712 			.sorted()
713 			.concurrent()
714 			.build();
715 
716 		assertNotNull(set);
717 		assertList(set, "a", "b", "c");
718 	}
719 
720 	@Test
721 	void r03_concurrent_withOrdered() {
722 		var set = Sets.create(String.class)
723 			.add("c", "a", "b")
724 			.ordered()
725 			.concurrent()
726 			.build();
727 
728 		assertNotNull(set);
729 		assertSize(3, set);
730 		assertTrue(set.contains("a"));
731 		assertTrue(set.contains("b"));
732 		assertTrue(set.contains("c"));
733 		// Order may not be preserved when concurrent is set, so we just verify all elements are present
734 	}
735 
736 	//-----------------------------------------------------------------------------------------------------------------
737 	// concurrent(boolean)
738 	//-----------------------------------------------------------------------------------------------------------------
739 
740 	@Test
741 	void s01_concurrent_boolean_true() {
742 		var set = Sets.create(String.class)
743 			.add("a", "b", "c")
744 			.concurrent(true)
745 			.build();
746 
747 		assertNotNull(set);
748 		assertSize(3, set);
749 	}
750 
751 	@Test
752 	void s02_concurrent_boolean_false() {
753 		var set = Sets.create(String.class)
754 			.add("a", "b", "c")
755 			.concurrent(false)
756 			.build();
757 
758 		assertNotNull(set);
759 		assertSize(3, set);
760 		// Should not be synchronized when false
761 	}
762 
763 	@Test
764 	void s03_concurrent_boolean_withSorted() {
765 		var set = Sets.create(String.class)
766 			.add("c", "a", "b")
767 			.sorted()
768 			.concurrent(true)
769 			.build();
770 
771 		assertNotNull(set);
772 		assertList(set, "a", "b", "c");
773 	}
774 
775 	//-----------------------------------------------------------------------------------------------------------------
776 	// filtered
777 	//-----------------------------------------------------------------------------------------------------------------
778 
779 	@Test
780 	void t01_filtered_defaultFiltering() {
781 		var set = Sets.create(Object.class)
782 			.filtered()
783 			.add("a", null, false, -1, new String[0], l(), m())
784 			.build();
785 
786 		assertList(set, "a");
787 	}
788 
789 	@Test
790 	void t02_filtered_withBooleanFalse() {
791 		var set = Sets.create(Boolean.class)
792 			.filtered()
793 			.add(true, false, true)
794 			.build();
795 
796 		assertList(set, true);
797 	}
798 
799 	@Test
800 	void t03_filtered_withNumberMinusOne() {
801 		var set = Sets.create(Integer.class)
802 			.filtered()
803 			.add(1, -1, 2, -1, 3)
804 			.build();
805 
806 		assertList(set, 1, 2, 3);
807 	}
808 
809 	@Test
810 	void t04_filtered_withEmptyArray() {
811 		var set = Sets.create(Object.class)
812 			.filtered()
813 			.add("a", new String[0], "b")
814 			.build();
815 
816 		assertList(set, "a", "b");
817 	}
818 
819 	@Test
820 	void t05_filtered_withEmptyMap() {
821 		var set = Sets.create(Object.class)
822 			.filtered()
823 			.add("a", m(), "b")
824 			.build();
825 
826 		assertList(set, "a", "b");
827 	}
828 
829 	@Test
830 	void t06_filtered_withEmptyCollection() {
831 		var set = Sets.create(Object.class)
832 			.filtered()
833 			.add("a", l(), "b")
834 			.build();
835 
836 		assertList(set, "a", "b");
837 	}
838 
839 	//-----------------------------------------------------------------------------------------------------------------
840 	// filtered(Predicate)
841 	//-----------------------------------------------------------------------------------------------------------------
842 
843 	@Test
844 	void u01_filtered_withPredicate() {
845 		var set = Sets.create(Integer.class)
846 			.filtered(v -> v != null && v > 0)
847 			.add(5, -1, 10, 0, 15)
848 			.build();
849 
850 		assertList(set, 5, 10, 15);
851 	}
852 
853 	@Test
854 	@BctConfig(sortCollections = TRUE)
855 	void u02_filtered_multipleFilters() {
856 		var set = Sets.create(Integer.class)
857 			.filtered(v -> v != null)
858 			.filtered(v -> v > 0)
859 			.filtered(v -> v < 100)
860 			.add(5, -1, 150, 0, 50, null)
861 			.build();
862 
863 		assertList(set, 5, 50);
864 	}
865 
866 	@Test
867 	void u03_filtered_withStringPredicate() {
868 		var set = Sets.create(String.class)
869 			.filtered(s -> s != null && s.length() > 2)
870 			.add("a", "ab", "abc", "abcd", "")
871 			.build();
872 
873 		assertList(set, "abc", "abcd");
874 	}
875 }