diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d2eb810..4daf35b5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,10 @@ if (POLICY CMP0048) cmake_policy(SET CMP0048 NEW) endif (POLICY CMP0048) +if (POLICY CMP0077) + cmake_policy(SET CMP0077 NEW) +endif (POLICY CMP0077) + project(googletest-distribution) set(GOOGLETEST_VERSION 1.11.0) diff --git a/ci/linux-presubmit.sh b/ci/linux-presubmit.sh index 0818ef0b..71471886 100644 --- a/ci/linux-presubmit.sh +++ b/ci/linux-presubmit.sh @@ -31,7 +31,7 @@ set -euox pipefail -readonly LINUX_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20220113" +readonly LINUX_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20220217" readonly LINUX_GCC_FLOOR_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-floor:20210617" if [[ -z ${GTEST_ROOT:-} ]]; then diff --git a/docs/reference/matchers.md b/docs/reference/matchers.md index 47d2808c..0f57db47 100644 --- a/docs/reference/matchers.md +++ b/docs/reference/matchers.md @@ -194,6 +194,7 @@ messages, you can use: | Matcher | Description | | :--------------- | :------------------------------------------------ | | `ResultOf(f, m)` | `f(argument)` matches matcher `m`, where `f` is a function or functor. | +| `ResultOf(result_description, f, m)` | The same as the two-parameter version, but provides a better error message. ## Pointer Matchers diff --git a/googlemock/CMakeLists.txt b/googlemock/CMakeLists.txt index 2b55ba15..3ab75a1b 100644 --- a/googlemock/CMakeLists.txt +++ b/googlemock/CMakeLists.txt @@ -105,11 +105,12 @@ endif() # to the targets for when we are part of a parent build (ie being pulled # in via add_subdirectory() rather than being a standalone build). if (DEFINED CMAKE_VERSION AND NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.11") + string(REPLACE ";" "$" dirs "${gmock_build_include_dirs}") target_include_directories(gmock SYSTEM INTERFACE - "$" + "$" "$/${CMAKE_INSTALL_INCLUDEDIR}>") target_include_directories(gmock_main SYSTEM INTERFACE - "$" + "$" "$/${CMAKE_INSTALL_INCLUDEDIR}>") endif() diff --git a/googlemock/include/gmock/gmock-matchers.h b/googlemock/include/gmock/gmock-matchers.h index 5cf5019d..95845864 100644 --- a/googlemock/include/gmock/gmock-matchers.h +++ b/googlemock/include/gmock/gmock-matchers.h @@ -2206,13 +2206,21 @@ template class ResultOfMatcher { public: ResultOfMatcher(Callable callable, InnerMatcher matcher) - : callable_(std::move(callable)), matcher_(std::move(matcher)) { + : ResultOfMatcher(/*result_description=*/"", std::move(callable), + std::move(matcher)) {} + + ResultOfMatcher(const std::string& result_description, Callable callable, + InnerMatcher matcher) + : result_description_(result_description), + callable_(std::move(callable)), + matcher_(std::move(matcher)) { CallableTraits::CheckIsValid(callable_); } template operator Matcher() const { - return Matcher(new Impl(callable_, matcher_)); + return Matcher( + new Impl(result_description_, callable_, matcher_)); } private: @@ -2225,16 +2233,27 @@ class ResultOfMatcher { public: template - Impl(const CallableStorageType& callable, const M& matcher) - : callable_(callable), matcher_(MatcherCast(matcher)) {} + Impl(const std::string& result_description, + const CallableStorageType& callable, const M& matcher) + : result_description_(result_description), + callable_(callable), + matcher_(MatcherCast(matcher)) {} void DescribeTo(::std::ostream* os) const override { - *os << "is mapped by the given callable to a value that "; + if (result_description_.empty()) { + *os << "is mapped by the given callable to a value that "; + } else { + *os << "whose " << result_description_ << " "; + } matcher_.DescribeTo(os); } void DescribeNegationTo(::std::ostream* os) const override { - *os << "is mapped by the given callable to a value that "; + if (result_description_.empty()) { + *os << "is mapped by the given callable to a value that "; + } else { + *os << "whose " << result_description_ << " "; + } matcher_.DescribeNegationTo(os); } @@ -2250,6 +2269,7 @@ class ResultOfMatcher { } private: + const std::string result_description_; // Functors often define operator() as non-const method even though // they are actually stateless. But we need to use them even when // 'this' is a const pointer. It's the user's responsibility not to @@ -2259,6 +2279,7 @@ class ResultOfMatcher { const Matcher matcher_; }; // class Impl + const std::string result_description_; const CallableStorageType callable_; const InnerMatcher matcher_; }; @@ -4422,6 +4443,16 @@ internal::ResultOfMatcher ResultOf( std::move(matcher)); } +// Same as ResultOf() above, but also takes a description of the `callable` +// result to provide better error messages. +template +internal::ResultOfMatcher ResultOf( + const std::string& result_description, Callable callable, + InnerMatcher matcher) { + return internal::ResultOfMatcher( + result_description, std::move(callable), std::move(matcher)); +} + // String matchers. // Matches a string equal to str. diff --git a/googlemock/test/gmock-matchers_test.cc b/googlemock/test/gmock-matchers_test.cc index 34282e6f..6d480e0e 100644 --- a/googlemock/test/gmock-matchers_test.cc +++ b/googlemock/test/gmock-matchers_test.cc @@ -4643,6 +4643,16 @@ TEST(ResultOfTest, CanDescribeItself) { "isn't equal to \"foo\"", DescribeNegation(matcher)); } +// Tests that ResultOf() can describe itself when provided a result description. +TEST(ResultOfTest, CanDescribeItselfWithResultDescription) { + Matcher matcher = + ResultOf("string conversion", &IntToStringFunction, StrEq("foo")); + + EXPECT_EQ("whose string conversion is equal to \"foo\"", Describe(matcher)); + EXPECT_EQ("whose string conversion isn't equal to \"foo\"", + DescribeNegation(matcher)); +} + // Tests that ResultOf() can explain the match result. int IntFunction(int input) { return input == 42 ? 80 : 90; } diff --git a/googletest/CMakeLists.txt b/googletest/CMakeLists.txt index eb03bfaf..aa00a5f3 100644 --- a/googletest/CMakeLists.txt +++ b/googletest/CMakeLists.txt @@ -131,11 +131,12 @@ set_target_properties(gtest_main PROPERTIES VERSION ${GOOGLETEST_VERSION}) # to the targets for when we are part of a parent build (ie being pulled # in via add_subdirectory() rather than being a standalone build). if (DEFINED CMAKE_VERSION AND NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.11") + string(REPLACE ";" "$" dirs "${gtest_build_include_dirs}") target_include_directories(gtest SYSTEM INTERFACE - "$" + "$" "$/${CMAKE_INSTALL_INCLUDEDIR}>") target_include_directories(gtest_main SYSTEM INTERFACE - "$" + "$" "$/${CMAKE_INSTALL_INCLUDEDIR}>") endif() if(CMAKE_SYSTEM_NAME MATCHES "QNX") diff --git a/googletest/src/gtest.cc b/googletest/src/gtest.cc index 833b9237..de774eb6 100644 --- a/googletest/src/gtest.cc +++ b/googletest/src/gtest.cc @@ -45,11 +45,13 @@ #include #include #include +#include #include #include #include #include // NOLINT #include +#include #include #include "gtest/gtest-assertion-result.h" @@ -727,6 +729,11 @@ static bool PatternMatchesString(const std::string& name_str, namespace { +bool IsGlobPattern(const std::string& pattern) { + return std::any_of(pattern.begin(), pattern.end(), + [](const char c) { return c == '?' || c == '*'; }); +} + class UnitTestFilter { public: UnitTestFilter() = default; @@ -734,13 +741,25 @@ class UnitTestFilter { // Constructs a filter from a string of patterns separated by `:`. explicit UnitTestFilter(const std::string& filter) { // By design "" filter matches "" string. - SplitString(filter, ':', &patterns_); + std::vector all_patterns; + SplitString(filter, ':', &all_patterns); + const auto exact_match_patterns_begin = std::partition( + all_patterns.begin(), all_patterns.end(), &IsGlobPattern); + + glob_patterns_.reserve(static_cast( + std::distance(all_patterns.begin(), exact_match_patterns_begin))); + std::move(all_patterns.begin(), exact_match_patterns_begin, + std::inserter(glob_patterns_, glob_patterns_.begin())); + std::move( + exact_match_patterns_begin, all_patterns.end(), + std::inserter(exact_match_patterns_, exact_match_patterns_.begin())); } // Returns true if and only if name matches at least one of the patterns in // the filter. bool MatchesName(const std::string& name) const { - return std::any_of(patterns_.begin(), patterns_.end(), + return exact_match_patterns_.count(name) > 0 || + std::any_of(glob_patterns_.begin(), glob_patterns_.end(), [&name](const std::string& pattern) { return PatternMatchesString( name, pattern.c_str(), @@ -749,7 +768,8 @@ class UnitTestFilter { } private: - std::vector patterns_; + std::vector glob_patterns_; + std::unordered_set exact_match_patterns_; }; class PositiveAndNegativeUnitTestFilter { diff --git a/googletest/test/gtest_help_test.py b/googletest/test/gtest_help_test.py index 3e628ae5..6d2dde00 100755 --- a/googletest/test/gtest_help_test.py +++ b/googletest/test/gtest_help_test.py @@ -45,6 +45,7 @@ from googletest.test import gtest_test_utils IS_LINUX = os.name == 'posix' and os.uname()[0] == 'Linux' IS_GNUHURD = os.name == 'posix' and os.uname()[0] == 'GNU' IS_GNUKFREEBSD = os.name == 'posix' and os.uname()[0] == 'GNU/kFreeBSD' +IS_OPENBSD = os.name == 'posix' and os.uname()[0] == 'OpenBSD' IS_WINDOWS = os.name == 'nt' PROGRAM_PATH = gtest_test_utils.GetTestExecutablePath('gtest_help_test_') @@ -113,7 +114,7 @@ class GTestHelpTest(gtest_test_utils.TestCase): self.assertEquals(0, exit_code) self.assert_(HELP_REGEX.search(output), output) - if IS_LINUX or IS_GNUHURD or IS_GNUKFREEBSD: + if IS_LINUX or IS_GNUHURD or IS_GNUKFREEBSD or IS_OPENBSD: self.assert_(STREAM_RESULT_TO_FLAG in output, output) else: self.assert_(STREAM_RESULT_TO_FLAG not in output, output)