mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 20:30:14 +01:00
Reduce use of gmock matcher infrastructure for diagnosing mismatches,
and instead manually stream an explanation of the difference. The
gmock-style "EXPECT_THAT" approach adds an unsuppressable "Actual: ..."
line into the output that only contains unreadable and redundant noise.
We're getting zero value from using a matcher diagnostic here, so don't.
Before:
```
Value of: SplitOutput(test_file.actual_stdout)
Expected: matches elements with unified diff
Actual: { "--- else.carbon", "", "constants {", " %F.type: type = fn_type @F [concrete]", " %empty_tuple.type: type = tuple_type () [concrete]", " %F: %F.type = struct_value () [concrete]", " %H.type: type = fn_type @H [concrete]", " %H: %H.type = struct_value () [concrete]", " %pattern_type: type = pattern_type bool [concrete]", " %b.param_patt: %pattern_type = value_param_pattern [concrete]", " %b.patt: %pattern_type = at_binding_pattern b, %b.param_patt [concrete]", " %If.type: type = fn_type @If [concrete]", " %If: %If.type = struct_value () [concrete]", "}", "", "file {", " %If.decl: %If.type = fn_decl @If [concrete = constants.%If] {", " %b.param_patt: %pattern_type = value_param_pattern [concrete = constants.%b.param_patt]", " %b.patt: %pattern_type = at_binding_pattern b, %b.param_patt [concrete = constants.%b.patt]", " } {", " %b.param: bool = value_param call_param0", " %.loc8: type = type_literal bool [concrete = bool]", " %b: bool = wrapper_binding b, %b.param", " }", "}", "", "fn @If(%b.param: bool) {", "!entry:", " %b.ref: bool = name_ref b, %b", " if %b.ref br !if.then else br !if.else", "", "!if.then:", ... }, unified diff (- expected, + actual):
=== diff in expected elements 4 to 11 (1-based index):
%F.type: type = fn_type @F [concrete]
%empty_tuple.type: type = tuple_type () [concrete]
%F: %F.type = struct_value () [concrete]
- is equal to " %G.type: type = fn_type @G [concrete]"
- is equal to " %G: %G.type = struct_value () [concrete]"
%H.type: type = fn_type @H [concrete]
%H: %H.type = struct_value () [concrete]
%pattern_type: type = pattern_type bool [concrete]
=== diff in expected elements 37 to 44 (1-based index):
br !if.done
!if.else:
- is equal to " %G.ref: %G.type = name_ref G, file.%G.decl [concrete = constants.%G]"
- is equal to " %G.call: init %empty_tuple.type = call %G.ref()"
br !if.done
!if.done:
=== diff end
```
After:
```
Value of: testing::Value(SplitOutput(test_file.actual_stdout), testing::ElementsAreArray(test_file.expected_stdout))
Actual: false
Expected: true
unified diff (- expected, + actual):
=== diff in expected elements 4 to 11 (1-based index):
%F.type: type = fn_type @F [concrete]
%empty_tuple.type: type = tuple_type () [concrete]
%F: %F.type = struct_value () [concrete]
- %G.type: type = fn_type @G [concrete]
- %G: %G.type = struct_value () [concrete]
%H.type: type = fn_type @H [concrete]
%H: %H.type = struct_value () [concrete]
%pattern_type: type = pattern_type bool [concrete]
=== diff in expected elements 37 to 44 (1-based index):
br !if.done
!if.else:
- %G.ref: %G.type = name_ref G, file.%G.decl [concrete = constants.%G]
- %G.call: init %empty_tuple.type = call %G.ref()
br !if.done
!if.done:
=== diff end
```
Assisted-by: Gemini via Antigravity
288 lines
7.3 KiB
C++
288 lines
7.3 KiB
C++
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
|
// Exceptions. See /LICENSE for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
#include "testing/base/unified_diff.h"
|
|
|
|
#include <gmock/gmock.h>
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <sstream>
|
|
#include <string>
|
|
|
|
#include "llvm/ADT/SmallVector.h"
|
|
|
|
namespace Carbon::Testing {
|
|
namespace {
|
|
|
|
using ::testing::ElementsAreArray;
|
|
using ::testing::Matcher;
|
|
using ::testing::MatchesRegex;
|
|
using ::testing::StrEq;
|
|
|
|
// Asserts that when expected does not match actual, the string
|
|
// representation of the produced diff equals expected_diff.
|
|
auto ExpectUnifiedDiff(const llvm::SmallVector<std::string>& actual,
|
|
const llvm::SmallVector<Matcher<std::string>>& expected,
|
|
const std::string& expected_diff) -> void {
|
|
std::stringstream ss;
|
|
ss << UnifiedDiff(expected, actual);
|
|
EXPECT_THAT(ss.str(), testing::Eq(expected_diff));
|
|
}
|
|
|
|
TEST(UnifiedDiffTest, Matches) {
|
|
llvm::SmallVector<std::string> actual = {"A", "B", "C"};
|
|
llvm::SmallVector<Matcher<std::string>> expected = {StrEq("A"), StrEq("B"),
|
|
StrEq("C")};
|
|
EXPECT_TRUE(testing::Value(actual, ElementsAreArray(expected)))
|
|
<< UnifiedDiff(expected, actual);
|
|
|
|
std::stringstream ss;
|
|
ss << UnifiedDiff(expected, actual);
|
|
EXPECT_THAT(ss.str(), testing::Eq(""));
|
|
}
|
|
|
|
TEST(UnifiedDiffTest, MismatchMissing) {
|
|
constexpr char ExpectedDiff[] = R"(unified diff (- expected, + actual):
|
|
=== diff in expected elements 1 to 3 (1-based index):
|
|
A
|
|
-B
|
|
C
|
|
=== diff end
|
|
)";
|
|
ExpectUnifiedDiff({"A", "C"}, {StrEq("A"), StrEq("B"), StrEq("C")},
|
|
ExpectedDiff);
|
|
}
|
|
|
|
TEST(UnifiedDiffTest, MismatchExtra) {
|
|
constexpr char ExpectedDiff[] = R"(unified diff (- expected, + actual):
|
|
=== diff in expected elements 1 to 2 (1-based index):
|
|
A
|
|
+B
|
|
C
|
|
=== diff end
|
|
)";
|
|
ExpectUnifiedDiff({"A", "B", "C"}, {StrEq("A"), StrEq("C")}, ExpectedDiff);
|
|
}
|
|
|
|
TEST(UnifiedDiffTest, MismatchBoth) {
|
|
constexpr char ExpectedDiff[] = R"(unified diff (- expected, + actual):
|
|
=== diff in expected elements 1 to 2 (1-based index):
|
|
A
|
|
-C
|
|
+B
|
|
=== diff end
|
|
)";
|
|
ExpectUnifiedDiff({"A", "B"}, {StrEq("A"), StrEq("C")}, ExpectedDiff);
|
|
}
|
|
|
|
TEST(UnifiedDiffTest, MismatchMultiple) {
|
|
constexpr char ExpectedDiff[] = R"(unified diff (- expected, + actual):
|
|
=== diff in expected elements 1 to 5 (1-based index):
|
|
A
|
|
-B
|
|
+X
|
|
C
|
|
-D
|
|
+Y
|
|
E
|
|
=== diff end
|
|
)";
|
|
ExpectUnifiedDiff(
|
|
{"A", "X", "C", "Y", "E"},
|
|
{StrEq("A"), StrEq("B"), StrEq("C"), StrEq("D"), StrEq("E")},
|
|
ExpectedDiff);
|
|
}
|
|
|
|
TEST(UnifiedDiffTest, MismatchLongContext) {
|
|
constexpr char ExpectedDiff[] = R"(unified diff (- expected, + actual):
|
|
=== diff in expected elements 2 to 8 (1-based index):
|
|
1
|
|
2
|
|
3
|
|
-X
|
|
+4
|
|
5
|
|
6
|
|
7
|
|
=== diff end
|
|
)";
|
|
ExpectUnifiedDiff({"0", "1", "2", "3", "4", "5", "6", "7", "8"},
|
|
{StrEq("0"), StrEq("1"), StrEq("2"), StrEq("3"), StrEq("X"),
|
|
StrEq("5"), StrEq("6"), StrEq("7"), StrEq("8")},
|
|
ExpectedDiff);
|
|
}
|
|
|
|
TEST(UnifiedDiffTest, Mismatch5LineContext) {
|
|
constexpr char ExpectedDiff[] = R"(unified diff (- expected, + actual):
|
|
=== diff in expected elements 1 to 7 (1-based index):
|
|
-X
|
|
+0
|
|
1
|
|
2
|
|
3
|
|
4
|
|
5
|
|
-Y
|
|
+6
|
|
=== diff end
|
|
)";
|
|
ExpectUnifiedDiff({"0", "1", "2", "3", "4", "5", "6"},
|
|
{StrEq("X"), StrEq("1"), StrEq("2"), StrEq("3"), StrEq("4"),
|
|
StrEq("5"), StrEq("Y")},
|
|
ExpectedDiff);
|
|
}
|
|
|
|
TEST(UnifiedDiffTest, Mismatch6LineContext) {
|
|
constexpr char ExpectedDiff[] = R"(unified diff (- expected, + actual):
|
|
=== diff in expected elements 1 to 8 (1-based index):
|
|
-X
|
|
+0
|
|
1
|
|
2
|
|
3
|
|
4
|
|
5
|
|
6
|
|
-Y
|
|
+7
|
|
=== diff end
|
|
)";
|
|
ExpectUnifiedDiff({"0", "1", "2", "3", "4", "5", "6", "7"},
|
|
{StrEq("X"), StrEq("1"), StrEq("2"), StrEq("3"), StrEq("4"),
|
|
StrEq("5"), StrEq("6"), StrEq("Y")},
|
|
ExpectedDiff);
|
|
}
|
|
|
|
TEST(UnifiedDiffTest, Mismatch7LineContext) {
|
|
constexpr char ExpectedDiff[] = R"(unified diff (- expected, + actual):
|
|
=== diff in expected elements 1 to 4 (1-based index):
|
|
-X
|
|
+0
|
|
1
|
|
2
|
|
3
|
|
=== diff in expected elements 6 to 9 (1-based index):
|
|
5
|
|
6
|
|
7
|
|
-Y
|
|
+8
|
|
=== diff end
|
|
)";
|
|
ExpectUnifiedDiff({"0", "1", "2", "3", "4", "5", "6", "7", "8"},
|
|
{StrEq("X"), StrEq("1"), StrEq("2"), StrEq("3"), StrEq("4"),
|
|
StrEq("5"), StrEq("6"), StrEq("7"), StrEq("Y")},
|
|
ExpectedDiff);
|
|
}
|
|
|
|
TEST(UnifiedDiffTest, MismatchEmptyExpected) {
|
|
constexpr char ExpectedDiff[] = R"(unified diff (- expected, + actual):
|
|
=== diff in expected elements 1 to 1 (1-based index):
|
|
+A
|
|
=== diff end
|
|
)";
|
|
ExpectUnifiedDiff({"A"}, {}, ExpectedDiff);
|
|
}
|
|
|
|
TEST(UnifiedDiffTest, MismatchEmptyActual) {
|
|
constexpr char ExpectedDiff[] = R"(unified diff (- expected, + actual):
|
|
=== diff in expected elements 1 to 1 (1-based index):
|
|
-A
|
|
=== diff end
|
|
)";
|
|
ExpectUnifiedDiff({}, {StrEq("A")}, ExpectedDiff);
|
|
}
|
|
|
|
TEST(UnifiedDiffTest, MismatchLongDifference) {
|
|
constexpr char ExpectedDiff[] = R"(unified diff (- expected, + actual):
|
|
=== diff in expected elements 1 to 4 (1-based index):
|
|
1
|
|
-2
|
|
-3
|
|
+X
|
|
+Y
|
|
+Z
|
|
4
|
|
=== diff end
|
|
)";
|
|
ExpectUnifiedDiff({"1", "X", "Y", "Z", "4"},
|
|
{StrEq("1"), StrEq("2"), StrEq("3"), StrEq("4")},
|
|
ExpectedDiff);
|
|
}
|
|
|
|
TEST(UnifiedDiffTest, MismatchGreedyResyncActualMissing) {
|
|
constexpr char ExpectedDiff[] = R"(unified diff (- expected, + actual):
|
|
=== diff in expected elements 1 to 6 (1-based index):
|
|
1
|
|
2
|
|
-3
|
|
+X
|
|
+7
|
|
4
|
|
5
|
|
6
|
|
=== diff end
|
|
)";
|
|
ExpectUnifiedDiff({"1", "2", "X", "7", "4", "5", "6", "7", "8", "9"},
|
|
{StrEq("1"), StrEq("2"), StrEq("3"), StrEq("4"), StrEq("5"),
|
|
StrEq("6"), StrEq("7"), StrEq("8"), StrEq("9")},
|
|
ExpectedDiff);
|
|
}
|
|
|
|
TEST(UnifiedDiffTest, MismatchGreedyResyncExpectedMissing) {
|
|
constexpr char ExpectedDiff[] = R"(unified diff (- expected, + actual):
|
|
=== diff in expected elements 1 to 7 (1-based index):
|
|
1
|
|
2
|
|
-X
|
|
-7
|
|
+3
|
|
4
|
|
5
|
|
6
|
|
=== diff end
|
|
)";
|
|
ExpectUnifiedDiff(
|
|
{"1", "2", "3", "4", "5", "6", "7", "8", "9"},
|
|
{StrEq("1"), StrEq("2"), StrEq("X"), StrEq("7"), StrEq("4"), StrEq("5"),
|
|
StrEq("6"), StrEq("7"), StrEq("8"), StrEq("9")},
|
|
ExpectedDiff);
|
|
}
|
|
|
|
TEST(UnifiedDiffTest, MismatchRegexMatcher) {
|
|
constexpr char ExpectedDiff[] = R"(unified diff (- expected, + actual):
|
|
=== diff in expected elements 1 to 3 (1-based index):
|
|
A
|
|
-matches regular expression ".*B.*"
|
|
C
|
|
=== diff end
|
|
)";
|
|
ExpectUnifiedDiff({"A", "C"}, {StrEq("A"), MatchesRegex(".*B.*"), StrEq("C")},
|
|
ExpectedDiff);
|
|
}
|
|
|
|
TEST(UnifiedDiffTest, CheckSubset) {
|
|
constexpr char ExpectedDiff[] =
|
|
R"(unified diff (- expected, + actual) [+ lines are normal]:
|
|
=== diff in expected elements 1 to 4 (1-based index):
|
|
-X
|
|
+0
|
|
1
|
|
2
|
|
3
|
|
=== diff end
|
|
)";
|
|
std::stringstream ss;
|
|
llvm::SmallVector<Matcher<std::string>> expected = {
|
|
StrEq("X"), StrEq("1"), StrEq("2"), StrEq("3"), StrEq("4"),
|
|
StrEq("5"), StrEq("6"), StrEq("7"), StrEq("8"), StrEq("9")};
|
|
llvm::SmallVector<std::string> actual = {"0", "1", "2", "3", "4", "5", "6",
|
|
"7", "8", "9", "10", "11", "12"};
|
|
ss << UnifiedDiff(expected, actual, /*check_subset=*/true);
|
|
EXPECT_THAT(ss.str(), testing::Eq(ExpectedDiff));
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace Carbon::Testing
|