Merge 18258591c9fb3b395c211159baefb6a78017e2a9 into 7140cd416cecd7462a8aae488024abeee55598e4

This commit is contained in:
Shruti Pundir 2026-06-02 21:56:23 -04:00 committed by GitHub
commit 75ff7601f4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 115 additions and 79 deletions

View File

@ -3708,7 +3708,9 @@ class [[nodiscard]] ElementsAreMatcherImpl
// prints the empty container. Otherwise we just need to show
// how many elements there actually are.
if (listener_interested && (actual_count != 0)) {
*listener << "which has " << Elements(actual_count);
*listener << "size mismatch:\n"
<< " Expected size: " << count() << "\n"
<< " Actual size: " << actual_count;
}
return false;
}
@ -3731,8 +3733,11 @@ class [[nodiscard]] ElementsAreMatcherImpl
// corresponding matcher description. Therefore we print the index, the
// value of the mismatched element, and the corresponding matcher
// description to ease debugging.
*listener << "whose element #" << exam_pos << " ("
<< PrintToString(*unmatched_it) << ") ";
*listener << "element mismatch at index " << exam_pos << ":\n";
*listener << " Actual: " << PrintToString(*unmatched_it) << "\n";
*listener << " Expected: ";
matchers_[exam_pos].DescribeTo(listener->stream());
*listener << "\n Detail: ";
matchers_[exam_pos].DescribeNegationTo(listener->stream());
PrintIfNotEmpty(explanations[exam_pos], listener->stream());
}
@ -3749,7 +3754,7 @@ class [[nodiscard]] ElementsAreMatcherImpl
if (reason_printed) {
*listener << ",\nand ";
}
*listener << "whose element #" << i << " matches, " << s;
*listener << "element #" << i << " matches: " << s;
reason_printed = true;
}
}

View File

@ -243,6 +243,19 @@ static void LogElementMatcherPairVec(const ElementMatcherPairs& pairs,
os << "\n}";
}
static void LogActualExpectedPairVec(const ElementMatcherPairs& pairs,
::std::ostream* stream) {
// Keep pairings in Actual/Expected order for quick visual diffing.
typedef ElementMatcherPairs::const_iterator Iter;
::std::ostream& os = *stream;
const char* sep = "";
for (Iter it = pairs.begin(); it != pairs.end(); ++it) {
os << sep << " - Actual #" << it->first << " <-> Expected #"
<< it->second;
sep = "\n";
}
}
bool MatchMatrix::NextGraph() {
for (size_t ilhs = 0; ilhs < LhsSize(); ++ilhs) {
for (size_t irhs = 0; irhs < RhsSize(); ++irhs) {
@ -399,33 +412,43 @@ bool UnorderedElementsAreMatcherImplBase::VerifyMatchMatrix(
}
if (match_flags() & UnorderedMatcherRequire::Superset) {
const char* sep =
"where the following matchers don't match any elements:\n";
const char* sep = "";
bool header_printed = false;
for (size_t mi = 0; mi < matcher_matched.size(); ++mi) {
if (matcher_matched[mi]) continue;
result = false;
if (listener->IsInterested()) {
*listener << sep << "matcher #" << mi << ": ";
if (!header_printed) {
*listener << "UnorderedElementsAre mismatch:\n"
<< "Expected entries with no matching actual value:\n";
header_printed = true;
}
*listener << sep << " - Expected #" << mi << ": ";
matcher_describers_[mi]->DescribeTo(listener->stream());
sep = ",\n";
sep = "\n";
}
}
}
if (match_flags() & UnorderedMatcherRequire::Subset) {
const char* sep =
"where the following elements don't match any matchers:\n";
const char* sep = "";
const char* outer_sep = "";
if (!result) {
outer_sep = "\nand ";
outer_sep = "\n";
}
bool header_printed = false;
for (size_t ei = 0; ei < element_matched.size(); ++ei) {
if (element_matched[ei]) continue;
result = false;
if (listener->IsInterested()) {
*listener << outer_sep << sep << "element #" << ei << ": "
if (!header_printed) {
*listener << outer_sep
<< "Actual entries with no matching expected value:\n";
header_printed = true;
}
*listener << sep << " - Actual #" << ei << ": "
<< element_printouts[ei];
sep = ",\n";
sep = "\n";
outer_sep = "";
}
}
@ -441,22 +464,22 @@ bool UnorderedElementsAreMatcherImplBase::FindPairing(
if ((match_flags() & UnorderedMatcherRequire::Superset) &&
max_flow < matrix.RhsSize()) {
if (listener->IsInterested()) {
*listener << "where no permutation of the elements can satisfy all "
"matchers, and the closest match is "
<< max_flow << " of " << matrix.RhsSize()
<< " matchers with the pairings:\n";
LogElementMatcherPairVec(matches, listener->stream());
*listener << "UnorderedElementsAre pairing mismatch:\n"
<< " Matched " << max_flow << " of " << matrix.RhsSize()
<< " expected entries.\n"
<< "Pairings (Actual <-> Expected):\n";
LogActualExpectedPairVec(matches, listener->stream());
}
return false;
}
if ((match_flags() & UnorderedMatcherRequire::Subset) &&
max_flow < matrix.LhsSize()) {
if (listener->IsInterested()) {
*listener
<< "where not all elements can be matched, and the closest match is "
<< max_flow << " of " << matrix.RhsSize()
<< " matchers with the pairings:\n";
LogElementMatcherPairVec(matches, listener->stream());
*listener << "UnorderedElementsAre pairing mismatch:\n"
<< " Matched " << max_flow << " of " << matrix.LhsSize()
<< " actual entries.\n"
<< "Pairings (Actual <-> Expected):\n";
LogActualExpectedPairVec(matches, listener->stream());
}
return false;
}
@ -465,8 +488,8 @@ bool UnorderedElementsAreMatcherImplBase::FindPairing(
if (listener->IsInterested()) {
const char* sep = "where:\n";
for (size_t mi = 0; mi < matches.size(); ++mi) {
*listener << sep << " - element #" << matches[mi].first
<< " is matched by matcher #" << matches[mi].second;
*listener << sep << " - Actual #" << matches[mi].first
<< " is matched by Expected #" << matches[mi].second;
sep = ",\n";
}
}

View File

@ -1274,7 +1274,10 @@ TEST(WhenSortedByTest, ExplainsMatchResult) {
const int a[] = {2, 1};
EXPECT_EQ(
Explain(WhenSortedBy(less<int>(), ElementsAre(2, 3)), a),
"which is { 1, 2 } when sorted, whose element #0 (1) isn't equal to 2");
"which is { 1, 2 } when sorted, element mismatch at index 0:\n"
" Actual: 1\n"
" Expected: is equal to 2\n"
" Detail: isn't equal to 2");
EXPECT_EQ(Explain(WhenSortedBy(less<int>(), ElementsAre(1, 2)), a),
"which is { 1, 2 } when sorted");
}
@ -1623,16 +1626,17 @@ TEST(IsSupersetOfTest, MatchAndExplain) {
ASSERT_FALSE(ExplainMatchResult(IsSupersetOf(expected), v, &listener))
<< listener.str();
EXPECT_THAT(listener.str(),
Eq("where the following matchers don't match any elements:\n"
"matcher #0: is equal to 1"));
Eq("UnorderedElementsAre mismatch:\n"
"Expected entries with no matching actual value:\n"
" - Expected #0: is equal to 1"));
v.push_back(1);
listener.Clear();
ASSERT_TRUE(ExplainMatchResult(IsSupersetOf(expected), v, &listener))
<< listener.str();
EXPECT_THAT(listener.str(), Eq("where:\n"
" - element #0 is matched by matcher #1,\n"
" - element #2 is matched by matcher #0"));
" - Actual #0 is matched by Expected #1,\n"
" - Actual #2 is matched by Expected #0"));
}
TEST(IsSupersetOfTest, WorksForRhsInitializerList) {
@ -1751,16 +1755,16 @@ TEST(IsSubsetOfTest, MatchAndExplain) {
ASSERT_FALSE(ExplainMatchResult(IsSubsetOf(expected), v, &listener))
<< listener.str();
EXPECT_THAT(listener.str(),
Eq("where the following elements don't match any matchers:\n"
"element #1: 3"));
Eq("Actual entries with no matching expected value:\n"
" - Actual #1: 3"));
expected.push_back(3);
listener.Clear();
ASSERT_TRUE(ExplainMatchResult(IsSubsetOf(expected), v, &listener))
<< listener.str();
EXPECT_THAT(listener.str(), Eq("where:\n"
" - element #0 is matched by matcher #1,\n"
" - element #1 is matched by matcher #2"));
" - Actual #0 is matched by Expected #1,\n"
" - Actual #1 is matched by Expected #2"));
}
TEST(IsSubsetOfTest, WorksForRhsInitializerList) {
@ -2314,12 +2318,13 @@ TEST_F(UnorderedElementsAreTest, FailMessageCountWrong) {
<< listener.str();
EXPECT_THAT(listener.str(),
Eq("which has 1 element\n"
"where the following matchers don't match any elements:\n"
"matcher #0: is equal to 1,\n"
"matcher #1: is equal to 2,\n"
"matcher #2: is equal to 3\n"
"and where the following elements don't match any matchers:\n"
"element #0: 4"));
"UnorderedElementsAre mismatch:\n"
"Expected entries with no matching actual value:\n"
" - Expected #0: is equal to 1\n"
" - Expected #1: is equal to 2\n"
" - Expected #2: is equal to 3\n"
"Actual entries with no matching expected value:\n"
" - Actual #0: 4"));
}
TEST_F(UnorderedElementsAreTest, FailMessageCountWrongZero) {
@ -2328,10 +2333,11 @@ TEST_F(UnorderedElementsAreTest, FailMessageCountWrongZero) {
EXPECT_FALSE(ExplainMatchResult(UnorderedElementsAre(1, 2, 3), v, &listener))
<< listener.str();
EXPECT_THAT(listener.str(),
Eq("where the following matchers don't match any elements:\n"
"matcher #0: is equal to 1,\n"
"matcher #1: is equal to 2,\n"
"matcher #2: is equal to 3"));
Eq("UnorderedElementsAre mismatch:\n"
"Expected entries with no matching actual value:\n"
" - Expected #0: is equal to 1\n"
" - Expected #1: is equal to 2\n"
" - Expected #2: is equal to 3"));
}
TEST_F(UnorderedElementsAreTest, FailMessageUnmatchedMatchers) {
@ -2342,8 +2348,9 @@ TEST_F(UnorderedElementsAreTest, FailMessageUnmatchedMatchers) {
EXPECT_FALSE(ExplainMatchResult(UnorderedElementsAre(1, 2), v, &listener))
<< listener.str();
EXPECT_THAT(listener.str(),
Eq("where the following matchers don't match any elements:\n"
"matcher #1: is equal to 2"));
Eq("UnorderedElementsAre mismatch:\n"
"Expected entries with no matching actual value:\n"
" - Expected #1: is equal to 2"));
}
TEST_F(UnorderedElementsAreTest, FailMessageUnmatchedElements) {
@ -2353,9 +2360,9 @@ TEST_F(UnorderedElementsAreTest, FailMessageUnmatchedElements) {
StringMatchResultListener listener;
EXPECT_FALSE(ExplainMatchResult(UnorderedElementsAre(1, 1), v, &listener))
<< listener.str();
EXPECT_THAT(listener.str(),
Eq("where the following elements don't match any matchers:\n"
"element #1: 2"));
EXPECT_THAT(listener.str(), Eq("Actual entries with no matching expected "
"value:\n"
" - Actual #1: 2"));
}
TEST_F(UnorderedElementsAreTest, FailMessageUnmatchedMatcherAndElement) {
@ -2366,20 +2373,11 @@ TEST_F(UnorderedElementsAreTest, FailMessageUnmatchedMatcherAndElement) {
EXPECT_FALSE(ExplainMatchResult(UnorderedElementsAre(1, 2), v, &listener))
<< listener.str();
EXPECT_THAT(listener.str(),
Eq("where"
" the following matchers don't match any elements:\n"
"matcher #0: is equal to 1\n"
"and"
" where"
" the following elements don't match any matchers:\n"
"element #1: 3"));
}
// Test helper for formatting element, matcher index pairs in expectations.
static std::string EMString(int element, int matcher) {
stringstream ss;
ss << "(element #" << element << ", matcher #" << matcher << ")";
return ss.str();
Eq("UnorderedElementsAre mismatch:\n"
"Expected entries with no matching actual value:\n"
" - Expected #0: is equal to 1\n"
"Actual entries with no matching expected value:\n"
" - Actual #1: 3"));
}
TEST_F(UnorderedElementsAreTest, FailMessageImperfectMatchOnly) {
@ -2394,20 +2392,22 @@ TEST_F(UnorderedElementsAreTest, FailMessageImperfectMatchOnly) {
UnorderedElementsAre("a", "a", AnyOf("b", "c")), v, &listener))
<< listener.str();
std::string prefix =
"where no permutation of the elements can satisfy all matchers, "
"and the closest match is 2 of 3 matchers with the "
"pairings:\n";
std::string prefix = "UnorderedElementsAre pairing mismatch:\n"
" Matched 2 of 3 expected entries.\n"
"Pairings (Actual <-> Expected):\n";
// We have to be a bit loose here, because there are 4 valid max matches.
EXPECT_THAT(
listener.str(),
AnyOf(
prefix + "{\n " + EMString(0, 0) + ",\n " + EMString(1, 2) + "\n}",
prefix + "{\n " + EMString(0, 1) + ",\n " + EMString(1, 2) + "\n}",
prefix + "{\n " + EMString(0, 0) + ",\n " + EMString(2, 2) + "\n}",
prefix + "{\n " + EMString(0, 1) + ",\n " + EMString(2, 2) +
"\n}"));
prefix + " - Actual #0 <-> Expected #0\n"
" - Actual #1 <-> Expected #2",
prefix + " - Actual #0 <-> Expected #1\n"
" - Actual #1 <-> Expected #2",
prefix + " - Actual #0 <-> Expected #0\n"
" - Actual #2 <-> Expected #2",
prefix + " - Actual #0 <-> Expected #1\n"
" - Actual #2 <-> Expected #2"));
}
TEST_F(UnorderedElementsAreTest, Describe) {
@ -2759,8 +2759,8 @@ TEST(UnorderedPointwiseTest, RejectsWrongContent) {
const int rhs[3] = {2, 6, 6};
EXPECT_THAT(lhs, Not(UnorderedPointwise(IsHalfOf(), rhs)));
EXPECT_EQ(
"where the following elements don't match any matchers:\n"
"element #1: 2",
"Actual entries with no matching expected value:\n"
" - Actual #1: 2",
Explain(UnorderedPointwise(IsHalfOf(), rhs), lhs));
}
@ -2938,8 +2938,8 @@ TEST_P(ElementsAreTestP, ExplainsNonTrivialMatch) {
const int a[] = {10, 0, 100};
vector<int> test_vector(std::begin(a), std::end(a));
EXPECT_EQ(
"whose element #0 matches, which is 9 more than 1,\n"
"and whose element #2 matches, which is 98 more than 2",
"element #0 matches: which is 9 more than 1,\n"
"and element #2 matches: which is 98 more than 2",
Explain(m, test_vector));
}
@ -2951,7 +2951,8 @@ TEST(ElementsAreTest, CanExplainMismatchWrongSize) {
EXPECT_EQ("", Explain(m, test_list));
test_list.push_back(1);
EXPECT_EQ("which has 1 element", Explain(m, test_list));
EXPECT_EQ("size mismatch:\n Expected size: 2\n Actual size: 1",
Explain(m, test_list));
}
TEST_P(ElementsAreTestP, CanExplainMismatchRightSize) {
@ -2960,11 +2961,18 @@ TEST_P(ElementsAreTestP, CanExplainMismatchRightSize) {
vector<int> v;
v.push_back(2);
v.push_back(1);
EXPECT_EQ(Explain(m, v), "whose element #0 (2) isn't equal to 1");
EXPECT_EQ(Explain(m, v),
"element mismatch at index 0:\n"
" Actual: 2\n"
" Expected: is equal to 1\n"
" Detail: isn't equal to 1");
v[0] = 1;
EXPECT_EQ(Explain(m, v),
"whose element #1 (1) is <= 5, which is 4 less than 5");
"element mismatch at index 1:\n"
" Actual: 1\n"
" Expected: is > 5\n"
" Detail: is <= 5, which is 4 less than 5");
}
TEST(ElementsAreTest, MatchesOneElementVector) {