/* * Created on Nov 19, 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.ShouldContainAtIndex.shouldContainAtIndex; import static org.fest.assertions.error.ShouldContainNull.shouldContainNull; import static org.fest.assertions.error.ShouldContainOnly.shouldContainOnly; import static org.fest.assertions.error.ShouldContainSequence.shouldContainSequence; import static org.fest.assertions.error.ShouldEndWith.shouldEndWith; import static org.fest.assertions.error.ShouldHaveSize.shouldHaveSize; import static org.fest.assertions.error.ShouldNotContainAtIndex.shouldNotContainAtIndex; import static org.fest.assertions.error.ShouldNotContainNull.shouldNotContainNull; import static org.fest.assertions.error.ShouldNotHaveDuplicates.shouldNotHaveDuplicates; import static org.fest.assertions.error.ShouldStartWith.shouldStartWith; import static org.fest.assertions.internal.CommonErrors.arrayOfValuesToLookForIsEmpty; import static org.fest.assertions.internal.CommonErrors.arrayOfValuesToLookForIsNull; import static org.fest.assertions.internal.CommonValidations.checkIndexValueIsValid; import static org.fest.util.Collections.duplicatesFrom; import java.util.Collection; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import org.fest.assertions.data.Index; import org.fest.assertions.description.Description; import org.fest.assertions.error.ShouldNotBeEmpty; import org.fest.util.VisibleForTesting; /** * Reusable assertions for <code>{@link List}</code>s. * * @author Alex Ruiz * @author Yvonne Wang */ public class Lists { private static final Lists INSTANCE = new Lists(); @VisibleForTesting Failures failures = Failures.instance(); /** * Returns the singleton instance of this class. * * @return the singleton instance of this class. */ public static Lists instance() { return INSTANCE; } private static Set<Object> containsOnly(Set<Object> actual, Object[] values) { Set<Object> notFound = new LinkedHashSet<Object>(); for (Object o : org.fest.util.Sets.newLinkedHashSet(values)) { if (actual.contains(o)) { actual.remove(o); } else { notFound.add(o); } } return notFound; } /** * Asserts that the given <code>{@link List}</code> is {@code null} or empty. * * @param description contains information about the assertion. * @param actual the given {@code List}. * @throws AssertionError if the given {@code List} is not {@code null} *and* contains one or more elements. */ public void assertNullOrEmpty(Description description, List<?> actual) { if (actual == null || actual.isEmpty()) { return; } throw failures.failure(description, shouldBeNullOrEmpty(actual)); } /** * Asserts that the given {@code List} is empty. * * @param description contains information about the assertion. * @param actual the given {@code List}. * @throws AssertionError if the given {@code List} is {@code null}. * @throws AssertionError if the given {@code List} is not empty. */ public void assertEmpty(Description description, List<?> actual) { assertNotNull(description, actual); if (!actual.isEmpty()) { throw failures.failure(description, shouldBeEmpty(actual)); } } /** * Asserts that the given {@code List} is not empty. * * @param description contains information about the assertion. * @param actual the given {@code List}. * @throws AssertionError if the given {@code List} is {@code null}. * @throws AssertionError if the given {@code List} is not empty. */ public void assertNotEmpty(Description description, List<?> actual) { assertNotNull(description, actual); checkNotEmpty(description, actual); } /** * Asserts that the number of elements in the given {@code List} is equal to the expected one. * * @param description contains information about the assertion. * @param actual the given {@code List}. * @param expectedSize the expected size of {@code actual}. * @throws AssertionError if the given {@code Collection} is {@code null}. * @throws AssertionError if the number of elements in the given {@code List} is different than the expected one. */ public void assertHasSize(Description description, List<?> actual, int expectedSize) { assertNotNull(description, actual); int sizeOfActual = actual.size(); if (sizeOfActual != expectedSize) { throw failures.failure(description, shouldHaveSize(actual, sizeOfActual, expectedSize)); } } /** * Asserts that the given {@code List} contains the given object at the given index. * * @param description contains information about the assertion. * @param actual the given {@code List}. * @param value the object to look for. * @param index the index where the object should be stored in the given {@code List}. * @throws AssertionError if the given {@code List} is {@code null} or empty. * @throws NullPointerException if the given {@code Index} is {@code null}. * @throws IndexOutOfBoundsException if the value of the given {@code Index} is equal to or greater than the size of * the given {@code List}. * @throws AssertionError if the given {@code List} does not contain the given object at the given index. */ public void assertContains(Description description, List<?> actual, Object value, Index index) { assertNotNull(description, actual); checkNotEmpty(description, actual); checkIndexValueIsValid(index, actual.size() - 1); Object actualElement = actual.get(index.value); if (!areEqual(actualElement, value)) { throw failures.failure(description, shouldContainAtIndex(actual, value, index, actual.get(index.value))); } } /** * Asserts that the given {@code List} contains {@code null}. * * @param description contains information about the assertion. * @param actual the given {@code Collection}. * @throws AssertionError if the given {@code List} is {@code null}. * @throws AssertionError if the given {@code List} does not contain null. */ public void assertContainsNull(Description description, List<?> actual) { assertNotNull(description, actual); if (!actual.contains(null)) { throw failures.failure(description, shouldContainNull(actual)); } } /** * Asserts that the given {@code List} contains only the given values and nothing else, in any order. Duplicates are * allowed. * * @param description contains information about the assertion. * @param actual the given {@code List}. * @param values the values that are expected to be in the given {@code List}. * @throws NullPointerException if the array of values is {@code null}. * @throws IllegalArgumentException if the array of values is empty. * @throws AssertionError if the given {@code List} is {@code null}. * @throws AssertionError if the given {@code List} does not contain the given values or if the given {@code List} * contains values that are not in the given array. */ public void assertContainsOnly(Description description, List<?> actual, Object[] values) { checkIsNotNullAndNotEmpty(values); assertNotNull(description, actual); Set<Object> notExpected = new LinkedHashSet<Object>(actual); Set<Object> notFound = containsOnly(notExpected, values); if (notExpected.isEmpty() && notFound.isEmpty()) { return; } throw failures.failure(description, shouldContainOnly(actual, values, notFound, notExpected)); } /** * Asserts that the given {@code List} contains all of the given values, in any order. Duplicates are allowed. * * @param description contains information about the assertion. * @param actual the given {@code List}. * @param values the values that are expected to be in the given {@code List}. * @throws NullPointerException if the array of values is {@code null}. * @throws IllegalArgumentException if the array of values is empty. * @throws AssertionError if the given {@code List} is {@code null}. * @throws AssertionError if the given {@code List} does not contain all the given values. */ public void assertContains(Description description, List<?> actual, Object[] values) { checkIsNotNullAndNotEmpty(values); assertNotNull(description, actual); Set<Object> copyOfActual = new LinkedHashSet<Object>(actual); Set<Object> notFound = containsOnly(copyOfActual, values); if (!notFound.isEmpty()) { throw failures.failure(description, shouldContain(actual, values, notFound)); } } /** * Verifies that the given <code>{@link List}</code> contains the given sequence(ordered) of objects, without any * other objects between them. Duplicates are allowed. * * @param description contains information about the assertion. * @param actual the given {@code List}. * @param sequence the sequence of objects to look for. * @throws AssertionError if the given {@code List} is {@code null}. * @throws NullPointerException if the given sequence is {@code null}. * @throws IllegalArgumentException if the given sequence is empty. * @throws AssertionError if the given {@code List} does not contain the given sequence of objects. */ public void assertContainsSequence(Description description, List<?> actual, Object[] sequence) { checkIsNotNullAndNotEmpty(sequence); assertNotNull(description, actual); boolean firstAlreadyFound = false; int i = 0; int sequenceSize = sequence.length; for (Object o : actual) { if (i >= sequenceSize) { break; } if (!firstAlreadyFound) { if (!areEqual(o, sequence[i])) { continue; } firstAlreadyFound = true; i++; continue; } if (areEqual(o, sequence[i++])) { continue; } throw actualDoesNotContainSequence(description, actual, sequence); } if (!firstAlreadyFound || i < sequenceSize) { throw actualDoesNotContainSequence(description, actual, sequence); } } private AssertionError actualDoesNotContainSequence(Description description, List<?> actual, Object[] sequence) { return failures.failure(description, shouldContainSequence(actual, sequence)); } /** * Verifies that the given {@code List} does not contain the given object at the given index. * * @param description contains information about the assertion. * @param actual the given {@code List}. * @param value the object to look for. * @param index the index where the object should be stored in the given {@code List}. * @throws AssertionError if the given {@code List} is {@code null}. * @throws NullPointerException if the given {@code Index} is {@code null}. * @throws AssertionError if the given {@code List} contains the given object at the given index. */ public void assertDoesNotContain(Description description, List<?> actual, Object value, Index index) { assertNotNull(description, actual); if (actual.isEmpty() || index.value >= actual.size()) { return; } Object actualElement = actual.get(index.value); if (areEqual(actualElement, value)) { throw failures.failure(description, shouldNotContainAtIndex(actual, value, index)); } } /** * Asserts that the given {@code List} does not contain {@code null}. * * @param description contains information about the assertion. * @param actual the given {@code List}. * @throws AssertionError if the given {@code List} is {@code null}. * @throws AssertionError if the given {@code List} contains any of given values. */ public void assertDoesNotContainNull(Description description, List<?> actual) { assertNotNull(description, actual); assertNotEmpty(description, actual); if (actual.contains(null)) { throw failures.failure(description, shouldNotContainNull(actual)); } } /** * Asserts that the given {@code List} does not have duplicate values. * * @param description contains information about the assertion. * @param actual the given {@code List}. * @throws NullPointerException if the array of values is {@code null}. * @throws IllegalArgumentException if the array of values is empty. * @throws AssertionError if the given {@code List} is {@code null}. * @throws AssertionError if the given {@code List} contains duplicate values. */ public void assertDoesNotHaveDuplicates(Description description, List<?> actual) { assertNotNull(description, actual); Collection<?> duplicates = duplicatesFrom(actual); if (duplicates.isEmpty()) { return; } throw failures.failure(description, shouldNotHaveDuplicates(actual, duplicates)); } /** * Asserts that the given {@code List} starts with the given sequence of objects, without any other objects between * them. Similar to <code>{@link #assertContainsSequence(Description, List, Object[])}</code>, but it also verifies * that the first element in the sequence is also the first element of the given {@code List}. * * @param description contains information about the assertion. * @param actual the given {@code List}. * @param sequence the sequence of objects to look for. * @throws NullPointerException if the given argument is {@code null}. * @throws IllegalArgumentException if the given argument is an empty array. * @throws AssertionError if the given {@code List} is {@code null}. * @throws AssertionError if the given {@code List} does not start with the given sequence of objects. */ public void assertStartsWith(Description description, List<?> actual, Object[] sequence) { checkIsNotNullAndNotEmpty(sequence); assertNotNull(description, actual); int sequenceSize = sequence.length; if (actual.size() < sequenceSize) { throw actualDoesNotStartWithSequence(description, actual, sequence); } int i = 0; for (Object o : actual) { if (i >= sequenceSize) { break; } if (areEqual(o, sequence[i++])) { continue; } throw actualDoesNotStartWithSequence(description, actual, sequence); } } /** * Verifies that the given {@code List} ends with the given sequence of objects, without any other objects between * them. Similar to <code>{@link #assertContainsSequence(Description, List, Object[])}</code>, but it also verifies * that the last element in the sequence is also the last element of the given {@code List}. * * @param description contains information about the assertion. * @param actual the given {@code List}. * @param sequence the sequence of objects to look for. * @throws NullPointerException if the given argument is {@code null}. * @throws IllegalArgumentException if the given argument is an empty array. * @throws AssertionError if the given {@code List} is {@code null}. * @throws AssertionError if the given {@code List} does not end with the given sequence of objects. */ public void assertEndsWith(Description description, List<?> actual, Object[] sequence) { checkIsNotNullAndNotEmpty(sequence); assertNotNull(description, actual); int sequenceSize = sequence.length; int sizeOfActual = actual.size(); if (sizeOfActual < sequenceSize) { throw actualDoesNotEndWithSequence(description, actual, sequence); } int start = actual.size() - sequenceSize; int sequenceIndex = 0, indexOfActual = 0; for (Object o : actual) { if (indexOfActual++ < start) { continue; } if (areEqual(o, sequence[sequenceIndex++])) { continue; } throw actualDoesNotEndWithSequence(description, actual, sequence); } } private AssertionError actualDoesNotStartWithSequence(Description description, List<?> actual, Object[] sequence) { return failures.failure(description, shouldStartWith(actual, sequence)); } private AssertionError actualDoesNotEndWithSequence(Description description, List<?> actual, Object[] sequence) { return failures.failure(description, shouldEndWith(actual, sequence)); } private void assertNotNull(Description description, List<?> actual) { Objects.instance().assertNotNull(description, actual); } private void checkNotEmpty(Description description, List<?> actual) { if (actual.isEmpty()) { throw failures.failure(description, ShouldNotBeEmpty.shouldNotBeEmpty()); } } private boolean areEqual(Object actual, Object other) { return org.fest.util.Objects.areEqual(actual, other); } private void checkIsNotNullAndNotEmpty(Object[] values) { if (values == null) { throw arrayOfValuesToLookForIsNull(); } if (values.length == 0) { throw arrayOfValuesToLookForIsEmpty(); } } }