• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2007 Mockito contributors
3  * This program is made available under the terms of the MIT License.
4  */
5 package org.mockito.internal.util.collections;
6 
7 import org.mockito.internal.util.Checks;
8 
9 import java.util.Arrays;
10 import java.util.Collection;
11 import java.util.HashSet;
12 import java.util.Iterator;
13 import java.util.Set;
14 
15 import static java.lang.reflect.Array.*;
16 
17 /**
18  * hashCode and equals safe hash based set.
19  *
20  * <p>
21  *     Useful for holding mocks that have un-stubbable hashCode or equals method,
22  *     meaning that in this scenario the real code is always called and will most probably
23  *     cause an {@link NullPointerException}.
24  * </p>
25  * <p>
26  *     This collection wraps the mock in an augmented type {@link HashCodeAndEqualsMockWrapper}
27  *     that have his own implementation.
28  * </p>
29  *
30  * @see HashCodeAndEqualsMockWrapper
31  */
32 public class HashCodeAndEqualsSafeSet implements Set<Object> {
33 
34     private HashSet<HashCodeAndEqualsMockWrapper> backingHashSet = new HashSet<HashCodeAndEqualsMockWrapper>();
35 
iterator()36     public Iterator<Object> iterator() {
37         return new Iterator<Object>() {
38             private Iterator<HashCodeAndEqualsMockWrapper> iterator = backingHashSet.iterator();
39 
40             public boolean hasNext() {
41                 return iterator.hasNext();
42             }
43 
44             public Object next() {
45                 return iterator.next().get();
46             }
47 
48             public void remove() {
49                 iterator.remove();
50             }
51         };
52     }
53 
size()54     public int size() {
55         return backingHashSet.size();
56     }
57 
isEmpty()58     public boolean isEmpty() {
59         return backingHashSet.isEmpty();
60     }
61 
contains(Object mock)62     public boolean contains(Object mock) {
63         return backingHashSet.contains(HashCodeAndEqualsMockWrapper.of(mock));
64     }
65 
add(Object mock)66     public boolean add(Object mock) {
67         return backingHashSet.add(HashCodeAndEqualsMockWrapper.of(mock));
68     }
69 
remove(Object mock)70     public boolean remove(Object mock) {
71         return backingHashSet.remove(HashCodeAndEqualsMockWrapper.of(mock));
72     }
73 
clear()74     public void clear() {
75         backingHashSet.clear();
76     }
77 
clone()78     @Override public Object clone() throws CloneNotSupportedException {
79         throw new CloneNotSupportedException();
80     }
81 
equals(Object o)82     @Override public boolean equals(Object o) {
83         if (!(o instanceof HashCodeAndEqualsSafeSet)) {
84             return false;
85         }
86         HashCodeAndEqualsSafeSet that = (HashCodeAndEqualsSafeSet) o;
87         return backingHashSet.equals(that.backingHashSet);
88     }
89 
hashCode()90     @Override public int hashCode() {
91         return backingHashSet.hashCode();
92     }
93 
toArray()94     public Object[] toArray() {
95         return unwrapTo(new Object[size()]);
96     }
97 
unwrapTo(T[] array)98     private <T> T[] unwrapTo(T[] array) {
99         Iterator<Object> iterator = iterator();
100         for (int i = 0, objectsLength = array.length; i < objectsLength; i++) {
101             if (iterator.hasNext()) {
102                 array[i] = (T) iterator.next();
103             }
104         }
105         return array;
106     }
107 
108 
toArray(T[] typedArray)109     public <T> T[] toArray(T[] typedArray) {
110         T[] array = typedArray.length >= size() ? typedArray :
111                 (T[]) newInstance(typedArray.getClass().getComponentType(), size());
112         return unwrapTo(array);
113     }
114 
removeAll(Collection<?> mocks)115     public boolean removeAll(Collection<?> mocks) {
116         return backingHashSet.removeAll(asWrappedMocks(mocks));
117     }
118 
containsAll(Collection<?> mocks)119     public boolean containsAll(Collection<?> mocks) {
120         return backingHashSet.containsAll(asWrappedMocks(mocks));
121     }
122 
addAll(Collection<?> mocks)123     public boolean addAll(Collection<?> mocks) {
124         return backingHashSet.addAll(asWrappedMocks(mocks));
125     }
126 
retainAll(Collection<?> mocks)127     public boolean retainAll(Collection<?> mocks) {
128         return backingHashSet.retainAll(asWrappedMocks(mocks));
129     }
130 
asWrappedMocks(Collection<?> mocks)131     private HashSet<HashCodeAndEqualsMockWrapper> asWrappedMocks(Collection<?> mocks) {
132         Checks.checkNotNull(mocks, "Passed collection should notify() be null");
133         HashSet<HashCodeAndEqualsMockWrapper> hashSet = new HashSet<HashCodeAndEqualsMockWrapper>();
134         for (Object mock : mocks) {
135             assert ! (mock instanceof HashCodeAndEqualsMockWrapper) : "WRONG";
136             hashSet.add(HashCodeAndEqualsMockWrapper.of(mock));
137         }
138         return hashSet;
139     }
140 
toString()141     @Override public String toString() {
142         return backingHashSet.toString();
143     }
144 
of(Object... mocks)145     public static HashCodeAndEqualsSafeSet of(Object... mocks) {
146         return of(Arrays.asList(mocks));
147     }
148 
of(Iterable<Object> objects)149     public static HashCodeAndEqualsSafeSet of(Iterable<Object> objects) {
150         HashCodeAndEqualsSafeSet hashCodeAndEqualsSafeSet = new HashCodeAndEqualsSafeSet();
151         if (objects != null) {
152             for (Object mock : objects) {
153                 hashCodeAndEqualsSafeSet.add(mock);
154             }
155         }
156         return hashCodeAndEqualsSafeSet;
157     }
158 }
159