diff --git a/core/src/main/java/com/google/common/truth/DefaultSubject.java b/core/src/main/java/com/google/common/truth/DefaultSubject.java index a7f0b7d2b..c68d8f3b8 100644 --- a/core/src/main/java/com/google/common/truth/DefaultSubject.java +++ b/core/src/main/java/com/google/common/truth/DefaultSubject.java @@ -17,8 +17,8 @@ import javax.annotation.Nullable; -public class DefaultSubject extends Subject { - public DefaultSubject(FailureStrategy failureStrategy, @Nullable Object o) { +public class DefaultSubject extends Subject, T> { + public DefaultSubject(FailureStrategy failureStrategy, @Nullable T o) { super(failureStrategy, o); } } diff --git a/core/src/main/java/com/google/common/truth/FauxComparable.java b/core/src/main/java/com/google/common/truth/FauxComparable.java new file mode 100644 index 000000000..0c3b8d4a3 --- /dev/null +++ b/core/src/main/java/com/google/common/truth/FauxComparable.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2015 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 java.util.Comparator; + +import javax.annotation.Nullable; + +/** + * Propositions which use an explicit {@link Comparator}. + * + * @author Ben Blank + */ +public class FauxComparable, T> { + private final Comparator comparator; + private final Subject subject; + + public FauxComparable(Comparator comparator, @Nullable Subject subject) { + this.comparator = comparator; + this.subject = subject; + } + + /** + * Fails if the subject is not equivalent to the given value according to + * the supplied {@link Comparator}, (i.e., fails if + * {@code comparator.compare(a, b) != 0}). + * + *

+ * Note: Do not use this method for checking object equality. + * Instead, use {@link #isEqualTo(Object)}. + */ + public void isEquivalentAccordingToComparator(T other) { + if (comparator.compare(subject.getSubject(), other) != 0) { + subject.failWithRawMessage( + "%s should have been equivalent to <%s> according to comparator <%s>", + subject.getDisplaySubject(), + other, + comparator); + } + } + + /** + * Fails if the subject is not greater than the given value. + */ + public final void isGreaterThan(T other) { + if (comparator.compare(subject.getSubject(), other) <= 0) { + subject.failWithRawMessage( + "Not true that %s is greater than <%s> according to comparator <%s>", + subject.getDisplaySubject(), + other, + comparator); + } + } + + /** + * Fails if the subject is not less than the given value. + */ + public final void isLessThan(T other) { + if (comparator.compare(subject.getSubject(), other) >= 0) { + subject.failWithRawMessage( + "Not true that %s is less than <%s> according to comparator <%s>", + subject.getDisplaySubject(), + other, + comparator); + } + } + + /** + * Fails if the subject is greater than the given value. + */ + public final void isAtMost(T other) { + if (comparator.compare(subject.getSubject(), other) > 0) { + subject.failWithRawMessage( + "Not true that %s is at most <%s> according to comparator <%s>", + subject.getDisplaySubject(), + other, + comparator); + } + } + + /** + * Fails if the subject is less than the given value. + */ + public final void isAtLeast(T other) { + if (comparator.compare(subject.getSubject(), other) < 0) { + subject.failWithRawMessage( + "Not true that %s is at least <%s> according to comparator <%s>", + subject.getDisplaySubject(), + other, + comparator); + } + } +} diff --git a/core/src/main/java/com/google/common/truth/Subject.java b/core/src/main/java/com/google/common/truth/Subject.java index 4ba9b215a..4fe7d1100 100644 --- a/core/src/main/java/com/google/common/truth/Subject.java +++ b/core/src/main/java/com/google/common/truth/Subject.java @@ -23,6 +23,7 @@ import com.google.common.base.Predicates; import com.google.common.collect.Iterables; +import java.util.Comparator; import java.util.List; import javax.annotation.Nullable; @@ -191,6 +192,10 @@ public void isNoneOf(@Nullable Object first, @Nullable Object second, @Nullable isNotIn(accumulate(first, second, rest)); } + public FauxComparable whenComparedUsing(Comparator comparator) { + return new FauxComparable(checkNotNull(comparator), this); + } + protected T getSubject() { return subject; } diff --git a/core/src/main/java/com/google/common/truth/TestVerb.java b/core/src/main/java/com/google/common/truth/TestVerb.java index e1c829864..ec1bf2982 100644 --- a/core/src/main/java/com/google/common/truth/TestVerb.java +++ b/core/src/main/java/com/google/common/truth/TestVerb.java @@ -50,7 +50,7 @@ public BigDecimalSubject that(@Nullable BigDecimal target) { return new BigDecimalSubject(getFailureStrategy(), target); } - public Subject that(@Nullable Object target) { + public Subject, T> that(@Nullable T target) { return new DefaultSubject(getFailureStrategy(), target); } diff --git a/core/src/main/java/com/google/common/truth/Truth.java b/core/src/main/java/com/google/common/truth/Truth.java index 5cdfdc5dc..aec8160c8 100644 --- a/core/src/main/java/com/google/common/truth/Truth.java +++ b/core/src/main/java/com/google/common/truth/Truth.java @@ -111,7 +111,7 @@ public static BigDecimalSubject assertThat(@Nullable BigDecimal target) { return assert_().that(target); } - public static Subject assertThat(@Nullable Object target) { + public static Subject, T> assertThat(@Nullable T target) { return assert_().that(target); } diff --git a/core/src/test/java/com/google/common/truth/FauxComparableTest.java b/core/src/test/java/com/google/common/truth/FauxComparableTest.java new file mode 100644 index 000000000..81c0699a7 --- /dev/null +++ b/core/src/test/java/com/google/common/truth/FauxComparableTest.java @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2015 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.assertAbout; +import static com.google.common.truth.Truth.assertThat; +import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource; +import static org.junit.Assert.fail; + +import java.util.Comparator; + +import javax.tools.JavaFileObject; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import com.google.testing.compile.JavaFileObjects; + +/** + * Tests for FauxComparable objects. + * + * @author Ben Blank + */ +@RunWith(JUnit4.class) +public class FauxComparableTest { + private static final Comparator ALWAYS_LESS = + new Comparator() { + @Override + public int compare(IncomparableType o1, IncomparableType o2) { + return -1; + } + + @Override + public String toString() { + return "always_less"; + } + }; + + private static final Comparator ALWAYS_EQUAL = + new Comparator() { + @Override + public int compare(IncomparableType o1, IncomparableType o2) { + return 0; + } + + @Override + public String toString() { + return "always_equal"; + } + }; + + private static final Comparator ALWAYS_MORE = + new Comparator() { + @Override + public int compare(IncomparableType o1, IncomparableType o2) { + return 1; + } + + @Override + public String toString() { + return "always_more"; + } + }; + + private static final IncomparableType FOO = new IncomparableType("foo"); + private static final IncomparableType BAR = new IncomparableType("bar"); + + @Test + public void testNull() { + try { + assertThat(FOO).whenComparedUsing(null); + fail("should have thrown"); + } catch (NullPointerException expected) { + } + } + + @Test + public void isEquivalentAccordingToCompareTo() { + try { + assertThat(FOO).whenComparedUsing(ALWAYS_LESS).isEquivalentAccordingToComparator(BAR); + fail("should have thrown"); + } catch (AssertionError e) { + assertThat(e.getMessage()) + .contains( + " should have been equivalent to according to comparator "); + } + assertThat(FOO).whenComparedUsing(ALWAYS_EQUAL).isEquivalentAccordingToComparator(BAR); + try { + assertThat(FOO).whenComparedUsing(ALWAYS_MORE).isEquivalentAccordingToComparator(BAR); + fail("should have thrown"); + } catch (AssertionError e) { + assertThat(e.getMessage()) + .contains( + " should have been equivalent to according to comparator "); + } + } + + @Test + public void isGreaterThan() { + try { + assertThat(FOO).whenComparedUsing(ALWAYS_LESS).isGreaterThan(BAR); + fail("should have thrown"); + } catch (AssertionError e) { + assertThat(e.getMessage()) + .contains( + "Not true that is greater than according to comparator "); + } + try { + assertThat(FOO).whenComparedUsing(ALWAYS_EQUAL).isGreaterThan(BAR); + fail("should have thrown"); + } catch (AssertionError e) { + assertThat(e.getMessage()) + .contains( + "Not true that is greater than according to comparator "); + } + assertThat(FOO).whenComparedUsing(ALWAYS_MORE).isGreaterThan(BAR); + } + + @Test + public void isLessThan() { + assertThat(FOO).whenComparedUsing(ALWAYS_LESS).isLessThan(BAR); + try { + assertThat(FOO).whenComparedUsing(ALWAYS_EQUAL).isLessThan(BAR); + fail("should have thrown"); + } catch (AssertionError e) { + assertThat(e.getMessage()) + .contains( + "Not true that is less than according to comparator "); + } + try { + assertThat(FOO).whenComparedUsing(ALWAYS_MORE).isLessThan(BAR); + fail("should have thrown"); + } catch (AssertionError e) { + assertThat(e.getMessage()) + .contains("Not true that is less than according to comparator "); + } + } + + @Test + public void isAtMost() { + assertThat(FOO).whenComparedUsing(ALWAYS_LESS).isAtMost(BAR); + assertThat(FOO).whenComparedUsing(ALWAYS_EQUAL).isAtMost(BAR); + try { + assertThat(FOO).whenComparedUsing(ALWAYS_MORE).isAtMost(BAR); + fail("should have thrown"); + } catch (AssertionError e) { + assertThat(e.getMessage()) + .contains("Not true that is at most according to comparator "); + } + } + + @Test + public void isAtLeast() { + try { + assertThat(FOO).whenComparedUsing(ALWAYS_LESS).isAtLeast(BAR); + fail("should have thrown"); + } catch (AssertionError e) { + assertThat(e.getMessage()) + .contains("Not true that is at least according to comparator "); + } + assertThat(FOO).whenComparedUsing(ALWAYS_EQUAL).isAtLeast(BAR); + assertThat(FOO).whenComparedUsing(ALWAYS_MORE).isAtLeast(BAR); + } + + @Test + public void broadComparator() { + assertThat(FOO) + .whenComparedUsing( + new Comparator() { + @Override + public int compare(Object o1, Object o2) { + return 0; + } + }) + .isEquivalentAccordingToComparator(BAR); + } + + @Test + public void incompatibleComparatorDoesntCompile() { + JavaFileObject file = + JavaFileObjects.forSourceLines( + "test.MyTest", + "package test;", + "import static com.google.common.truth.Truth.assertThat;", + "import java.util.Comparator;", + "class MyTest {", + " private static final Comparator COMPARATOR = new Comparator() {", + " @Override", + " public int compare(String s1, String s2) {", + " return 0;", + " }", + " };", + " public void testFoo() {", + " assertThat(new Object()).whenComparedUsing(COMPARATOR);", + " }", + "}"); + + assertAbout(javaSource()) + .that(file) + .failsToCompile() + .withErrorContaining( + "java.util.Comparator cannot be converted to java.util.Comparator") + .in(file) + .onLine(12); + } + + @Test + public void incompatibleTypeDoesntCompile() { + JavaFileObject file = + JavaFileObjects.forSourceLines( + "test.MyTest", + "package test;", + "import static com.google.common.truth.Truth.assertThat;", + "import java.util.Comparator;", + "class MyTest {", + " private static final Comparator COMPARATOR = new Comparator() {", + " @Override", + " public int compare(String s1, String s2) {", + " return 0;", + " }", + " };", + " public void testFoo() {", + " assertThat(\"\").whenComparedUsing(COMPARATOR).isGreaterThan(6);", + " }", + "}"); + + assertAbout(javaSource()) + .that(file) + .failsToCompile() + .withErrorContaining( + "int cannot be converted to java.lang.String") + .in(file) + .onLine(12); + } + + private static class IncomparableType { + private final String name; + + public IncomparableType(String name) { + this.name = name; + } + + @Override + public String toString() { + return this.name; + } + } +}