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.commons.collections4.collection;
18  
19  import static org.junit.jupiter.api.Assertions.assertEquals;
20  import static org.junit.jupiter.api.Assertions.assertFalse;
21  import static org.junit.jupiter.api.Assertions.assertNotNull;
22  import static org.junit.jupiter.api.Assertions.assertNull;
23  import static org.junit.jupiter.api.Assertions.assertThrows;
24  import static org.junit.jupiter.api.Assertions.assertTrue;
25  import static org.junit.jupiter.api.Assertions.fail;
26  
27  import java.io.ByteArrayInputStream;
28  import java.io.ByteArrayOutputStream;
29  import java.io.ObjectInputStream;
30  import java.io.ObjectOutputStream;
31  import java.io.Serializable;
32  import java.lang.reflect.Array;
33  import java.util.ArrayList;
34  import java.util.Arrays;
35  import java.util.Collection;
36  import java.util.Collections;
37  import java.util.ConcurrentModificationException;
38  import java.util.HashMap;
39  import java.util.HashSet;
40  import java.util.Iterator;
41  import java.util.List;
42  import java.util.Map;
43  import java.util.NoSuchElementException;
44  import java.util.Objects;
45  import java.util.function.Predicate;
46  
47  import org.apache.commons.collections4.AbstractObjectTest;
48  import org.apache.commons.lang3.ArrayUtils;
49  import org.apache.commons.lang3.StringUtils;
50  import org.junit.jupiter.api.Test;
51  
52  /**
53   * Abstract test class for {@link java.util.Collection} methods and contracts.
54   * <p>
55   * You should create a concrete subclass of this class to test any custom
56   * {@link Collection} implementation.  At minimum, you'll have to
57   * implement the {@link #makeObject()}, {@link #makeConfirmedCollection()}
58   * and {@link #makeConfirmedFullCollection()} methods.
59   * You might want to override some of the additional public methods as well:
60   * <p>
61   * <b>Element Population Methods</b>
62   * <p>
63   * Override these if your collection restricts what kind of elements are
64   * allowed (for instance, if {@code null} is not permitted):
65   * <ul>
66   * <li>{@link #getFullElements()}
67   * <li>{@link #getOtherElements()}
68   * </ul>
69   * <p>
70   * <b>Supported Operation Methods</b>
71   * <p>
72   * Override these if your collection doesn't support certain operations:
73   * <ul>
74   * <li>{@link #isAddSupported()}
75   * <li>{@link #isRemoveSupported()}
76   * <li>{@link #areEqualElementsDistinguishable()}
77   * <li>{@link #isNullSupported()}
78   * <li>{@link #isFailFastSupported()}
79   * </ul>
80   * <p>
81   * <b>Indicate Collection Behaviour</b>
82   * <p>
83   * Override these if your collection makes specific behavior guarantees:
84   * <ul>
85   * <li>{@link #getIterationBehaviour()}</li>
86   * </ul>
87   * <p>
88   * <b>Fixture Methods</b>
89   * <p>
90   * Fixtures are used to verify that the operation results in correct state
91   * for the collection.  Basically, the operation is performed against your
92   * collection implementation, and an identical operation is performed against a
93   * <i>confirmed</i> collection implementation.  A confirmed collection
94   * implementation is something like {@link java.util.ArrayList}, which is
95   * known to conform exactly to its collection interface's contract.  After the
96   * operation takes place on both your collection implementation and the
97   * confirmed collection implementation, the two collections are compared to see
98   * if their state is identical.  The comparison is usually much more involved
99   * than a simple {@code equals} test.  This verification is used to ensure
100  * proper modifications are made along with ensuring that the collection does
101  * not change when read-only modifications are made.
102  * <p>
103  * The {@link #collection} field holds an instance of your collection
104  * implementation; the {@link #confirmed} field holds an instance of the
105  * confirmed collection implementation.  The {@link #resetEmpty()} and
106  * {@link #resetFull()} methods set these fields to empty or full collections,
107  * so that tests can proceed from a known state.
108  * <p>
109  * After a modification operation to both {@link #collection} and
110  * {@link #confirmed}, the {@link #verify()} method is invoked to compare
111  * the results.  You may want to override {@link #verify()} to perform
112  * additional verifications.  For instance, when testing the collection
113  * views of a map, {@link org.apache.commons.collections4.map.AbstractMapTest AbstractTestMap}
114  * would override {@link #verify()} to make
115  * sure the map is changed after the collection view is changed.
116  * <p>
117  * If you're extending this class directly, you will have to provide
118  * implementations for the following:
119  * <ul>
120  * <li>{@link #makeConfirmedCollection()}
121  * <li>{@link #makeConfirmedFullCollection()}
122  * </ul>
123  * <p>
124  * Those methods should provide a confirmed collection implementation
125  * that's compatible with your collection implementation.
126  * <p>
127  * If you're extending {@link org.apache.commons.collections4.list.AbstractListTest AbstractListTest},
128  * {@link org.apache.commons.collections4.set.AbstractSetTest AbstractTestSet},
129  * or {@link org.apache.commons.collections4.bag.AbstractBagTest AbstractBagTest},
130  * you probably don't have to worry about the
131  * above methods, because those three classes already override the methods
132  * to provide standard JDK confirmed collections.<P>
133  * <p>
134  * <b>Other notes</b>
135  * <p>
136  * If your {@link Collection} fails one of these tests by design,
137  * you may still use this base set of cases.  Simply override the
138  * test case (method) your {@link Collection} fails.
139  */
140 public abstract class AbstractCollectionTest<E> extends AbstractObjectTest {
141 
142     //
143     // NOTE:
144     //
145     // Collection doesn't define any semantics for equals, and recommends you
146     // use reference-based default behavior of Object.equals.  (And a test for
147     // that already exists in AbstractTestObject).  Tests for equality of lists, sets
148     // and bags will have to be written in test subclasses.  Thus, there is no
149     // tests on Collection.equals nor any for Collection.hashCode.
150     //
151 
152     /**
153      * Flag to indicate the collection makes no ordering guarantees for the iterator. If this is not used
154      * then the behavior is assumed to be ordered and the output order of the iterator is matched by
155      * the toArray method.
156      */
157     public static final int UNORDERED = 0x1;
158 
159     // These fields are used by reset() and verify(), and any test
160     // method that tests a modification.
161 
162     /**
163      * Handle the optional exceptions declared by {@link Collection#contains(Object)}
164      * @param coll
165      * @param element
166      */
167     protected static void assertNotCollectionContains(final Collection<?> coll, final Object element) {
168         try {
169             assertFalse(coll.contains(element));
170         } catch (final ClassCastException | NullPointerException e) {
171             //apparently not
172         }
173     }
174 
175     /**
176      * Handle the optional exceptions declared by {@link Collection#containsAll(Collection)}
177      * @param coll
178      * @param sub
179      */
180     protected static void assertNotCollectionContainsAll(final Collection<?> coll, final Collection<?> sub) {
181         try {
182             assertFalse(coll.containsAll(sub));
183         } catch (final ClassCastException | NullPointerException e) {
184             //apparently not
185         }
186     }
187 
188     /**
189      * Handle optional exceptions of {@link Collection#removeAll(Collection)}
190      * @param coll
191      * @param sub
192      */
193     protected static void assertNotRemoveAllFromCollection(final Collection<?> coll, final Collection<?> sub) {
194         try {
195             assertFalse(coll.removeAll(sub));
196         } catch (final ClassCastException | NullPointerException e) {
197             //apparently not
198         }
199     }
200 
201     /**
202      * Handle optional exceptions of {@link Collection#remove(Object)}
203      * @param coll
204      * @param element
205      */
206     protected static void assertNotRemoveFromCollection(final Collection<?> coll, final Object element) {
207         try {
208             assertFalse(coll.remove(element));
209         } catch (final ClassCastException | NullPointerException e) {
210             //apparently not
211         }
212     }
213 
214     /**
215      * Assert the arrays contain the same elements, ignoring the order.
216      *
217      * <p>Note this does not test the arrays are deeply equal. Array elements are compared
218      * using {@link Object#equals(Object)}.
219      *
220      * @param a1 First array
221      * @param a2 Second array
222      * @param msg Failure message prefix
223      */
224     private static void assertUnorderedArrayEquals(final Object[] a1, final Object[] a2, final String msg) {
225         assertEquals(a1.length, a2.length, () -> msg + ": length");
226         final int size = a1.length;
227         // Track values that have been matched once (and only once)
228         final boolean[] matched = new boolean[size];
229         NEXT_OBJECT:
230         for (final Object o : a1) {
231             for (int i = 0; i < size; i++) {
232                 if (matched[i]) {
233                     // skip values already matched
234                     continue;
235                 }
236                 if (Objects.equals(o, a2[i])) {
237                     // values matched
238                     matched[i] = true;
239                     // continue to the outer loop
240                     continue NEXT_OBJECT;
241                 }
242             }
243             fail(msg + ": array 2 does not have object: " + o);
244         }
245     }
246 
247     /**
248      *  A collection instance that will be used for testing.
249      */
250     private Collection<E> collection;
251 
252     /**
253      *  Confirmed collection.  This is an instance of a collection that is
254      *  confirmed to conform exactly to the java.util.Collection contract.
255      *  Modification operations are tested by performing a mod on your
256      *  collection, performing the exact same mod on an equivalent confirmed
257      *  collection, and then calling verify() to make sure your collection
258      *  still matches the confirmed collection.
259      */
260     private Collection<E> confirmed;
261 
262     /**
263      * JUnit constructor.
264      *
265      * @param testName  the test class name
266      */
267     public AbstractCollectionTest(final String testName) {
268         super(testName);
269     }
270 
271     /**
272      *  Specifies whether equal elements in the collection are, in fact,
273      *  distinguishable with information not readily available.  That is, if a
274      *  particular value is to be removed from the collection, then there is
275      *  one and only one value that can be removed, even if there are other
276      *  elements which are equal to it.
277      *
278      *  <P>In most collection cases, elements are not distinguishable (equal is
279      *  equal), thus this method defaults to return false.  In some cases,
280      *  however, they are.  For example, the collection returned from the map's
281      *  values() collection view are backed by the map, so while there may be
282      *  two values that are equal, their associated keys are not.  Since the
283      *  keys are distinguishable, the values are.
284      *
285      *  <P>This flag is used to skip some verifications for iterator.remove()
286      *  where it is impossible to perform an equivalent modification on the
287      *  confirmed collection because it is not possible to determine which
288      *  value in the confirmed collection to actually remove.  Tests that
289      *  override the default (i.e. where equal elements are distinguishable),
290      *  should provide additional tests on iterator.remove() to make sure the
291      *  proper elements are removed when remove() is called on the iterator.
292      **/
293     public boolean areEqualElementsDistinguishable() {
294         return false;
295     }
296 
297     /**
298      * Creates a new Map Entry that is independent of the first and the map.
299      */
300     public Map.Entry<E, E> cloneMapEntry(final Map.Entry<E, E> entry) {
301         final HashMap<E, E> map = new HashMap<>();
302         map.put(entry.getKey(), entry.getValue());
303         return map.entrySet().iterator().next();
304     }
305 
306     public Collection<E> getCollection() {
307         return collection;
308     }
309 
310     public Collection<E> getConfirmed() {
311         return confirmed;
312     }
313 
314     /**
315      *  Returns an array of objects that are contained in a collection
316      *  produced by {@link #makeFullCollection()}.  Every element in the
317      *  returned array <I>must</I> be an element in a full collection.<P>
318      *  The default implementation returns a heterogeneous array of
319      *  objects with some duplicates. null is added if allowed.
320      *  Override if you require specific testing elements.  Note that if you
321      *  override {@link #makeFullCollection()}, you <I>must</I> override
322      *  this method to reflect the contents of a full collection.
323      */
324     @SuppressWarnings("unchecked")
325     public E[] getFullElements() {
326         if (isNullSupported()) {
327             final ArrayList<E> list = new ArrayList<>(Arrays.asList(getFullNonNullElements()));
328             list.add(4, null);
329             return (E[]) list.toArray();
330         }
331         return getFullNonNullElements().clone();
332     }
333 
334     /**
335      *  Returns a list of elements suitable for return by
336      *  {@link #getFullElements()}.  The array returned by this method
337      *  does not include null, but does include a variety of objects
338      *  of different types.  Override getFullElements to return
339      *  the results of this method if your collection does not support
340      *  the null element.
341      */
342     @SuppressWarnings("unchecked")
343     public E[] getFullNonNullElements() {
344         return (E[]) new Object[] {
345             StringUtils.EMPTY,
346             "One",
347             Integer.valueOf(2),
348             "Three",
349             Integer.valueOf(4),
350             "One",
351             Double.valueOf(5),
352             Float.valueOf(6),
353             "Seven",
354             "Eight",
355             "Nine",
356             Integer.valueOf(10),
357             Short.valueOf((short) 11),
358             Long.valueOf(12),
359             "Thirteen",
360             "14",
361             "15",
362             Byte.valueOf((byte) 16)
363         };
364     }
365 
366     /**
367      *  Returns a list of string elements suitable for return by
368      *  {@link #getFullElements()}.  Override getFullElements to return
369      *  the results of this method if your collection does not support
370      *  heterogeneous elements or the null element.
371      */
372     public Object[] getFullNonNullStringElements() {
373         return new Object[] {
374             "If", "the", "dull", "substance", "of", "my", "flesh", "were",
375             "thought", "Injurious", "distance", "could", "not", "stop", "my", "way",
376         };
377     }
378 
379     /**
380      * Return a flag specifying the iteration behavior of the collection.
381      * This is used to change the assertions used by specific tests.
382      * The default implementation returns 0 which indicates ordered iteration behavior.
383      *
384      * @return the iteration behavior
385      * @see #UNORDERED
386      */
387     protected int getIterationBehaviour(){
388         return 0;
389     }
390 
391     /**
392      *  Returns an array of elements that are <I>not</I> contained in a
393      *  full collection.  Every element in the returned array must
394      *  not exist in a collection returned by {@link #makeFullCollection()}.
395      *  The default implementation returns a heterogeneous array of elements
396      *  without null.  Note that some of the tests add these elements
397      *  to an empty or full collection, so if your collection restricts
398      *  certain kinds of elements, you should override this method.
399      */
400     public E[] getOtherElements() {
401         return getOtherNonNullElements();
402     }
403 
404     /**
405      *  Returns the default list of objects returned by
406      *  {@link #getOtherElements()}.  Includes many objects
407      *  of different types.
408      */
409     @SuppressWarnings("unchecked")
410     public E[] getOtherNonNullElements() {
411         return (E[]) new Object[] {
412             Integer.valueOf(0),
413             Float.valueOf(0),
414             Double.valueOf(0),
415             "Zero",
416             Short.valueOf((short) 0),
417             Byte.valueOf((byte) 0),
418             Long.valueOf(0),
419             Character.valueOf('\u0000'),
420             "0"
421         };
422     }
423 
424     /**
425      *  Returns a list of string elements suitable for return by
426      *  {@link #getOtherElements()}.  Override getOtherElements to return
427      *  the results of this method if your collection does not support
428      *  heterogeneous elements or the null element.
429      */
430     public Object[] getOtherNonNullStringElements() {
431         return new Object[] {
432             "For", "then", "despite", /* of */"space", "I", "would", "be",
433             "brought", "From", "limits", "far", "remote", "where", "thou", "dost", "stay"
434         };
435     }
436 
437     /**
438      *  Returns true if the collections produced by
439      *  {@link #makeObject()} and {@link #makeFullCollection()}
440      *  support the {@code add} and {@code addAll}
441      *  operations.<P>
442      *  Default implementation returns true.  Override if your collection
443      *  class does not support add or addAll.
444      */
445     public boolean isAddSupported() {
446         return true;
447     }
448 
449     /**
450      * Returns true to indicate that the collection supports equals() comparisons.
451      * This implementation returns false;
452      */
453     @Override
454     public boolean isEqualsCheckable() {
455         return false;
456     }
457 
458     /**
459      * Returns true to indicate that the collection supports fail fast iterators.
460      * The default implementation returns true;
461      */
462     public boolean isFailFastSupported() {
463         return false;
464     }
465 
466     /**
467      * Returns true to indicate that the collection supports holding null.
468      * The default implementation returns true;
469      */
470     public boolean isNullSupported() {
471         return true;
472     }
473 
474     /**
475      *  Returns true if the collections produced by
476      *  {@link #makeObject()} and {@link #makeFullCollection()}
477      *  support the {@code remove}, {@code removeAll},
478      *  {@code retainAll}, {@code clear} and
479      *  {@code iterator().remove()} methods.
480      *  Default implementation returns true.  Override if your collection
481      *  class does not support removal operations.
482      */
483     public boolean isRemoveSupported() {
484         return true;
485     }
486 
487     /**
488      *  Returns a confirmed empty collection.
489      *  For instance, an {@link java.util.ArrayList} for lists or a
490      *  {@link java.util.HashSet} for sets.
491      *
492      *  @return a confirmed empty collection
493      */
494     public abstract Collection<E> makeConfirmedCollection();
495 
496     /**
497      *  Returns a confirmed full collection.
498      *  For instance, an {@link java.util.ArrayList} for lists or a
499      *  {@link java.util.HashSet} for sets.  The returned collection
500      *  should contain the elements returned by {@link #getFullElements()}.
501      *
502      *  @return a confirmed full collection
503      */
504     public abstract Collection<E> makeConfirmedFullCollection();
505 
506     /**
507      *  Returns a full collection to be used for testing.  The collection
508      *  returned by this method should contain every element returned by
509      *  {@link #getFullElements()}.  The default implementation, in fact,
510      *  simply invokes {@code addAll} on an empty collection with
511      *  the results of {@link #getFullElements()}.  Override this default
512      *  if your collection doesn't support addAll.
513      */
514     public Collection<E> makeFullCollection() {
515         final Collection<E> c = makeObject();
516         c.addAll(Arrays.asList(getFullElements()));
517         return c;
518     }
519 
520     /**
521      * Return a new, empty {@link Collection} to be used for testing.
522      */
523     @Override
524     public abstract Collection<E> makeObject();
525 
526     /**
527      *  Resets the {@link #collection} and {@link #confirmed} fields to empty
528      *  collections.  Invoke this method before performing a modification
529      *  test.
530      */
531     public void resetEmpty() {
532         this.setCollection(makeObject());
533         this.setConfirmed(makeConfirmedCollection());
534     }
535 
536     /**
537      *  Resets the {@link #collection} and {@link #confirmed} fields to full
538      *  collections.  Invoke this method before performing a modification
539      *  test.
540      */
541     public void resetFull() {
542         this.setCollection(makeFullCollection());
543         this.setConfirmed(makeConfirmedFullCollection());
544     }
545 
546     /**
547      * Sets the collection.
548      * @param collection the Collection<E> to set
549      */
550     public void setCollection(final Collection<E> collection) {
551         this.collection = collection;
552     }
553 
554     /**
555      * Sets the confirmed.
556      * @param confirmed the Collection<E> to set
557      */
558     public void setConfirmed(final Collection<E> confirmed) {
559         this.confirmed = confirmed;
560     }
561 
562     // Tests
563     /**
564      *  Tests {@link Collection#add(Object)}.
565      */
566     @Test
567     public void testCollectionAdd() {
568         if (!isAddSupported()) {
569             return;
570         }
571 
572         final E[] elements = getFullElements();
573         for (final E element : elements) {
574             resetEmpty();
575             final boolean r = getCollection().add(element);
576             getConfirmed().add(element);
577             verify();
578             assertTrue(r, "Empty collection changed after add");
579             assertEquals(1, getCollection().size(), "Collection size is 1 after first add");
580         }
581 
582         resetEmpty();
583         int size = 0;
584         for (final E element : elements) {
585             final boolean r = getCollection().add(element);
586             getConfirmed().add(element);
587             verify();
588             if (r) {
589                 size++;
590             }
591             assertEquals(size, getCollection().size(), "Collection size should grow after add");
592             assertTrue(getCollection().contains(element), "Collection should contain added element");
593         }
594     }
595 
596     /**
597      *  Tests {@link Collection#addAll(Collection)}.
598      */
599     @Test
600     public void testCollectionAddAll() {
601         if (!isAddSupported()) {
602             return;
603         }
604 
605         resetEmpty();
606         E[] elements = getFullElements();
607         boolean r = getCollection().addAll(Arrays.asList(elements));
608         getConfirmed().addAll(Arrays.asList(elements));
609         verify();
610         assertTrue(r, "Empty collection should change after addAll");
611         for (final E element : elements) {
612             assertTrue(getCollection().contains(element), "Collection should contain added element");
613         }
614 
615         resetFull();
616         int size = getCollection().size();
617         elements = getOtherElements();
618         r = getCollection().addAll(Arrays.asList(elements));
619         getConfirmed().addAll(Arrays.asList(elements));
620         verify();
621         assertTrue(r, "Full collection should change after addAll");
622         for (final E element : elements) {
623             assertTrue(getCollection().contains(element),
624                     "Full collection should contain added element");
625         }
626         assertEquals(size + elements.length, getCollection().size(), "Size should increase after addAll");
627 
628         resetFull();
629         size = getCollection().size();
630         r = getCollection().addAll(Arrays.asList(getFullElements()));
631         getConfirmed().addAll(Arrays.asList(getFullElements()));
632         verify();
633         if (r) {
634             assertTrue(size < getCollection().size(), "Size should increase if addAll returns true");
635         } else {
636             assertEquals(size, getCollection().size(), "Size should not change if addAll returns false");
637         }
638     }
639 
640     /**
641      *  Test {@link Collection#clear()}.
642      */
643     @Test
644     public void testCollectionClear() {
645         if (!isRemoveSupported()) {
646             return;
647         }
648 
649         resetEmpty();
650         getCollection().clear(); // just to make sure it doesn't raise anything
651         verify();
652 
653         resetFull();
654         getCollection().clear();
655         getConfirmed().clear();
656         verify();
657     }
658 
659     /**
660      *  Tests {@link Collection#contains(Object)}.
661      */
662     @Test
663     public void testCollectionContains() {
664         Object[] elements;
665 
666         resetEmpty();
667         elements = getFullElements();
668         for (int i = 0; i < elements.length; i++) {
669             assertFalse(getCollection().contains(elements[i]), "Empty collection shouldn't contain element[" + i + "]");
670         }
671         // make sure calls to "contains" don't change anything
672         verify();
673 
674         elements = getOtherElements();
675         for (int i = 0; i < elements.length; i++) {
676             assertFalse(getCollection().contains(elements[i]), "Empty collection shouldn't contain element[" + i + "]");
677         }
678         // make sure calls to "contains" don't change anything
679         verify();
680 
681         resetFull();
682         elements = getFullElements();
683         for (int i = 0; i < elements.length; i++) {
684             assertTrue(getCollection().contains(elements[i]),
685                     "Full collection should contain element[" + i + "]");
686         }
687         // make sure calls to "contains" don't change anything
688         verify();
689 
690         resetFull();
691         elements = getOtherElements();
692         for (final Object element : elements) {
693             assertFalse(getCollection().contains(element), "Full collection shouldn't contain element");
694         }
695     }
696 
697     /**
698      *  Tests {@link Collection#containsAll(Collection)}.
699      */
700     @Test
701     public void testCollectionContainsAll() {
702         resetEmpty();
703         Collection<E> col = new HashSet<>();
704         assertTrue(getCollection().containsAll(col),
705                 "Every Collection should contain all elements of an " + "empty Collection.");
706         col.addAll(Arrays.asList(getOtherElements()));
707         assertFalse(getCollection().containsAll(col),
708                 "Empty Collection shouldn't contain all elements of " + "a non-empty Collection.");
709         // make sure calls to "containsAll" don't change anything
710         verify();
711 
712         resetFull();
713         assertFalse(getCollection().containsAll(col), "Full collection shouldn't contain other elements");
714 
715         col.clear();
716         col.addAll(Arrays.asList(getFullElements()));
717         assertTrue(getCollection().containsAll(col),
718                 "Full collection should containAll full elements");
719         // make sure calls to "containsAll" don't change anything
720         verify();
721 
722         final int min = getFullElements().length < 4 ? 0 : 2;
723         final int max = getFullElements().length == 1 ? 1 :
724                 getFullElements().length <= 5 ? getFullElements().length - 1 : 5;
725         col = Arrays.asList(getFullElements()).subList(min, max);
726         assertTrue(getCollection().containsAll(col),
727                 "Full collection should containAll partial full elements");
728         assertTrue(getCollection().containsAll(getCollection()),
729                 "Full collection should containAll itself");
730         // make sure calls to "containsAll" don't change anything
731         verify();
732 
733         col = new ArrayList<>(Arrays.asList(getFullElements()));
734         col.addAll(Arrays.asList(getFullElements()));
735         assertTrue(getCollection().containsAll(col),
736                 "Full collection should containAll duplicate full elements");
737 
738         // make sure calls to "containsAll" don't change anything
739         verify();
740     }
741 
742     /**
743      *  Tests {@link Collection#isEmpty()}.
744      */
745     @Test
746     public void testCollectionIsEmpty() {
747         resetEmpty();
748         assertTrue(getCollection().isEmpty(), "New Collection should be empty.");
749         // make sure calls to "isEmpty() don't change anything
750         verify();
751 
752         resetFull();
753         assertFalse(getCollection().isEmpty(), "Full collection shouldn't be empty");
754         // make sure calls to "isEmpty() don't change anything
755         verify();
756     }
757 
758     /**
759      *  Tests the read-only functionality of {@link Collection#iterator()}.
760      */
761     @Test
762     public void testCollectionIterator() {
763         resetEmpty();
764         Iterator<E> it1 = getCollection().iterator();
765         assertFalse(it1.hasNext(), "Iterator for empty Collection shouldn't have next.");
766         final Iterator<E> finalIt1 = it1;
767         assertThrows(NoSuchElementException.class, () -> finalIt1.next(),
768                 "Iterator at end of Collection should throw NoSuchElementException when next is called.");
769         // make sure nothing has changed after non-modification
770         verify();
771 
772         resetFull();
773         it1 = getCollection().iterator();
774         for (final E element : getCollection()) {
775             assertTrue(it1.hasNext(), "Iterator for full collection should haveNext");
776             it1.next();
777         }
778         assertFalse(it1.hasNext(), "Iterator should be finished");
779 
780         final ArrayList<E> list = new ArrayList<>();
781         it1 = getCollection().iterator();
782         for (int i = 0; i < getCollection().size(); i++) {
783             final E next = it1.next();
784             assertTrue(getCollection().contains(next),
785                     "Collection should contain element returned by its iterator");
786             list.add(next);
787         }
788         final Iterator<E> finalIt2 = it1;
789         assertThrows(NoSuchElementException.class, () -> finalIt2.next(),
790                 "iterator.next() should raise NoSuchElementException after it finishes");
791         // make sure nothing has changed after non-modification
792         verify();
793     }
794 
795     /**
796      *  Tests that the collection's iterator is fail-fast.
797      */
798     @Test
799     public void testCollectionIteratorFailFast() {
800         if (!isFailFastSupported()) {
801             return;
802         }
803 
804         if (isAddSupported()) {
805             resetFull();
806             final Iterator<E> iter0 = getCollection().iterator();
807             final E o = getOtherElements()[0];
808             getCollection().add(o);
809             getConfirmed().add(o);
810             assertThrows(ConcurrentModificationException.class, () -> iter0.next(),
811                     "next after add should raise ConcurrentModification");
812             verify();
813 
814             resetFull();
815             final Iterator<E> iter = getCollection().iterator();
816             getCollection().addAll(Arrays.asList(getOtherElements()));
817             getConfirmed().addAll(Arrays.asList(getOtherElements()));
818             assertThrows(ConcurrentModificationException.class, () -> iter.next(),
819                     "next after addAll should raise ConcurrentModification");
820             verify();
821         }
822 
823         if (!isRemoveSupported()) {
824             return;
825         }
826 
827         resetFull();
828         try {
829             final Iterator<E> iter = getCollection().iterator();
830             getCollection().clear();
831             iter.next();
832             fail("next after clear should raise ConcurrentModification");
833         } catch (final ConcurrentModificationException | NoSuchElementException e) {
834             // ConcurrentModificationException: expected
835             // NoSuchElementException: (also legal given spec)
836         }
837 
838         resetFull();
839         final Iterator<E> iter0 = getCollection().iterator();
840         getCollection().remove(getFullElements()[0]);
841         assertThrows(ConcurrentModificationException.class, () -> iter0.next(),
842                 "next after remove should raise ConcurrentModification");
843 
844         resetFull();
845         final Iterator<E> iter1 = getCollection().iterator();
846         getCollection().removeIf(e -> false);
847         assertThrows(ConcurrentModificationException.class, () -> iter1.next(),
848                 "next after removeIf should raise ConcurrentModification");
849 
850         resetFull();
851         final Iterator<E> iter2 = getCollection().iterator();
852         final List<E> sublist = Arrays.asList(getFullElements()).subList(2, 5);
853         getCollection().removeAll(sublist);
854         assertThrows(ConcurrentModificationException.class, () -> iter2.next(),
855                 "next after removeAll should raise ConcurrentModification");
856 
857         resetFull();
858         final Iterator<E> iter3 = getCollection().iterator();
859         final List<E> sublist3 = Arrays.asList(getFullElements()).subList(2, 5);
860         getCollection().retainAll(sublist3);
861         assertThrows(ConcurrentModificationException.class, () -> iter3.next(),
862                 "next after retainAll should raise ConcurrentModification");
863     }
864 
865     /**
866      *  Tests removals from {@link Collection#iterator()}.
867      */
868     @Test
869     @SuppressWarnings("unchecked")
870     public void testCollectionIteratorRemove() {
871         if (!isRemoveSupported()) {
872             return;
873         }
874 
875         resetEmpty();
876         assertThrows(IllegalStateException.class, () -> getCollection().iterator().remove(),
877                 "New iterator.remove should raise IllegalState");
878         verify();
879 
880         final Iterator<E> iter0 = getCollection().iterator();
881         iter0.hasNext();
882         assertThrows(IllegalStateException.class, () -> iter0.remove(),
883                 "New iterator.remove should raise IllegalState even after hasNext");
884         verify();
885 
886         resetFull();
887         int size = getCollection().size();
888         Iterator<E> iter = getCollection().iterator();
889         while (iter.hasNext()) {
890             Object o = iter.next();
891             // TreeMap reuses the Map Entry, so the verify below fails
892             // Clone it here if necessary
893             if (o instanceof Map.Entry) {
894                 o = cloneMapEntry((Map.Entry<E, E>) o);
895             }
896             iter.remove();
897 
898             // if the elements aren't distinguishable, we can just remove a
899             // matching element from the confirmed collection and verify
900             // contents are still the same.  Otherwise, we don't have the
901             // ability to distinguish the elements and determine which to
902             // remove from the confirmed collection (in which case, we don't
903             // verify because we don't know how).
904             //
905             // see areEqualElementsDistinguishable()
906             if (!areEqualElementsDistinguishable()) {
907                 getConfirmed().remove(o);
908                 verify();
909             }
910 
911             size--;
912             assertEquals(size, getCollection().size(),
913                     "Collection should shrink by one after iterator.remove");
914         }
915         assertTrue(getCollection().isEmpty(), "Collection should be empty after iterator purge");
916 
917         resetFull();
918         iter = getCollection().iterator();
919         iter.next();
920         iter.remove();
921         final Iterator<E> finalIter = iter;
922         assertThrows(IllegalStateException.class, () -> finalIter.remove(),
923                 "Second iter.remove should raise IllegalState");
924     }
925 
926     /**
927      *  Tests {@link Collection#remove(Object)}.
928      */
929     @Test
930     public void testCollectionRemove() {
931         if (!isRemoveSupported()) {
932             return;
933         }
934 
935         resetEmpty();
936         final E[] elements = getFullElements();
937         for (final E element : elements) {
938             assertFalse(getCollection().remove(element), "Shouldn't remove nonexistent element");
939             verify();
940         }
941 
942         final E[] other = getOtherElements();
943 
944         resetFull();
945         for (final E element : other) {
946             assertFalse(getCollection().remove(element), "Shouldn't remove nonexistent other element");
947             verify();
948         }
949 
950         final int size = getCollection().size();
951         for (final E element : elements) {
952             resetFull();
953             assertTrue(getCollection().remove(element),
954                     "Collection should remove extant element: " + element);
955 
956             // if the elements aren't distinguishable, we can just remove a
957             // matching element from the confirmed collection and verify
958             // contents are still the same.  Otherwise, we don't have the
959             // ability to distinguish the elements and determine which to
960             // remove from the confirmed collection (in which case, we don't
961             // verify because we don't know how).
962             //
963             // see areEqualElementsDistinguishable()
964             if (!areEqualElementsDistinguishable()) {
965                 getConfirmed().remove(element);
966                 verify();
967             }
968 
969             assertEquals(size - 1, getCollection().size(), "Collection should shrink after remove");
970         }
971     }
972 
973     /**
974      *  Tests {@link Collection#removeAll(Collection)}.
975      */
976     @Test
977     public void testCollectionRemoveAll() {
978         if (!isRemoveSupported()) {
979             return;
980         }
981 
982         resetEmpty();
983         assertFalse(getCollection().removeAll(Collections.EMPTY_SET), "Empty collection removeAll should return false for empty input");
984         verify();
985 
986         assertFalse(getCollection().removeAll(new ArrayList<>(getCollection())), "Empty collection removeAll should return false for nonempty input");
987         verify();
988 
989         resetFull();
990         assertFalse(getCollection().removeAll(Collections.EMPTY_SET), "Full collection removeAll should return false for empty input");
991         verify();
992 
993         assertFalse(getCollection().removeAll(Arrays.asList(getOtherElements())), "Full collection removeAll should return false for other elements");
994         verify();
995 
996         assertTrue(getCollection().removeAll(new HashSet<>(getCollection())),
997                 "Full collection removeAll should return true for full elements");
998         getConfirmed().removeAll(new HashSet<>(getConfirmed()));
999         verify();
1000 
1001         resetFull();
1002         final int size = getCollection().size();
1003         final int min = getFullElements().length < 4 ? 0 : 2;
1004         final int max = getFullElements().length == 1 ? 1 :
1005                 getFullElements().length <= 5 ? getFullElements().length - 1 : 5;
1006         final Collection<E> all = Arrays.asList(getFullElements()).subList(min, max);
1007         assertTrue(getCollection().removeAll(all), "Full collection removeAll should work");
1008         getConfirmed().removeAll(all);
1009         verify();
1010 
1011         assertTrue(getCollection().size() < size, "Collection should shrink after removeAll");
1012         for (final E element : all) {
1013             assertFalse(getCollection().contains(element), "Collection shouldn't contain removed element");
1014         }
1015     }
1016 
1017     /**
1018      *  Tests {@link Collection#removeIf(Predicate)}.
1019      */
1020     @Test
1021     public void testCollectionRemoveIf() {
1022         if (!isRemoveSupported()) {
1023             return;
1024         }
1025 
1026         resetEmpty();
1027         assertFalse(getCollection().removeIf(e -> false), "Empty collection removeIf should return false for a predicate that returns only false");
1028         verify();
1029 
1030         assertFalse(getCollection().removeIf(e -> true), "Empty collection removeIf should return false for a predicate that returns only true");
1031         verify();
1032 
1033         resetFull();
1034         assertFalse(getCollection().removeIf(e -> false), "Full collection removeIf should return false for a predicate that returns only false");
1035         verify();
1036 
1037         assertTrue(getCollection().removeIf(e -> true), "Full collection removeIf should return true for a predicate that returns only true");
1038         getConfirmed().removeIf(e -> true);
1039         verify();
1040 
1041         resetFull();
1042         final List<E> elements = Arrays.asList(getFullElements());
1043 
1044         final int mid = getFullElements().length / 2;
1045         final E target = elements.get(mid);
1046 
1047         final int size = getCollection().size();
1048         final int targetCount = Collections.frequency(elements, target);
1049 
1050         final Predicate<E> filter = target::equals;
1051 
1052         assertTrue(getCollection().removeIf(filter), "Full collection removeIf should work");
1053         getConfirmed().removeIf(filter);
1054         verify();
1055 
1056         assertEquals(getCollection().size(), size - targetCount, "Collection should shrink after removeIf");
1057         assertFalse(getCollection().contains(target), "Collection shouldn't contain removed element");
1058     }
1059 
1060     /**
1061      *  Tests {@link Collection#retainAll(Collection)}.
1062      */
1063     @Test
1064     public void testCollectionRetainAll() {
1065         if (!isRemoveSupported()) {
1066             return;
1067         }
1068 
1069         resetEmpty();
1070         final List<E> elements = Arrays.asList(getFullElements());
1071         final List<E> other = Arrays.asList(getOtherElements());
1072 
1073         assertFalse(getCollection().retainAll(Collections.EMPTY_SET), "Empty retainAll() should return false");
1074         verify();
1075 
1076         assertFalse(getCollection().retainAll(elements), "Empty retainAll() should return false");
1077         verify();
1078 
1079         resetFull();
1080         assertTrue(getCollection().retainAll(Collections.EMPTY_SET),
1081                 "Collection should change from retainAll empty");
1082         getConfirmed().retainAll(Collections.EMPTY_SET);
1083         verify();
1084 
1085         resetFull();
1086         assertTrue(getCollection().retainAll(other), "Collection changed from retainAll other");
1087         getConfirmed().retainAll(other);
1088         verify();
1089 
1090         resetFull();
1091         int size = getCollection().size();
1092         assertFalse(getCollection().retainAll(elements), "Collection shouldn't change from retainAll elements");
1093         verify();
1094         assertEquals(size, getCollection().size(), "Collection size shouldn't change");
1095 
1096         if (getFullElements().length > 1) {
1097             resetFull();
1098             size = getCollection().size();
1099             final int min = getFullElements().length < 4 ? 0 : 2;
1100             final int max = getFullElements().length <= 5 ? getFullElements().length - 1 : 5;
1101             assertTrue(getCollection().retainAll(elements.subList(min, max)),
1102                     "Collection should changed by partial retainAll");
1103             getConfirmed().retainAll(elements.subList(min, max));
1104             verify();
1105 
1106             for (final E element : getCollection()) {
1107                 assertTrue(elements.subList(min, max).contains(element), "Collection only contains retained element");
1108             }
1109         }
1110 
1111         resetFull();
1112         final HashSet<E> set = new HashSet<>(elements);
1113         size = getCollection().size();
1114         assertFalse(getCollection().retainAll(set),
1115                 "Collection shouldn't change from retainAll without " + "duplicate elements");
1116         verify();
1117         assertEquals(size, getCollection().size(),
1118                 "Collection size didn't change from nonduplicate " + "retainAll");
1119     }
1120 
1121     /**
1122      *  Tests {@link Collection#size()}.
1123      */
1124     @Test
1125     public void testCollectionSize() {
1126         resetEmpty();
1127         assertEquals(0, getCollection().size(), "Size of new Collection is 0.");
1128 
1129         resetFull();
1130         assertFalse(getCollection().isEmpty(), "Size of full collection should be greater than zero");
1131     }
1132 
1133     /**
1134      *  Tests {@link Collection#toArray()}.
1135      */
1136     @Test
1137     public void testCollectionToArray() {
1138         resetEmpty();
1139         assertEquals(0, getCollection().toArray().length,
1140                 "Empty Collection should return empty array for toArray");
1141 
1142         resetFull();
1143         final Object[] array = getCollection().toArray();
1144         assertEquals(array.length, getCollection().size(),
1145                 "Full collection toArray should be same size as collection");
1146         final Object[] confirmedArray = getConfirmed().toArray();
1147         assertEquals(confirmedArray.length, array.length, "length of array from confirmed collection should "
1148                 + "match the length of the collection's array");
1149         final boolean[] matched = new boolean[array.length];
1150 
1151         for (int i = 0; i < array.length; i++) {
1152             assertTrue(getCollection().contains(array[i]),
1153                     "Collection should contain element in toArray");
1154 
1155             boolean match = false;
1156             // find a match in the confirmed array
1157             for (int j = 0; j < array.length; j++) {
1158                 // skip already matched
1159                 if (matched[j]) {
1160                     continue;
1161                 }
1162                 if (Objects.equals(array[i], confirmedArray[j])) {
1163                     matched[j] = true;
1164                     match = true;
1165                     break;
1166                 }
1167             }
1168             if (!match) {
1169                 fail("element " + i + " in returned array should be found "
1170                         + "in the confirmed collection's array");
1171             }
1172         }
1173         for (final boolean element : matched) {
1174             assertTrue(element, "Collection should return all its elements in " + "toArray");
1175         }
1176     }
1177 
1178     /**
1179      *  Tests {@link Collection#toArray(Object[])}.
1180      */
1181     @Test
1182     public void testCollectionToArray2() {
1183         resetEmpty();
1184         Object[] a = { new Object(), null, null };
1185         Object[] array = getCollection().toArray(a);
1186         assertEquals(array, a, "Given array shouldn't shrink");
1187         assertNull(a[0], "Last element should be set to null");
1188         verify();
1189 
1190         resetFull();
1191         assertThrows(ArrayStoreException.class, () -> getCollection().toArray(new Void[0]),
1192                 "toArray(new Void[0]) should raise ArrayStore");
1193         verify();
1194 
1195         // Casting to Object[] allows compilation on Java 11.
1196         assertThrows(NullPointerException.class, () -> getCollection().toArray((Object[]) null),
1197                 "toArray(null) should raise NPE");
1198         verify();
1199 
1200         array = getCollection().toArray(ArrayUtils.EMPTY_OBJECT_ARRAY);
1201         a = getCollection().toArray();
1202 
1203         if ((getIterationBehaviour() & UNORDERED) != 0) {
1204             assertUnorderedArrayEquals(array, a, "toArray(Object[]) and toArray()");
1205         } else {
1206             assertEquals(Arrays.asList(array), Arrays.asList(a), "toArrays should be equal");
1207         }
1208         // Figure out if they're all the same class
1209         // TODO: It'd be nicer to detect a common superclass
1210         final HashSet<Class<?>> classes = new HashSet<>();
1211         for (final Object element : array) {
1212             classes.add(element == null ? null : element.getClass());
1213         }
1214         if (classes.size() > 1) {
1215             return;
1216         }
1217 
1218         Class<?> cl = classes.iterator().next();
1219         if (Map.Entry.class.isAssignableFrom(cl)) {  // check needed for protective cases like Predicated/Unmod map entrySet
1220             cl = Map.Entry.class;
1221         }
1222         a = (Object[]) Array.newInstance(cl, 0);
1223         array = getCollection().toArray(a);
1224         assertEquals(a.getClass(), array.getClass(),
1225                 "toArray(Object[]) should return correct array type");
1226 
1227         if ((getIterationBehaviour() & UNORDERED) != 0) {
1228             assertUnorderedArrayEquals(array, getCollection().toArray(), "type-specific toArray(T[]) and toArray()");
1229         } else {
1230             assertEquals(Arrays.asList(array),
1231                     Arrays.asList(getCollection().toArray()),
1232                     "type-specific toArrays should be equal");
1233         }
1234         verify();
1235     }
1236 
1237     /**
1238      *  Tests {@code toString} on a collection.
1239      */
1240     @Test
1241     public void testCollectionToString() {
1242         resetEmpty();
1243         assertNotNull(getCollection().toString(), "toString shouldn't return null");
1244 
1245         resetFull();
1246         assertNotNull(getCollection().toString(), "toString shouldn't return null");
1247     }
1248 
1249     @Test
1250     @Override
1251     public void testSerializeDeserializeThenCompare() throws Exception {
1252         Object obj = makeObject();
1253         if (obj instanceof Serializable && isTestSerialization()) {
1254             final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
1255             final ObjectOutputStream out = new ObjectOutputStream(buffer);
1256             out.writeObject(obj);
1257             out.close();
1258 
1259             final ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(buffer.toByteArray()));
1260             final Object dest = in.readObject();
1261             in.close();
1262             if (isEqualsCheckable()) {
1263                 assertEquals(obj, dest, "obj != deserialize(serialize(obj)) - EMPTY Collection");
1264             }
1265         }
1266         obj = makeFullCollection();
1267         if (obj instanceof Serializable && isTestSerialization()) {
1268             final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
1269             final ObjectOutputStream out = new ObjectOutputStream(buffer);
1270             out.writeObject(obj);
1271             out.close();
1272 
1273             final ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(buffer.toByteArray()));
1274             final Object dest = in.readObject();
1275             in.close();
1276             if (isEqualsCheckable()) {
1277                 assertEquals(obj, dest, "obj != deserialize(serialize(obj)) - FULL Collection");
1278             }
1279         }
1280     }
1281 
1282     /**
1283      *  If {@link #isAddSupported()} returns false, tests that add operations
1284      *  raise <code>UnsupportedOperationException.
1285      */
1286     @Test
1287     public void testUnsupportedAdd() {
1288         if (isAddSupported()) {
1289             return;
1290         }
1291 
1292         resetEmpty();
1293         assertThrows(UnsupportedOperationException.class, () -> getCollection().add(getFullNonNullElements()[0]),
1294                 "Empty collection should not support add.");
1295         // make sure things didn't change even if the expected exception was
1296         // thrown.
1297         verify();
1298 
1299         assertThrows(UnsupportedOperationException.class, () -> getCollection().addAll(Arrays.asList(getFullElements())),
1300                 "Empty collection should not support addAll.");
1301         // make sure things didn't change even if the expected exception was
1302         // thrown.
1303         verify();
1304 
1305         resetFull();
1306         assertThrows(UnsupportedOperationException.class, () -> getCollection().add(getFullNonNullElements()[0]),
1307                 "Full collection should not support add.");
1308         // make sure things didn't change even if the expected exception was
1309         // thrown.
1310         verify();
1311 
1312         assertThrows(UnsupportedOperationException.class, () -> getCollection().addAll(Arrays.asList(getOtherElements())),
1313                 "Full collection should not support addAll.");
1314         // make sure things didn't change even if the expected exception was
1315         // thrown.
1316         verify();
1317     }
1318 
1319     /**
1320      *  If isRemoveSupported() returns false, tests to see that remove
1321      *  operations raise an UnsupportedOperationException.
1322      */
1323     @Test
1324     public void testUnsupportedRemove() {
1325         if (isRemoveSupported()) {
1326             return;
1327         }
1328 
1329         resetEmpty();
1330         assertThrows(UnsupportedOperationException.class, () -> getCollection().clear(),
1331                 "clear should raise UnsupportedOperationException");
1332         verify();
1333 
1334         assertThrows(UnsupportedOperationException.class, () -> getCollection().remove(null),
1335                 "remove should raise UnsupportedOperationException");
1336         verify();
1337 
1338         assertThrows(UnsupportedOperationException.class, () -> getCollection().removeIf(e -> true),
1339                 "removeIf should raise UnsupportedOperationException");
1340         verify();
1341 
1342         assertThrows(UnsupportedOperationException.class, () -> getCollection().removeAll(null),
1343                 "removeAll should raise UnsupportedOperationException");
1344         verify();
1345 
1346         assertThrows(UnsupportedOperationException.class, () -> getCollection().retainAll(null),
1347                 "retainAll should raise UnsupportedOperationException");
1348         verify();
1349 
1350         resetFull();
1351         final Iterator<E> iterator = getCollection().iterator();
1352         iterator.next();
1353         assertThrows(UnsupportedOperationException.class, () -> iterator.remove(),
1354                 "iterator.remove should raise UnsupportedOperationException");
1355         verify();
1356 
1357     }
1358 
1359     /**
1360      *  Verifies that {@link #collection} and {@link #confirmed} have
1361      *  identical state.
1362      */
1363     public void verify() {
1364         final int confirmedSize = getConfirmed().size();
1365         assertEquals(confirmedSize, getCollection().size(),
1366                 "Collection size should match confirmed collection's");
1367         assertEquals(getConfirmed().isEmpty(), getCollection().isEmpty(),
1368                 "Collection isEmpty() result should match confirmed collection's");
1369 
1370         // verify the collections are the same by attempting to match each
1371         // object in the collection and confirmed collection.  To account for
1372         // duplicates and differing orders, each confirmed element is copied
1373         // into an array and a flag is maintained for each element to determine
1374         // whether it has been matched once and only once.  If all elements in
1375         // the confirmed collection are matched once and only once and there
1376         // aren't any elements left to be matched in the collection,
1377         // verification is a success.
1378 
1379         // copy each collection value into an array
1380         final Object[] confirmedValues = new Object[confirmedSize];
1381 
1382         Iterator<E> iter;
1383 
1384         iter = getConfirmed().iterator();
1385         int pos = 0;
1386         while (iter.hasNext()) {
1387             confirmedValues[pos++] = iter.next();
1388         }
1389 
1390         // allocate an array of boolean flags for tracking values that have
1391         // been matched once and only once.
1392         final boolean[] matched = new boolean[confirmedSize];
1393 
1394         // now iterate through the values of the collection and try to match
1395         // the value with one in the confirmed array.
1396         iter = getCollection().iterator();
1397         while (iter.hasNext()) {
1398             final Object o = iter.next();
1399             boolean match = false;
1400             for (int i = 0; i < confirmedSize; i++) {
1401                 if (matched[i]) {
1402                     // skip values already matched
1403                     continue;
1404                 }
1405                 if (Objects.equals(o, confirmedValues[i])) {
1406                     // values matched
1407                     matched[i] = true;
1408                     match = true;
1409                     break;
1410                 }
1411             }
1412             // no match found!
1413             if (!match) {
1414                 fail("Collection should not contain a value that the "
1415                         + "confirmed collection does not have: " + o + "\nTest: " + getCollection()
1416                         + "\nReal: " + getConfirmed());
1417             }
1418         }
1419 
1420         // make sure there aren't any unmatched values
1421         for (int i = 0; i < confirmedSize; i++) {
1422             if (!matched[i]) {
1423                 // the collection didn't match all the confirmed values
1424                 fail("Collection should contain all values that are in the confirmed collection"
1425                         + "\nTest: " + getCollection() + "\nReal: " + getConfirmed());
1426             }
1427         }
1428     }
1429 
1430 }