1 /*
2  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License").
5  * You may not use this file except in compliance with the License.
6  * A copy of the License is located at
7  *
8  *  http://aws.amazon.com/apache2.0
9  *
10  * or in the "license" file accompanying this file. This file is distributed
11  * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12  * express or implied. See the License for the specific language governing
13  * permissions and limitations under the License.
14  */
15 
16 package software.amazon.awssdk.testutils;
17 
18 import java.util.Collection;
19 import java.util.HashSet;
20 import java.util.Set;
21 
22 /**
23  * This class includes some utility methods for comparing two unordered
24  * collections.
25  */
26 public final class UnorderedCollectionComparator {
27 
UnorderedCollectionComparator()28     private UnorderedCollectionComparator() {
29     }
30 
31     /**
32      * Compares two unordered lists of the same type.
33      */
equalUnorderedCollections( Collection<T> colA, Collection<T> colB)34     public static <T> boolean equalUnorderedCollections(
35             Collection<T> colA, Collection<T> colB) {
36         return equalUnorderedCollections(colA, colB, (a, b) -> (a == b) || a != null && a.equals(b));
37     }
38 
39     /**
40      * Compares two unordered lists of different types, using the specified
41      * cross-type comparator. Null collections are treated as empty ones.
42      * Naively implemented using N(n^2) algorithm.
43      */
equalUnorderedCollections( Collection<A> colA, Collection<B> colB, final CrossTypeComparator<A, B> comparator)44     public static <A, B> boolean equalUnorderedCollections(
45             Collection<A> colA, Collection<B> colB,
46             final CrossTypeComparator<A, B> comparator) {
47         if (colA == null || colB == null) {
48             if ((colA == null || colA.isEmpty())
49                 && (colB == null || colB.isEmpty())) {
50                 return true;
51             } else {
52                 return false;
53             }
54         }
55 
56         // Add all elements into sets to remove duplicates.
57         Set<A> setA = new HashSet<>(colA);
58         Set<B> setB = new HashSet<>(colB);
59 
60         if (setA.size() != setB.size()) {
61             return false;
62         }
63 
64         for (A a : setA) {
65             boolean foundA = false;
66             for (B b : setB) {
67                 if (comparator.equals(a, b)) {
68                     foundA = true;
69                     break;
70                 }
71             }
72             if (!foundA) {
73                 return false;
74             }
75         }
76         return true;
77     }
78 
79     /**
80      * A simple interface that attempts to compare objects of two different types
81      */
82     public interface CrossTypeComparator<A, B> {
83         /**
84          * @return True if a and b should be treated as equal.
85          */
equals(A a, B b)86         boolean equals(A a, B b);
87     }
88 }
89