/* * Created on Aug 5, 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.Lists.newArrayList; import static org.fest.util.Objects.HASH_CODE_PRIME; import static org.fest.util.Objects.areEqual; import static org.fest.util.Objects.hashCodeFor; import static org.fest.util.ToString.toStringOf; import java.util.List; import org.fest.assertions.description.Description; import org.fest.assertions.internal.Failures; import org.fest.util.VisibleForTesting; /** * Creates an {@link AssertionError} indicating that an assertion that verifies that two objects are equal failed. * * @author Alex Ruiz * @author Yvonne Wang * @author Joel Costigliola */ public class NotEqualErrorFactory implements AssertionErrorFactory { private static final Class<?>[] MSG_ARG_TYPES = new Class<?>[] { String.class, String.class, String.class }; private static final String DETAILED_TO_STRING_FORMAT = "%s (@%d)"; @VisibleForTesting ConstructorInvoker constructorInvoker = new ConstructorInvoker(); @VisibleForTesting MessageFormatter messageFormatter = MessageFormatter.instance(); @VisibleForTesting DescriptionFormatter descriptionFormatter = DescriptionFormatter.instance(); private final Object actual; private final Object expected; /** * Creates a new {@link NotEqualErrorFactory}. * * @param actual the <em>actual</em> value in the failed assertion. * @param expected the <em>expected value</em> in the failed assertion. * @return the created {@code NotEqualErrorFactory}. */ public static NotEqualErrorFactory shouldBeEqual(Object actual, Object expected) { return new NotEqualErrorFactory(actual, expected); } @VisibleForTesting public NotEqualErrorFactory(Object actual, Object expected) { this.actual = actual; this.expected = expected; } /** * Creates an {@link AssertionError} indicating that an assertion that verifies that two objects are equal, failed. * <p> * If JUnit 4 is in the classpath, this method will instead create a {@code org.junit.ComparisonFailure} that * highlights the difference(s) between the expected and actual objects. * </p> * * @param description the description of the failed assertion. * @return the created {@code AssertionError}. */ @Override public AssertionError newAssertionError(Description description) { AssertionError error = comparisonFailure(description); if (error != null) { return error; } return Failures.instance().failure(defaultErrorMessage(description)); } private String defaultErrorMessage(Description d) { return messageFormatter.format(d, "expected:<%s> but was:<%s>", expected, actual); } private AssertionError comparisonFailure(Description description) { try { AssertionError comparisonFailure = newComparisonFailure(descriptionFormatter.format(description).trim()); Failures.instance().removeFestRelatedElementsFromStackTraceIfNeeded(comparisonFailure); return comparisonFailure; } catch (Throwable e) { return null; } } private AssertionError newComparisonFailure(String description) throws Exception { Object o = constructorInvoker.newInstance("org.junit.ComparisonFailure", MSG_ARG_TYPES, msgArgs(description)); if (o instanceof AssertionError) { return (AssertionError) o; } return null; } private Object[] msgArgs(String description) { List<Object> args = newArrayList(); args.add(description); args.addAll(expectedAndActualToString()); return args.toArray(); } private List<String> expectedAndActualToString() { String e = toStringOf(expected); String a = toStringOf(actual); if (e != null && e.equals(a)) { e = String.format(DETAILED_TO_STRING_FORMAT, e, System.identityHashCode(expected)); a = String.format(DETAILED_TO_STRING_FORMAT, a, System.identityHashCode(actual)); } return newArrayList(e, a); } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null) { return false; } if (getClass() != o.getClass()) { return false; } NotEqualErrorFactory other = (NotEqualErrorFactory) o; if (!areEqual(actual, other.actual)) { return false; } return areEqual(expected, other.expected); } @Override public int hashCode() { int result = 1; result = HASH_CODE_PRIME * result + hashCodeFor(actual); result = HASH_CODE_PRIME * result + hashCodeFor(expected); return result; } }