/* * Created on Dec 21, 2010 * * 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 @2010-2013 the original author or authors. */ package org.fest.assertions.internal; import static org.fest.assertions.error.ShouldBeEmpty.shouldBeEmpty; import static org.fest.assertions.error.ShouldBeNullOrEmpty.shouldBeNullOrEmpty; import static org.fest.assertions.error.ShouldContain.shouldContain; import static org.fest.assertions.error.ShouldContainKey.shouldContainKey; import static org.fest.assertions.error.ShouldContainOnly.shouldContainOnly; import static org.fest.assertions.error.ShouldContainValue.shouldContainValue; import static org.fest.assertions.error.ShouldHaveSize.shouldHaveSize; import static org.fest.assertions.error.ShouldNotBeEmpty.shouldNotBeEmpty; import static org.fest.assertions.error.ShouldNotContain.shouldNotContain; import static org.fest.assertions.error.ShouldNotContainKey.shouldNotContainKey; import static org.fest.assertions.error.ShouldNotContainValue.shouldNotContainValue; import static org.fest.assertions.error.ShouldNotHaveDuplicates.shouldNotHaveDuplicates; import static org.fest.util.Collections.duplicatesFrom; import static org.fest.util.Objects.areEqual; import java.util.Collection; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import org.fest.assertions.data.MapEntry; import org.fest.assertions.description.Description; import org.fest.util.VisibleForTesting; /** * Reusable assertions for <code>{@link Map}</code>s. * * @author Alex Ruiz * @author Nicolas François * @author Yvonne Wang */ public class Maps { private static 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 description 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(Description description, Map<?, ?> actual) { if (actual == null || actual.isEmpty()) { return; } throw failures.failure(description, shouldBeNullOrEmpty(actual)); } /** * Asserts that the given {@code Map} is empty. * * @param description 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(Description description, Map<?, ?> actual) { assertNotNull(description, actual); if (!actual.isEmpty()) { throw failures.failure(description, shouldBeEmpty(actual)); } } /** * Asserts that the given {@code Map} is not empty. * * @param description 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(Description description, Map<?, ?> actual) { assertNotNull(description, actual); if (actual.isEmpty()) { throw failures.failure(description, shouldNotBeEmpty()); } } /** * Asserts that the given {@code Map} contains the given entries, in any order. * * @param description 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(Description description, Map<?, ?> actual, MapEntry[] entries) { isNotEmptyOrNull(entries); assertNotNull(description, actual); Set<MapEntry> notFound = new LinkedHashSet<MapEntry>(); for (MapEntry entry : entries) { if (!containsEntry(actual, entry)) { notFound.add(entry); } } if (!notFound.isEmpty()) { throw failures.failure(description, shouldContain(actual, entries, notFound)); } } /** * Asserts that the given {@code Map} contains only the given entries, nothing else. * * @param description 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 <K, V> void assertContainsOnly(Description description, Map<K, V> actual, MapEntry[] entries) { isNotEmptyOrNull(entries); assertNotNull(description, actual); Map<K, V> notExpected = new LinkedHashMap<K, V>(actual); Set<MapEntry> notFound = containsOnly(actual, entries, notExpected); if (!notFound.isEmpty() || !notExpected.isEmpty()) { throw failures.failure(description, shouldContainOnly(actual, entries, notFound, notExpected)); } } private <K, V> Set<MapEntry> containsOnly(Map<K, V> actual, MapEntry[] entries, Map<K, V> notExpected) { Set<MapEntry> notFound = new LinkedHashSet<MapEntry>(); Set<?> notExpectedKeys = notExpected.keySet(); Collection<?> notExpectedValues = notExpected.values(); for (MapEntry entry : entries) { if (!containsEntry(actual, entry)) { notFound.add(entry); } else { notExpectedKeys.remove(entry.key); notExpectedValues.remove(entry.value); } } return notFound; } /** * Asserts that the given {@code Map} does not contain the given entries. * * @param description 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(Description description, Map<?, ?> actual, MapEntry[] entries) { isNotEmptyOrNull(entries); assertNotNull(description, actual); Set<MapEntry> found = new LinkedHashSet<MapEntry>(); for (MapEntry entry : entries) { if (containsEntry(actual, entry)) { found.add(entry); } } if (!found.isEmpty()) { throw failures.failure(description, shouldNotContain(actual, entries, found)); } } /** * Asserts that the actual map contain the given key. * * @param description 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 not contains the given key. */ public <K> void assertContainsKey(Description description, Map<?, ?> actual, K key) { assertNotNull(description, actual); if (!actual.containsKey(key)) { throw failures.failure(description, shouldContainKey(actual, key)); } } /** * Asserts that the actual map not contains the given key. * * @param description 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 <K> void assertDoesNotContainKey(Description description, Map<?, ?> actual, K key) { assertNotNull(description, actual); if (actual.containsKey(key)) { throw failures.failure(description, shouldNotContainKey(actual, key)); } } /** * Asserts that the actual map contain the given value. * * @param description 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 <V> void assertContainsValue(Description description, Map<?, ?> actual, V value) { assertNotNull(description, actual); if (!actual.containsValue(value)) { throw failures.failure(description, shouldContainValue(actual, value)); } } /** * Asserts that the actual map does not contain the given value. * * @param description 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 <V> void assertDoesNotContainValue(Description description, Map<?, ?> actual, V value) { assertNotNull(description, actual); if (actual.containsValue(value)) { throw failures.failure(description, shouldNotContainValue(actual, value)); } } /** * Asserts that the actual map does not contain the duplicate values. * * @param description contains information about the assertion. * @param actual the given {@code Map}. * @throws AssertionError if the actual map is {@code null}. * @throws AssertionError if the actual map contains the given value. */ public <K, V> void assertDoesNotContainDuplicateValues(Description description, Map<K, V> actual) { assertNotNull(description, actual); Collection<?> duplicates = duplicatesFrom(actual.values()); if (!duplicates.isEmpty()) { throw failures.failure(description, shouldNotHaveDuplicates(actual, duplicates)); } } /** * Asserts that the number of entries in the given {@code Map} is equal to the expected one. * * @param description 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 <K, V> void assertHasSize(Description description, Map<K, V> actual, int expectedSize) { assertNotNull(description, actual); int sizeOfActual = actual.size(); if (sizeOfActual != expectedSize) { throw failures.failure(description, shouldHaveSize(actual, sizeOfActual, expectedSize)); } } private void isNotEmptyOrNull(MapEntry[] entries) { if (entries == null) { throw new NullPointerException("The array of entries to look for should not be null"); } if (entries.length == 0) { throw new IllegalArgumentException("The array of entries to look for should not be empty"); } } private boolean containsEntry(Map<?, ?> actual, MapEntry entry) { if (entry == null) { throw new NullPointerException("Entries to look for should not be null"); } if (!actual.containsKey(entry.key)) { return false; } return areEqual(actual.get(entry.key), entry.value); } private <K, V> void assertNotNull(Description description, Map<K, V> actual) { Objects.instance().assertNotNull(description, actual); } }