/*
 * Created on Dec 22, 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.ShouldEndWith.shouldEndWith;
import static org.fest.assertions.error.ShouldHaveSize.shouldHaveSize;
import static org.fest.assertions.error.ShouldNotBeEmpty.shouldNotBeEmpty;
import static org.fest.assertions.error.ShouldStartWith.shouldStartWith;
import static org.fest.util.Preconditions.checkNotNull;
import static org.fest.util.Strings.isNullOrEmpty;

import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import org.fest.assertions.description.Description;
import org.fest.assertions.error.BasicErrorMessageFactory;
import org.fest.util.InternalApi;
import org.fest.util.VisibleForTesting;

/**
 * Reusable assertions for {@link String}s.
 *
 * @author Alex Ruiz
 */
@InternalApi
public class Strings {
  private static final Strings INSTANCE = new Strings();

  public static @Nonnull Strings instance() {
    return INSTANCE;
  }

  @VisibleForTesting
  Failures failures = Failures.instance();

  @VisibleForTesting
  Strings() {}

  /**
   * Asserts that the actual {@code String} is {@code null} or empty.
   *
   * @param description the description of the actual {@code String}.
   * @param actual the actual {@code String}.
   * @throws AssertionError if the actual {@code String} is not {@code null} and not empty.
   */
  public void assertNullOrEmpty(@Nullable Description description, @Nullable String actual) {
    if (!isNullOrEmpty(actual)) {
      throw failures.failure(description, shouldBeNullOrEmpty(actual));
    }
  }

  /**
   * Asserts that the actual {@code String} is empty.
   *
   * @param description the description of the actual {@code String}.
   * @param actual the actual {@code String}.
   * @throws AssertionError if the actual {@code String} is {@code null}.
   * @throws AssertionError if the actual {@code String} is not empty.
   */
  public void assertEmpty(@Nullable Description description, @Nullable String actual) {
    assertNotNull(description, actual);
    if (!actual.isEmpty()) {
      throw failures.failure(description, shouldBeEmpty(actual));
    }
  }

  /**
   * Asserts that the actual {@code String} is not empty.
   *
   * @param description the description of the actual {@code String}.
   * @param actual the actual {@code String}.
   * @throws AssertionError if the actual {@code String} is {@code null}.
   * @throws AssertionError if the actual {@code String} is empty.
   */
  public void assertNotEmpty(@Nullable Description description, @Nullable String actual) {
    assertNotNull(description, actual);
    if (actual.isEmpty()) {
      throw failures.failure(description, shouldNotBeEmpty());
    }
  }

  /**
   * Asserts that the size of the actual {@code String} is equal to the expected one.
   *
   * @param description the description of the actual {@code String}.
   * @param actual the actual {@code String}.
   * @param expectedSize the expected size of {@code actual}.
   * @throws AssertionError if the actual {@code String} is {@code null}.
   * @throws AssertionError if the size of the actual {@code String} is different than the expected one.
   */
  public void assertHasSize(@Nullable Description description, @Nullable String actual, int expectedSize) {
    assertNotNull(description, actual);
    int actualSize = actual.length();
    if (actualSize != expectedSize) {
      throw failures.failure(description, shouldHaveSize(actual, actualSize, expectedSize));
    }
  }

  /**
   * Verifies that two {@code String}s are equal, ignoring case considerations.
   *
   * @param description the description of the actual {@code String}.
   * @param actual the actual {@code String}.
   * @param expected the expected {@code String}.
   * @throws AssertionError if the given {@code String}s are not equal.
   */
  public void assertEqualsIgnoringCase(@Nullable Description description, @Nullable String actual,
      @Nullable String expected) {
    if (!areEqualIgnoringCase(actual, expected)) {
      String format = "expecting:<%s> to be equal to:<%s>, ignoring case considerations";
      throw failures.failure(description, new BasicErrorMessageFactory(format, actual, expected));
    }
  }

  private boolean areEqualIgnoringCase(String actual, String expected) {
    if (actual == null) {
      return expected == null;
    }
    return actual.equalsIgnoreCase(expected);
  }

  /**
   * Verifies that the actual {@code String} contains the given sequence.
   *
   * @param description the description of the actual {@code String}.
   * @param actual the actual {@code String}.
   * @param sequence the sequence to look for.
   * @throws NullPointerException if the given sequence is {@code null}.
   * @throws AssertionError if the actual {@code String} is {@code null}.
   * @throws AssertionError if the actual {@code String} does not contain the given sequence.
   */
  public void assertContains(@Nullable Description description, @Nullable String actual, @Nonnull String sequence) {
    checkNotNull(sequence);
    assertNotNull(description, actual);
    if (!actual.contains(sequence)) {
      String format = "expecting:<%s> to contain:<%s>";
      throw failures.failure(description, new BasicErrorMessageFactory(format, actual, sequence));
    }
  }

  /**
   * Verifies that the actual {@code String} does not contain the given sequence.
   *
   * @param description the description of the actual {@code String}.
   * @param actual the actual {@code String}.
   * @param sequence the sequence to look for.
   * @throws NullPointerException if the given sequence is {@code null}.
   * @throws AssertionError if the actual {@code String} is {@code null}.
   * @throws AssertionError if the actual {@code String} contains the given sequence.
   */
  public void assertDoesNotContain(@Nullable Description description, @Nullable String actual,
      @Nonnull String sequence) {
    checkNotNull(sequence);
    assertNotNull(description, actual);
    if (actual.contains(sequence)) {
      String format = "expecting:<%s> not to contain:<%s>";
      throw failures.failure(description, new BasicErrorMessageFactory(format, actual, sequence));
    }
  }

  /**
   * Verifies that the actual {@code String} starts with the given prefix.
   *
   * @param description the description of the actual {@code String}.
   * @param actual the actual {@code String}.
   * @param prefix the given prefix.
   * @throws NullPointerException if the given sequence is {@code null}.
   * @throws AssertionError if the actual {@code String} is {@code null}.
   * @throws AssertionError if the actual {@code String} does not start with the given prefix.
   */
  public void assertStartsWith(@Nullable Description description, @Nullable String actual, @Nonnull String prefix) {
    checkNotNull(prefix);
    assertNotNull(description, actual);
    if (!actual.startsWith(prefix)) {
      throw failures.failure(description, shouldStartWith(actual, prefix));
    }
  }

  /**
   * Verifies that the actual {@code String} ends with the given suffix.
   *
   * @param description the description of the actual {@code String}.
   * @param actual the actual {@code String}.
   * @param suffix the given suffix.
   * @throws NullPointerException if the given sequence is {@code null}.
   * @throws AssertionError if the actual {@code String} is {@code null}.
   * @throws AssertionError if the actual {@code String} does not end with the given suffix.
   */
  public void assertEndsWith(@Nullable Description description, @Nullable String actual, @Nonnull String suffix) {
    checkNotNull(suffix);
    assertNotNull(description, actual);
    if (!actual.endsWith(suffix)) {
      throw failures.failure(description, shouldEndWith(actual, suffix));
    }
  }

  /**
   * Verifies that the actual {@code String} matches the given regular expression.
   *
   * @param description the description of the actual {@code String}.
   * @param actual the actual {@code String}.
   * @param regex the regular expression to which the actual {@code String} is to be matched.
   * @throws NullPointerException if the given regular expression is {@code null}.
   * @throws PatternSyntaxException if the regular expression's syntax is invalid.
   * @throws AssertionError if the actual {@code String} is {@code null}.
   * @throws AssertionError if the actual {@code String} does not match the given regular expression.
   */
  public void assertMatches(@Nullable Description description, @Nullable String actual, @Nonnull String regex) {
    checkNotNull(regex);
    assertMatches(description, actual, Pattern.compile(regex));
  }

  /**
   * Verifies that the actual {@code String} matches the given regular expression.
   *
   * @param description the description of the actual {@code String}.
   * @param actual the actual {@code String}.
   * @param pattern the compiled representation of the regular expression pattern to which the actual
   *        {@code String} is to be matched.
   * @throws NullPointerException if the given pattern is {@code null}.
   * @throws AssertionError if the actual {@code String} is {@code null}.
   * @throws AssertionError if the actual {@code String} does not match the given regular expression.
   */
  public void assertMatches(@Nullable Description description, @Nullable String actual, @Nonnull Pattern pattern) {
    checkNotNull(pattern);
    assertNotNull(description, actual);
    if (!pattern.matcher(actual).matches()) {
      String format = "expecting:<%s> to match regular expression:<%s>";
      throw failures.failure(description, new BasicErrorMessageFactory(format, actual, pattern.pattern()));
    }
  }

  /**
   * Verifies that the actual {@code String} does not match the given regular expression.
   *
   * @param description the description of the actual {@code String}.
   * @param actual the actual {@code String}.
   * @param regex the regular expression to which the actual {@code String} is to be matched.
   * @throws NullPointerException if the given pattern is {@code null}.
   * @throws PatternSyntaxException if the regular expression's syntax is invalid.
   * @throws AssertionError if the actual {@code String} matches the given regular expression.
   */
  public void assertDoesNotMatch(@Nullable Description description, @Nullable String actual, @Nonnull String regex) {
    checkNotNull(regex);
    assertDoesNotMatch(description, actual, Pattern.compile(regex));
  }

  /**
   * Verifies that the actual {@code String} does not match the given regular expression.
   *
   * @param description the description of the actual {@code String}.
   * @param actual the actual {@code String}.
   * @param pattern the compiled representation of the regular expression pattern to which the actual
   *        {@code String} is to be matched.
   * @throws NullPointerException if the given pattern is {@code null}.
   * @throws AssertionError if the actual {@code String} matches the given regular expression.
   */
  public void assertDoesNotMatch(@Nullable Description description, @Nullable String actual, @Nonnull Pattern pattern) {
    checkNotNull(pattern);
    if (actual != null && pattern.matcher(actual).matches()) {
      String format = "expecting:<%s> not to match regular expression:<%s>";
      throw failures.failure(description, new BasicErrorMessageFactory(format, actual, pattern.pattern()));
    }
  }

  private void assertNotNull(@Nullable Description description, @Nullable String actual) {
    Objects.instance().assertNotNull(description, actual);
  }
}


/*
 * Created on Jul 15, 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-2012 the original author or authors.
 */
package org.fest.assertions.internal;

import static org.fest.util.Preconditions.checkNotNull;

import org.fest.assertions.core.Matcher;
import org.fest.assertions.description.Description;
import org.fest.assertions.error.BasicErrorMessageFactory;
import org.fest.util.VisibleForTesting;

/**
 * Verifies that a value satisfies a {@link Matcher}.
 *
 * @author Alex Ruiz
 * @author Yvonne Wang
 */
public class Matchers {
  private static final Matchers INSTANCE = new Matchers();

  public static Matchers instance() {
    return INSTANCE;
  }

  @VisibleForTesting
  Failures failures = Failures.instance();

  @VisibleForTesting
  Matchers() {}

  /**
   * Asserts that the actual value satisfies the given {@link Matcher}.
   *
   * @param <T> the type of the actual value and the type of values that given {@code Matcher} takes.
   * @param description the description of the actual object.
   * @param actual the actual value.
   * @param matcher the given {@code Matcher}.
   * @throws NullPointerException if the given {@code Matcher} is {@code null}.
   * @throws AssertionError if the actual value does not satisfy the given {@code Matcher}.
   */
  public <T> void assertIs(Description description, T actual, Matcher<? super T> matcher) {
    checkNotNull(matcher);
    if (!matcher.matches(actual)) {
      String format = "expecting:<%s> to be:<%s>";
      throw failures.failure(description, new BasicErrorMessageFactory(format, actual, matcher));
    }
  }

  /**
   * Asserts that the actual value does not satisfy the given {@link Matcher}.
   *
   * @param <T> the type of the actual value and the type of values that given {@code Matcher} takes.
   * @param description the description of the actual object.
   * @param actual the actual value.
   * @param matcher the given {@code Matcher}.
   * @throws NullPointerException if the given {@code Matcher} is {@code null}.
   * @throws AssertionError if the actual value satisfies the given {@code Matcher}.
   */
  public <T> void assertIsNot(Description description, T actual, Matcher<? super T> matcher) {
    checkNotNull(matcher);
    if (matcher.matches(actual)) {
      String format = "expecting:<%s> not to be:<%s>";
      throw failures.failure(description, new BasicErrorMessageFactory(format, actual, matcher));
    }
  }

  /**
   * Asserts that the actual value satisfies the given {@link Matcher}.
   *
   * @param <T> the type of the actual value and the type of values that given {@code Matcher} takes.
   * @param description the description of the actual object.
   * @param actual the actual value.
   * @param matcher the given {@code Matcher}.
   * @throws NullPointerException if the given {@code Matcher} is {@code null}.
   * @throws AssertionError if the actual value does not satisfy the given {@code Matcher}.
   */
  public <T> void assertHas(Description description, T actual, Matcher<? super T> matcher) {
    checkNotNull(matcher);
    if (!matcher.matches(actual)) {
      String format = "expecting:<%s> to have:<%s>";
      throw failures.failure(description, new BasicErrorMessageFactory(format, actual, matcher));
    }
  }

  /**
   * Asserts that the actual value does not satisfy the given {@link Matcher}.
   *
   * @param <T> the type of the actual value and the type of values that given {@code Matcher} takes.
   * @param description the description of the actual object.
   * @param actual the actual value.
   * @param matcher the given {@code Matcher}.
   * @throws NullPointerException if the given {@code Matcher} is {@code null}.
   * @throws AssertionError if the actual value satisfies the given {@code Matcher}.
   */
  public <T> void assertDoesNotHave(Description description, T actual, Matcher<? super T> matcher) {
    if (matcher.matches(actual)) {
      String format = "expecting:<%s> not to have:<%s>";
      throw failures.failure(description, new BasicErrorMessageFactory(format, actual, matcher));
    }
  }
}


/*
 * Created on Oct 23, 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 java.lang.Character.isLowerCase;
import static java.lang.Character.isUpperCase;

import static org.fest.assertions.error.ShouldBeEqual.shouldBeEqual;
import static org.fest.assertions.error.ShouldBeGreaterThan.shouldBeGreaterThan;
import static org.fest.assertions.error.ShouldBeLessThan.shouldBeLessThan;
import static org.fest.assertions.error.ShouldBeLowerCase.shouldBeLowerCase;
import static org.fest.assertions.error.ShouldBeUpperCase.shouldBeUpperCase;
import static org.fest.assertions.error.ShouldNotBeEqual.shouldNotBeEqual;
import static org.fest.assertions.error.ShouldNotBeGreaterThan.shouldNotBeGreaterThan;

import org.fest.assertions.description.Description;
import org.fest.assertions.error.ShouldNotBeLessThan;
import org.fest.util.VisibleForTesting;

/**
 * Reusable assertions for {@link Character}.
 *
 * @author Alex Ruiz
 * @author Yvonne Wang
 */
public class Characters {

  private static final Characters INSTANCE = new Characters();

  /**
   * Returns the singleton instance of this class.
   *
   * @return the singleton instance of this class.
   */
  public static Characters instance() {
    return INSTANCE;
  }

  @VisibleForTesting
  Failures failures = Failures.instance();

  @VisibleForTesting
  Characters() {
  }

  /**
   * Asserts that two characters are equal.
   *
   * @param description contains information about the assertion.
   * @param actual the actual value.
   * @param expected the expected value.
   * @throws AssertionError if the actual value is {@code null}.
   * @throws AssertionError if the actual value is not equal to the expected one. This method will throw a
   *           {@code org.junit.ComparisonFailure} instead if JUnit is in the classpath and the expected and actual
   *           values are not equal.
   */
  public void assertEqual(Description description, Character actual, char expected) {
    assertNotNull(description, actual);
    if (actual.charValue() != expected) {
      throw failures.failure(description, shouldBeEqual(actual, expected));
    }
  }

  /**
   * Asserts that two characters are not equal.
   *
   * @param description contains information about the assertion.
   * @param actual the actual value.
   * @param other the value to compare the actual value to.
   * @throws AssertionError if the actual value is {@code null}.
   * @throws AssertionError if the actual value is equal to the other one.
   */
  public void assertNotEqual(Description description, Character actual, char other) {
    assertNotNull(description, actual);
    if (actual.charValue() == other) {
      throw failures.failure(description, shouldNotBeEqual(actual, other));
    }
  }

  /**
   * Asserts that the actual value is less than the other one.
   *
   * @param description contains information about the assertion.
   * @param actual the actual value.
   * @param other the value to compare the actual value to.
   * @throws AssertionError if the actual value is {@code null}.
   * @throws AssertionError if the actual value is not less than the other one: this assertion will fail if the actual
   *           value is equal to or greater than the other value.
   */
  public void assertLessThan(Description description, Character actual, char other) {
    assertNotNull(description, actual);
    if (!isLessThan(actual, other)) {
      throw failures.failure(description, shouldBeLessThan(actual, other));
    }
  }

  /**
   * Asserts that the actual value is less than or equal to the other one.
   *
   * @param description contains information about the assertion.
   * @param actual the actual value.
   * @param other the value to compare the actual value to.
   * @throws AssertionError if the actual value is {@code null}.
   * @throws AssertionError if the actual value is greater than the other one.
   */
  public void assertNotGreaterThan(Description description, Character actual, char other) {
    assertNotNull(description, actual);
    if (isGreaterThan(actual, other)) {
      throw failures.failure(description, shouldNotBeGreaterThan(actual, other));
    }
  }

  /**
   * Asserts that the actual value is greater than the other one.
   *
   * @param description contains information about the assertion.
   * @param actual the actual value.
   * @param other the value to compare the actual value to.
   * @throws AssertionError if the actual value is {@code null}.
   * @throws AssertionError if the actual value is not greater than the other one: this assertion will fail if the
   *           actual value is equal to or less than the other value.
   */
  public void assertGreaterThan(Description description, Character actual, char other) {
    assertNotNull(description, actual);
    if (!isGreaterThan(actual, other)) {
      throw failures.failure(description, shouldBeGreaterThan(actual, other));
    }
  }

  /**
   * Asserts that the actual value is greater than or equal to the other one.
   *
   * @param description contains information about the assertion.
   * @param actual the actual value.
   * @param other the value to compare the actual value to.
   * @throws AssertionError if the actual value is {@code null}.
   * @throws AssertionError if the actual value is less than the other one.
   */
  public void assertNotLessThan(Description description, Character actual, char other) {
    assertNotNull(description, actual);
    if (isLessThan(actual, other)) {
      throw failures.failure(description, ShouldNotBeLessThan.shouldNotBeLessThan(actual, other));
    }
  }

  /**
   * Asserts that the actual value is a lowercase character.
   *
   * @param description contains information about the assertion.
   * @param actual the actual value.
   * @throws AssertionError if the actual value is {@code null}.
   * @throws AssertionError if the actual value is not a lowercase character.
   */
  public void assertLowerCase(Description description, Character actual) {
    assertNotNull(description, actual);
    if (!isLowerCase(actual)) {
      throw failures.failure(description, shouldBeLowerCase(actual));
    }
  }

  /**
   * Asserts that the actual value is a uppercase character.
   *
   * @param description contains information about the assertion.
   * @param actual the actual value.
   * @throws AssertionError if the actual value is {@code null}.
   * @throws AssertionError if the actual value is not a uppercase character.
   */
  public void assertUpperCase(Description description, Character actual) {
    assertNotNull(description, actual);
    if (!isUpperCase(actual)) {
      throw failures.failure(description, shouldBeUpperCase(actual));
    }
  }

  private static boolean isGreaterThan(Character actual, char other) {
    return actual.charValue() > other;
  }

  private static boolean isLessThan(Character actual, char other) {
    return actual.charValue() < other;
  }

  private static void assertNotNull(Description description, Character actual) {
    Objects.instance().assertNotNull(description, actual);
  }
}


/*
 * 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 {@link List}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 {@link List} 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 {@link List} 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 {@link #assertContainsSequence(Description, List, Object[])}, 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 {@link #assertContainsSequence(Description, List, Object[])}, 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();
    }
  }
}


/*
 * Created on Oct 18, 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.error;

/**
 * Creates an error message indicating that an assertion that verifies a group of elements does not contain a given set
 * of values failed. A group of elements can be a collection, an array or a {@code String}.
 *
 * @author Alex Ruiz
 * @author Yvonne Wang
 */
public class ShouldNotContain extends BasicErrorMessageFactory {
  /**
   * Creates a new </code>{@link ShouldNotContain}</code>.
   *
   * @param actual the actual value in the failed assertion.
   * @param expected values expected not to be contained in {@code actual}.
   * @param found the values in {@code expected} found in {@code actual}.
   * @return the created {@code ErrorMessageFactory}.
   */
  public static ErrorMessageFactory shouldNotContain(Object actual, Object expected, Object found) {
    return new ShouldNotContain(actual, expected, found);
  }

  private ShouldNotContain(Object actual, Object expected, Object found) {
    super("expecting:\n<%s>\n not to contain\n<%s>\n but found\n<%s>", actual, expected, found);
  }
}


/*
 * Created on Oct 18, 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.error;

import java.util.Date;

/**
 * Creates an error message indicating that an assertion that verifies that a {@link Date} is not between start - end
 * dates (inclusive or not) failed.
 *
 * @author Joel Costigliola
 * @author Yvonne Wang
 */
public class ShouldNotBeBetween extends BasicErrorMessageFactory {

  /**
   * Creates a new </code>{@link ShouldNotBeBetween}</code>.
   *
   * @param actual the actual value in the failed assertion.
   * @param start the lower boundary of date period.
   * @param end the lower boundary of date period.
   * @param inclusiveStart wether to include start date in period.
   * @param inclusiveEnd wether to include end date in period.
   * @return the created {@code ErrorMessageFactory}.
   */
  public static ErrorMessageFactory shouldNotBeBetween(Date actual, Date start, Date end, boolean inclusiveStart,
      boolean inclusiveEnd) {
    return new ShouldNotBeBetween(actual, start, end, inclusiveStart, inclusiveEnd);
  }

  private ShouldNotBeBetween(Date actual, Date start, Date end, boolean inclusiveStart, boolean inclusiveEnd) {
    super("expecting:\n<%s> not to be in period %s%s, %s%s%s", actual, inclusiveStart ? '[' : ']', start, end,
        inclusiveEnd);
  }
}


/*
 * Created on Feb 8, 2011
 *
 * 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 @2013 the original author or authors.
 */
package org.fest.assertions.api;

import org.fest.assertions.core.UnevenComparableAssert;
import org.fest.assertions.description.Description;

/**
 * Base class for all implementations of {@link UnevenComparableAssert}.
 *
 * @param <S> the "self" type of this assertion class. Please read "Emulating 'self types' using Java Generics to simplify fluent API implementation"
 *          for more details.
 * @param  the type of the "actual" value.
 *
 * @author Alex Ruiz
 * @author Yvonne Wang
 */
public abstract class AbstractUnevenComparableAssert<S extends AbstractUnevenComparableAssert<S, A>, A extends Comparable>
    extends AbstractComparableAssert<S, A> implements UnevenComparableAssert<S, A> {

  protected AbstractUnevenComparableAssert(A actual, Class<S> selfType) {
    super(actual, selfType);
  }

  protected AbstractUnevenComparableAssert(A actual, Class<S> selfType, Description description) {
    super(actual, selfType, description);
  }

  /** {@inheritDoc} */
  @Override
  public S isEqualByComparingTo(A expected) {
    comparables.assertEqual(description, actual, expected);
    return myself;
  }

  /** {@inheritDoc} */
  @Override
  public S isNotEqualByComparingTo(A other) {
    comparables.assertNotEqual(description, actual, other);
    return myself;
  }
}


/*
 * Created on Mar 17, 2012
 *
 * 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 the original author or authors.
 */
package org.fest.assertions.error;

import org.fest.assertions.core.Matcher;

/**
 * Creates an error message indicating that an assertion that verifies elements of a group satisfies exactly n times a
 * {@code Condition} A group of elements can be a collection, an array.

 *
 * @author Nicolas François
 * @author Mikhail Mazursky
 * @author Joel Costigliola
 */
public class ElementsShouldHaveExactly extends BasicErrorMessageFactory {

  /**
   * Creates a new {@link ElementsShouldHaveExactly}.
   * @param actual the actual value in the failed assertion.
   * @param times exactly times the condition should be verify.
   * @param condition the {@code Condition}.
   * @return the created {@code ErrorMessageFactory}.
   */
  public static <E> ErrorMessageFactory elementsShouldHaveExactly(Object actual, int times, Matcher<?> condition) {
    return new ElementsShouldHaveExactly(actual, times, condition);
  }

  private ElementsShouldHaveExactly(Object actual, int times, Matcher<?> condition) {
    super("expecting elements:\n<%s>\n to have exactly %s times <%s>", actual, times, condition);
  }
}


/*
 * Created on Nov 20, 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-2011 the original author or authors.
 */
package org.fest.assertions.error;

import org.fest.assertions.data.Index;

/**
 * Creates an error message indicating that an assertion that verifies a group of elements contains a value at a given index
 * failed. A group of elements can be a collection, an array or a {@code String}.

 *
 * @author Alex Ruiz
 */
public class ShouldContainAtIndex extends BasicErrorMessageFactory {

  /**
   * Creates a new {@link ShouldContainAtIndex}.
   *
   * @param actual the actual value in the failed assertion.
   * @param expected value expected to be in {@code actual}.
   * @param index the index of the expected value.
   * @param found the value in {@code actual} stored under {@code index}.
   * @return the created {@code ErrorMessageFactory}.
   */
  public static ErrorMessageFactory shouldContainAtIndex(Object actual, Object expected, Index index, Object found) {
    return new ShouldContainAtIndex(actual, expected, index, found);
  }

  private ShouldContainAtIndex(Object actual, Object expected, Index index, Object found) {
    super("expecting:\n<%s> at index <%s> but found <%s> in:\n <%s>", expected, index.value, found, actual);
  }
}


/*
 * Created on Mar 17, 2012
 *
 * 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 the original author or authors.
 */
package org.fest.assertions.error;

import org.fest.assertions.core.Matcher;

/**
 * Creates an error message indicating that an assertion that not verifies elements of a group satisfies exactly n times a
 * {@code Condition} A group of elements can be a collection, an array.

 *
 * @author Nicolas François
 * @author Mikhail Mazursky
 * @author Joel Costigliola
 */
public class ElementsShouldNotHaveExactly extends BasicErrorMessageFactory {

  /**
   * Creates a new {@link ElementsShouldNotHaveExactly}.
   * @param actual the actual value in the failed assertion.
   * @param times exactly times the condition should be verify.
   * @param condition the {@code Condition}.
   * @return the created {@code ErrorMessageFactory}.
   */
  public static <E> ErrorMessageFactory elementsShouldNotHaveExactly(Object actual, int times, Matcher<?> condition) {
    return new ElementsShouldNotHaveExactly(actual, times, condition);
  }

  private ElementsShouldNotHaveExactly(Object actual, int times, Matcher<?> condition) {
    super("expecting elements:\n<%s>\n not to have exactly %s times <%s>", actual, times, condition);
  }
}


/*
 * Created on Oct 18, 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-2012 the original author or authors.
 */
package org.fest.assertions.error;

/**
 * Creates an error message indicating that an assertion that verifies that a value have certain size failed.
 *
 * @author Alex Ruiz
 */
public class ShouldHaveSize extends BasicErrorMessageFactory {
  /**
   * Creates a new {@link ShouldHaveSize}.
   *
   * @param actual the actual value in the failed assertion.
   * @param actualSize the size of {@code actual}.
   * @param expectedSize the expected size.
   * @return the created {@code ShouldHaveSize}.
   */
  public static ErrorMessageFactory shouldHaveSize(Object actual, Object actualSize, Object expectedSize) {
    return new ShouldHaveSize(actual, actualSize, expectedSize);
  }

  private ShouldHaveSize(Object actual, Object actualSize, Object expectedSize) {
    super("expecting:\n<%s> but was:<%s> in:<%s>", expectedSize, actualSize, actual);
  }
}


/*
 * Created on Jan 28, 2011
 *
 * 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 @2011-2013 the original author or authors.
 */
package org.fest.assertions.api;

import static java.nio.charset.Charset.defaultCharset;

import java.io.File;
import java.nio.charset.Charset;

import org.fest.assertions.description.Description;
import org.fest.assertions.internal.Files;
import org.fest.util.IORuntimeException;
import org.fest.util.VisibleForTesting;

/**
 * Assertion methods for {@link File}s.
 *

 * To create a new instance of this class, invoke {@link Assertions#assertThat(File)}.
 *

 *
 * @author David DIDIER
 * @author Yvonne Wang
 * @author Alex Ruiz
 * @author Olivier Michallat
 * @author Olivier Demeijer
 */
public class FileAssert extends AbstractAssert<FileAssert, File> {
  @VisibleForTesting
  Files files = Files.instance();

  protected FileAssert(File actual) {
    super(actual, FileAssert.class);
  }

  protected FileAssert(File actual, Description description) {
    super(actual, FileAssert.class, description);
  }

  /**
   * Verifies that the actual {@link File} represents an existing file or directory.
   *
   * @return {@code this} assertion object.
   * @throws AssertionError if the actual {@code File} is {@code null}.
   * @throws AssertionError if the actual {@link File} represents a file or directory that does not exist.
   */
  public FileAssert exists() {
    files.assertExists(description, actual);
    return this;
  }

  /**
   * Verifies that the actual {@link File} represents a file or directory that does not exist.
   *
   * @return {@code this} assertion object.
   * @throws AssertionError if the actual {@code File} is {@code null}.
   * @throws AssertionError if the actual {@link File} represents an existing file or directory.
   */
  public FileAssert doesNotExist() {
    files.assertDoesNotExist(description, actual);
    return this;
  }

  /**
   * Verifies that the actual {@code File} represents an existing file.
   *
   * @return {@code this} assertion object.
   * @throws AssertionError if the actual {@code File} is {@code null}.
   * @throws AssertionError if the actual {@code File} does not represent an existing file.
   */
  public FileAssert isFile() {
    files.assertIsFile(description, actual);
    return this;
  }

  /**
   * Verifies that the actual {@code File} represents an existing directory.
   *
   * @return {@code this} assertion object.
   * @throws AssertionError if the actual {@code File} is {@code null}.
   * @throws AssertionError if the actual {@code File} does not represent an existing directory.
   */
  public FileAssert isDirectory() {
    files.assertIsDirectory(description, actual);
    return this;
  }

  /**
   * Verifies that the content of the file represented by the actual {@code File} is equal to the content of
   * the file represented by the given {@code File}. It is assumed that the content of the files is text. This method
   * uses the charset in {@link Charset#defaultCharset()} to read the contents of the files.
   *
   * @param expected the expected {@code File}.
   * @return {@code this} assertion object.
   * @throws NullPointerException if the expected {@code File} is {@code null}.
   * @throws IllegalArgumentException if the expected {@code File} does not represent an existing file.
   * @throws AssertionError if the actual {@code File} is {@code null}.
   * @throws AssertionError if the actual {@code File} does not represent an existing file.
   * @throws IORuntimeException if an I/O error occurs.
   * @throws AssertionError if the content of the file represented by the actual {@code File} is not equal to
   *           the content of the file represented by the given {@code File}.
   */
  public FileAssert hasContentEqualTo(File expected) {
    return hasContentEqualTo(expected, defaultCharset());
  }

  /**
   * Verifies that the content of the file represented by the actual {@code File} is equal to the content of
   * the file represented by the given {@code File}. It is assumed that the content of the files is text.
   *
   * @param expected the expected {@code File}.
   * @param charset the charset to use when reading the contents of the {@code File}s.
   * @return {@code this} assertion object.
   * @throws NullPointerException if the expected {@code File} is {@code null}.
   * @throws IllegalArgumentException if the expected {@code File} does not represent an existing file.
   * @throws NullPointerException if the given charset is {@code null}.
   * @throws AssertionError if the actual {@code File} is {@code null}.
   * @throws AssertionError if the actual {@code File} does not represent an existing file.
   * @throws IORuntimeException if an I/O error occurs.
   * @throws AssertionError if the content of the file represented by the actual {@code File} is not equal to
   *           the content of the file represented by the given {@code File}.
   */
  public FileAssert hasContentEqualTo(File expected, Charset charset) {
    files.assertEqualContent(description, actual, expected, charset);
    return this;
  }
}


/*
 * Created on May 1, 2013
 *
 * 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 @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.ShouldContainOnly.shouldContainOnly;
import static org.fest.assertions.error.ShouldHaveSize.shouldHaveSize;
import static org.fest.assertions.error.ShouldNotBeLessThan.shouldNotBeLessThan;
import static org.fest.assertions.error.ShouldNotContain.shouldNotContain;
import static org.fest.assertions.internal.CommonErrors.arrayOfValuesToLookForIsEmpty;
import static org.fest.assertions.internal.CommonErrors.arrayOfValuesToLookForIsNull;

import java.util.LinkedHashSet;
import java.util.Set;

import org.fest.assertions.description.Description;
import org.fest.assertions.error.ShouldContain;
import org.fest.assertions.error.ShouldNotBeEmpty;
import org.fest.util.VisibleForTesting;

/**
 * Reusable assertions for {@link Set}.
 *
 * @author Yvonne Wang
 */
public class Sets {

  private static final Sets INSTANCE = new Sets();

  /**
   * Returns the singleton instance of this class.
   *
   * @return the singleton instance of this class.
   */
  public static Sets instance() {
    return INSTANCE;
  }

  @VisibleForTesting
  Failures failures = Failures.instance();

  /**
   * Asserts that the given {@link Set} is {@code null} or empty.
   *
   * @param description contains information about the assertion.
   * @param actual the given {@code Set}.
   * @throws AssertionError if the given {@code Set} is not {@code null} *and* contains one or more elements.
   */
  public void assertNullOrEmpty(Description description, Set<?> actual) {
    if (actual == null || actual.isEmpty()) {
      return;
    }
    throw failures.failure(description, shouldBeNullOrEmpty(actual));
  }

  /**
   * Asserts that the given {@code Set} is empty.
   *
   * @param description contains information about the assertion.
   * @param actual the given {@code Set}.
   * @throws AssertionError if the given {@code Set} is {@code null}.
   * @throws AssertionError if the given {@code Set} is not empty.
   */
  public void assertEmpty(Description description, Set<?> actual) {
    assertNotNull(description, actual);
    if (!actual.isEmpty()) {
      throw failures.failure(description, shouldBeEmpty(actual));
    }
  }

  /**
   * Asserts that the given {@code Set} is not empty.
   *
   * @param description contains information about the assertion.
   * @param actual the given {@code List}.
   * @throws AssertionError if the given {@code Set} is {@code null}.
   * @throws AssertionError if the given {@code Set} is not empty.
   */
  public void assertNotEmpty(Description description, Set<?> actual) {
    assertNotNull(description, actual);
    checkNotEmpty(description, actual);
  }

  private void checkNotEmpty(Description description, Set<?> actual) {
    if (actual.isEmpty()) {
      throw failures.failure(description, ShouldNotBeEmpty.shouldNotBeEmpty());
    }
  }

  /**
   * Asserts that the given {@code Set} contains the given object.
   *
   * @param description contains information about the assertion.
   * @param actual the given {@code Set}.
   * @param values the object to look for.
   * @throws AssertionError if the given {@code Set} is {@code null} or empty.
   * @throws AssertionError if the given {@code Set} does not contain the given object.
   */
  public void assertContains(Description description, Set<?> actual, Object[] values) {
    assertNotNull(description, actual);
    checkNotEmpty(description, actual);
    checkIsNotNullAndNotEmpty(values);
    Set<Object> notFound = new LinkedHashSet<Object>();
    for (Object value : values) {
      if (!actual.contains(value)) {
        notFound.add(value);
      }
    }
    if (!notFound.isEmpty()) {
      throw failures.failure(description, ShouldContain.shouldContain(actual, values, notFound));
    }
  }

  /**
   * Asserts that the given {@code Set} does not contain the given values.
   *
   * @param description contains information about the assertion.
   * @param actual the given {@code Set}.
   * @param values the entries that are expected to be in the given {@code Set}.
   * @throws NullPointerException if the array of values is {@code null}.
   * @throws IllegalArgumentException if the array of values is empty.
   * @throws NullPointerException if any of the values in the given array is {@code null}.
   * @throws AssertionError if the given {@code Set} is {@code null}.
   * @throws AssertionError if the given {@code Set} contains any of the given values.
   */
  public void assertDoesNotContain(Description description, Set<?> actual, Object[] values) {
    checkIsNotNullAndNotEmpty(values);
    assertNotNull(description, actual);
    checkNotEmpty(description, actual);
    Set<Object> found = new LinkedHashSet<Object>();
    for (Object value : values) {
      if (actual.contains(value)) {
        found.add(value);
      }
    }
    if (!found.isEmpty()) {
      throw failures.failure(description, shouldNotContain(actual, values, found));
    }
  }

  /**
   * Asserts that the given {@code Set} contains only the given entries, nothing else.
   *
   * @param description contains information about the assertion.
   * @param actual the given {@code Set}.
   * @param values the values that are expected to be in the given {@code Set}.
   * @throws NullPointerException if the array of values is {@code null}.
   * @throws IllegalArgumentException if the array of values is empty.
   * @throws NullPointerException if any of the values in the given array is {@code null}.
   * @throws AssertionError if the given {@code Set} is {@code null}.
   * @throws AssertionError if the given {@code Set} does not contain the given values.
   */
  public void assertContainsOnly(Description description, Set<?> actual, Object[] values) {
    assertNotNull(description, actual);
    checkNotEmpty(description, actual);
    checkIsNotNullAndNotEmpty(values);
    Set<Object> notExpected = new LinkedHashSet<Object>(actual);
    Set<Object> notFound = containsOnly(actual, notExpected, values);
    if (!notFound.isEmpty() || !notExpected.isEmpty()) {
      throw failures.failure(description, shouldContainOnly(actual, values, notFound, notExpected));
    }
  }

  /**
   * Asserts that the number of values in the given {@code Set} is equal to the expected one.
   *
   * @param description contains information about the assertion.
   * @param actual the given {@code Set}.
   * @param expectedSize the expected size of {@code actual}.
   * @throws AssertionError if the given {@code Set} is {@code null}.
   * @throws AssertionError if the number of values in the given {@code Set} is different than the expected one.
   */
  public void assertHasSize(Description description, Set<?> actual, int expectedSize) {
    assertNotNull(description, actual);
    if (expectedSize < 0) {
      throw failures.failure(description, shouldNotBeLessThan(expectedSize, 0));
    }
    int sizeOfActual = actual.size();
    if (sizeOfActual != expectedSize) {
      throw failures.failure(description, shouldHaveSize(actual, sizeOfActual, expectedSize));
    }
  }

  private void checkIsNotNullAndNotEmpty(Object[] values) {
    if (values == null) {
      throw arrayOfValuesToLookForIsNull();
    }
    if (values.length == 0) {
      throw arrayOfValuesToLookForIsEmpty();
    }
  }

  private Set<Object> containsOnly(Set<?> actual, Set<?> notExpected, Object[] values) {
    Set<Object> notFound = new LinkedHashSet<Object>();
    for (Object value : values) {
      if (!actual.contains(value)) {
        notFound.add(value);
      } else {
        notExpected.remove(value);
      }
    }
    return notFound;
  }

  private void assertNotNull(Description description, Set<?> actual) {
    Objects.instance().assertNotNull(description, actual);
  }
}


/*
 * Created on Dec 2, 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.error;

import org.fest.assertions.data.Index;

/**
 * Creates an error message indicating that an assertion that verifies a group of elements does not contain a value at a
 * given index failed. A group of elements can be a collection, an array or a {@code String}.

 *
 * @author Alex Ruiz
 * @author Yvonne Wang
 */
public class ShouldNotContainAtIndex extends BasicErrorMessageFactory {

  /**
   * Creates a new {@link ShouldNotContainAtIndex}.
   *
   * @param actual the actual value in the failed assertion.
   * @param expected value expected to be in {@code actual}.
   * @param index the index of the expected value.
   * @return the created {@code ErrorMessageFactory}.
   */
  public static ErrorMessageFactory shouldNotContainAtIndex(Object actual, Object expected, Index index) {
    return new ShouldNotContainAtIndex(actual, expected, index);
  }

  private ShouldNotContainAtIndex(Object actual, Object expected, Index index) {
    super("expecting:\n<%s>\n not to contain \n<%s>\n at index <%s>", actual, expected, index.value);
  }
}


/*
 * Created on Feb 5, 2011
 *
 * 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 @2011 the original author or authors.
 */
package org.fest.assertions.condition;

import org.fest.assertions.core.Matcher;

/**
 * Returns {@code true} if any of the joined conditions is satisfied.
 * @param <T> the type of object this condition accepts.
 *
 * @author Yvonne Wang
 * @author Mikhail Mazursky
 */
public class AnyOf<T> extends Join<T> {

  /**
   * Creates a new {@link AnyOf}
   * @param <T> the type of object the given condition accept.
   * @param conditions the conditions to evaluate.
   * @return the created {@code AnyOf}.
   * @throws NullPointerException if the given array is {@code null}.
   * @throws NullPointerException if any of the elements in the given array is {@code null}.
   */
  public static <T> Matcher<T> anyOf(Matcher<? super T>... conditions) {
    return new AnyOf<T>(conditions);
  }

  /**
   * Creates a new {@link AnyOf}
   * @param <T> the type of object the given condition accept.
   * @param conditions the conditions to evaluate.
   * @return the created {@code AnyOf}.
   * @throws NullPointerException if the given iterable is {@code null}.
   * @throws NullPointerException if any of the elements in the given iterable is {@code null}.
   */
  public static <T> Matcher<T> anyOf(Iterable<? extends Matcher<? super T>> conditions) {
    return new AnyOf<T>(conditions);
  }

  private AnyOf(Matcher<? super T>... conditions) {
    super(conditions);
  }

  private AnyOf(Iterable<? extends Matcher<? super T>> conditions) {
    super(conditions);
  }

  /** {@inheritDoc} */
  @Override
  public boolean matches(T value) {
    for (Matcher<? super T> condition : conditions)
      if (condition.matches(value)) return true;
    return false;
  }

  @Override
  public String toString() {
    return String.format("any of:<%s>", conditions);
  }
}


/*
 * Created on Apr 27, 2012
 *
 * 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-2012 the original author or authors.
 */
package org.fest.assertions.error;

/**
 * Creates an error message indicating that an assertion that verifies that a value have certain size failed.
 *
 * @author Nicolas François
 */
public class ShouldHaveSameSizeAs extends BasicErrorMessageFactory {

  /**
   * Creates a new </code>{@link ShouldHaveSameSizeAs}</code>.
   * @param actual the actual value in the failed assertion.
   * @param actualSize the size of {@code actual}.
   * @param expectedSize the expected size.
   * @return the created {@code ErrorMessageFactory}.
   */
  public static ErrorMessageFactory shouldHaveSameSizeAs(Object actual, Object actualSize, Object expectedSize) {
    return new ShouldHaveSameSizeAs(actual, actualSize, expectedSize);
  }

  private ShouldHaveSameSizeAs(Object actual, Object actualSize, Object expectedSize) {
    super("expecting:\n actual and expected should have same size but actual size is:<%s> while expected is:<%s>, actual was:<%s>",
        actualSize, expectedSize, actual);
  }
}


/*
 * Created on Oct 18, 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-2011 the original author or authors.
 */
package org.fest.assertions.error;

import java.util.Date;

/**
 * Creates an error message indicating that an assertion that verifies that a {@link Date} is within a year, month, day, ...
 * failed.
 *
 * @author Joel Costigliola
 */
public class ShouldBeWithin extends BasicErrorMessageFactory {

  /**
   * Creates a new </code>{@link ShouldBeWithin}</code>.
   * @param actual the actual value in the failed assertion.
   * @param fieldDescription the fieldDescription of value : year, month, day, ...
   * @param fieldValue the field value used in the failed assertion to compare the actual date field value to.
   * @return the created {@code ErrorMessageFactory}.
   */
  public static ErrorMessageFactory shouldBeWithin(Date actual, String fieldDescription, int fieldValue) {
    return new ShouldBeWithin(actual, fieldDescription, fieldValue);
  }

  private ShouldBeWithin(Date actual, String fieldDescription, int fieldValue) {
    super("expecting:\n<%s> to be to be on %s <%s>", actual, fieldDescription, fieldValue);
  }
}


/*
 * Created on Sep 8, 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-2012 the original author or authors.
 */
package org.fest.assertions.error;

import static org.fest.util.Preconditions.checkNotNull;
import static org.fest.util.ToString.toStringOf;

import org.fest.assertions.description.Description;
import org.fest.util.ToString;
import org.fest.util.VisibleForTesting;

/**
 * Formats the messages to be included in assertion errors.
 *
 * @author Alex Ruiz
 */
public class MessageFormatter {
  private static final MessageFormatter INSTANCE = new MessageFormatter();

  public static MessageFormatter instance() {
    return INSTANCE;
  }

  @VisibleForTesting
  DescriptionFormatter descriptionFormatter = DescriptionFormatter.instance();

  @VisibleForTesting
  MessageFormatter() {}

  /**
   * Interprets a printf-style format {@code String} for failed assertion messages. It is similar to
   * {@link String#format(String, Object...)}, except for:
   *

   *
the value of the given {@link Description} is used as the first argument referenced in the format
   * string

   *
each of the arguments in the given array is converted to a {@code String} by invoking
   * {@link ToString#toStringOf(Object)}.
   *

   *
   * @param d the description of the failed assertion, may be {@code null}.
   * @param format the format string.
   * @param args arguments referenced by the format specifiers in the format string.
   * @throws NullPointerException if the format string is {@code null}.
   * @return A formatted {@code String}.
   */
  public String format(Description d, String format, Object... args) {
    checkNotNull(format);
    checkNotNull(args);
    return descriptionFormatter.format(d) + String.format(format, format(args));
  }

  private Object[] format(Object[] args) {
    int argCount = args.length;
    String[] formatted = new String[argCount];
    for (int i = 0; i < argCount; i++) {
      formatted[i] = toStringOf(args[i]);
    }
    return formatted;
  }
}


/*
 * Created on Dec 20, 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.api;

import javax.annotation.Nonnull;

import org.fest.assertions.core.EnumerableAssert;
import org.fest.assertions.data.Index;
import org.fest.assertions.description.Description;
import org.fest.assertions.internal.DoubleArrays;
import org.fest.util.VisibleForTesting;

/**
 * Assertion methods for arrays of {@code double}s.
 *

 * To create an instance of this class, invoke {@link Assertions#assertThat(double[])}.
 *

 *
 * @author Yvonne Wang
 * @author Alex Ruiz
 */
public class DoubleArrayAssert extends AbstractAssert<DoubleArrayAssert, double[]> implements
    EnumerableAssert<DoubleArrayAssert> {

  @VisibleForTesting
  DoubleArrays arrays = DoubleArrays.instance();

  protected DoubleArrayAssert(double[] actual) {
    super(actual, DoubleArrayAssert.class);
  }

  protected DoubleArrayAssert(double[] actual, Description description) {
    super(actual, DoubleArrayAssert.class, description);
  }

  /** {@inheritDoc} */
  @Override
  public DoubleArrayAssert isNullOrEmpty() {
    arrays.assertNullOrEmpty(description, actual);
    return this;
  }

  /** {@inheritDoc} */
  @Override
  public DoubleArrayAssert isEmpty() {
    arrays.assertEmpty(description, actual);
    return this;
  }

  /** {@inheritDoc} */
  @Nonnull
  @Override
  public DoubleArrayAssert isNotEmpty() {
    arrays.assertNotEmpty(description, actual);
    return this;
  }

  /** {@inheritDoc} */
  @Nonnull
  @Override
  public DoubleArrayAssert hasSize(int expected) {
    arrays.assertHasSize(description, actual, expected);
    return this;
  }

  /**
   * Verifies that the given array contains the given value at the given index.
   *
   * @param value the value to look for.
   * @param index the index where the value should be stored in the given array.
   * @return {@code this} assertion object.
   * @throws AssertionError if the given array 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 array.
   * @throws AssertionError if the given array does not contain the given value at the given index.
   */
  public DoubleArrayAssert contains(double value, Index index) {
    arrays.assertContains(description, actual, value, index);
    return this;
  }

  /**
   * Verifies that the given array does not contain the given value at the given index.
   *
   * @param value the value to look for.
   * @param index the index where the value should be stored in the given array.
    * @return {@code this} assertion object.
   * @throws AssertionError if the given array is {@code null}.
   * @throws NullPointerException if the given {@code Index} is {@code null}.
   * @throws AssertionError if the given array contains the given value at the given index.
   */
  public DoubleArrayAssert doesNotContain(double value, Index index) {
    arrays.assertDoesNotContain(description, actual, value, index);
    return this;
  }

  /**
   * Verifies that the actual array contains the given values, in any order.
   *
   * @param values the given values.
   * @return {@code this} assertion object.
   * @throws NullPointerException if the given argument is {@code null}.
   * @throws IllegalArgumentException if the given argument is an empty array.
   * @throws AssertionError if the actual array is {@code null}.
   * @throws AssertionError if the actual array does not contain the given values.
   */
  public DoubleArrayAssert contains(double... values) {
    arrays.assertContains(description, actual, values);
    return this;
  }

  /**
   * Verifies that the actual array contains only the given values and nothing else, in any order.
   *
   * @param values the given values.
   * @return {@code this} assertion object.
   * @throws NullPointerException if the given argument is {@code null}.
   * @throws IllegalArgumentException if the given argument is an empty array.
   * @throws AssertionError if the actual array is {@code null}.
   * @throws AssertionError if the actual array does not contain the given values, i.e. the actual array contains some
   *           or none of the given values, or the actual array contains more values than the given ones.
   */
  public DoubleArrayAssert containsOnly(double... values) {
    arrays.assertContainsOnly(description, actual, values);
    return this;
  }

  /**
   * Verifies that the actual array contains the given sequence, without any other values between them.
   *
   * @param sequence the sequence of values to look for.
   * @return this assertion object.
   * @throws AssertionError if the actual array is {@code null}.
   * @throws AssertionError if the given array is {@code null}.
   * @throws AssertionError if the actual array does not contain the given sequence.
   */
  public DoubleArrayAssert containsSequence(double... sequence) {
    arrays.assertContainsSequence(description, actual, sequence);
    return this;
  }

  /**
   * Verifies that the actual array does not contain the given values.
   *
   * @param values the given values.
   * @return {@code this} assertion object.
   * @throws NullPointerException if the given argument is {@code null}.
   * @throws IllegalArgumentException if the given argument is an empty array.
   * @throws AssertionError if the actual array is {@code null}.
   * @throws AssertionError if the actual array contains any of the given values.
   */
  public DoubleArrayAssert doesNotContain(double... values) {
    arrays.assertDoesNotContain(description, actual, values);
    return this;
  }

  /**
   * Verifies that the actual array does not contain duplicates.
   *
   * @return {@code this} assertion object.
   * @throws AssertionError if the actual array is {@code null}.
   * @throws AssertionError if the actual array contains duplicates.
   */
  public DoubleArrayAssert doesNotHaveDuplicates() {
    arrays.assertDoesNotHaveDuplicates(description, actual);
    return this;
  }

  /**
   * Verifies that the actual array starts with the given sequence of values, without any other values between them.
   * Similar to {@link #containsSequence(double...)}, but it also verifies that the first element in the
   * sequence is also first element of the actual array.
   *
   * @param sequence the sequence of values to look for.
   * @return this assertion object.
   * @throws NullPointerException if the given argument is {@code null}.
   * @throws IllegalArgumentException if the given argument is an empty array.
   * @throws AssertionError if the actual array is {@code null}.
   * @throws AssertionError if the actual array does not start with the given sequence.
   */
  public DoubleArrayAssert startsWith(double... sequence) {
    arrays.assertStartsWith(description, actual, sequence);
    return this;
  }

  /**
   * Verifies that the actual array ends with the given sequence of values, without any other values between them.
   * Similar to {@link #containsSequence(double...)}, but it also verifies that the last element in the
   * sequence is also last element of the actual array.
   *
   * @param sequence the sequence of values to look for.
   * @return this assertion object.
   * @throws NullPointerException if the given argument is {@code null}.
   * @throws IllegalArgumentException if the given argument is an empty array.
   * @throws AssertionError if the actual array is {@code null}.
   * @throws AssertionError if the actual array does not end with the given sequence.
   */
  public DoubleArrayAssert endsWith(double... sequence) {
    arrays.assertEndsWith(description, actual, sequence);
    return this;
  }
}


/*
 * Created on Mar 17, 2012
 *
 * 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 the original author or authors.
 */
package org.fest.assertions.error;

import org.fest.assertions.core.Matcher;

/**
 * Creates an error message indicating that an assertion that not verifies elements of a group satisfies exactly n times a
 * {@code Condition} A group of elements can be a collection, an array.

 *
 * @author Nicolas François
 * @author Mikhail Mazursky
 * @author Joel Costigliola
 */
public class ElementsShouldNotBeExactly extends BasicErrorMessageFactory {

  /**
   * Creates a new {@link ElementsShouldNotBeExactly}.
   * @param actual the actual value in the failed assertion.
   * @param times exactly times the condition should be verify.
   * @param condition the {@code Condition}.
   * @return the created {@code ErrorMessageFactory}.
   */
  public static <E> ErrorMessageFactory elementsShouldNotBeExactly(Object actual, int times, Matcher<?> condition) {
    return new ElementsShouldNotBeExactly(actual, times, condition);
  }

  private ElementsShouldNotBeExactly(Object actual, int times, Matcher<?> condition) {
    super("expecting elements:\n<%s>\n not to be exactly %s times <%s>", actual, times, condition);
  }
}


package org.fest.assertions.error;

import java.util.List;

import org.fest.assertions.core.Matcher;
import org.fest.assertions.data.Index;

/**
 * Creates an error message indicating that an assertion that verifies a group of elements contains a value at a given index that
 * satisfies a {@link Matcher} failed.
 *
 * @author Bo Gotthardt
 */
public class ShouldBeAtIndex extends BasicErrorMessageFactory {
  /**
   * Creates a new {@link ShouldBeAtIndex}.
   * @param <T> guarantees that the type of the actual value and the generic type of the {@code Condition} are the same.
   * @param actual the actual value in the failed assertion.
   * @param condition the {@code Condition}.
   * @param index the index of the expected value.
   * @param found the value in {@code actual} stored under {@code index}.
   * @return the created {@code ErrorMessageFactory}.
   */
  public static <T> ErrorMessageFactory shouldBeAtIndex(List<T> actual, Matcher<? super T> condition, Index index, T found) {
    return new ShouldBeAtIndex(actual, condition, index, found);
  }

  private <T> ShouldBeAtIndex(List<T> actual, Matcher<? super T> condition, Index index, T found) {
    super("expecting:\n<%s> at index <%s> to be:<%s> in:\n <%s>\n", found, index.value, condition, actual);
  }
}