Skip to content

Commit

Permalink
Suffix "Did you mean to call containsExactlyElementsIn instead?" to c…
Browse files Browse the repository at this point in the history
…alls to containsExactly(Object...) where there's just a single Iterable argument supplied. This should help test writers when they accidentally call the wrong method by pointing out the method they probably want instead.

-------------
Created by MOE: http://code.google.com/p/moe-java
MOE_MIGRATED_REVID=83138731
  • Loading branch information
sameb authored and cpovirk committed Jan 9, 2015
1 parent 7078adc commit 4ed4f0d
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 43 deletions.
52 changes: 41 additions & 11 deletions core/src/main/java/com/google/common/truth/IterableSubject.java
Expand Up @@ -306,7 +306,8 @@ public Ordered containsOnlyElementsIn(Iterable<?> expected) {
* contents must be contained in the given order. * contents must be contained in the given order.
*/ */
public Ordered containsExactly(@Nullable Object... varargs) { public Ordered containsExactly(@Nullable Object... varargs) {
return containsExactly("contains exactly", asList(varargs)); return containsExactly("contains exactly", asList(varargs),
varargs != null && varargs.length == 1 && varargs[0] instanceof Iterable);
} }


/** /**
Expand All @@ -320,10 +321,15 @@ public Ordered containsExactly(@Nullable Object... varargs) {
* contents must be contained in the given order. * contents must be contained in the given order.
*/ */
public Ordered containsExactlyElementsIn(Iterable<?> expected) { public Ordered containsExactlyElementsIn(Iterable<?> expected) {
return containsExactly("contains exactly", expected); return containsExactly("contains exactly", expected, false);
} }


private Ordered containsExactly(String failVerb, Iterable<?> required) { private Ordered containsExactly(String failVerb, Iterable<?> required,
boolean addElementsInWarning) {
String failSuffix = !addElementsInWarning ? "" :
". Passing an iterable to the varargs method containsExactly(Object...) is "
+ "often not the correct thing to do. Did you mean to call "
+ "containsExactlyElementsIn(Iterable) instead?";
Iterator<?> actualIter = getSubject().iterator(); Iterator<?> actualIter = getSubject().iterator();
Iterator<?> requiredIter = required.iterator(); Iterator<?> requiredIter = required.iterator();


Expand Down Expand Up @@ -365,15 +371,18 @@ private Ordered containsExactly(String failVerb, Iterable<?> required) {
if (!extra.isEmpty()) { if (!extra.isEmpty()) {
// Subject is both missing required elements and contains extra elements // Subject is both missing required elements and contains extra elements
failWithRawMessage( failWithRawMessage(
"Not true that %s %s <%s>. It is missing <%s> and has unexpected items <%s>", "Not true that %s %s <%s>. It is missing <%s> and has unexpected items <%s>%s",
getDisplaySubject(), failVerb, required, getDisplaySubject(), failVerb, required,
countDuplicates(missing), countDuplicates(extra)); countDuplicates(missing), countDuplicates(extra),
failSuffix);
} else { } else {
failWithBadResults(failVerb, required, "is missing", countDuplicates(missing)); failWithBadResultsAndSuffix(failVerb, required, "is missing", countDuplicates(missing),
failSuffix);
} }
} }
if (!extra.isEmpty()) { if (!extra.isEmpty()) {
failWithBadResults(failVerb, required, "has unexpected items", countDuplicates(extra)); failWithBadResultsAndSuffix(failVerb, required, "has unexpected items",
countDuplicates(extra), failSuffix);
} }


// Since we know the iterables were not in the same order, inOrder() can just fail. // Since we know the iterables were not in the same order, inOrder() can just fail.
Expand All @@ -385,18 +394,39 @@ private Ordered containsExactly(String failVerb, Iterable<?> required) {
// pairs of elements that differ. If the actual iterator still has elements, they're // pairs of elements that differ. If the actual iterator still has elements, they're
// extras. If the required iterator has elements, they're missing elements. // extras. If the required iterator has elements, they're missing elements.
if (actualIter.hasNext()) { if (actualIter.hasNext()) {
failWithBadResults(failVerb, required, "has unexpected items", failWithBadResultsAndSuffix(failVerb, required, "has unexpected items",
countDuplicates(Lists.newArrayList(actualIter))); countDuplicates(Lists.newArrayList(actualIter)), failSuffix);
} else if (requiredIter.hasNext()) { } else if (requiredIter.hasNext()) {
failWithBadResults(failVerb, required, "is missing", failWithBadResultsAndSuffix(failVerb, required, "is missing",
countDuplicates(Lists.newArrayList(requiredIter))); countDuplicates(Lists.newArrayList(requiredIter)), failSuffix);
} }


// If neither iterator has elements, we reached the end and the elements were in // If neither iterator has elements, we reached the end and the elements were in
// order, so inOrder() can just succeed. // order, so inOrder() can just succeed.
return IN_ORDER; return IN_ORDER;
} }


/**
* Fails with the bad results and a suffix.
*
* @param verb the proposition being asserted
* @param expected the expectations against which the subject is compared
* @param failVerb the failure of the proposition being asserted
* @param actual the actual value the subject was compared against
* @param suffix a suffix to append to the failure message
*/
protected void failWithBadResultsAndSuffix(String verb, Object expected, String failVerb,
Object actual, String suffix) {
failWithRawMessage(
"Not true that %s %s <%s>. It %s <%s>%s",
getDisplaySubject(),
verb,
expected,
failVerb,
((actual == null) ? "null reference" : actual),
suffix);
}

/** /**
* Attests that a subject contains none of the provided objects * Attests that a subject contains none of the provided objects
* or fails, eliding duplicates. * or fails, eliding duplicates.
Expand Down

0 comments on commit 4ed4f0d

Please sign in to comment.