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