blob: d9c82cf89a36d1574fb74479833e972986700efc [file] [log] [blame]
/*
* Copyright (c) 2007 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockito.internal.util.collections;
import org.mockito.internal.util.Checks;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import static java.lang.reflect.Array.*;
/**
* hashCode and equals safe hash based set.
*
* <p>
* Useful for holding mocks that have un-stubbable hashCode or equals method,
* meaning that in this scenario the real code is always called and will most probably
* cause an {@link NullPointerException}.
* </p>
* <p>
* This collection wraps the mock in an augmented type {@link HashCodeAndEqualsMockWrapper}
* that have his own implementation.
* </p>
*
* @see HashCodeAndEqualsMockWrapper
*/
public class HashCodeAndEqualsSafeSet implements Set<Object> {
private HashSet<HashCodeAndEqualsMockWrapper> backingHashSet = new HashSet<HashCodeAndEqualsMockWrapper>();
public Iterator<Object> iterator() {
return new Iterator<Object>() {
private Iterator<HashCodeAndEqualsMockWrapper> iterator = backingHashSet.iterator();
public boolean hasNext() {
return iterator.hasNext();
}
public Object next() {
return iterator.next().get();
}
public void remove() {
iterator.remove();
}
};
}
public int size() {
return backingHashSet.size();
}
public boolean isEmpty() {
return backingHashSet.isEmpty();
}
public boolean contains(Object mock) {
return backingHashSet.contains(HashCodeAndEqualsMockWrapper.of(mock));
}
public boolean add(Object mock) {
return backingHashSet.add(HashCodeAndEqualsMockWrapper.of(mock));
}
public boolean remove(Object mock) {
return backingHashSet.remove(HashCodeAndEqualsMockWrapper.of(mock));
}
public void clear() {
backingHashSet.clear();
}
@Override public Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
@Override public boolean equals(Object o) {
if (!(o instanceof HashCodeAndEqualsSafeSet)) {
return false;
}
HashCodeAndEqualsSafeSet that = (HashCodeAndEqualsSafeSet) o;
return backingHashSet.equals(that.backingHashSet);
}
@Override public int hashCode() {
return backingHashSet.hashCode();
}
public Object[] toArray() {
return unwrapTo(new Object[size()]);
}
private <T> T[] unwrapTo(T[] array) {
Iterator<Object> iterator = iterator();
for (int i = 0, objectsLength = array.length; i < objectsLength; i++) {
if (iterator.hasNext()) {
array[i] = (T) iterator.next();
}
}
return array;
}
public <T> T[] toArray(T[] typedArray) {
T[] array = typedArray.length >= size() ? typedArray :
(T[]) newInstance(typedArray.getClass().getComponentType(), size());
return unwrapTo(array);
}
public boolean removeAll(Collection<?> mocks) {
return backingHashSet.removeAll(asWrappedMocks(mocks));
}
public boolean containsAll(Collection<?> mocks) {
return backingHashSet.containsAll(asWrappedMocks(mocks));
}
public boolean addAll(Collection<?> mocks) {
return backingHashSet.addAll(asWrappedMocks(mocks));
}
public boolean retainAll(Collection<?> mocks) {
return backingHashSet.retainAll(asWrappedMocks(mocks));
}
private HashSet<HashCodeAndEqualsMockWrapper> asWrappedMocks(Collection<?> mocks) {
Checks.checkNotNull(mocks, "Passed collection should notify() be null");
HashSet<HashCodeAndEqualsMockWrapper> hashSet = new HashSet<HashCodeAndEqualsMockWrapper>();
for (Object mock : mocks) {
assert ! (mock instanceof HashCodeAndEqualsMockWrapper) : "WRONG";
hashSet.add(HashCodeAndEqualsMockWrapper.of(mock));
}
return hashSet;
}
@Override public String toString() {
return backingHashSet.toString();
}
public static HashCodeAndEqualsSafeSet of(Object... mocks) {
return of(Arrays.asList(mocks));
}
public static HashCodeAndEqualsSafeSet of(Iterable<Object> objects) {
HashCodeAndEqualsSafeSet hashCodeAndEqualsSafeSet = new HashCodeAndEqualsSafeSet();
if (objects != null) {
for (Object mock : objects) {
hashCodeAndEqualsSafeSet.add(mock);
}
}
return hashCodeAndEqualsSafeSet;
}
}