Skip to content

Commit

Permalink
Handle exceptions from Correspondence.compare in the Fuzzy Truth asse…
Browse files Browse the repository at this point in the history
…rtions implemented directly in MultimapSubject.

They were already handled in containsExactly(EntriesIn) because those methods delegate to IterableSubject which handled them. However, this CL does add some tests for those (because at some point we plan to implement them directly in MultimapSubject to improve the failure messages, and it would be good to have the test cases in place before we do that).

This completes the work for Correspondence.compare. There's still work to do for exceptions from Correspondence.formatDiff, and from the function used to pair elements for diffing.

RELNOTES=All Fuzzy Truth assertions now handle exceptions thrown by Correspondence.compare (see the javadoc of that method for details).

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=228137650
  • Loading branch information
peteg authored and ronshapiro committed Jan 8, 2019
1 parent bd86b71 commit a474ac1
Show file tree
Hide file tree
Showing 3 changed files with 296 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,6 @@ public String toString() {
* returned false. (Note that, in the latter case at least, it is likely that the test author's
* intention was <i>not</i> for the test to pass with these values.)
*/
// TODO(b/119038411): Ensure that all callers in Truth handle exceptions sensibly
// TODO(b/119038894): Simplify the 'for example' by using a factory method when it's ready
public abstract boolean compare(@NullableDecl A actual, @NullableDecl E expected);

Expand Down
110 changes: 82 additions & 28 deletions core/src/main/java/com/google/common/truth/MultimapSubject.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Strings.lenientFormat;
import static com.google.common.collect.Maps.immutableEntry;
import static com.google.common.truth.Fact.fact;
import static com.google.common.truth.Fact.simpleFact;
import static com.google.common.truth.Facts.facts;
import static com.google.common.truth.SubjectUtils.HUMAN_UNDERSTANDABLE_EMPTY_STRING;
import static com.google.common.truth.SubjectUtils.countDuplicatesAndAddTypeInfo;
import static com.google.common.truth.SubjectUtils.hasMatchingToStringPair;
Expand Down Expand Up @@ -475,43 +477,74 @@ public void containsEntry(@NullableDecl Object expectedKey, @NullableDecl E expe
if (actual().containsKey(expectedKey)) {
// Found matching key.
Collection<A> actualValues = getCastActual().asMap().get(expectedKey);
Correspondence.ExceptionStore compareExceptions =
Correspondence.ExceptionStore.forMapValuesCompare();
for (A actualValue : actualValues) {
if (correspondence.compare(actualValue, expectedValue)) {
// Found matching key and value. Test passes!
if (correspondence.safeCompare(actualValue, expectedValue, compareExceptions)) {
// Found matching key and value, but we still need to fail if we hit an exception along
// the way.
if (!compareExceptions.isEmpty()) {
failWithActual(
compareExceptions
.describeAsMainCause()
.and(
simpleFact(
"comparing contents by testing that at least one entry had a key "
+ "equal to the expected key and a value that "
+ correspondence
+ " the expected value"),
fact("expected key", expectedKey),
fact("expected value", expectedValue)));
}
return;
}
}
// Found matching key with non-matching values.
failWithoutActual(
simpleFact(
lenientFormat(
"Not true that %s contains at least one entry with key <%s> and a value that "
+ "%s <%s>. However, it has a mapping from that key to <%s>",
actualAsString(), expectedKey, correspondence, expectedValue, actualValues)));
facts(
simpleFact(
lenientFormat(
"Not true that %s contains at least one entry with key <%s> and a "
+ "value that %s <%s>. However, it has a mapping from that key to "
+ "<%s>",
actualAsString(),
expectedKey,
correspondence,
expectedValue,
actualValues)))
.and(compareExceptions.describeAsAdditionalInfo()));
} else {
// Did not find matching key.
Set<Object> keys = new LinkedHashSet<>();
Correspondence.ExceptionStore compareExceptions =
Correspondence.ExceptionStore.forMapValuesCompare();
for (Entry<?, A> actualEntry : getCastActual().entries()) {
if (correspondence.compare(actualEntry.getValue(), expectedValue)) {
if (correspondence.safeCompare(
actualEntry.getValue(), expectedValue, compareExceptions)) {
keys.add(actualEntry.getKey());
}
}
if (!keys.isEmpty()) {
// Found matching values with non-matching keys.
failWithoutActual(
simpleFact(
lenientFormat(
"Not true that %s contains at least one entry with key <%s> and a value that "
+ "%s <%s>. However, the following keys are mapped to such values: <%s>",
actualAsString(), expectedKey, correspondence, expectedValue, keys)));
facts(
simpleFact(
lenientFormat(
"Not true that %s contains at least one entry with key <%s> and a "
+ "value that %s <%s>. However, the following keys are mapped to "
+ "such values: <%s>",
actualAsString(), expectedKey, correspondence, expectedValue, keys)))
.and(compareExceptions.describeAsAdditionalInfo()));
} else {
// Did not find matching key or value.
failWithoutActual(
simpleFact(
lenientFormat(
"Not true that %s contains at least one entry with key <%s> and a value that "
+ "%s <%s>",
actualAsString(), expectedKey, correspondence, expectedValue)));
facts(
simpleFact(
lenientFormat(
"Not true that %s contains at least one entry with key <%s> and a "
+ "value that %s <%s>",
actualAsString(), expectedKey, correspondence, expectedValue)))
.and(compareExceptions.describeAsAdditionalInfo()));
}
}
}
Expand All @@ -525,22 +558,43 @@ public void doesNotContainEntry(
if (actual().containsKey(excludedKey)) {
Collection<A> actualValues = getCastActual().asMap().get(excludedKey);
List<A> matchingValues = new ArrayList<>();
Correspondence.ExceptionStore compareExceptions =
Correspondence.ExceptionStore.forMapValuesCompare();
for (A actualValue : actualValues) {
if (correspondence.compare(actualValue, excludedValue)) {
if (correspondence.safeCompare(actualValue, excludedValue, compareExceptions)) {
matchingValues.add(actualValue);
}
}
// Fail if we found a matching value for the key.
if (!matchingValues.isEmpty()) {
failWithoutActual(
simpleFact(
lenientFormat(
"Not true that %s did not contain an entry with key <%s> and a value that %s <%s>. "
+ "It maps that key to the following such values: <%s>",
actualAsString(),
excludedKey,
correspondence,
excludedValue,
matchingValues)));
facts(
simpleFact(
lenientFormat(
"Not true that %s did not contain an entry with key <%s> and a value "
+ "that %s <%s>. It maps that key to the following such values: "
+ "<%s>",
actualAsString(),
excludedKey,
correspondence,
excludedValue,
matchingValues)))
.and(compareExceptions.describeAsAdditionalInfo()));
} else {
// No value matched, but we still need to fail if we hit an exception along the way.
if (!compareExceptions.isEmpty()) {
failWithActual(
compareExceptions
.describeAsMainCause()
.and(
simpleFact(
"comparing contents by testing that no entry had the forbidden key and "
+ "a value that "
+ correspondence
+ " the forbidden value"),
fact("forbidden key", excludedKey),
fact("forbidden value", excludedValue)));
}
}
}
}
Expand Down
Loading

0 comments on commit a474ac1

Please sign in to comment.