@CanIgnoreReturnValue
  public final Ordered containsExactlyEntriesIn(Multimap<?, ?> expectedMultimap) {
    checkNotNull(expectedMultimap, "expectedMultimap");
    checkNotNull(actual);
    ListMultimap<?, ?> missing = difference(expectedMultimap, actual);
    ListMultimap<?, ?> extra = difference(actual, expectedMultimap);

    // TODO(kak): Possible enhancement: Include "[1 copy]" if the element does appear in
    // the subject but not enough times. Similarly for unexpected extra items.
    if (!missing.isEmpty()) {
      if (!extra.isEmpty()) {
        boolean addTypeInfo = hasMatchingToStringPair(missing.entries(), extra.entries());
        // Note: The usage of countDuplicatesAndAddTypeInfo() below causes entries no longer to be
        // grouped by key in the 'missing' and 'unexpected items' parts of the message (we still
        // show the actual and expected multimaps in the standard format).
        String missingDisplay =
            addTypeInfo
                ? countDuplicatesAndAddTypeInfo(annotateEmptyStringsMultimap(missing).entries())
                : countDuplicatesMultimap(annotateEmptyStringsMultimap(missing));
        String extraDisplay =
            addTypeInfo
                ? countDuplicatesAndAddTypeInfo(annotateEmptyStringsMultimap(extra).entries())
                : countDuplicatesMultimap(annotateEmptyStringsMultimap(extra));
        failWithActual(
            fact("missing", missingDisplay),
            fact("unexpected", extraDisplay),
            simpleFact("---"),
            fact("expected", annotateEmptyStringsMultimap(expectedMultimap)));
        return ALREADY_FAILED;
      } else {
        failWithActual(
            fact("missing", countDuplicatesMultimap(annotateEmptyStringsMultimap(missing))),
            simpleFact("---"),
            fact("expected", annotateEmptyStringsMultimap(expectedMultimap)));
        return ALREADY_FAILED;
      }
    } else if (!extra.isEmpty()) {
      failWithActual(
          fact("unexpected", countDuplicatesMultimap(annotateEmptyStringsMultimap(extra))),
          simpleFact("---"),
          fact("expected", annotateEmptyStringsMultimap(expectedMultimap)));
      return ALREADY_FAILED;
    }

    return new MultimapInOrder(/* allowUnexpected = */ false, expectedMultimap);
  }
@Test
  public void containsExactlyRejectsNull() {
    ImmutableMultimap<Integer, String> multimap =
        ImmutableMultimap.of(3, "one", 3, "six", 3, "two", 4, "five", 4, "four");

    try {
      assertThat(multimap).containsExactlyEntriesIn(null);
      fail("Should have thrown.");
    } catch (NullPointerException expected) {
    }
  }