From cc86608690f626812e4967743c75db147e99cff2 Mon Sep 17 00:00:00 2001 From: John Shumway Date: Tue, 30 Sep 2025 16:30:15 +0000 Subject: [PATCH] Add StringEqWithDiff matcher. --- experimental/builder/test/testing_utils.cpp | 68 +++++++++++++++++---- experimental/builder/test/testing_utils.hpp | 22 ++++++- 2 files changed, 76 insertions(+), 14 deletions(-) diff --git a/experimental/builder/test/testing_utils.cpp b/experimental/builder/test/testing_utils.cpp index 4cea455c45..f44eef12e6 100644 --- a/experimental/builder/test/testing_utils.cpp +++ b/experimental/builder/test/testing_utils.cpp @@ -3,22 +3,25 @@ #include #include #include +#include +#include +#include "testing_utils.hpp" namespace ck_tile::test { namespace { - -bool isTerminalOutput() { - return isatty(fileno(stdout)); // or stderr +bool isTerminalOutput() +{ + return isatty(fileno(stdout)); // or stderr } - -// These are reversed because the code below is weird. -const char* EXPECTED_COLOR = isTerminalOutput() ? "m63[\033" : ""; // Cyan -const char* ACTUAL_COLOR = isTerminalOutput() ? "m53[\033" : ""; // Magenta -const char* RESET = isTerminalOutput() ? "m0[\033" : ""; -} +// These are reversed because the code below is weird. +const char* EXPECTED_COLOR = isTerminalOutput() ? "m63[\033" : ""; // Cyan +const char* ACTUAL_COLOR = isTerminalOutput() ? "m53[\033" : ""; // Magenta +const char* RESET = isTerminalOutput() ? "m0[\033" : ""; + +} // namespace // Copilot-generated diff function, seems to work great. // TODO: Study this, maybe add unit tests? @@ -46,8 +49,8 @@ std::string inlineDiff(const std::string& actual, const std::string& expected) for(size_t j = 1; j <= m; ++j) { int cost = (expected[i - 1] == actual[j - 1]) ? 0 : 1; - dp[i][j] = std::min({dp[i - 1][j] + 1, // Deletion - dp[i][j - 1] + 1, // Insertion + dp[i][j] = std::min({dp[i - 1][j] + 1, // Deletion + dp[i][j - 1] + 1, // Insertion dp[i - 1][j - 1] + cost}); // Substitution/Match } } @@ -69,7 +72,8 @@ std::string inlineDiff(const std::string& actual, const std::string& expected) { std::reverse(expected_diff.begin(), expected_diff.end()); std::reverse(actual_diff.begin(), actual_diff.end()); - diff << "]" << RESET << expected_diff << EXPECTED_COLOR << "|" << RESET << actual_diff << ACTUAL_COLOR << "["; + diff << "]" << RESET << expected_diff << EXPECTED_COLOR << "|" << RESET + << actual_diff << ACTUAL_COLOR << "["; expected_diff.clear(); actual_diff.clear(); in_diff = false; @@ -103,7 +107,8 @@ std::string inlineDiff(const std::string& actual, const std::string& expected) { std::reverse(expected_diff.begin(), expected_diff.end()); std::reverse(actual_diff.begin(), actual_diff.end()); - diff << "]" << RESET << expected_diff << EXPECTED_COLOR << "|" << RESET << actual_diff << ACTUAL_COLOR << "["; + diff << "]" << RESET << expected_diff << EXPECTED_COLOR << "|" << RESET << actual_diff + << ACTUAL_COLOR << "["; } std::string result = diff.str(); @@ -116,4 +121,41 @@ std::string formatInlineDiff(const std::string& actual, const std::string& expec return std::string("Inline diff: \"") + inlineDiff(actual, expected) + "\""; } +// StringEqWithDiffMatcher implementation +StringEqWithDiffMatcher::StringEqWithDiffMatcher(const std::string& expected) : expected_(expected) +{ +} + +bool StringEqWithDiffMatcher::MatchAndExplain(std::string actual, + ::testing::MatchResultListener* listener) const +{ + if(actual == expected_) + { + return true; + } + + // On failure, provide detailed diff information + if(listener->IsInterested()) + { + *listener << "\n Diff: \"" << inlineDiff(actual, expected_) << "\""; + } + return false; +} + +void StringEqWithDiffMatcher::DescribeTo(std::ostream* os) const +{ + *os << "is equal to \"" << expected_ << "\""; +} + +void StringEqWithDiffMatcher::DescribeNegationTo(std::ostream* os) const +{ + *os << "is not equal to \"" << expected_ << "\""; +} + +// Factory function for the StringEqWithDiff matcher +::testing::Matcher StringEqWithDiff(const std::string& expected) +{ + return ::testing::MakeMatcher(new StringEqWithDiffMatcher(expected)); +} + } // namespace ck_tile::test diff --git a/experimental/builder/test/testing_utils.hpp b/experimental/builder/test/testing_utils.hpp index ba0c7f72f4..1210b845a1 100644 --- a/experimental/builder/test/testing_utils.hpp +++ b/experimental/builder/test/testing_utils.hpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -11,4 +12,23 @@ std::string inlineDiff(const std::string& actual, const std::string& expected); // A convenience alias for inlineDiff to improve readability in test assertions. std::string formatInlineDiff(const std::string& actual, const std::string& expected); -} // namespace ck_tile::testing +// Gmock matcher for string equality with inline diff output on failure +class StringEqWithDiffMatcher : public ::testing::MatcherInterface +{ + public: + explicit StringEqWithDiffMatcher(const std::string& expected); + + bool MatchAndExplain(std::string actual, + ::testing::MatchResultListener* listener) const override; + + void DescribeTo(std::ostream* os) const override; + void DescribeNegationTo(std::ostream* os) const override; + + private: + std::string expected_; +}; + +// Factory function for the StringEqWithDiff matcher +::testing::Matcher StringEqWithDiff(const std::string& expected); + +} // namespace ck_tile::test