From 6464cb5caac4815e4ae9caff99ebdf04c90d09c3 Mon Sep 17 00:00:00 2001 From: cpovirk Date: Mon, 11 Dec 2023 12:47:21 -0800 Subject: [PATCH] Add `isWithin().of()` support to `IntegerSubject`. To make `IntegerSubjectTest` match `LongSubjectTest` more closely, I moved some of the existing `IntegerSubjectTest` tests into a new `NumericComparisonTest` class. This is arguably how they should always have been: The tests there don't exercise logic implemented in `IntegerSubject` but rather logic in `Subject` itself. (So yes, the tests could also go into `SubjectTest`. But that class is already quite long.) This CL is otherwise a mechanical copy-paste of cl/586097910. RELNOTES=Added `isWithin().of()` support to `IntegerSubject`. PiperOrigin-RevId: 589914997 --- .../google/common/truth/IntegerSubject.java | 112 +++++++- .../com/google/common/truth/LongSubject.java | 4 +- .../com/google/common/truth/MathUtil.java | 16 ++ .../common/truth/IntegerSubjectTest.java | 259 ++++++++---------- .../common/truth/NumericComparisonTest.java | 194 +++++++++++++ 5 files changed, 435 insertions(+), 150 deletions(-) create mode 100644 core/src/test/java/com/google/common/truth/NumericComparisonTest.java diff --git a/core/src/main/java/com/google/common/truth/IntegerSubject.java b/core/src/main/java/com/google/common/truth/IntegerSubject.java index bf1446408..ba3119c2d 100644 --- a/core/src/main/java/com/google/common/truth/IntegerSubject.java +++ b/core/src/main/java/com/google/common/truth/IntegerSubject.java @@ -15,6 +15,11 @@ */ package com.google.common.truth; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.truth.Fact.fact; +import static com.google.common.truth.MathUtil.equalWithinTolerance; + import org.checkerframework.checker.nullness.qual.Nullable; /** @@ -25,12 +30,110 @@ * @author Kurt Alfred Kluever */ public class IntegerSubject extends ComparableSubject { + private final @Nullable Integer actual; + /** * Constructor for use by subclasses. If you want to create an instance of this class itself, call * {@link Subject#check(String, Object...) check(...)}{@code .that(actual)}. */ - protected IntegerSubject(FailureMetadata metadata, @Nullable Integer integer) { - super(metadata, integer); + protected IntegerSubject(FailureMetadata metadata, @Nullable Integer actual) { + super(metadata, actual); + this.actual = actual; + } + + /** + * A partially specified check about an approximate relationship to a {@code int} subject using a + * tolerance. + * + * @since 1.2 + */ + public abstract static class TolerantIntegerComparison { + + // Prevent subclassing outside of this class + private TolerantIntegerComparison() {} + + /** + * Fails if the subject was expected to be within the tolerance of the given value but was not + * or if it was expected not to be within the tolerance but was. The subject and + * tolerance are specified earlier in the fluent call chain. + */ + public abstract void of(int expectedInteger); + + /** + * @throws UnsupportedOperationException always + * @deprecated {@link Object#equals(Object)} is not supported on TolerantIntegerComparison. If + * you meant to compare ints, use {@link #of(int)} instead. + */ + @Deprecated + @Override + public boolean equals(@Nullable Object o) { + throw new UnsupportedOperationException( + "If you meant to compare ints, use .of(int) instead."); + } + + /** + * @throws UnsupportedOperationException always + * @deprecated {@link Object#hashCode()} is not supported on TolerantIntegerComparison + */ + @Deprecated + @Override + public int hashCode() { + throw new UnsupportedOperationException("Subject.hashCode() is not supported."); + } + } + + /** + * Prepares for a check that the subject is a number within the given tolerance of an expected + * value that will be provided in the next call in the fluent chain. + * + * @param tolerance an inclusive upper bound on the difference between the subject and object + * allowed by the check, which must be a non-negative value. + * @since 1.2 + */ + public TolerantIntegerComparison isWithin(int tolerance) { + return new TolerantIntegerComparison() { + @Override + public void of(int expected) { + Integer actual = IntegerSubject.this.actual; + checkNotNull( + actual, "actual value cannot be null. tolerance=%s expected=%s", tolerance, expected); + checkTolerance(tolerance); + + if (!equalWithinTolerance(actual, expected, tolerance)) { + failWithoutActual( + fact("expected", Integer.toString(expected)), + butWas(), + fact("outside tolerance", Integer.toString(tolerance))); + } + } + }; + } + + /** + * Prepares for a check that the subject is a number not within the given tolerance of an expected + * value that will be provided in the next call in the fluent chain. + * + * @param tolerance an exclusive lower bound on the difference between the subject and object + * allowed by the check, which must be a non-negative value. + * @since 1.2 + */ + public TolerantIntegerComparison isNotWithin(int tolerance) { + return new TolerantIntegerComparison() { + @Override + public void of(int expected) { + Integer actual = IntegerSubject.this.actual; + checkNotNull( + actual, "actual value cannot be null. tolerance=%s expected=%s", tolerance, expected); + checkTolerance(tolerance); + + if (equalWithinTolerance(actual, expected, tolerance)) { + failWithoutActual( + fact("expected not to be", Integer.toString(expected)), + butWas(), + fact("within tolerance", Integer.toString(tolerance))); + } + } + }; } /** @@ -41,4 +144,9 @@ protected IntegerSubject(FailureMetadata metadata, @Nullable Integer integer) { public final void isEquivalentAccordingToCompareTo(@Nullable Integer other) { super.isEquivalentAccordingToCompareTo(other); } + + /** Ensures that the given tolerance is a non-negative value. */ + private static void checkTolerance(int tolerance) { + checkArgument(tolerance >= 0, "tolerance (%s) cannot be negative", tolerance); + } } diff --git a/core/src/main/java/com/google/common/truth/LongSubject.java b/core/src/main/java/com/google/common/truth/LongSubject.java index 4985bf725..32ca51593 100644 --- a/core/src/main/java/com/google/common/truth/LongSubject.java +++ b/core/src/main/java/com/google/common/truth/LongSubject.java @@ -17,8 +17,8 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.truth.MathUtil.equalWithinTolerance; import static com.google.common.truth.Fact.fact; +import static com.google.common.truth.MathUtil.equalWithinTolerance; import org.checkerframework.checker.nullness.qual.Nullable; @@ -147,7 +147,7 @@ public final void isEquivalentAccordingToCompareTo(@Nullable Long other) { } /** Ensures that the given tolerance is a non-negative value. */ - static void checkTolerance(long tolerance) { + private static void checkTolerance(long tolerance) { checkArgument(tolerance >= 0, "tolerance (%s) cannot be negative", tolerance); } diff --git a/core/src/main/java/com/google/common/truth/MathUtil.java b/core/src/main/java/com/google/common/truth/MathUtil.java index c10e85625..cad5015c8 100644 --- a/core/src/main/java/com/google/common/truth/MathUtil.java +++ b/core/src/main/java/com/google/common/truth/MathUtil.java @@ -40,6 +40,22 @@ private MathUtil() {} } } + /** + * Returns true iff {@code left} and {@code right} are values within {@code tolerance} of each + * other. + */ + /* package */ static boolean equalWithinTolerance(int left, int right, int tolerance) { + try { + // subtractExact is always desugared. + @SuppressWarnings({"AndroidJdkLibsChecker", "Java7ApiChecker"}) + int absDiff = Math.abs(subtractExact(left, right)); + return 0 <= absDiff && absDiff <= Math.abs(tolerance); + } catch (ArithmeticException e) { + // The numbers are so far apart their difference isn't even a int. + return false; + } + } + /** * Returns true iff {@code left} and {@code right} are finite values within {@code tolerance} of * each other. Note that both this method and {@link #notEqualWithinTolerance} returns false if diff --git a/core/src/test/java/com/google/common/truth/IntegerSubjectTest.java b/core/src/test/java/com/google/common/truth/IntegerSubjectTest.java index bc6a5a02b..a233f6c5d 100644 --- a/core/src/test/java/com/google/common/truth/IntegerSubjectTest.java +++ b/core/src/test/java/com/google/common/truth/IntegerSubjectTest.java @@ -15,9 +15,12 @@ */ package com.google.common.truth; +import static com.google.common.truth.ExpectFailure.assertThat; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.fail; -import com.google.common.collect.ImmutableSet; +import com.google.common.truth.ExpectFailure.SimpleSubjectBuilderCallback; +import com.google.errorprone.annotations.CanIgnoreReturnValue; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -116,160 +119,124 @@ public void overflowBetweenIntegerAndLong_shouldBeDifferent_max() { expectFailureWhenTestingThat(Integer.MAX_VALUE).isEqualTo(Long.MAX_VALUE); } - @SuppressWarnings("TruthSelfEquals") @Test - public void testPrimitivesVsBoxedPrimitivesVsObject_int() { - int int42 = 42; - Integer integer42 = new Integer(42); - Object object42 = (Object) 42; - - assertThat(int42).isEqualTo(int42); - assertThat(integer42).isEqualTo(int42); - assertThat(object42).isEqualTo(int42); - - assertThat(int42).isEqualTo(integer42); - assertThat(integer42).isEqualTo(integer42); - assertThat(object42).isEqualTo(integer42); - - assertThat(int42).isEqualTo(object42); - assertThat(integer42).isEqualTo(object42); - assertThat(object42).isEqualTo(object42); - } - - @SuppressWarnings("TruthSelfEquals") - @Test - public void testPrimitivesVsBoxedPrimitivesVsObject_long() { - long longPrim42 = 42; - Long long42 = new Long(42); - Object object42 = (Object) 42L; - - assertThat(longPrim42).isEqualTo(longPrim42); - assertThat(long42).isEqualTo(longPrim42); - assertThat(object42).isEqualTo(longPrim42); - - assertThat(longPrim42).isEqualTo(long42); - assertThat(long42).isEqualTo(long42); - assertThat(object42).isEqualTo(long42); - - assertThat(longPrim42).isEqualTo(object42); - assertThat(long42).isEqualTo(object42); - assertThat(object42).isEqualTo(object42); - } - - @Test - public void testAllCombinations_pass() { - assertThat(42).isEqualTo(42L); - assertThat(42).isEqualTo(new Long(42L)); - assertThat(new Integer(42)).isEqualTo(42L); - assertThat(new Integer(42)).isEqualTo(new Long(42L)); - assertThat(42L).isEqualTo(42); - assertThat(42L).isEqualTo(new Integer(42)); - assertThat(new Long(42L)).isEqualTo(42); - assertThat(new Long(42L)).isEqualTo(new Integer(42)); - - assertThat(42).isEqualTo(42); - assertThat(42).isEqualTo(new Integer(42)); - assertThat(new Integer(42)).isEqualTo(42); - assertThat(new Integer(42)).isEqualTo(new Integer(42)); - assertThat(42L).isEqualTo(42L); - assertThat(42L).isEqualTo(new Long(42L)); - assertThat(new Long(42L)).isEqualTo(42L); - assertThat(new Long(42L)).isEqualTo(new Long(42L)); - } - - @Test - public void testNumericTypeWithSameValue_shouldBeEqual_int_long() { - expectFailureWhenTestingThat(42).isNotEqualTo(42L); - } - - @Test - public void testNumericTypeWithSameValue_shouldBeEqual_int_int() { - expectFailureWhenTestingThat(42).isNotEqualTo(42); - } - - @Test - public void testNumericPrimitiveTypes_isNotEqual_shouldFail_intToChar() { - expectFailureWhenTestingThat(42).isNotEqualTo((char) 42); - // 42 in ASCII is '*' - assertFailureValue("expected not to be", "*"); - assertFailureValue("but was; string representation of actual value", "42"); + public void isWithinOf() { + assertThat(20000).isWithin(0).of(20000); + assertThat(20000).isWithin(1).of(20000); + assertThat(20000).isWithin(10000).of(20000); + assertThat(20000).isWithin(10000).of(30000); + assertThat(Integer.MIN_VALUE).isWithin(1).of(Integer.MIN_VALUE + 1); + assertThat(Integer.MAX_VALUE).isWithin(1).of(Integer.MAX_VALUE - 1); + assertThat(Integer.MAX_VALUE / 2).isWithin(Integer.MAX_VALUE).of(-Integer.MAX_VALUE / 2); + assertThat(-Integer.MAX_VALUE / 2).isWithin(Integer.MAX_VALUE).of(Integer.MAX_VALUE / 2); + + assertThatIsWithinFails(20000, 9999, 30000); + assertThatIsWithinFails(20000, 10000, 30001); + assertThatIsWithinFails(Integer.MIN_VALUE, 0, Integer.MAX_VALUE); + assertThatIsWithinFails(Integer.MAX_VALUE, 0, Integer.MIN_VALUE); + assertThatIsWithinFails(Integer.MIN_VALUE, 1, Integer.MIN_VALUE + 2); + assertThatIsWithinFails(Integer.MAX_VALUE, 1, Integer.MAX_VALUE - 2); + // Don't fall for rollover + assertThatIsWithinFails(Integer.MIN_VALUE, 1, Integer.MAX_VALUE); + assertThatIsWithinFails(Integer.MAX_VALUE, 1, Integer.MIN_VALUE); + } + + private static void assertThatIsWithinFails(int actual, int tolerance, int expected) { + ExpectFailure.SimpleSubjectBuilderCallback callback = + new ExpectFailure.SimpleSubjectBuilderCallback() { + @Override + public void invokeAssertion(SimpleSubjectBuilder expect) { + expect.that(actual).isWithin(tolerance).of(expected); + } + }; + AssertionError failure = expectFailure(callback); + assertThat(failure) + .factKeys() + .containsExactly("expected", "but was", "outside tolerance") + .inOrder(); + assertThat(failure).factValue("expected").isEqualTo(Integer.toString(expected)); + assertThat(failure).factValue("but was").isEqualTo(Integer.toString(actual)); + assertThat(failure).factValue("outside tolerance").isEqualTo(Integer.toString(tolerance)); + } + + @Test + public void isNotWithinOf() { + assertThatIsNotWithinFails(20000, 0, 20000); + assertThatIsNotWithinFails(20000, 1, 20000); + assertThatIsNotWithinFails(20000, 10000, 20000); + assertThatIsNotWithinFails(20000, 10000, 30000); + assertThatIsNotWithinFails(Integer.MIN_VALUE, 1, Integer.MIN_VALUE + 1); + assertThatIsNotWithinFails(Integer.MAX_VALUE, 1, Integer.MAX_VALUE - 1); + assertThatIsNotWithinFails(Integer.MAX_VALUE / 2, Integer.MAX_VALUE, -Integer.MAX_VALUE / 2); + assertThatIsNotWithinFails(-Integer.MAX_VALUE / 2, Integer.MAX_VALUE, Integer.MAX_VALUE / 2); + + assertThat(20000).isNotWithin(9999).of(30000); + assertThat(20000).isNotWithin(10000).of(30001); + assertThat(Integer.MIN_VALUE).isNotWithin(0).of(Integer.MAX_VALUE); + assertThat(Integer.MAX_VALUE).isNotWithin(0).of(Integer.MIN_VALUE); + assertThat(Integer.MIN_VALUE).isNotWithin(1).of(Integer.MIN_VALUE + 2); + assertThat(Integer.MAX_VALUE).isNotWithin(1).of(Integer.MAX_VALUE - 2); + // Don't fall for rollover + assertThat(Integer.MIN_VALUE).isNotWithin(1).of(Integer.MAX_VALUE); + assertThat(Integer.MAX_VALUE).isNotWithin(1).of(Integer.MIN_VALUE); + } + + private static void assertThatIsNotWithinFails(int actual, int tolerance, int expected) { + ExpectFailure.SimpleSubjectBuilderCallback callback = + new ExpectFailure.SimpleSubjectBuilderCallback() { + @Override + public void invokeAssertion(SimpleSubjectBuilder expect) { + expect.that(actual).isNotWithin(tolerance).of(expected); + } + }; + AssertionError failure = expectFailure(callback); + assertThat(failure).factValue("expected not to be").isEqualTo(Integer.toString(expected)); + assertThat(failure).factValue("within tolerance").isEqualTo(Integer.toString(tolerance)); + } + + @Test + public void isWithinNegativeTolerance() { + isWithinNegativeToleranceThrowsIAE(0, -10, 5); + isWithinNegativeToleranceThrowsIAE(0, -10, 20); + isNotWithinNegativeToleranceThrowsIAE(0, -10, 5); + isNotWithinNegativeToleranceThrowsIAE(0, -10, 20); + } + + private static void isWithinNegativeToleranceThrowsIAE(int actual, int tolerance, int expected) { + try { + assertThat(actual).isWithin(tolerance).of(expected); + fail("Expected IllegalArgumentException to be thrown but wasn't"); + } catch (IllegalArgumentException iae) { + assertThat(iae) + .hasMessageThat() + .isEqualTo("tolerance (" + tolerance + ") cannot be negative"); + } } - @Test - public void testNumericPrimitiveTypes_isNotEqual_shouldFail_charToInt() { - // Uses Object overload rather than Integer. - expectFailure.whenTesting().that((char) 42).isNotEqualTo(42); - // 42 in ASCII is '*' - assertFailureValue("expected not to be", "42"); - assertFailureValue("but was; string representation of actual value", "*"); + private static void isNotWithinNegativeToleranceThrowsIAE( + int actual, int tolerance, int expected) { + try { + assertThat(actual).isNotWithin(tolerance).of(expected); + fail("Expected IllegalArgumentException to be thrown but wasn't"); + } catch (IllegalArgumentException iae) { + assertThat(iae) + .hasMessageThat() + .isEqualTo("tolerance (" + tolerance + ") cannot be negative"); + } } - private static final Subject.Factory DEFAULT_SUBJECT_FACTORY = - new Subject.Factory() { + private static final Subject.Factory INTEGER_SUBJECT_FACTORY = + new Subject.Factory() { @Override - public Subject createSubject(FailureMetadata metadata, Object that) { - return new Subject(metadata, that); + public IntegerSubject createSubject(FailureMetadata metadata, Integer that) { + return new IntegerSubject(metadata, that); } }; - private static void expectFailure( - ExpectFailure.SimpleSubjectBuilderCallback callback) { - AssertionError unused = ExpectFailure.expectFailureAbout(DEFAULT_SUBJECT_FACTORY, callback); - } - - @Test - public void testNumericPrimitiveTypes() { - byte byte42 = (byte) 42; - short short42 = (short) 42; - char char42 = (char) 42; - int int42 = 42; - long long42 = (long) 42; - - ImmutableSet fortyTwos = - ImmutableSet.of(byte42, short42, char42, int42, long42); - for (Object actual : fortyTwos) { - for (Object expected : fortyTwos) { - assertThat(actual).isEqualTo(expected); - } - } - - ImmutableSet fortyTwosNoChar = ImmutableSet.of(byte42, short42, int42, long42); - for (Object actual : fortyTwosNoChar) { - for (Object expected : fortyTwosNoChar) { - ExpectFailure.SimpleSubjectBuilderCallback actualFirst = - new ExpectFailure.SimpleSubjectBuilderCallback() { - @Override - public void invokeAssertion(SimpleSubjectBuilder expect) { - expect.that(actual).isNotEqualTo(expected); - } - }; - ExpectFailure.SimpleSubjectBuilderCallback expectedFirst = - new ExpectFailure.SimpleSubjectBuilderCallback() { - @Override - public void invokeAssertion(SimpleSubjectBuilder expect) { - expect.that(expected).isNotEqualTo(actual); - } - }; - expectFailure(actualFirst); - expectFailure(expectedFirst); - } - } - - byte byte41 = (byte) 41; - short short41 = (short) 41; - char char41 = (char) 41; - int int41 = 41; - long long41 = (long) 41; - - ImmutableSet fortyOnes = - ImmutableSet.of(byte41, short41, char41, int41, long41); - - for (Object first : fortyTwos) { - for (Object second : fortyOnes) { - assertThat(first).isNotEqualTo(second); - assertThat(second).isNotEqualTo(first); - } - } + @CanIgnoreReturnValue + private static AssertionError expectFailure( + SimpleSubjectBuilderCallback callback) { + return ExpectFailure.expectFailureAbout(INTEGER_SUBJECT_FACTORY, callback); } private IntegerSubject expectFailureWhenTestingThat(Integer actual) { diff --git a/core/src/test/java/com/google/common/truth/NumericComparisonTest.java b/core/src/test/java/com/google/common/truth/NumericComparisonTest.java new file mode 100644 index 000000000..46e53e6d4 --- /dev/null +++ b/core/src/test/java/com/google/common/truth/NumericComparisonTest.java @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2011 Google, Inc. + * + * 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. + */ +package com.google.common.truth; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.common.collect.ImmutableSet; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Tests for comparisons between various integral types. + * + * @author David Saff + * @author Christian Gruber + * @author Kurt Alfred Kluever + */ +@RunWith(JUnit4.class) +public class NumericComparisonTest extends BaseSubjectTestCase { + + @SuppressWarnings("TruthSelfEquals") + @Test + public void testPrimitivesVsBoxedPrimitivesVsObject_int() { + int int42 = 42; + Integer integer42 = new Integer(42); + Object object42 = (Object) 42; + + assertThat(int42).isEqualTo(int42); + assertThat(integer42).isEqualTo(int42); + assertThat(object42).isEqualTo(int42); + + assertThat(int42).isEqualTo(integer42); + assertThat(integer42).isEqualTo(integer42); + assertThat(object42).isEqualTo(integer42); + + assertThat(int42).isEqualTo(object42); + assertThat(integer42).isEqualTo(object42); + assertThat(object42).isEqualTo(object42); + } + + @SuppressWarnings("TruthSelfEquals") + @Test + public void testPrimitivesVsBoxedPrimitivesVsObject_long() { + long longPrim42 = 42; + Long long42 = new Long(42); + Object object42 = (Object) 42L; + + assertThat(longPrim42).isEqualTo(longPrim42); + assertThat(long42).isEqualTo(longPrim42); + assertThat(object42).isEqualTo(longPrim42); + + assertThat(longPrim42).isEqualTo(long42); + assertThat(long42).isEqualTo(long42); + assertThat(object42).isEqualTo(long42); + + assertThat(longPrim42).isEqualTo(object42); + assertThat(long42).isEqualTo(object42); + assertThat(object42).isEqualTo(object42); + } + + @Test + public void testAllCombinations_pass() { + assertThat(42).isEqualTo(42L); + assertThat(42).isEqualTo(new Long(42L)); + assertThat(new Integer(42)).isEqualTo(42L); + assertThat(new Integer(42)).isEqualTo(new Long(42L)); + assertThat(42L).isEqualTo(42); + assertThat(42L).isEqualTo(new Integer(42)); + assertThat(new Long(42L)).isEqualTo(42); + assertThat(new Long(42L)).isEqualTo(new Integer(42)); + + assertThat(42).isEqualTo(42); + assertThat(42).isEqualTo(new Integer(42)); + assertThat(new Integer(42)).isEqualTo(42); + assertThat(new Integer(42)).isEqualTo(new Integer(42)); + assertThat(42L).isEqualTo(42L); + assertThat(42L).isEqualTo(new Long(42L)); + assertThat(new Long(42L)).isEqualTo(42L); + assertThat(new Long(42L)).isEqualTo(new Long(42L)); + } + + @Test + public void testNumericTypeWithSameValue_shouldBeEqual_int_long() { + expectFailureWhenTestingThat(42).isNotEqualTo(42L); + } + + @Test + public void testNumericTypeWithSameValue_shouldBeEqual_int_int() { + expectFailureWhenTestingThat(42).isNotEqualTo(42); + } + + @Test + public void testNumericPrimitiveTypes_isNotEqual_shouldFail_intToChar() { + expectFailureWhenTestingThat(42).isNotEqualTo((char) 42); + // 42 in ASCII is '*' + assertFailureValue("expected not to be", "*"); + assertFailureValue("but was; string representation of actual value", "42"); + } + + @Test + public void testNumericPrimitiveTypes_isNotEqual_shouldFail_charToInt() { + // Uses Object overload rather than Integer. + expectFailure.whenTesting().that((char) 42).isNotEqualTo(42); + // 42 in ASCII is '*' + assertFailureValue("expected not to be", "42"); + assertFailureValue("but was; string representation of actual value", "*"); + } + + private static final Subject.Factory DEFAULT_SUBJECT_FACTORY = + new Subject.Factory() { + @Override + public Subject createSubject(FailureMetadata metadata, Object that) { + return new Subject(metadata, that); + } + }; + + private static void expectFailure( + ExpectFailure.SimpleSubjectBuilderCallback callback) { + AssertionError unused = ExpectFailure.expectFailureAbout(DEFAULT_SUBJECT_FACTORY, callback); + } + + @Test + public void testNumericPrimitiveTypes() { + byte byte42 = (byte) 42; + short short42 = (short) 42; + char char42 = (char) 42; + int int42 = 42; + long long42 = (long) 42; + + ImmutableSet fortyTwos = + ImmutableSet.of(byte42, short42, char42, int42, long42); + for (Object actual : fortyTwos) { + for (Object expected : fortyTwos) { + assertThat(actual).isEqualTo(expected); + } + } + + ImmutableSet fortyTwosNoChar = ImmutableSet.of(byte42, short42, int42, long42); + for (Object actual : fortyTwosNoChar) { + for (Object expected : fortyTwosNoChar) { + ExpectFailure.SimpleSubjectBuilderCallback actualFirst = + new ExpectFailure.SimpleSubjectBuilderCallback() { + @Override + public void invokeAssertion(SimpleSubjectBuilder expect) { + expect.that(actual).isNotEqualTo(expected); + } + }; + ExpectFailure.SimpleSubjectBuilderCallback expectedFirst = + new ExpectFailure.SimpleSubjectBuilderCallback() { + @Override + public void invokeAssertion(SimpleSubjectBuilder expect) { + expect.that(expected).isNotEqualTo(actual); + } + }; + expectFailure(actualFirst); + expectFailure(expectedFirst); + } + } + + byte byte41 = (byte) 41; + short short41 = (short) 41; + char char41 = (char) 41; + int int41 = 41; + long long41 = (long) 41; + + ImmutableSet fortyOnes = + ImmutableSet.of(byte41, short41, char41, int41, long41); + + for (Object first : fortyTwos) { + for (Object second : fortyOnes) { + assertThat(first).isNotEqualTo(second); + assertThat(second).isNotEqualTo(first); + } + } + } + + private IntegerSubject expectFailureWhenTestingThat(Integer actual) { + return expectFailure.whenTesting().that(actual); + } +}