com.fitbur.assertj.internal.Maps Maven / Gradle / Ivy
The newest version!
/**
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* Copyright 2012-2016 the original author or authors.
*/
package com.fitbur.assertj.internal;
import static com.fitbur.assertj.data.MapEntry.entry;
import static com.fitbur.assertj.error.ShouldBeEmpty.shouldBeEmpty;
import static com.fitbur.assertj.error.ShouldBeNullOrEmpty.shouldBeNullOrEmpty;
import static com.fitbur.assertj.error.ShouldContain.shouldContain;
import static com.fitbur.assertj.error.ShouldContainExactly.elementsDifferAtIndex;
import static com.fitbur.assertj.error.ShouldContainExactly.shouldContainExactly;
import static com.fitbur.assertj.error.ShouldContainKeys.shouldContainKeys;
import static com.fitbur.assertj.error.ShouldContainOnly.shouldContainOnly;
import static com.fitbur.assertj.error.ShouldContainOnlyKeys.shouldContainOnlyKeys;
import static com.fitbur.assertj.error.ShouldContainValue.shouldContainValue;
import static com.fitbur.assertj.error.ShouldContainValues.shouldContainValues;
import static com.fitbur.assertj.error.ShouldNotBeEmpty.shouldNotBeEmpty;
import static com.fitbur.assertj.error.ShouldNotContain.shouldNotContain;
import static com.fitbur.assertj.error.ShouldNotContainKey.shouldNotContainKey;
import static com.fitbur.assertj.error.ShouldNotContainKeys.shouldNotContainKeys;
import static com.fitbur.assertj.error.ShouldNotContainValue.shouldNotContainValue;
import static com.fitbur.assertj.internal.Arrays.assertIsArray;
import static com.fitbur.assertj.internal.CommonValidations.checkSizes;
import static com.fitbur.assertj.internal.CommonValidations.hasSameSizeAsCheck;
import static com.fitbur.assertj.util.Objects.areEqual;
import static com.fitbur.assertj.util.Preconditions.checkNotNull;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import com.fitbur.assertj.api.AssertionInfo;
import com.fitbur.assertj.util.VisibleForTesting;
/**
* Reusable assertions for {@link Map}
s.
*
* @author Alex Ruiz
* @author Nicolas François
* @author dorzey
*/
public class Maps {
private static final Maps INSTANCE = new Maps();
/**
* Returns the singleton instance of this class.
*
* @return the singleton instance of this class.
*/
public static Maps instance() {
return INSTANCE;
}
@VisibleForTesting
Failures failures = Failures.instance();
@VisibleForTesting
Maps() {}
/**
* Asserts that the given {@code Map} is {@code null} or empty.
*
* @param info contains information about the assertion.
* @param actual the given map.
* @throws AssertionError if the given {@code Map} is not {@code null} *and* contains one or more entries.
*/
public void assertNullOrEmpty(AssertionInfo info, Map, ?> actual) {
if (actual != null && !actual.isEmpty()) throw failures.failure(info, shouldBeNullOrEmpty(actual));
}
/**
* Asserts that the given {@code Map} is empty.
*
* @param info contains information about the assertion.
* @param actual the given {@code Map}.
* @throws AssertionError if the given {@code Map} is {@code null}.
* @throws AssertionError if the given {@code Map} is not empty.
*/
public void assertEmpty(AssertionInfo info, Map, ?> actual) {
assertNotNull(info, actual);
if (!actual.isEmpty()) throw failures.failure(info, shouldBeEmpty(actual));
}
/**
* Asserts that the given {@code Map} is not empty.
*
* @param info contains information about the assertion.
* @param actual the given {@code Map}.
* @throws AssertionError if the given {@code Map} is {@code null}.
* @throws AssertionError if the given {@code Map} is empty.
*/
public void assertNotEmpty(AssertionInfo info, Map, ?> actual) {
assertNotNull(info, actual);
if (actual.isEmpty()) throw failures.failure(info, shouldNotBeEmpty());
}
/**
* Asserts that the number of entries in the given {@code Map} is equal to the expected one.
*
* @param info contains information about the assertion.
* @param actual the given {@code Map}.
* @param expectedSize the expected size of {@code actual}.
* @throws AssertionError if the given {@code Map} is {@code null}.
* @throws AssertionError if the number of entries in the given {@code Map} is different than the expected one.
*/
public void assertHasSize(AssertionInfo info, Map, ?> actual, int expectedSize) {
assertNotNull(info, actual);
checkSizes(actual, actual.size(), expectedSize, info);
}
/**
* Asserts that the number of entries in the given {@code Map} has the same size as the other {@code Iterable}.
*
* @param info contains information about the assertion.
* @param map the given {@code Map}.
* @param other the group to compare
* @throws AssertionError if the given {@code Map} is {@code null}.
* @throws AssertionError if the given {@code Iterable} is {@code null}.
* @throws AssertionError if the number of entries in the given {@code Map} does not have the same size.
*/
public void assertHasSameSizeAs(AssertionInfo info, Map, ?> map, Iterable> other) {
assertNotNull(info, map);
hasSameSizeAsCheck(info, map, other, map.size());
}
/**
* Asserts that the number of entries in the given {@code Map} has the same size as the other array.
*
* @param info contains information about the assertion.
* @param map the given {@code Map}.
* @param other the group to compare
* @throws AssertionError if the given {@code Map} is {@code null}.
* @throws AssertionError if the given array is {@code null}.
* @throws AssertionError if the number of entries in the given {@code Map} does not have the same size.
*/
public void assertHasSameSizeAs(AssertionInfo info, Map, ?> map, Object other) {
assertNotNull(info, map);
assertIsArray(info, other);
hasSameSizeAsCheck(info, map, other, map.size());
}
/**
* Asserts that the size of the given {@code Map} is equal to the size of the other {@code Map}.
*
* @param info contains information about the assertion.
* @param map the given {@code Map}.
* @param other the other {@code Map} to compare
* @throws NullPointerException if the other {@code Map} is {@code null}.
* @throws AssertionError if the given {@code Map} is {@code null}.
* @throws AssertionError if the size of the given {@code Map} is not equal to the other {@code Map} size
*/
public void assertHasSameSizeAs(AssertionInfo info, Map, ?> map, Map, ?> other) {
assertNotNull(info, map);
hasSameSizeAsCheck(info, map, other, map.size());
}
/**
* Asserts that the given {@code Map} contains the given entries, in any order.
*
* @param info contains information about the assertion.
* @param actual the given {@code Map}.
* @param entries the entries that are expected to be in the given {@code Map}.
* @throws NullPointerException if the array of entries is {@code null}.
* @throws IllegalArgumentException if the array of entries is empty.
* @throws NullPointerException if any of the entries in the given array is {@code null}.
* @throws AssertionError if the given {@code Map} is {@code null}.
* @throws AssertionError if the given {@code Map} does not contain the given entries.
*/
public void assertContains(AssertionInfo info, Map actual, Map.Entry extends K, ? extends V>[] entries) {
failIfNull(entries);
assertNotNull(info, actual);
// if both actual and values are empty, then assertion passes.
if (actual.isEmpty() && entries.length == 0)
return;
failIfEmptySinceActualIsNotEmpty(entries);
Set> notFound = new LinkedHashSet<>();
for (Map.Entry extends K, ? extends V> entry : entries) {
if (!containsEntry(actual, entry)) {
notFound.add(entry);
}
}
if (notFound.isEmpty()) return;
throw failures.failure(info, shouldContain(actual, entries, notFound));
}
/**
* Asserts that the given {@code Map} does not contain the given entries.
*
* @param info contains information about the assertion.
* @param actual the given {@code Map}.
* @param entries the entries that are expected to be in the given {@code Map}.
* @throws NullPointerException if the array of entries is {@code null}.
* @throws IllegalArgumentException if the array of entries is empty.
* @throws NullPointerException if any of the entries in the given array is {@code null}.
* @throws AssertionError if the given {@code Map} is {@code null}.
* @throws AssertionError if the given {@code Map} contains any of the given entries.
*/
public void assertDoesNotContain(AssertionInfo info, Map actual,
Map.Entry extends K, ? extends V>[] entries) {
failIfNullOrEmpty(entries);
assertNotNull(info, actual);
Set> found = new LinkedHashSet<>();
for (Map.Entry extends K, ? extends V> entry : entries) {
if (containsEntry(actual, entry)) {
found.add(entry);
}
}
if (found.isEmpty()) return;
throw failures.failure(info, shouldNotContain(actual, entries, found));
}
/**
* Verifies that the actual map contain the given key.
*
* @param info contains information about the assertion.
* @param actual the given {@code Map}.
* @param keys the given keys
* @throws AssertionError if the actual map is {@code null}.
* @throws AssertionError if the actual map not contains the given key.
*/
public void assertContainsKeys(AssertionInfo info, Map actual, @SuppressWarnings("unchecked") K... keys) {
assertNotNull(info, actual);
Set notFound = new LinkedHashSet<>();
for (K key : keys) {
if (!actual.containsKey(key)) {
notFound.add(key);
}
}
if (notFound.isEmpty()) return;
throw failures.failure(info, shouldContainKeys(actual, notFound));
}
/**
* Verifies that the actual map not contains the given key.
*
* @param info contains information about the assertion.
* @param actual the given {@code Map}.
* @param key the given key
* @throws AssertionError if the actual map is {@code null}.
* @throws AssertionError if the actual map contains the given key.
*/
public void assertDoesNotContainKey(AssertionInfo info, Map actual, K key) {
assertNotNull(info, actual);
if (actual.containsKey(key)) throw failures.failure(info, shouldNotContainKey(actual, key));
}
/**
* Verifies that the actual map not contains all the given keys.
*
* @param info contains information about the assertion.
* @param actual the given {@code Map}.
* @param keys the given keys
* @throws AssertionError if the actual map is {@code null}.
* @throws AssertionError if the actual map contains all the given keys.
*/
public void assertDoesNotContainKeys(AssertionInfo info, Map actual,
@SuppressWarnings("unchecked") K... keys) {
assertNotNull(info, actual);
Set found = new LinkedHashSet<>();
for (K key : keys) {
if (key != null && actual.containsKey(key)) {
found.add(key);
}
}
if (!found.isEmpty()) throw failures.failure(info, shouldNotContainKeys(actual, found));
}
/**
* Verifies that the actual map contains only the given keys and nothing else, in any order.
*
* @param info contains information about the assertion.
* @param actual the given {@code Map}.
* @param keys the keys that are expected to be in the given {@code Map}.
* @throws NullPointerException if the array of keys is {@code null}.
* @throws IllegalArgumentException if the array of keys is empty.
* @throws AssertionError if the given {@code Map} is {@code null}.
* @throws AssertionError if the given {@code Map} does not contain the given keys or if the given {@code Map}
* contains keys that are not in the given array.
*/
public void assertContainsOnlyKeys(AssertionInfo info, Map actual,
@SuppressWarnings("unchecked") K... keys) {
assertNotNull(info, actual);
failIfNull(keys);
if (actual.isEmpty() && keys.length == 0) {
return;
}
failIfEmpty(keys);
Set notFound = new LinkedHashSet<>();
Set notExpected = new LinkedHashSet<>();
compareActualMapAndExpectedKeys(actual, keys, notExpected, notFound);
if (!notFound.isEmpty() || !notExpected.isEmpty())
throw failures.failure(info, shouldContainOnlyKeys(actual, keys, notFound, notExpected));
}
/**
* Verifies that the actual map contain the given value.
*
* @param info contains information about the assertion.
* @param actual the given {@code Map}.
* @param value the given value
* @throws AssertionError if the actual map is {@code null}.
* @throws AssertionError if the actual map not contains the given value.
*/
public void assertContainsValue(AssertionInfo info, Map actual, V value) {
assertNotNull(info, actual);
if (!actual.containsValue(value)) throw failures.failure(info, shouldContainValue(actual, value));
}
/**
* Verifies that the actual map contain the given values.
*
* @param info contains information about the assertion.
* @param actual the given {@code Map}.
* @param values the given values
* @throws AssertionError if the actual map is {@code null}.
* @throws AssertionError if the actual map not contains the given values.
* @throws NullPointerException if values vararg is {@code null}.
*/
public void assertContainsValues(AssertionInfo info, Map actual,
@SuppressWarnings("unchecked") V... values) {
assertNotNull(info, actual);
checkNotNull(values, "The array of values to look for should not be null");
if (actual.isEmpty() && values.length == 0) return;
//
Set valuesNotFound = new LinkedHashSet<>();
for (V valueToLookFor : values) {
if (!actual.containsValue(valueToLookFor)) valuesNotFound.add(valueToLookFor);
}
if (!valuesNotFound.isEmpty()) throw failures.failure(info, shouldContainValues(actual, valuesNotFound));
}
/**
* Verifies that the actual map not contains the given value.
*
* @param info contains information about the assertion.
* @param actual the given {@code Map}.
* @param value the given value
* @throws AssertionError if the actual map is {@code null}.
* @throws AssertionError if the actual map contains the given value.
*/
public void assertDoesNotContainValue(AssertionInfo info, Map actual, V value) {
assertNotNull(info, actual);
if (actual.containsValue(value)) throw failures.failure(info, shouldNotContainValue(actual, value));
}
/**
* Verifies that the actual map contains only the given entries and nothing else, in any order.
*
* @param info contains information about the assertion.
* @param actual the given {@code Map}.
* @param entries the entries that should be in the actual map.
* @throws AssertionError if the actual map is {@code null}.
* @throws NullPointerException if the given entries array is {@code null}.
* @throws IllegalArgumentException if the given entries array is empty.
* @throws AssertionError if the actual map does not contain the given entries, i.e. the actual map contains some or
* none of the given entries, or the actual map contains more entries than the given ones.
*/
public void assertContainsOnly(AssertionInfo info, Map actual,
@SuppressWarnings("unchecked") Map.Entry extends K, ? extends V>... entries) {
doCommonContainsCheck(info, actual, entries);
if (actual.isEmpty() && entries.length == 0) {
return;
}
failIfEmpty(entries);
Set> notFound = new LinkedHashSet<>();
Set> notExpected = new LinkedHashSet<>();
compareActualMapAndExpectedEntries(actual, entries, notExpected, notFound);
if (!notFound.isEmpty() || !notExpected.isEmpty())
throw failures.failure(info, shouldContainOnly(actual, entries, notFound, notExpected));
}
/**
* Verifies that the actual map contains only the given entries and nothing else, in order.
* This assertion should only be used with map that have a consistent iteration order (i.e. don't use it with
* {@link java.util.HashMap}).
*
* @param info contains information about the assertion.
* @param actual the given {@code Map}.
* @param entries the given entries.
* @throws NullPointerException if the given entries array is {@code null}.
* @throws AssertionError if the actual map is {@code null}.
* @throws IllegalArgumentException if the given entries array is empty.
* @throws AssertionError if the actual map does not contain the given entries with same order, i.e. the actual map
* contains some or none of the given entries, or the actual map contains more entries than the given ones
* or entries are the same but the order is not.
*/
public void assertContainsExactly(AssertionInfo info, Map actual,
@SuppressWarnings("unchecked") Map.Entry extends K, ? extends V>... entries) {
doCommonContainsCheck(info, actual, entries);
if (actual.isEmpty() && entries.length == 0) return;
failIfEmpty(entries);
assertHasSameSizeAs(info, actual, entries);
Set> notFound = new LinkedHashSet<>();
Set> notExpected = new LinkedHashSet<>();
compareActualMapAndExpectedEntries(actual, entries, notExpected, notFound);
if (notExpected.isEmpty() && notFound.isEmpty()) {
// check entries order
int index = 0;
for (K keyFromActual : actual.keySet()) {
if (!areEqual(keyFromActual, entries[index].getKey())) {
Map.Entry actualEntry = entry(keyFromActual, actual.get(keyFromActual));
throw failures.failure(info, elementsDifferAtIndex(actualEntry, entries[index], index));
}
index++;
}
// all entries are in the same order.
return;
}
throw failures.failure(info, shouldContainExactly(actual, entries, notFound, notExpected));
}
private void compareActualMapAndExpectedKeys(Map actual, K[] keys, Set notExpected, Set notFound) {
Map actualEntries = new LinkedHashMap<>(actual);
for (K key : keys) {
if (actualEntries.containsKey(key)) {
// this is an expected key
actualEntries.remove(key);
} else {
// this is a not found key
notFound.add(key);
}
}
// All remaining keys from actual copy are not expected entries.
for (K key : actualEntries.keySet()) {
notExpected.add(key);
}
}
private void compareActualMapAndExpectedEntries(Map actual,
Map.Entry extends K, ? extends V>[] entries,
Set> notExpected,
Set> notFound) {
Map expectedEntries = entriesToMap(entries);
Map actualEntries = new LinkedHashMap<>(actual);
for (Map.Entry entry : expectedEntries.entrySet()) {
if (containsEntry(actualEntries, entry(entry.getKey(), entry.getValue()))) {
// this is an expected entry
actualEntries.remove(entry.getKey());
} else {
// this is a not found entry
notFound.add(entry(entry.getKey(), entry.getValue()));
}
}
// All remaining entries from actual copy are not expected entries.
for (Map.Entry entry : actualEntries.entrySet()) {
notExpected.add(entry(entry.getKey(), entry.getValue()));
}
}
private void doCommonContainsCheck(AssertionInfo info, Map actual,
Map.Entry extends K, ? extends V>[] entries) {
assertNotNull(info, actual);
failIfNull(entries);
}
private static Map entriesToMap(Map.Entry extends K, ? extends V>[] entries) {
Map expectedEntries = new LinkedHashMap<>();
for (Map.Entry extends K, ? extends V> entry : entries) {
expectedEntries.put(entry.getKey(), entry.getValue());
}
return expectedEntries;
}
private static void failIfEmpty(K[] keys) {
if (keys.length == 0) throw new IllegalArgumentException("The array of keys to look for should not be empty");
}
private static void failIfEmpty(Map.Entry extends K, ? extends V>[] entries) {
if (entries.length == 0)
throw new IllegalArgumentException("The array of entries to look for should not be empty");
}
private static void failIfNullOrEmpty(Map.Entry extends K, ? extends V>[] entries) {
failIfNull(entries);
failIfEmpty(entries);
}
private static void failIfNull(K[] keys) {
checkNotNull(keys, "The array of keys to look for should not be null");
}
private static void failIfNull(Map.Entry extends K, ? extends V>[] entries) {
checkNotNull(entries, "The array of entries to look for should not be null");
}
private boolean containsEntry(Map actual, Map.Entry extends K, ? extends V> entry) {
checkNotNull(entry, "Entries to look for should not be null");
return actual.containsKey(entry.getKey()) ? areEqual(actual.get(entry.getKey()), entry.getValue()) : false;
}
private void assertNotNull(AssertionInfo info, Map, ?> actual) {
Objects.instance().assertNotNull(info, actual);
}
private static void failIfEmptySinceActualIsNotEmpty(Map.Entry extends K, ? extends V>[] values) {
if (values.length == 0) throw new AssertionError("actual is not empty");
}
}