Throw ComparisonFailure from assertThat(singleElementIterable).containsExactly(otherSingleElementIterable).

RELNOTES=Began throwing `ComparisonFailure` from `assertThat(singleElementIterable).containsExactly(otherSingleElementIterable)`.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=191909189
diff --git a/core/src/main/java/com/google/common/truth/IterableSubject.java b/core/src/main/java/com/google/common/truth/IterableSubject.java
index 531e6d7..cd28958 100644
--- a/core/src/main/java/com/google/common/truth/IterableSubject.java
+++ b/core/src/main/java/com/google/common/truth/IterableSubject.java
@@ -366,6 +366,7 @@
     }
 
     // Step through both iterators comparing elements pairwise.
+    boolean isFirst = true;
     while (actualIter.hasNext() && requiredIter.hasNext()) {
       Object actualElement = actualIter.next();
       Object requiredElement = requiredIter.next();
@@ -375,6 +376,28 @@
       // Since any previous pairs of elements we iterated over were equal, they have no
       // effect on the result now.
       if (!Objects.equal(actualElement, requiredElement)) {
+        if (isFirst && !actualIter.hasNext() && !requiredIter.hasNext()) {
+          /*
+           * There's exactly one actual element and exactly one expected element, and they don't
+           * match, so throw a ComparisonFailure. The logical way to do that would be
+           * `check(...).that(actualElement).isEqualTo(requiredElement)`. But isEqualTo has magic
+           * behavior for arrays and primitives, behavior that's inconsistent with how this method
+           * otherwise behaves. For consistency, we want to rely only on the equal() call we've
+           * already made. So we expose a special method for this and call it from here.
+           *
+           * TODO(cpovirk): Consider always throwing ComparisonFailure if there is exactly one
+           * missing and exactly one extra element, even if there were additional (matching)
+           * elements. However, this will probably be useful less often, and it will be tricky to
+           * explain. First, what would we say, "value of: iterable.onlyElementThatDidNotMatch()?"
+           * And second, it feels weirder to call out a single element when the expected and actual
+           * values had multiple elements. Granted, Fuzzy Truth already does this, so maybe it's OK?
+           * But Fuzzy Truth doesn't (yet) make the mismatched value so prominent.
+           */
+          check("onlyElement()")
+              .that(actualElement)
+              .failEqualityCheckForEqualsWithoutDescription(requiredElement);
+          return ALREADY_FAILED;
+        }
         // Missing elements; elements that are not missing will be removed as we iterate.
         Collection<Object> missing = newArrayList();
         missing.add(requiredElement);
@@ -404,6 +427,8 @@
         }
         return failExactly(required, addElementsInWarning, missing, extra);
       }
+
+      isFirst = false;
     }
 
     // Here,  we must have reached the end of one of the iterators without finding any
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 0fc9cc6..4f7f11b 100644
--- a/core/src/main/java/com/google/common/truth/Subject.java
+++ b/core/src/main/java/com/google/common/truth/Subject.java
@@ -814,7 +814,15 @@
     }
   }
 
-  private void failEqualityCheck(
+  /**
+   * Special version of {@link #failEqualityCheck} for use from {@link IterableSubject}, documented
+   * further there.
+   */
+  final void failEqualityCheckForEqualsWithoutDescription(Object expected) {
+    failEqualityCheck(EqualityCheck.EQUAL, expected, ComparisonResult.differentNoDescription());
+  }
+
+  private final void failEqualityCheck(
       EqualityCheck equalityCheck, Object expected, ComparisonResult difference) {
     String actualString = actualCustomStringRepresentation();
     String expectedString = formatActualOrExpected(expected);
diff --git a/core/src/test/java/com/google/common/truth/IterableSubjectTest.java b/core/src/test/java/com/google/common/truth/IterableSubjectTest.java
index 2a5e881..a31cdc9 100644
--- a/core/src/test/java/com/google/common/truth/IterableSubjectTest.java
+++ b/core/src/test/java/com/google/common/truth/IterableSubjectTest.java
@@ -637,6 +637,20 @@
   }
 
   @Test
+  public void iterableContainsExactlySingleElement() {
+    assertThat(asList(1)).containsExactly(1);
+
+    expectFailureWhenTestingThat(asList(1)).containsExactly(2);
+    assertFailureValue("value of", "iterable.onlyElement()");
+  }
+
+  @Test
+  public void iterableContainsExactlySingleElementNoEqualsMagic() {
+    expectFailureWhenTestingThat(asList(1)).containsExactly(1L);
+    assertFailureValueIndexed("an instance of", 0, "java.lang.Long");
+  }
+
+  @Test
   public void iterableContainsExactlyWithElementsThatThrowWhenYouCallHashCode() {
     HashCodeThrower one = new HashCodeThrower();
     HashCodeThrower two = new HashCodeThrower();
diff --git a/core/src/test/java/com/google/common/truth/MultimapSubjectTest.java b/core/src/test/java/com/google/common/truth/MultimapSubjectTest.java
index a23e8fb..fb8143f 100644
--- a/core/src/test/java/com/google/common/truth/MultimapSubjectTest.java
+++ b/core/src/test/java/com/google/common/truth/MultimapSubjectTest.java
@@ -169,25 +169,36 @@
      * including eliminating named() itself. Or we could just special-case our logic to skip the
      * name for non-throwables. For now, I'm not too worried about this.
      */
-    assertThat(expectFailure.getFailure())
-        .hasMessageThat()
-        .isEqualTo(
-            "value of: multymap.valuesForKey(1)\n"
-                + "Not true that <[5]> contains exactly <[4]>. "
-                + "It is missing <[4]> and has unexpected items <[5]>\n"
-                + "multimap was: multymap ({1=[5]})");
+    assertFailureKeys("value of", "expected", "but was", "multimap was");
+    assertFailureValue("value of", "multymap.valuesForKey(1).onlyElement()");
+    assertFailureValue("multimap was", "multymap ({1=[5]})");
   }
 
   @Test
-  public void valuesForKeyNamed() {
+  public void valuesForKeyNamedSingleElements() {
+    /*
+     * TODO(cpovirk): We fail to include the name "valuez" in the failure message here. Fortunately,
+     * I see only 1 usage of valuesForKey().named() in the depot. Also "fortunately," something like
+     * 1/3 of all assertion methods fail to include the name, so the right fix is probably going to
+     * be to delete named() entirely.
+     */
     ImmutableMultimap<Integer, Integer> multimap = ImmutableMultimap.of(1, 5);
     expectFailureWhenTestingThat(multimap).valuesForKey(1).named("valuez").containsExactly(4);
+    assertFailureKeys("value of", "expected", "but was", "multimap was");
+    assertFailureValue("value of", "multimap.valuesForKey(1).onlyElement()");
+    assertFailureValue("multimap was", "{1=[5]}");
+  }
+
+  @Test
+  public void valuesForKeyNamedMultipleElements() {
+    ImmutableMultimap<Integer, Integer> multimap = ImmutableMultimap.of(1, 5);
+    expectFailureWhenTestingThat(multimap).valuesForKey(1).named("valuez").containsExactly(3, 4);
     assertThat(expectFailure.getFailure())
         .hasMessageThat()
         .isEqualTo(
             "value of: multimap.valuesForKey(1)\n"
-                + "Not true that valuez (<[5]>) contains exactly <[4]>. "
-                + "It is missing <[4]> and has unexpected items <[5]>\n"
+                + "Not true that valuez (<[5]>) contains exactly <[3, 4]>. "
+                + "It is missing <[3, 4]> and has unexpected items <[5]>\n"
                 + "multimap was: {1=[5]}");
   }