Update googletest Fixed: 419067923 Change-Id: Ida41103ce2edf5f408e47f69f81abb0575b44eb3 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/79448 Commit-Queue: David Benjamin <davidben@google.com> Reviewed-by: Adam Langley <agl@google.com> Auto-Submit: David Benjamin <davidben@google.com> Commit-Queue: Adam Langley <agl@google.com>
diff --git a/third_party/googletest/BUILD.bazel b/third_party/googletest/BUILD.bazel index 0306468..cc25445 100644 --- a/third_party/googletest/BUILD.bazel +++ b/third_party/googletest/BUILD.bazel
@@ -83,6 +83,10 @@ ) # Google Test including Google Mock + +# For an actual test, use `gtest` and also `gtest_main` if you depend on gtest's +# main(). For a library, use `gtest_for_library` instead if the library can be +# testonly. cc_library( name = "gtest", srcs = glob( @@ -147,10 +151,7 @@ "@abseil-cpp//absl/flags:reflection", "@abseil-cpp//absl/flags:usage", "@abseil-cpp//absl/strings", - "@abseil-cpp//absl/types:any", - "@abseil-cpp//absl/types:optional", - "@abseil-cpp//absl/types:variant", - "@re2//:re2", + "@re2", ], "//conditions:default": [], }) + select({ @@ -167,6 +168,16 @@ }), ) +# `gtest`, but testonly. See guidance on `gtest` for when to use this. +alias( + name = "gtest_for_library", + testonly = True, + actual = ":gtest", +) + +# Implements main() for tests using gtest. Prefer to depend on `gtest` as well +# to ensure compliance with the layering_check Bazel feature where only the +# direct hdrs values are available. cc_library( name = "gtest_main", srcs = ["googlemock/src/gmock_main.cc"],
diff --git a/third_party/googletest/METADATA b/third_party/googletest/METADATA index 7679179..d7ae5fc 100644 --- a/third_party/googletest/METADATA +++ b/third_party/googletest/METADATA
@@ -6,6 +6,6 @@ type: HOMEPAGE value: "https://github.com/google/googletest" } - version: "54501746a6cfd366b6e7bab3c902e0f8d5826521" - last_upgrade_date { year: 2025 month: 2 day: 24 } + version: "16d4f8eff6d7cefca6975d82a53f8fc995a6feb7" + last_upgrade_date { year: 2025 month: 5 day: 20 } }
diff --git a/third_party/googletest/MODULE.bazel b/third_party/googletest/MODULE.bazel index 66eee54..c2fb850 100644 --- a/third_party/googletest/MODULE.bazel +++ b/third_party/googletest/MODULE.bazel
@@ -41,20 +41,20 @@ bazel_dep( name = "abseil-cpp", - version = "20250127.0", + version = "20250512.0", ) bazel_dep( name = "platforms", - version = "0.0.10", + version = "0.0.11", ) bazel_dep( name = "re2", - version = "2024-07-02", + version = "2024-07-02.bcr.1", ) bazel_dep( name = "rules_python", - version = "1.1.0", + version = "1.3.0", dev_dependency = True, )
diff --git a/third_party/googletest/README.md b/third_party/googletest/README.md index 2a2a722..54b1237 100644 --- a/third_party/googletest/README.md +++ b/third_party/googletest/README.md
@@ -2,30 +2,19 @@ ### Announcements -#### Live at Head - -GoogleTest now follows the -[Abseil Live at Head philosophy](https://abseil.io/about/philosophy#upgrade-support). -We recommend -[updating to the latest commit in the `main` branch as often as possible](https://github.com/abseil/abseil-cpp/blob/master/FAQ.md#what-is-live-at-head-and-how-do-i-do-it). -We do publish occasional semantic versions, tagged with -`v${major}.${minor}.${patch}` (e.g. `v1.16.0`). - #### Documentation Updates Our documentation is now live on GitHub Pages at https://google.github.io/googletest/. We recommend browsing the documentation on GitHub Pages rather than directly in the repository. -#### Release 1.16.0 +#### Release 1.17.0 -[Release 1.16.0](https://github.com/google/googletest/releases/tag/v1.16.0) is +[Release 1.17.0](https://github.com/google/googletest/releases/tag/v1.17.0) is now available. -The 1.16.x branch requires at least C++14. - -The 1.16.x branch will be the last to support C++14. Future development will -[require at least C++17](https://opensource.google/documentation/policies/cplusplus-support#c_language_standard). +The 1.17.x branch [requires at least +C++17]((https://opensource.google/documentation/policies/cplusplus-support#c_language_standard). #### Continuous Integration
diff --git a/third_party/googletest/WORKSPACE b/third_party/googletest/WORKSPACE index 4c76102..0ae5dee 100644 --- a/third_party/googletest/WORKSPACE +++ b/third_party/googletest/WORKSPACE
@@ -37,9 +37,9 @@ http_archive( name = "rules_python", - sha256 = "9c6e26911a79fbf510a8f06d8eedb40f412023cf7fa6d1461def27116bff022c", - strip_prefix = "rules_python-1.1.0", - url = "https://github.com/bazelbuild/rules_python/releases/download/1.1.0/rules_python-1.1.0.tar.gz", + sha256 = "2cc26bbd53854ceb76dd42a834b1002cd4ba7f8df35440cf03482e045affc244", + strip_prefix = "rules_python-1.3.0", + url = "https://github.com/bazelbuild/rules_python/releases/download/1.3.0/rules_python-1.3.0.tar.gz", ) # https://github.com/bazelbuild/rules_python/releases/tag/1.1.0 load("@rules_python//python:repositories.bzl", "py_repositories") @@ -54,8 +54,8 @@ http_archive( name = "platforms", urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/platforms/releases/download/0.0.10/platforms-0.0.10.tar.gz", - "https://github.com/bazelbuild/platforms/releases/download/0.0.10/platforms-0.0.10.tar.gz", + "https://mirror.bazel.build/github.com/bazelbuild/platforms/releases/download/0.0.11/platforms-0.0.11.tar.gz", + "https://github.com/bazelbuild/platforms/releases/download/0.0.11/platforms-0.0.11.tar.gz", ], - sha256 = "218efe8ee736d26a3572663b374a253c012b716d8af0c07e842e82f238a0a7ee", + sha256 = "29742e87275809b5e598dc2f04d86960cc7a55b3067d97221c9abbc9926bff0f", )
diff --git a/third_party/googletest/ci/linux-presubmit.sh b/third_party/googletest/ci/linux-presubmit.sh index 6491e79..c4ad579 100644 --- a/third_party/googletest/ci/linux-presubmit.sh +++ b/third_party/googletest/ci/linux-presubmit.sh
@@ -31,15 +31,23 @@ set -euox pipefail -readonly LINUX_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20241218" -readonly LINUX_GCC_FLOOR_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-floor:20250205" +readonly LINUX_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20250430" +readonly LINUX_GCC_FLOOR_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-floor:20250430" if [[ -z ${GTEST_ROOT:-} ]]; then GTEST_ROOT="$(realpath $(dirname ${0})/..)" fi +# Use Bazel Vendor mode to reduce reliance on external dependencies. +# See https://bazel.build/external/vendor and the Dockerfile for +# an explaination of how this works. +if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -f "${KOKORO_GFILE_DIR}/distdir/googletest_vendor.tar.gz" ]]; then + DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly --env=BAZEL_VENDOR_ARCHIVE=/distdir/googletest_vendor.tar.gz ${DOCKER_EXTRA_ARGS:-}" + BAZEL_EXTRA_ARGS="--vendor_dir=/googletest_vendor ${BAZEL_EXTRA_ARGS:-}" +fi + if [[ -z ${STD:-} ]]; then - STD="c++17 c++20" + STD="c++17 c++20 c++23" fi # Test CMake + GCC @@ -93,18 +101,21 @@ --rm \ --env="CC=/usr/local/bin/gcc" \ --env="BAZEL_CXXOPTS=-std=c++17" \ + ${DOCKER_EXTRA_ARGS:-} \ ${LINUX_GCC_FLOOR_CONTAINER} \ + /bin/bash --login -c " /usr/local/bin/bazel test ... \ - --copt="-Wall" \ - --copt="-Werror" \ - --copt="-Wuninitialized" \ - --copt="-Wundef" \ - --copt="-Wno-error=pragmas" \ + --copt=\"-Wall\" \ + --copt=\"-Werror\" \ + --copt=\"-Wuninitialized\" \ + --copt=\"-Wundef\" \ + --copt=\"-Wno-error=pragmas\" \ --enable_bzlmod=false \ --features=external_include_paths \ --keep_going \ --show_timestamps \ - --test_output=errors + --test_output=errors \ + ${BAZEL_EXTRA_ARGS:-}" # Test GCC for std in ${STD}; do @@ -115,18 +126,21 @@ --rm \ --env="CC=/usr/local/bin/gcc" \ --env="BAZEL_CXXOPTS=-std=${std}" \ + ${DOCKER_EXTRA_ARGS:-} \ ${LINUX_LATEST_CONTAINER} \ - /usr/local/bin/bazel test ... \ - --copt="-Wall" \ - --copt="-Werror" \ - --copt="-Wuninitialized" \ - --copt="-Wundef" \ - --define="absl=${absl}" \ - --enable_bzlmod=true \ - --features=external_include_paths \ - --keep_going \ - --show_timestamps \ - --test_output=errors + /bin/bash --login -c " + /usr/local/bin/bazel test ... \ + --copt=\"-Wall\" \ + --copt=\"-Werror\" \ + --copt=\"-Wuninitialized\" \ + --copt=\"-Wundef\" \ + --define=\"absl=${absl}\" \ + --enable_bzlmod=true \ + --features=external_include_paths \ + --keep_going \ + --show_timestamps \ + --test_output=errors \ + ${BAZEL_EXTRA_ARGS:-}" done done @@ -139,19 +153,22 @@ --rm \ --env="CC=/opt/llvm/clang/bin/clang" \ --env="BAZEL_CXXOPTS=-std=${std}" \ + ${DOCKER_EXTRA_ARGS:-} \ ${LINUX_LATEST_CONTAINER} \ - /usr/local/bin/bazel test ... \ - --copt="--gcc-toolchain=/usr/local" \ - --copt="-Wall" \ - --copt="-Werror" \ - --copt="-Wuninitialized" \ - --copt="-Wundef" \ - --define="absl=${absl}" \ - --enable_bzlmod=true \ - --features=external_include_paths \ - --keep_going \ - --linkopt="--gcc-toolchain=/usr/local" \ - --show_timestamps \ - --test_output=errors + /bin/bash --login -c " + /usr/local/bin/bazel test ... \ + --copt=\"--gcc-toolchain=/usr/local\" \ + --copt=\"-Wall\" \ + --copt=\"-Werror\" \ + --copt=\"-Wuninitialized\" \ + --copt=\"-Wundef\" \ + --define=\"absl=${absl}\" \ + --enable_bzlmod=true \ + --features=external_include_paths \ + --keep_going \ + --linkopt=\"--gcc-toolchain=/usr/local\" \ + --show_timestamps \ + --test_output=errors \ + ${BAZEL_EXTRA_ARGS:-}" done done
diff --git a/third_party/googletest/ci/macos-presubmit.sh b/third_party/googletest/ci/macos-presubmit.sh index 5370ed6..63cf814 100644 --- a/third_party/googletest/ci/macos-presubmit.sh +++ b/third_party/googletest/ci/macos-presubmit.sh
@@ -56,7 +56,7 @@ # Test the Bazel build # If we are running on Kokoro, check for a versioned Bazel binary. -KOKORO_GFILE_BAZEL_BIN="bazel-8.0.0-darwin-x86_64" +KOKORO_GFILE_BAZEL_BIN="bazel-8.2.1-darwin-x86_64" if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -f ${KOKORO_GFILE_DIR}/${KOKORO_GFILE_BAZEL_BIN} ]]; then BAZEL_BIN="${KOKORO_GFILE_DIR}/${KOKORO_GFILE_BAZEL_BIN}" chmod +x ${BAZEL_BIN} @@ -64,6 +64,12 @@ BAZEL_BIN="bazel" fi +# Use Bazel Vendor mode to reduce reliance on external dependencies. +if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -f "${KOKORO_GFILE_DIR}/distdir/googletest_vendor.tar.gz" ]]; then + tar -xf "${KOKORO_GFILE_DIR}/distdir/googletest_vendor.tar.gz" -C "${TMP}/" + BAZEL_EXTRA_ARGS="--vendor_dir=\"${TMP}/googletest_vendor\" ${BAZEL_EXTRA_ARGS:-}" +fi + cd ${GTEST_ROOT} for absl in 0 1; do ${BAZEL_BIN} test ... \ @@ -76,5 +82,6 @@ --features=external_include_paths \ --keep_going \ --show_timestamps \ - --test_output=errors + --test_output=errors \ + ${BAZEL_EXTRA_ARGS:-} done
diff --git a/third_party/googletest/ci/windows-presubmit.bat b/third_party/googletest/ci/windows-presubmit.bat index e2664c5..267e2e9 100644 --- a/third_party/googletest/ci/windows-presubmit.bat +++ b/third_party/googletest/ci/windows-presubmit.bat
@@ -1,6 +1,6 @@ SETLOCAL ENABLEDELAYEDEXPANSION -SET BAZEL_EXE=%KOKORO_GFILE_DIR%\bazel-8.0.0-windows-x86_64.exe +SET BAZEL_EXE=%KOKORO_GFILE_DIR%\bazel-8.2.1-windows-x86_64.exe SET PATH=C:\Python34;%PATH% SET BAZEL_PYTHON=C:\python34\python.exe @@ -48,6 +48,14 @@ :: --output_user_root=C:\tmp causes Bazel to use a shorter path. SET BAZEL_VS=C:\Program Files\Microsoft Visual Studio\2022\Community +:: Use Bazel Vendor mode to reduce reliance on external dependencies. +IF EXIST "%KOKORO_GFILE_DIR%\distdir\googletest_vendor.tar.gz" ( + tar --force-local -xf "%KOKORO_GFILE_DIR%\distdir\googletest_vendor.tar.gz" -C c: + SET VENDOR_FLAG=--vendor_dir=c:\googletest_vendor +) ELSE ( + SET VENDOR_FLAG= +) + :: C++17 %BAZEL_EXE% ^ --output_user_root=C:\tmp ^ @@ -58,7 +66,8 @@ --enable_bzlmod=true ^ --keep_going ^ --test_output=errors ^ - --test_tag_filters=-no_test_msvc2017 + --test_tag_filters=-no_test_msvc2017 ^ + %VENDOR_FLAG% IF %errorlevel% neq 0 EXIT /B 1 :: C++20 @@ -71,5 +80,6 @@ --enable_bzlmod=true ^ --keep_going ^ --test_output=errors ^ - --test_tag_filters=-no_test_msvc2017 + --test_tag_filters=-no_test_msvc2017 ^ + %VENDOR_FLAG% IF %errorlevel% neq 0 EXIT /B 1
diff --git a/third_party/googletest/docs/advanced.md b/third_party/googletest/docs/advanced.md index 9b1220a..35a237d 100644 --- a/third_party/googletest/docs/advanced.md +++ b/third_party/googletest/docs/advanced.md
@@ -1471,10 +1471,7 @@ Another way to test private members is to refactor them into an implementation class, which is then declared in a `*-internal.h` file. Your - clients aren't allowed to include this header but your tests can. Such is - called the - [Pimpl](https://www.gamedev.net/articles/programming/general-and-gameplay-programming/the-c-pimpl-r1794/) - (Private Implementation) idiom. + clients aren't allowed to include this header but your tests can. Or, you can declare an individual test as a friend of your class by adding this line in the class body:
diff --git a/third_party/googletest/docs/faq.md b/third_party/googletest/docs/faq.md index c7d10b5..4e95838 100644 --- a/third_party/googletest/docs/faq.md +++ b/third_party/googletest/docs/faq.md
@@ -511,19 +511,6 @@ list of the constructor. (Early versions of `gcc` doesn't force you to initialize the const member. It's a bug that has been fixed in `gcc 4`.) -## Why does ASSERT_DEATH complain about previous threads that were already joined? - -With the Linux pthread library, there is no turning back once you cross the line -from a single thread to multiple threads. The first time you create a thread, a -manager thread is created in addition, so you get 3, not 2, threads. Later when -the thread you create joins the main thread, the thread count decrements by 1, -but the manager thread will never be killed, so you still have 2 threads, which -means you cannot safely run a death test. - -The new NPTL thread library doesn't suffer from this problem, as it doesn't -create a manager thread. However, if you don't control which machine your test -runs on, you shouldn't depend on this. - ## Why does GoogleTest require the entire test suite, instead of individual tests, to be named `*DeathTest` when it uses `ASSERT_DEATH`? GoogleTest does not interleave tests from different test suites. That is, it
diff --git a/third_party/googletest/docs/gmock_cook_book.md b/third_party/googletest/docs/gmock_cook_book.md index 633dbc3..9e59b4c 100644 --- a/third_party/googletest/docs/gmock_cook_book.md +++ b/third_party/googletest/docs/gmock_cook_book.md
@@ -3567,10 +3567,15 @@ ### Writing New Monomorphic Matchers -A matcher of argument type `T` implements the matcher interface for `T` and does -two things: it tests whether a value of type `T` matches the matcher, and can -describe what kind of values it matches. The latter ability is used for -generating readable error messages when expectations are violated. +A matcher of type `testing::Matcher<T>` implements the matcher interface for `T` +and does two things: it tests whether a value of type `T` matches the matcher, +and can describe what kind of values it matches. The latter ability is used for +generating readable error messages when expectations are violated. Some matchers +can even explain why it matches or doesn't match a certain value, which can be +helpful when the reason isn't obvious. + +Because a matcher of type `testing::Matcher<T>` for a particular type `T` can +only be used to match a value of type `T`, we call it "monomorphic." A matcher of `T` must declare a typedef like: @@ -3662,8 +3667,16 @@ ### Writing New Polymorphic Matchers -Expanding what we learned above to *polymorphic* matchers is now just as simple -as adding templates in the right place. +Unlike a monomorphic matcher, which can only be used to match a value of a +particular type, a *polymorphic* matcher is one that can be used to match values +of multiple types. For example, `Eq(5)` is a polymorhpic matcher as it can be +used to match an `int`, a `double`, a `float`, and so on. You should think of a +polymorphic matcher as a *matcher factory* as opposed to a +`testing::Matcher<SomeType>` - itself is not an actual matcher, but can be +implicitly converted to a `testing::Matcher<SomeType>` depending on the context. + +Expanding what we learned above to polymorphic matchers is now as simple as +adding templates in the right place. ```cpp @@ -3789,6 +3802,26 @@ Like in a monomorphic matcher, you may explain the match result by streaming additional information to the `listener` argument in `MatchAndExplain()`. +### Implementing Composite Matchers {#CompositeMatchers} + +Sometimes we want to define a matcher that takes other matchers as parameters. +For example, `DistanceFrom(target, m)` is a polymorphic matcher that takes a +matcher `m` as a parameter. It tests that the distance from `target` to the +value being matched satisfies sub-matcher `m`. + +If you are implementing such a composite matcher, you'll need to generate the +description of the matcher based on the description(s) of its sub-matcher(s). +You can see the implementation of `DistanceFrom()` in +`googlemock/include/gmock/gmock-matchers.h` for an example. In particular, pay +attention to `DistanceFromMatcherImpl`. Notice that it stores the sub-matcher as +a `const Matcher<const Distance&> distance_matcher_` instead of a polymorphic +matcher - this allows it to call `distance_matcher_.DescribeTo(os)` to describe +the sub-matcher. If the sub-matcher is stored as a polymorphic matcher instead, +it would not be possible to get its description as in general polymorphic +matchers don't know how to describe themselves - they are matcher factories +instead of actual matchers; only after being converted to `Matcher<SomeType>` +can they be described. + ### Writing New Cardinalities A cardinality is used in `Times()` to tell gMock how many times you expect a
diff --git a/third_party/googletest/docs/quickstart-bazel.md b/third_party/googletest/docs/quickstart-bazel.md index 5750f02..04fa829 100644 --- a/third_party/googletest/docs/quickstart-bazel.md +++ b/third_party/googletest/docs/quickstart-bazel.md
@@ -9,7 +9,7 @@ To complete this tutorial, you'll need: * A compatible operating system (e.g. Linux, macOS, Windows). -* A compatible C++ compiler that supports at least C++14. +* A compatible C++ compiler that supports at least C++17. * [Bazel](https://bazel.build/) 7.0 or higher, the preferred build system used by the GoogleTest team. @@ -48,7 +48,7 @@ # Choose the most recent version available at # https://registry.bazel.build/modules/googletest -bazel_dep(name = "googletest", version = "1.15.2") +bazel_dep(name = "googletest", version = "1.17.0") ``` Now you're ready to build C++ code that uses GoogleTest. @@ -99,16 +99,16 @@ [Bazel C++ Tutorial](https://docs.bazel.build/versions/main/tutorial/cpp.html). {: .callout .note} -NOTE: In the example below, we assume Clang or GCC and set `--cxxopt=-std=c++14` -to ensure that GoogleTest is compiled as C++14 instead of the compiler's default -setting (which could be C++11). For MSVC, the equivalent would be -`--cxxopt=/std:c++14`. See [Supported Platforms](platforms.md) for more details -on supported language versions. +NOTE: In the example below, we assume Clang or GCC and set `--cxxopt=-std=c++17` +to ensure that GoogleTest is compiled as C++17 instead of the compiler's default +setting. For MSVC, the equivalent would be `--cxxopt=/std:c++17`. See +[Supported Platforms](platforms.md) for more details on supported language +versions. Now you can build and run your test: <pre> -<strong>$ bazel test --cxxopt=-std=c++14 --test_output=all //:hello_test</strong> +<strong>$ bazel test --cxxopt=-std=c++17 --test_output=all //:hello_test</strong> INFO: Analyzed target //:hello_test (26 packages loaded, 362 targets configured). INFO: Found 1 test target... INFO: From Testing //:hello_test:
diff --git a/third_party/googletest/docs/quickstart-cmake.md b/third_party/googletest/docs/quickstart-cmake.md index 4e422b7..bcdb1b5 100644 --- a/third_party/googletest/docs/quickstart-cmake.md +++ b/third_party/googletest/docs/quickstart-cmake.md
@@ -10,7 +10,7 @@ To complete this tutorial, you'll need: * A compatible operating system (e.g. Linux, macOS, Windows). -* A compatible C++ compiler that supports at least C++14. +* A compatible C++ compiler that supports at least C++17. * [CMake](https://cmake.org/) and a compatible build tool for building the project. * Compatible build tools include @@ -52,8 +52,8 @@ cmake_minimum_required(VERSION 3.14) project(my_project) -# GoogleTest requires at least C++14 -set(CMAKE_CXX_STANDARD 14) +# GoogleTest requires at least C++17 +set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) include(FetchContent)
diff --git a/third_party/googletest/docs/reference/actions.md b/third_party/googletest/docs/reference/actions.md index 0ebdc1e..2ca3a9f 100644 --- a/third_party/googletest/docs/reference/actions.md +++ b/third_party/googletest/docs/reference/actions.md
@@ -48,8 +48,8 @@ | `InvokeWithoutArgs(object_pointer, &class::method)` | Invoke the method on the object, which takes no arguments. | | `InvokeArgument<N>(arg1, arg2, ..., argk)` | Invoke the mock function's `N`-th (0-based) argument, which must be a function or a functor, with the `k` arguments. | -The return value of the invoked function is used as the return value of the -action. +The return value of the invoked function (except `InvokeArgument`) is used as +the return value of the action. When defining a callable to be used with `Invoke*()`, you can declare any unused parameters as `Unused`:
diff --git a/third_party/googletest/docs/reference/matchers.md b/third_party/googletest/docs/reference/matchers.md index 16397ef..8ff9e0b 100644 --- a/third_party/googletest/docs/reference/matchers.md +++ b/third_party/googletest/docs/reference/matchers.md
@@ -42,6 +42,8 @@ | `Lt(value)` | `argument < value` | | `Ne(value)` | `argument != value` | | `IsFalse()` | `argument` evaluates to `false` in a Boolean context. | +| `DistanceFrom(target, m)` | The distance between `argument` and `target` (computed by `abs(argument - target)`) matches `m`. | +| `DistanceFrom(target, get_distance, m)` | The distance between `argument` and `target` (computed by `get_distance(argument, target)`) matches `m`. | | `IsTrue()` | `argument` evaluates to `true` in a Boolean context. | | `IsNull()` | `argument` is a `NULL` pointer (raw or smart). | | `NotNull()` | `argument` is a non-null pointer (raw or smart). |
diff --git a/third_party/googletest/docs/reference/testing.md b/third_party/googletest/docs/reference/testing.md index 3ed5211..d7dc5cf 100644 --- a/third_party/googletest/docs/reference/testing.md +++ b/third_party/googletest/docs/reference/testing.md
@@ -110,7 +110,7 @@ | `ValuesIn(container)` or `ValuesIn(begin,end)` | Yields values from a C-style array, an STL-style container, or an iterator range `[begin, end)`. | | `Bool()` | Yields sequence `{false, true}`. | | `Combine(g1, g2, ..., gN)` | Yields as `std::tuple` *n*-tuples all combinations (Cartesian product) of the values generated by the given *n* generators `g1`, `g2`, ..., `gN`. | -| `ConvertGenerator<T>(g)` | Yields values generated by generator `g`, `static_cast` to `T`. | +| `ConvertGenerator<T>(g)` or `ConvertGenerator(g, func)` | Yields values generated by generator `g`, `static_cast` from `T`. (Note: `T` might not be what you expect. See [*Using ConvertGenerator*](#using-convertgenerator) below.) The second overload uses `func` to perform the conversion. | The optional last argument *`name_generator`* is a function or functor that generates custom test name suffixes based on the test parameters. The function @@ -137,6 +137,103 @@ See also [`GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST`](#GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST). +###### Using `ConvertGenerator` + +The functions listed in the table above appear to return generators that create +values of the desired types, but this is not generally the case. Rather, they +typically return factory objects that convert to the the desired generators. +This affords some flexibility in allowing you to specify values of types that +are different from, yet implicitly convertible to, the actual parameter type +required by your fixture class. + +For example, you can do the following with a fixture that requires an `int` +parameter: + +```cpp +INSTANTIATE_TEST_SUITE_P(MyInstantiation, MyTestSuite, + testing::Values(1, 1.2)); // Yes, Values() supports heterogeneous argument types. +``` + +It might seem obvious that `1.2` — a `double` — will be converted to +an `int` but in actuality it requires some template gymnastics involving the +indirection described in the previous paragraph. + +What if your parameter type is not implicitly convertible from the generated +type but is *explicitly* convertible? There will be no automatic conversion, but +you can force it by applying `ConvertGenerator<T>`. The compiler can +automatically deduce the target type (your fixture's parameter type), but +because of the aforementioned indirection it cannot decide what the generated +type should be. You need to tell it, by providing the type `T` explicitly. Thus +`T` should not be your fixture's parameter type, but rather an intermediate type +that is supported by the factory object, and which can be `static_cast` to the +fixture's parameter type: + +```cpp +// The fixture's parameter type. +class MyParam { + public: + // Explicit converting ctor. + explicit MyParam(const std::tuple<int, bool>& t); + ... +}; + +INSTANTIATE_TEST_SUITE_P(MyInstantiation, MyTestSuite, + ConvertGenerator<std::tuple<int, bool>>(Combine(Values(0.1, 1.2), Bool()))); +``` + +In this example `Combine` supports the generation of `std::tuple<int, bool>>` +objects (even though the provided values for the first tuple element are +`double`s) and those `tuple`s get converted into `MyParam` objects by virtue of +the call to `ConvertGenerator`. + +For parameter types that are not convertible from the generated types you can +provide a callable that does the conversion. The callable accepts an object of +the generated type and returns an object of the fixture's parameter type. The +generated type can often be deduced by the compiler from the callable's call +signature so you do not usually need specify it explicitly (but see a caveat +below). + +```cpp +// The fixture's parameter type. +class MyParam { + public: + MyParam(int, bool); + ... +}; + +INSTANTIATE_TEST_SUITE_P(MyInstantiation, MyTestSuite, + ConvertGenerator(Combine(Values(1, 1.2), Bool()), + [](const std::tuple<int i, bool>& t){ + const auto [i, b] = t; + return MyParam(i, b); + })); +``` + +The callable may be anything that can be used to initialize a `std::function` +with the appropriate call signature. Note the callable's return object gets +`static_cast` to the fixture's parameter type, so it does not have to be of that +exact type, only convertible to it. + +**Caveat:** Consider the following example. + +```cpp +INSTANTIATE_TEST_SUITE_P(MyInstantiation, MyTestSuite, + ConvertGenerator(Values(std::string("s")), [](std::string_view s) { ... })); +``` + +The `string` argument gets copied into the factory object returned by `Values`. +Then, because the generated type deduced from the lambda is `string_view`, the +factory object spawns a generator that holds a `string_view` referencing that +`string`. Unfortunately, by the time this generator gets invoked, the factory +object is gone and the `string_view` is dangling. + +To overcome this problem you can specify the generated type explicitly: +`ConvertGenerator<std::string>(Values(std::string("s")), [](std::string_view s) +{ ... })`. Alternatively, you can change the lambda's signature to take a +`std::string` or a `const std::string&` (the latter will not leave you with a +dangling reference because the type deduction strips off the reference and the +`const`). + ### TYPED_TEST_SUITE {#TYPED_TEST_SUITE} `TYPED_TEST_SUITE(`*`TestFixtureName`*`,`*`Types`*`)`
diff --git a/third_party/googletest/googlemock/include/gmock/gmock-actions.h b/third_party/googletest/googlemock/include/gmock/gmock-actions.h index 040e702..5fe50e3 100644 --- a/third_party/googletest/googlemock/include/gmock/gmock-actions.h +++ b/third_party/googletest/googlemock/include/gmock/gmock-actions.h
@@ -835,6 +835,10 @@ Result operator()(const InArgs&...) const { return function_impl(); } + template <typename... InArgs> + Result operator()(const InArgs&...) { + return function_impl(); + } FunctionImpl function_impl; }; @@ -1451,6 +1455,30 @@ return OA{std::move(inner_action)}; } + // As above, but in the case where we want to create a OnceAction from a const + // WithArgsAction. This is fine as long as the inner action doesn't need to + // move any of its state to create a OnceAction. + template < + typename R, typename... Args, + typename std::enable_if< + std::is_convertible<const InnerAction&, + OnceAction<R(internal::TupleElement< + I, std::tuple<Args...>>...)>>::value, + int>::type = 0> + operator OnceAction<R(Args...)>() const& { // NOLINT + struct OA { + OnceAction<InnerSignature<R, Args...>> inner_action; + + R operator()(Args&&... args) && { + return std::move(inner_action) + .Call(std::get<I>( + std::forward_as_tuple(std::forward<Args>(args)...))...); + } + }; + + return OA{inner_action}; + } + template < typename R, typename... Args, typename std::enable_if< @@ -1703,9 +1731,8 @@ struct ReturnArgAction { template <typename... Args, typename = typename std::enable_if<(k < sizeof...(Args))>::type> - auto operator()(Args&&... args) const - -> decltype(std::get<k>( - std::forward_as_tuple(std::forward<Args>(args)...))) { + auto operator()(Args&&... args) const -> decltype(std::get<k>( + std::forward_as_tuple(std::forward<Args>(args)...))) { return std::get<k>(std::forward_as_tuple(std::forward<Args>(args)...)); } };
diff --git a/third_party/googletest/googlemock/include/gmock/gmock-matchers.h b/third_party/googletest/googlemock/include/gmock/gmock-matchers.h index 8903c7a..b999d6e 100644 --- a/third_party/googletest/googlemock/include/gmock/gmock-matchers.h +++ b/third_party/googletest/googlemock/include/gmock/gmock-matchers.h
@@ -257,6 +257,7 @@ #include <algorithm> #include <cmath> +#include <cstddef> #include <exception> #include <functional> #include <initializer_list> @@ -1311,6 +1312,15 @@ bool MatchAndExplain(const T& x, MatchResultListener* listener) const override { + if (!listener->IsInterested()) { + // Fast path to avoid unnecessary formatting. + for (const Matcher<T>& matcher : matchers_) { + if (!matcher.Matches(x)) { + return false; + } + } + return true; + } // This method uses matcher's explanation when explaining the result. // However, if matcher doesn't provide one, this method uses matcher's // description. @@ -1430,6 +1440,15 @@ bool MatchAndExplain(const T& x, MatchResultListener* listener) const override { + if (!listener->IsInterested()) { + // Fast path to avoid unnecessary formatting of match explanations. + for (const Matcher<T>& matcher : matchers_) { + if (matcher.Matches(x)) { + return true; + } + } + return false; + } // This method uses matcher's explanation when explaining the result. // However, if matcher doesn't provide one, this method uses matcher's // description. @@ -2097,11 +2116,11 @@ template <typename Class, typename FieldType> class FieldMatcher { public: - FieldMatcher(FieldType Class::*field, + FieldMatcher(FieldType Class::* field, const Matcher<const FieldType&>& matcher) : field_(field), matcher_(matcher), whose_field_("whose given field ") {} - FieldMatcher(const std::string& field_name, FieldType Class::*field, + FieldMatcher(const std::string& field_name, FieldType Class::* field, const Matcher<const FieldType&>& matcher) : field_(field), matcher_(matcher), @@ -2145,7 +2164,7 @@ return MatchAndExplainImpl(std::false_type(), *p, listener); } - const FieldType Class::*field_; + const FieldType Class::* field_; const Matcher<const FieldType&> matcher_; // Contains either "whose given field " if the name of the field is unknown @@ -2855,6 +2874,54 @@ } }; +// Implements DistanceFrom(target, get_distance, distance_matcher) for the given +// argument types: +// * V is the type of the value to be matched. +// * T is the type of the target value. +// * Distance is the type of the distance between V and T. +// * GetDistance is the type of the functor for computing the distance between +// V and T. +template <typename V, typename T, typename Distance, typename GetDistance> +class DistanceFromMatcherImpl : public MatcherInterface<V> { + public: + // Arguments: + // * target: the target value. + // * get_distance: the functor for computing the distance between the value + // being matched and target. + // * distance_matcher: the matcher for checking the distance. + DistanceFromMatcherImpl(T target, GetDistance get_distance, + Matcher<const Distance&> distance_matcher) + : target_(std::move(target)), + get_distance_(std::move(get_distance)), + distance_matcher_(std::move(distance_matcher)) {} + + // Describes what this matcher does. + void DescribeTo(::std::ostream* os) const override { + distance_matcher_.DescribeTo(os); + *os << " away from " << PrintToString(target_); + } + + void DescribeNegationTo(::std::ostream* os) const override { + distance_matcher_.DescribeNegationTo(os); + *os << " away from " << PrintToString(target_); + } + + bool MatchAndExplain(V value, MatchResultListener* listener) const override { + const auto distance = get_distance_(value, target_); + const bool match = distance_matcher_.Matches(distance); + if (!match && listener->IsInterested()) { + *listener << "which is " << PrintToString(distance) << " away from " + << PrintToString(target_); + } + return match; + } + + private: + const T target_; + const GetDistance get_distance_; + const Matcher<const Distance&> distance_matcher_; +}; + // Implements Each(element_matcher) for the given argument type Container. // Symmetric to ContainsMatcherImpl. template <typename Container> @@ -2990,6 +3057,52 @@ } } // namespace pair_getters +// Default functor for computing the distance between two values. +struct DefaultGetDistance { + template <typename T, typename U> + auto operator()(const T& lhs, const U& rhs) const { + using std::abs; + // Allow finding abs() in the type's namespace via ADL. + return abs(lhs - rhs); + } +}; + +// Implements polymorphic DistanceFrom(target, get_distance, distance_matcher) +// matcher. Template arguments: +// * T is the type of the target value. +// * GetDistance is the type of the functor for computing the distance between +// the value being matched and the target. +// * DistanceMatcher is the type of the matcher for checking the distance. +template <typename T, typename GetDistance, typename DistanceMatcher> +class DistanceFromMatcher { + public: + // Arguments: + // * target: the target value. + // * get_distance: the functor for computing the distance between the value + // being matched and target. + // * distance_matcher: the matcher for checking the distance. + DistanceFromMatcher(T target, GetDistance get_distance, + DistanceMatcher distance_matcher) + : target_(std::move(target)), + get_distance_(std::move(get_distance)), + distance_matcher_(std::move(distance_matcher)) {} + + DistanceFromMatcher(const DistanceFromMatcher& other) = default; + + // Implicitly converts to a monomorphic matcher of the given type. + template <typename V> + operator Matcher<V>() const { // NOLINT + using Distance = decltype(get_distance_(std::declval<V>(), target_)); + return Matcher<V>(new DistanceFromMatcherImpl<V, T, Distance, GetDistance>( + target_, get_distance_, distance_matcher_)); + } + + private: + const T target_; + const GetDistance get_distance_; + const DistanceMatcher distance_matcher_; +}; + // Implements Key(inner_matcher) for the given argument pair type. // Key(inner_matcher) matches an std::pair whose 'first' field matches // inner_matcher. For example, Contains(Key(Ge(5))) can be used to match an @@ -3197,8 +3310,8 @@ }; template <typename T, size_t... I> -auto UnpackStructImpl(const T& t, std::index_sequence<I...>, - int) -> decltype(std::tie(get<I>(t)...)) { +auto UnpackStructImpl(const T& t, std::index_sequence<I...>, int) + -> decltype(std::tie(get<I>(t)...)) { static_assert(std::tuple_size<T>::value == sizeof...(I), "Number of arguments doesn't match the number of fields."); return std::tie(get<I>(t)...); @@ -3305,6 +3418,29 @@ const auto& [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t] = u; return std::tie(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t); } +template <typename T> +auto UnpackStructImpl(const T& in, std::make_index_sequence<21>, char) { + const auto& [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u] = + in; + return std::tie(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, + u); +} + +template <typename T> +auto UnpackStructImpl(const T& in, std::make_index_sequence<22>, char) { + const auto& [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, + v] = in; + return std::tie(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, + v); +} + +template <typename T> +auto UnpackStructImpl(const T& in, std::make_index_sequence<23>, char) { + const auto& [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, + w] = in; + return std::tie(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, + v, w); +} #endif // defined(__cpp_structured_bindings) template <size_t I, typename T> @@ -3480,7 +3616,7 @@ StlContainerReference stl_container = View::ConstReference(container); auto it = stl_container.begin(); size_t exam_pos = 0; - bool mismatch_found = false; // Have we found a mismatched element yet? + bool unmatched_found = false; // Go through the elements and matchers in pairs, until we reach // the end of either the elements or the matchers, or until we find a @@ -3496,11 +3632,23 @@ } if (!match) { - mismatch_found = true; + unmatched_found = true; + // We cannot store the iterator for the unmatched element to be used + // later, as some users use ElementsAre() with a "container" whose + // iterator is not copy-constructible or copy-assignable. + // + // We cannot store a pointer to the element either, as some container's + // iterators return a temporary. + // + // We cannot store the element itself either, as the element may not be + // copyable. + // + // Therefore, we just remember the index of the unmatched element, + // and use it later to print the unmatched element. break; } } - // If mismatch_found is true, 'exam_pos' is the index of the mismatch. + // If unmatched_found is true, exam_pos is the index of the mismatch. // Find how many elements the actual container has. We avoid // calling size() s.t. this code works for stream-like "containers" @@ -3521,10 +3669,27 @@ return false; } - if (mismatch_found) { + if (unmatched_found) { // The element count matches, but the exam_pos-th element doesn't match. if (listener_interested) { - *listener << "whose element #" << exam_pos << " doesn't match"; + // Find the unmatched element. + auto unmatched_it = stl_container.begin(); + // We cannot call std::advance() on the iterator, as some users use + // ElementsAre() with a "container" whose iterator is incompatible with + // std::advance() (e.g. it may not have the difference_type member + // type). + for (size_t i = 0; i != exam_pos; ++i) { + ++unmatched_it; + } + + // If the array is long or the elements' print-out is large, it may be + // hard for the user to find the mismatched element and its + // 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) << ") "; + matchers_[exam_pos].DescribeNegationTo(listener->stream()); PrintIfNotEmpty(explanations[exam_pos], listener->stream()); } return false; @@ -3930,15 +4095,15 @@ // Overloads to support `OptionalMatcher` being used with a type that either // supports implicit conversion to bool or a `has_value()` method. template <typename Optional> -auto IsOptionalEngaged(const Optional& optional, - Rank1) -> decltype(!!optional) { +auto IsOptionalEngaged(const Optional& optional, Rank1) + -> decltype(!!optional) { // The use of double-negation here is to preserve historical behavior where // the matcher used `operator!` rather than directly using `operator bool`. return !static_cast<bool>(!optional); } template <typename Optional> -auto IsOptionalEngaged(const Optional& optional, - Rank0) -> decltype(!optional.has_value()) { +auto IsOptionalEngaged(const Optional& optional, Rank0) + -> decltype(!optional.has_value()) { return optional.has_value(); } @@ -3979,6 +4144,10 @@ return false; } const ValueType& value = *optional; + if (!listener->IsInterested()) { + // Fast path to avoid unnecessary generation of match explanation. + return value_matcher_.Matches(value); + } StringMatchResultListener value_listener; const bool match = value_matcher_.MatchAndExplain(value, &value_listener); *listener << "whose value " << PrintToString(value) @@ -4365,6 +4534,42 @@ return internal::FloatingEqMatcher<double>(rhs, false, max_abs_error); } +// The DistanceFrom(target, get_distance, m) and DistanceFrom(target, m) +// matchers work on arbitrary types that have the "distance" concept. What they +// do: +// +// 1. compute the distance between the value and the target using +// get_distance(value, target) if get_distance is provided; otherwise compute +// the distance as abs(value - target). +// 2. match the distance against the user-provided matcher m; if the match +// succeeds, the DistanceFrom() match succeeds. +// +// Examples: +// +// // 0.5's distance from 0.6 should be <= 0.2. +// EXPECT_THAT(0.5, DistanceFrom(0.6, Le(0.2))); +// +// Vector2D v1(3.0, 4.0), v2(3.2, 6.0); +// // v1's distance from v2, as computed by EuclideanDistance(v1, v2), +// // should be >= 1.0. +// EXPECT_THAT(v1, DistanceFrom(v2, EuclideanDistance, Ge(1.0))); + +template <typename T, typename GetDistance, typename DistanceMatcher> +inline internal::DistanceFromMatcher<T, GetDistance, DistanceMatcher> +DistanceFrom(T target, GetDistance get_distance, + DistanceMatcher distance_matcher) { + return internal::DistanceFromMatcher<T, GetDistance, DistanceMatcher>( + std::move(target), std::move(get_distance), std::move(distance_matcher)); +} + +template <typename T, typename DistanceMatcher> +inline internal::DistanceFromMatcher<T, internal::DefaultGetDistance, + DistanceMatcher> +DistanceFrom(T target, DistanceMatcher distance_matcher) { + return DistanceFrom(std::move(target), internal::DefaultGetDistance(), + std::move(distance_matcher)); +} + // Creates a matcher that matches any double argument approximately equal to // rhs, up to the specified max absolute error bound, including NaN values when // rhs is NaN. The max absolute error bound must be non-negative. @@ -4430,7 +4635,7 @@ // matches a Foo object x if and only if x.number >= 5. template <typename Class, typename FieldType, typename FieldMatcher> inline PolymorphicMatcher<internal::FieldMatcher<Class, FieldType>> Field( - FieldType Class::*field, const FieldMatcher& matcher) { + FieldType Class::* field, const FieldMatcher& matcher) { return MakePolymorphicMatcher(internal::FieldMatcher<Class, FieldType>( field, MatcherCast<const FieldType&>(matcher))); // The call to MatcherCast() is required for supporting inner @@ -4443,7 +4648,7 @@ // messages. template <typename Class, typename FieldType, typename FieldMatcher> inline PolymorphicMatcher<internal::FieldMatcher<Class, FieldType>> Field( - const std::string& field_name, FieldType Class::*field, + const std::string& field_name, FieldType Class::* field, const FieldMatcher& matcher) { return MakePolymorphicMatcher(internal::FieldMatcher<Class, FieldType>( field_name, field, MatcherCast<const FieldType&>(matcher)));
diff --git a/third_party/googletest/googlemock/test/gmock-actions_test.cc b/third_party/googletest/googlemock/test/gmock-actions_test.cc index 84db511..46b0e91 100644 --- a/third_party/googletest/googlemock/test/gmock-actions_test.cc +++ b/third_party/googletest/googlemock/test/gmock-actions_test.cc
@@ -1645,6 +1645,22 @@ EXPECT_EQ(19, mock.AsStdFunction()(0, 17)); } +// It should be fine to provide an lvalue WithArgsAction to WillOnce, even when +// the inner action only wants to convert to OnceAction. +TEST(WithArgsTest, ProvideAsLvalueToWillOnce) { + struct SomeAction { + operator OnceAction<int(int)>() const { // NOLINT + return [](const int arg) { return arg + 2; }; + } + }; + + const auto wa = WithArg<1>(SomeAction{}); + + MockFunction<int(int, int)> mock; + EXPECT_CALL(mock, Call).WillOnce(wa); + EXPECT_EQ(19, mock.AsStdFunction()(0, 17)); +} + #ifndef GTEST_OS_WINDOWS_MOBILE class SetErrnoAndReturnTest : public testing::Test {
diff --git a/third_party/googletest/googlemock/test/gmock-matchers-arithmetic_test.cc b/third_party/googletest/googlemock/test/gmock-matchers-arithmetic_test.cc index 06b0b47..b6c3511 100644 --- a/third_party/googletest/googlemock/test/gmock-matchers-arithmetic_test.cc +++ b/third_party/googletest/googlemock/test/gmock-matchers-arithmetic_test.cc
@@ -34,6 +34,7 @@ #include <cmath> #include <limits> #include <memory> +#include <ostream> #include <string> #include "gmock/gmock.h" @@ -398,6 +399,188 @@ EXPECT_EQ("are an almost-equal pair", Describe(m)); } +// Tests that DistanceFrom() can describe itself properly. +TEST(DistanceFrom, CanDescribeSelf) { + Matcher<double> m = DistanceFrom(1.5, Lt(0.1)); + EXPECT_EQ(Describe(m), "is < 0.1 away from 1.5"); + + m = DistanceFrom(2.5, Gt(0.2)); + EXPECT_EQ(Describe(m), "is > 0.2 away from 2.5"); +} + +// Tests that DistanceFrom() can explain match failure. +TEST(DistanceFrom, CanExplainMatchFailure) { + Matcher<double> m = DistanceFrom(1.5, Lt(0.1)); + EXPECT_EQ(Explain(m, 2.0), "which is 0.5 away from 1.5"); +} + +// Tests that DistanceFrom() matches a double that is within the given range of +// the given value. +TEST(DistanceFrom, MatchesDoubleWithinRange) { + const Matcher<double> m = DistanceFrom(0.5, Le(0.1)); + EXPECT_TRUE(m.Matches(0.45)); + EXPECT_TRUE(m.Matches(0.5)); + EXPECT_TRUE(m.Matches(0.55)); + EXPECT_FALSE(m.Matches(0.39)); + EXPECT_FALSE(m.Matches(0.61)); +} + +// Tests that DistanceFrom() matches a double reference that is within the given +// range of the given value. +TEST(DistanceFrom, MatchesDoubleRefWithinRange) { + const Matcher<const double&> m = DistanceFrom(0.5, Le(0.1)); + EXPECT_TRUE(m.Matches(0.45)); + EXPECT_TRUE(m.Matches(0.5)); + EXPECT_TRUE(m.Matches(0.55)); + EXPECT_FALSE(m.Matches(0.39)); + EXPECT_FALSE(m.Matches(0.61)); +} + +// Tests that DistanceFrom() can be implicitly converted to a matcher depending +// on the type of the argument. +TEST(DistanceFrom, CanBeImplicitlyConvertedToMatcher) { + EXPECT_THAT(0.58, DistanceFrom(0.5, Le(0.1))); + EXPECT_THAT(0.2, Not(DistanceFrom(0.5, Le(0.1)))); + + EXPECT_THAT(0.58f, DistanceFrom(0.5f, Le(0.1f))); + EXPECT_THAT(0.7f, Not(DistanceFrom(0.5f, Le(0.1f)))); +} + +// Tests that DistanceFrom() can be used on compatible types (i.e. not +// everything has to be of the same type). +TEST(DistanceFrom, CanBeUsedOnCompatibleTypes) { + EXPECT_THAT(0.58, DistanceFrom(0.5, Le(0.1f))); + EXPECT_THAT(0.2, Not(DistanceFrom(0.5, Le(0.1f)))); + + EXPECT_THAT(0.58, DistanceFrom(0.5f, Le(0.1))); + EXPECT_THAT(0.2, Not(DistanceFrom(0.5f, Le(0.1)))); + + EXPECT_THAT(0.58, DistanceFrom(0.5f, Le(0.1f))); + EXPECT_THAT(0.2, Not(DistanceFrom(0.5f, Le(0.1f)))); + + EXPECT_THAT(0.58f, DistanceFrom(0.5, Le(0.1))); + EXPECT_THAT(0.2f, Not(DistanceFrom(0.5, Le(0.1)))); + + EXPECT_THAT(0.58f, DistanceFrom(0.5, Le(0.1f))); + EXPECT_THAT(0.2f, Not(DistanceFrom(0.5, Le(0.1f)))); + + EXPECT_THAT(0.58f, DistanceFrom(0.5f, Le(0.1))); + EXPECT_THAT(0.2f, Not(DistanceFrom(0.5f, Le(0.1)))); +} + +// A 2-dimensional point. For testing using DistanceFrom() with a custom type +// that doesn't have a built-in distance function. +class Point { + public: + Point(double x, double y) : x_(x), y_(y) {} + double x() const { return x_; } + double y() const { return y_; } + + private: + double x_; + double y_; +}; + +// Returns the distance between two points. +double PointDistance(const Point& lhs, const Point& rhs) { + return std::sqrt(std::pow(lhs.x() - rhs.x(), 2) + + std::pow(lhs.y() - rhs.y(), 2)); +} + +// Tests that DistanceFrom() can be used on a type with a custom distance +// function. +TEST(DistanceFrom, CanBeUsedOnTypeWithCustomDistanceFunction) { + const Matcher<Point> m = + DistanceFrom(Point(0.5, 0.5), PointDistance, Le(0.1)); + EXPECT_THAT(Point(0.45, 0.45), m); + EXPECT_THAT(Point(0.2, 0.45), Not(m)); +} + +// A wrapper around a double value. For testing using DistanceFrom() with a +// custom type that has neither a built-in distance function nor a built-in +// distance comparator. +class Double { + public: + explicit Double(double value) : value_(value) {} + Double(const Double& other) = default; + double value() const { return value_; } + + // Defines how to print a Double value. We don't use the AbslStringify API + // because googletest doesn't require absl yet. + friend void PrintTo(const Double& value, std::ostream* os) { + *os << "Double(" << value.value() << ")"; + } + + private: + double value_; +}; + +// Returns the distance between two Double values. +Double DoubleDistance(Double lhs, Double rhs) { + return Double(std::abs(lhs.value() - rhs.value())); +} + +MATCHER_P(DoubleLe, rhs, (negation ? "is > " : "is <= ") + PrintToString(rhs)) { + return arg.value() <= rhs.value(); +} + +// Tests that DistanceFrom() can describe itself properly for a type with a +// custom printer. +TEST(DistanceFrom, CanDescribeWithCustomPrinter) { + const Matcher<Double> m = + DistanceFrom(Double(0.5), DoubleDistance, DoubleLe(Double(0.1))); + EXPECT_EQ(Describe(m), "is <= Double(0.1) away from Double(0.5)"); + EXPECT_EQ(DescribeNegation(m), "is > Double(0.1) away from Double(0.5)"); +} + +// Tests that DistanceFrom() can be used with a custom distance function and +// comparator. +TEST(DistanceFrom, CanCustomizeDistanceAndComparator) { + const Matcher<Double> m = + DistanceFrom(Double(0.5), DoubleDistance, DoubleLe(Double(0.1))); + EXPECT_TRUE(m.Matches(Double(0.45))); + EXPECT_TRUE(m.Matches(Double(0.5))); + EXPECT_FALSE(m.Matches(Double(0.39))); + EXPECT_FALSE(m.Matches(Double(0.61))); +} + +// For testing using DistanceFrom() with a type that supports both - and abs. +class Float { + public: + explicit Float(float value) : value_(value) {} + Float(const Float& other) = default; + float value() const { return value_; } + + private: + float value_ = 0.0f; +}; + +// Returns the difference between two Float values. This must be defined in the +// same namespace as Float. +Float operator-(const Float& lhs, const Float& rhs) { + return Float(lhs.value() - rhs.value()); +} + +// Returns the absolute value of a Float value. This must be defined in the +// same namespace as Float. +Float abs(Float value) { return Float(std::abs(value.value())); } + +// Returns true if and only if the first Float value is less than the second +// Float value. This must be defined in the same namespace as Float. +bool operator<(const Float& lhs, const Float& rhs) { + return lhs.value() < rhs.value(); +} + +// Tests that DistanceFrom() can be used with a type that supports both - and +// abs. +TEST(DistanceFrom, CanBeUsedWithTypeThatSupportsBothMinusAndAbs) { + const Matcher<Float> m = DistanceFrom(Float(0.5f), Lt(Float(0.1f))); + EXPECT_TRUE(m.Matches(Float(0.45f))); + EXPECT_TRUE(m.Matches(Float(0.55f))); + EXPECT_FALSE(m.Matches(Float(0.39f))); + EXPECT_FALSE(m.Matches(Float(0.61f))); +} + // Tests that Not(m) matches any value that doesn't match m. TEST(NotTest, NegatesMatcher) { Matcher<int> m;
diff --git a/third_party/googletest/googlemock/test/gmock-matchers-comparisons_test.cc b/third_party/googletest/googlemock/test/gmock-matchers-comparisons_test.cc index a331aec..87eca08 100644 --- a/third_party/googletest/googlemock/test/gmock-matchers-comparisons_test.cc +++ b/third_party/googletest/googlemock/test/gmock-matchers-comparisons_test.cc
@@ -33,6 +33,7 @@ #include <functional> #include <memory> +#include <optional> #include <string> #include <tuple> #include <vector> @@ -2396,6 +2397,74 @@ EXPECT_EQ("is >= 2, and is <= 3", Explain(m, 2)); } +// A matcher that records whether the listener was interested. +template <typename T> +class CountingMatcher : public MatcherInterface<T> { + public: + explicit CountingMatcher(const Matcher<T>& base_matcher, + std::vector<bool>* listener_interested) + : base_matcher_(base_matcher), + listener_interested_(listener_interested) {} + + bool MatchAndExplain(T x, MatchResultListener* listener) const override { + listener_interested_->push_back(listener->IsInterested()); + return base_matcher_.MatchAndExplain(x, listener); + } + + void DescribeTo(ostream* os) const override { base_matcher_.DescribeTo(os); } + + private: + Matcher<T> base_matcher_; + std::vector<bool>* listener_interested_; +}; + +TEST(AllOfTest, DoesNotFormatChildMatchersWhenNotInterested) { + std::vector<bool> listener_interested; + Matcher<int> matcher = + MakeMatcher(new CountingMatcher<int>(Eq(1), &listener_interested)); + EXPECT_TRUE(matcher.Matches(1)); + EXPECT_THAT(listener_interested, ElementsAre(false)); + listener_interested.clear(); + Matcher<int> all_of_matcher = AllOf(matcher, matcher); + EXPECT_TRUE(all_of_matcher.Matches(1)); + EXPECT_THAT(listener_interested, ElementsAre(false, false)); + listener_interested.clear(); + EXPECT_FALSE(all_of_matcher.Matches(0)); + EXPECT_THAT(listener_interested, ElementsAre(false)); +} + +TEST(AnyOfTest, DoesNotFormatChildMatchersWhenNotInterested) { + std::vector<bool> listener_interested; + Matcher<int> matcher = + MakeMatcher(new CountingMatcher<int>(Eq(1), &listener_interested)); + EXPECT_TRUE(matcher.Matches(1)); + EXPECT_THAT(listener_interested, ElementsAre(false)); + listener_interested.clear(); + Matcher<int> any_of_matcher = AnyOf(matcher, matcher); + EXPECT_TRUE(any_of_matcher.Matches(1)); + EXPECT_THAT(listener_interested, ElementsAre(false)); + listener_interested.clear(); + EXPECT_FALSE(any_of_matcher.Matches(0)); + EXPECT_THAT(listener_interested, ElementsAre(false, false)); +} + +TEST(OptionalTest, DoesNotFormatChildMatcherWhenNotInterested) { + std::vector<bool> listener_interested; + Matcher<int> matcher = + MakeMatcher(new CountingMatcher<int>(Eq(1), &listener_interested)); + EXPECT_TRUE(matcher.Matches(1)); + EXPECT_THAT(listener_interested, ElementsAre(false)); + listener_interested.clear(); + Matcher<std::optional<int>> optional_matcher = Optional(matcher); + EXPECT_FALSE(optional_matcher.Matches(std::nullopt)); + EXPECT_THAT(listener_interested, ElementsAre()); + EXPECT_TRUE(optional_matcher.Matches(1)); + EXPECT_THAT(listener_interested, ElementsAre(false)); + listener_interested.clear(); + EXPECT_FALSE(matcher.Matches(0)); + EXPECT_THAT(listener_interested, ElementsAre(false)); +} + INSTANTIATE_GTEST_MATCHER_TEST_P(ExplainmatcherResultTest); TEST_P(ExplainmatcherResultTestP, MonomorphicMatcher) {
diff --git a/third_party/googletest/googlemock/test/gmock-matchers-containers_test.cc b/third_party/googletest/googlemock/test/gmock-matchers-containers_test.cc index 751fb60..e9f1a02 100644 --- a/third_party/googletest/googlemock/test/gmock-matchers-containers_test.cc +++ b/third_party/googletest/googlemock/test/gmock-matchers-containers_test.cc
@@ -33,6 +33,7 @@ #include <algorithm> #include <array> +#include <cstddef> #include <deque> #include <forward_list> #include <iterator> @@ -1271,10 +1272,11 @@ TEST(WhenSortedByTest, ExplainsMatchResult) { const int a[] = {2, 1}; - EXPECT_EQ("which is { 1, 2 } when sorted, whose element #0 doesn't match", - Explain(WhenSortedBy(less<int>(), ElementsAre(2, 3)), a)); - EXPECT_EQ("which is { 1, 2 } when sorted", - Explain(WhenSortedBy(less<int>(), ElementsAre(1, 2)), a)); + 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"); + EXPECT_EQ(Explain(WhenSortedBy(less<int>(), ElementsAre(1, 2)), a), + "which is { 1, 2 } when sorted"); } // WhenSorted() is a simple wrapper on WhenSortedBy(). Hence we don't @@ -1775,6 +1777,295 @@ helper.Call(MakeUniquePtrs({2})); } +// A container whose iterator returns a temporary. This can iterate over the +// characters in a string. +class CharString { + public: + using value_type = char; + + class const_iterator { + public: + using iterator_category = std::input_iterator_tag; + using value_type = char; + using difference_type = std::ptrdiff_t; + using pointer = const char*; + using reference = const char&; + + // Create an iterator that points to the given character. + explicit const_iterator(const char* ptr) : ptr_(ptr) {} + + // Returns the current character. IMPORTANT: this must return a temporary, + // not a reference, to test that ElementsAre() works with containers whose + // iterators return temporaries. + char operator*() const { return *ptr_; } + + // Advances to the next character. + const_iterator& operator++() { + ++ptr_; + return *this; + } + + // Compares two iterators. + bool operator==(const const_iterator& other) const { + return ptr_ == other.ptr_; + } + bool operator!=(const const_iterator& other) const { + return ptr_ != other.ptr_; + } + + private: + const char* ptr_ = nullptr; + }; + + // Creates a CharString that contains the given string. + explicit CharString(const std::string& s) : s_(s) {} + + // Returns an iterator pointing to the first character in the string. + const_iterator begin() const { return const_iterator(s_.c_str()); } + + // Returns an iterator pointing past the last character in the string. + const_iterator end() const { return const_iterator(s_.c_str() + s_.size()); } + + private: + std::string s_; +}; + +// Tests using ElementsAre() with a container whose iterator returns a +// temporary. +TEST(ElementsAreTest, WorksWithContainerThatReturnsTempInIterator) { + CharString s("abc"); + EXPECT_THAT(s, ElementsAre('a', 'b', 'c')); + EXPECT_THAT(s, Not(ElementsAre('a', 'b', 'd'))); +} + +// Tests using ElementsAreArray() with a container whose iterator returns a +// temporary. +TEST(ElementsAreArrayTest, WorksWithContainerThatReturnsTempInIterator) { + CharString s("abc"); + EXPECT_THAT(s, ElementsAreArray({'a', 'b', 'c'})); + EXPECT_THAT(s, Not(ElementsAreArray({'a', 'b', 'd'}))); +} + +// A container whose iterator returns a temporary and is not copy-assignable. +// This simulates the behavior of the proxy object returned by absl::StrSplit(). +class CharString2 { + public: + using value_type = char; + + class const_iterator { + public: + using iterator_category = std::input_iterator_tag; + using value_type = char; + using difference_type = std::ptrdiff_t; + using pointer = const char*; + using reference = const char&; + + // Make const_iterator copy-constructible but not copy-assignable, + // simulating the behavior of the proxy object returned by absl::StrSplit(). + const_iterator(const const_iterator&) = default; + const_iterator& operator=(const const_iterator&) = delete; + + // Create an iterator that points to the given character. + explicit const_iterator(const char* ptr) : ptr_(ptr) {} + + // Returns the current character. IMPORTANT: this must return a temporary, + // not a reference, to test that ElementsAre() works with containers whose + // iterators return temporaries. + char operator*() const { return *ptr_; } + + // Advances to the next character. + const_iterator& operator++() { + ++ptr_; + return *this; + } + + // Compares two iterators. + bool operator==(const const_iterator& other) const { + return ptr_ == other.ptr_; + } + bool operator!=(const const_iterator& other) const { + return ptr_ != other.ptr_; + } + + private: + const char* ptr_ = nullptr; + }; + + // Creates a CharString that contains the given string. + explicit CharString2(const std::string& s) : s_(s) {} + + // Returns an iterator pointing to the first character in the string. + const_iterator begin() const { return const_iterator(s_.c_str()); } + + // Returns an iterator pointing past the last character in the string. + const_iterator end() const { return const_iterator(s_.c_str() + s_.size()); } + + private: + std::string s_; +}; + +// Tests using ElementsAre() with a container whose iterator returns a +// temporary and is not copy-assignable. +TEST(ElementsAreTest, WorksWithContainerThatReturnsTempInUnassignableIterator) { + CharString2 s("abc"); + EXPECT_THAT(s, ElementsAre('a', 'b', 'c')); + EXPECT_THAT(s, Not(ElementsAre('a', 'b', 'd'))); +} + +// Tests using ElementsAreArray() with a container whose iterator returns a +// temporary and is not copy-assignable. +TEST(ElementsAreArrayTest, + WorksWithContainerThatReturnsTempInUnassignableIterator) { + CharString2 s("abc"); + EXPECT_THAT(s, ElementsAreArray({'a', 'b', 'c'})); + EXPECT_THAT(s, Not(ElementsAreArray({'a', 'b', 'd'}))); +} + +// A container whose iterator returns a temporary and is neither +// copy-constructible nor copy-assignable. +class CharString3 { + public: + using value_type = char; + + class const_iterator { + public: + using iterator_category = std::input_iterator_tag; + using value_type = char; + using difference_type = std::ptrdiff_t; + using pointer = const char*; + using reference = const char&; + + // Make const_iterator neither copy-constructible nor copy-assignable. + const_iterator(const const_iterator&) = delete; + const_iterator& operator=(const const_iterator&) = delete; + + // Create an iterator that points to the given character. + explicit const_iterator(const char* ptr) : ptr_(ptr) {} + + // Returns the current character. IMPORTANT: this must return a temporary, + // not a reference, to test that ElementsAre() works with containers whose + // iterators return temporaries. + char operator*() const { return *ptr_; } + + // Advances to the next character. + const_iterator& operator++() { + ++ptr_; + return *this; + } + + // Compares two iterators. + bool operator==(const const_iterator& other) const { + return ptr_ == other.ptr_; + } + bool operator!=(const const_iterator& other) const { + return ptr_ != other.ptr_; + } + + private: + const char* ptr_ = nullptr; + }; + + // Creates a CharString that contains the given string. + explicit CharString3(const std::string& s) : s_(s) {} + + // Returns an iterator pointing to the first character in the string. + const_iterator begin() const { return const_iterator(s_.c_str()); } + + // Returns an iterator pointing past the last character in the string. + const_iterator end() const { return const_iterator(s_.c_str() + s_.size()); } + + private: + std::string s_; +}; + +// Tests using ElementsAre() with a container whose iterator returns a +// temporary and is neither copy-constructible nor copy-assignable. +TEST(ElementsAreTest, WorksWithContainerThatReturnsTempInUncopyableIterator) { + CharString3 s("abc"); + EXPECT_THAT(s, ElementsAre('a', 'b', 'c')); + EXPECT_THAT(s, Not(ElementsAre('a', 'b', 'd'))); +} + +// Tests using ElementsAreArray() with a container whose iterator returns a +// temporary and is neither copy-constructible nor copy-assignable. +TEST(ElementsAreArrayTest, + WorksWithContainerThatReturnsTempInUncopyableIterator) { + CharString3 s("abc"); + EXPECT_THAT(s, ElementsAreArray({'a', 'b', 'c'})); + EXPECT_THAT(s, Not(ElementsAreArray({'a', 'b', 'd'}))); +} + +// A container whose iterator returns a temporary, is neither +// copy-constructible nor copy-assignable, and has no member types. +class CharString4 { + public: + using value_type = char; + + class const_iterator { + public: + // Do not define difference_type, etc. + + // Make const_iterator neither copy-constructible nor copy-assignable. + const_iterator(const const_iterator&) = delete; + const_iterator& operator=(const const_iterator&) = delete; + + // Create an iterator that points to the given character. + explicit const_iterator(const char* ptr) : ptr_(ptr) {} + + // Returns the current character. IMPORTANT: this must return a temporary, + // not a reference, to test that ElementsAre() works with containers whose + // iterators return temporaries. + char operator*() const { return *ptr_; } + + // Advances to the next character. + const_iterator& operator++() { + ++ptr_; + return *this; + } + + // Compares two iterators. + bool operator==(const const_iterator& other) const { + return ptr_ == other.ptr_; + } + bool operator!=(const const_iterator& other) const { + return ptr_ != other.ptr_; + } + + private: + const char* ptr_ = nullptr; + }; + + // Creates a CharString that contains the given string. + explicit CharString4(const std::string& s) : s_(s) {} + + // Returns an iterator pointing to the first character in the string. + const_iterator begin() const { return const_iterator(s_.c_str()); } + + // Returns an iterator pointing past the last character in the string. + const_iterator end() const { return const_iterator(s_.c_str() + s_.size()); } + + private: + std::string s_; +}; + +// Tests using ElementsAre() with a container whose iterator returns a +// temporary, is neither copy-constructible nor copy-assignable, and has no +// member types. +TEST(ElementsAreTest, WorksWithContainerWithIteratorWithNoMemberTypes) { + CharString4 s("abc"); + EXPECT_THAT(s, ElementsAre('a', 'b', 'c')); + EXPECT_THAT(s, Not(ElementsAre('a', 'b', 'd'))); +} + +// Tests using ElementsAreArray() with a container whose iterator returns a +// temporary, is neither copy-constructible nor copy-assignable, and has no +// member types. +TEST(ElementsAreArrayTest, WorksWithContainerWithIteratorWithNoMemberTypes) { + CharString4 s("abc"); + EXPECT_THAT(s, ElementsAreArray({'a', 'b', 'c'})); + EXPECT_THAT(s, Not(ElementsAreArray({'a', 'b', 'd'}))); +} + // Tests using ElementsAre() and ElementsAreArray() with stream-like // "containers". @@ -2155,7 +2446,7 @@ Matcher<set<int>> m = Each(2); EXPECT_EQ("", Explain(m, a)); - Matcher<const int(&)[1]> n = Each(1); // NOLINT + Matcher<const int (&)[1]> n = Each(1); // NOLINT const int b[1] = {1}; EXPECT_EQ("", Explain(n, b)); @@ -2290,7 +2581,7 @@ rhs.push_back(4); int lhs[] = {1, 2}; - const Matcher<const int(&)[2]> m = Pointwise(IsHalfOf(), rhs); + const Matcher<const int (&)[2]> m = Pointwise(IsHalfOf(), rhs); EXPECT_THAT(lhs, m); // Changing rhs now shouldn't affect m, which made a copy of rhs. @@ -2418,7 +2709,7 @@ rhs.push_back(4); int lhs[] = {2, 1}; - const Matcher<const int(&)[2]> m = UnorderedPointwise(IsHalfOf(), rhs); + const Matcher<const int (&)[2]> m = UnorderedPointwise(IsHalfOf(), rhs); EXPECT_THAT(lhs, m); // Changing rhs now shouldn't affect m, which made a copy of rhs. @@ -2669,11 +2960,11 @@ vector<int> v; v.push_back(2); v.push_back(1); - EXPECT_EQ("whose element #0 doesn't match", Explain(m, v)); + EXPECT_EQ(Explain(m, v), "whose element #0 (2) isn't equal to 1"); v[0] = 1; - EXPECT_EQ("whose element #1 doesn't match, which is 4 less than 5", - Explain(m, v)); + EXPECT_EQ(Explain(m, v), + "whose element #1 (1) is <= 5, which is 4 less than 5"); } TEST(ElementsAreTest, MatchesOneElementVector) { @@ -3073,7 +3364,7 @@ TEST_P(ContainsTestP, ExplainsMatchResultCorrectly) { const int a[2] = {1, 2}; - Matcher<const int(&)[2]> m = Contains(2); + Matcher<const int (&)[2]> m = Contains(2); EXPECT_EQ("whose element #1 matches", Explain(m, a)); m = Contains(3);
diff --git a/third_party/googletest/googletest/CMakeLists.txt b/third_party/googletest/googletest/CMakeLists.txt index dce6a7c..2e53889 100644 --- a/third_party/googletest/googletest/CMakeLists.txt +++ b/third_party/googletest/googletest/CMakeLists.txt
@@ -132,9 +132,6 @@ absl::flags_reflection absl::flags_usage absl::strings - absl::any - absl::optional - absl::variant re2::re2 ) endif()
diff --git a/third_party/googletest/googletest/README.md b/third_party/googletest/googletest/README.md index 5de23c5..26e48d1 100644 --- a/third_party/googletest/googletest/README.md +++ b/third_party/googletest/googletest/README.md
@@ -25,7 +25,7 @@ with ``` -git clone https://github.com/google/googletest.git -b v1.16.0 +git clone https://github.com/google/googletest.git -b v1.17.0 cd googletest # Main directory of the cloned repository. mkdir build # Create a directory to hold the build output. cd build @@ -124,9 +124,9 @@ #### C++ Standard Version -An environment that supports C++14 is required in order to successfully build +An environment that supports C++17 is required in order to successfully build GoogleTest. One way to ensure this is to specify the standard in the top-level -project, for example by using the `set(CMAKE_CXX_STANDARD 14)` command along +project, for example by using the `set(CMAKE_CXX_STANDARD 17)` command along with `set(CMAKE_CXX_STANDARD_REQUIRED ON)`. If this is not feasible, for example in a C project using GoogleTest for validation, then it can be specified by adding it to the options for cmake via the`-DCMAKE_CXX_FLAGS` option. @@ -145,9 +145,9 @@ ### Multi-threaded Tests GoogleTest is thread-safe where the pthread library is available. After -`#include <gtest/gtest.h>`, you can check the -`GTEST_IS_THREADSAFE` macro to see whether this is the case (yes if the macro is -`#defined` to 1, no if it's undefined.). +`#include <gtest/gtest.h>`, you can check the `GTEST_IS_THREADSAFE` macro to see +whether this is the case (yes if the macro is `#defined` to 1, no if it's +undefined.). If GoogleTest doesn't correctly detect whether pthread is available in your environment, you can force it with
diff --git a/third_party/googletest/googletest/include/gtest/gtest-param-test.h b/third_party/googletest/googletest/include/gtest/gtest-param-test.h index dbfc5c8..9e023f9 100644 --- a/third_party/googletest/googletest/include/gtest/gtest-param-test.h +++ b/third_party/googletest/googletest/include/gtest/gtest-param-test.h
@@ -174,6 +174,7 @@ #endif // 0 +#include <functional> #include <iterator> #include <utility> @@ -413,7 +414,8 @@ // Synopsis: // ConvertGenerator<T>(gen) // - returns a generator producing the same elements as generated by gen, but -// each element is static_cast to type T before being returned +// each T-typed element is static_cast to a type deduced from the interface +// that accepts this generator, and then returned // // It is useful when using the Combine() function to get the generated // parameters in a custom type instead of std::tuple @@ -441,10 +443,65 @@ // Combine(Values("cat", "dog"), // Values(BLACK, WHITE)))); // -template <typename T> -internal::ParamConverterGenerator<T> ConvertGenerator( - internal::ParamGenerator<T> gen) { - return internal::ParamConverterGenerator<T>(gen); +template <typename RequestedT> +internal::ParamConverterGenerator<RequestedT> ConvertGenerator( + internal::ParamGenerator<RequestedT> gen) { + return internal::ParamConverterGenerator<RequestedT>(std::move(gen)); +} + +// As above, but takes a callable as a second argument. The callable converts +// the generated parameter to the test fixture's parameter type. This allows you +// to use a parameter type that does not have a converting constructor from the +// generated type. +// +// Example: +// +// This will instantiate tests in test suite AnimalTest each one with +// the parameter values tuple("cat", BLACK), tuple("cat", WHITE), +// tuple("dog", BLACK), and tuple("dog", WHITE): +// +// enum Color { BLACK, GRAY, WHITE }; +// struct ParamType { +// std::string animal; +// Color color; +// }; +// class AnimalTest +// : public testing::TestWithParam<ParamType> {...}; +// +// TEST_P(AnimalTest, AnimalLooksNice) {...} +// +// INSTANTIATE_TEST_SUITE_P( +// AnimalVariations, AnimalTest, +// ConvertGenerator(Combine(Values("cat", "dog"), Values(BLACK, WHITE)), +// [](std::tuple<std::string, Color> t) { +// return ParamType{.animal = std::get<0>(t), +// .color = std::get<1>(t)}; +// })); +// +template <typename T, int&... ExplicitArgumentBarrier, typename Gen, + typename Func, + typename StdFunction = decltype(std::function(std::declval<Func>()))> +internal::ParamConverterGenerator<T, StdFunction> ConvertGenerator(Gen&& gen, + Func&& f) { + return internal::ParamConverterGenerator<T, StdFunction>( + std::forward<Gen>(gen), std::forward<Func>(f)); +} + +// As above, but infers the T from the supplied std::function instead of +// having the caller specify it. +template <int&... ExplicitArgumentBarrier, typename Gen, typename Func, + typename StdFunction = decltype(std::function(std::declval<Func>()))> +auto ConvertGenerator(Gen&& gen, Func&& f) { + constexpr bool is_single_arg_std_function = + internal::IsSingleArgStdFunction<StdFunction>::value; + if constexpr (is_single_arg_std_function) { + return ConvertGenerator< + typename internal::FuncSingleParamType<StdFunction>::type>( + std::forward<Gen>(gen), std::forward<Func>(f)); + } else { + static_assert(is_single_arg_std_function, + "The call signature must contain a single argument."); + } } #define TEST_P(test_suite_name, test_name) \
diff --git a/third_party/googletest/googletest/include/gtest/gtest-printers.h b/third_party/googletest/googletest/include/gtest/gtest-printers.h index 198a769..cb73ef2 100644 --- a/third_party/googletest/googletest/include/gtest/gtest-printers.h +++ b/third_party/googletest/googletest/include/gtest/gtest-printers.h
@@ -104,8 +104,10 @@ #ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ #define GOOGLETEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ +#include <any> #include <functional> #include <memory> +#include <optional> #include <ostream> // NOLINT #include <sstream> #include <string> @@ -113,6 +115,7 @@ #include <type_traits> #include <typeinfo> #include <utility> +#include <variant> #include <vector> #ifdef GTEST_HAS_ABSL @@ -521,11 +524,15 @@ GTEST_API_ void PrintTo(char32_t c, ::std::ostream* os); inline void PrintTo(char16_t c, ::std::ostream* os) { - PrintTo(ImplicitCast_<char32_t>(c), os); + // TODO(b/418738869): Incorrect for values not representing valid codepoints. + // Also see https://github.com/google/googletest/issues/4762. + PrintTo(static_cast<char32_t>(c), os); } #ifdef __cpp_lib_char8_t inline void PrintTo(char8_t c, ::std::ostream* os) { - PrintTo(ImplicitCast_<char32_t>(c), os); + // TODO(b/418738869): Incorrect for values not representing valid codepoints. + // Also see https://github.com/google/googletest/issues/4762. + PrintTo(static_cast<char32_t>(c), os); } #endif @@ -890,14 +897,11 @@ template <typename T> class UniversalPrinter<const T> : public UniversalPrinter<T> {}; -#if GTEST_INTERNAL_HAS_ANY - -// Printer for std::any / absl::any - +// Printer for std::any template <> -class UniversalPrinter<Any> { +class UniversalPrinter<std::any> { public: - static void Print(const Any& value, ::std::ostream* os) { + static void Print(const std::any& value, ::std::ostream* os) { if (value.has_value()) { *os << "value of type " << GetTypeName(value); } else { @@ -906,7 +910,7 @@ } private: - static std::string GetTypeName(const Any& value) { + static std::string GetTypeName(const std::any& value) { #if GTEST_HAS_RTTI return internal::GetTypeName(value.type()); #else @@ -916,16 +920,11 @@ } }; -#endif // GTEST_INTERNAL_HAS_ANY - -#if GTEST_INTERNAL_HAS_OPTIONAL - -// Printer for std::optional / absl::optional - +// Printer for std::optional template <typename T> -class UniversalPrinter<Optional<T>> { +class UniversalPrinter<std::optional<T>> { public: - static void Print(const Optional<T>& value, ::std::ostream* os) { + static void Print(const std::optional<T>& value, ::std::ostream* os) { *os << '('; if (!value) { *os << "nullopt"; @@ -937,29 +936,18 @@ }; template <> -class UniversalPrinter<decltype(Nullopt())> { +class UniversalPrinter<std::nullopt_t> { public: - static void Print(decltype(Nullopt()), ::std::ostream* os) { - *os << "(nullopt)"; - } + static void Print(std::nullopt_t, ::std::ostream* os) { *os << "(nullopt)"; } }; -#endif // GTEST_INTERNAL_HAS_OPTIONAL - -#if GTEST_INTERNAL_HAS_VARIANT - -// Printer for std::variant / absl::variant - +// Printer for std::variant template <typename... T> -class UniversalPrinter<Variant<T...>> { +class UniversalPrinter<std::variant<T...>> { public: - static void Print(const Variant<T...>& value, ::std::ostream* os) { + static void Print(const std::variant<T...>& value, ::std::ostream* os) { *os << '('; -#ifdef GTEST_HAS_ABSL - absl::visit(Visitor{os, value.index()}, value); -#else std::visit(Visitor{os, value.index()}, value); -#endif // GTEST_HAS_ABSL *os << ')'; } @@ -976,8 +964,6 @@ }; }; -#endif // GTEST_INTERNAL_HAS_VARIANT - // UniversalPrintArray(begin, len, os) prints an array of 'len' // elements, starting at address 'begin'. template <typename T>
diff --git a/third_party/googletest/googletest/include/gtest/gtest.h b/third_party/googletest/googletest/include/gtest/gtest.h index 7be0caa..cbe680c 100644 --- a/third_party/googletest/googletest/include/gtest/gtest.h +++ b/third_party/googletest/googletest/include/gtest/gtest.h
@@ -1693,7 +1693,7 @@ // The current parameter value. Is also available in the test fixture's // constructor. - static const ParamType& GetParam() { + [[nodiscard]] static const ParamType& GetParam() { GTEST_CHECK_(parameter_ != nullptr) << "GetParam() can only be called inside a value-parameterized test " << "-- did you intend to write TEST_P instead of TEST_F?";
diff --git a/third_party/googletest/googletest/include/gtest/internal/gtest-internal.h b/third_party/googletest/googletest/include/gtest/internal/gtest-internal.h index dcab397..808d89b 100644 --- a/third_party/googletest/googletest/include/gtest/internal/gtest-internal.h +++ b/third_party/googletest/googletest/include/gtest/internal/gtest-internal.h
@@ -290,17 +290,17 @@ // around may change its bits, although the new value is guaranteed // to be also a NAN. Therefore, don't expect this constructor to // preserve the bits in x when x is a NAN. - explicit FloatingPoint(const RawType& x) { u_.value_ = x; } + explicit FloatingPoint(RawType x) { memcpy(&bits_, &x, sizeof(x)); } // Static methods // Reinterprets a bit pattern as a floating-point number. // // This function is needed to test the AlmostEquals() method. - static RawType ReinterpretBits(const Bits bits) { - FloatingPoint fp(0); - fp.u_.bits_ = bits; - return fp.u_.value_; + static RawType ReinterpretBits(Bits bits) { + RawType fp; + memcpy(&fp, &bits, sizeof(fp)); + return fp; } // Returns the floating-point number that represent positive infinity. @@ -309,16 +309,16 @@ // Non-static methods // Returns the bits that represents this number. - const Bits& bits() const { return u_.bits_; } + const Bits& bits() const { return bits_; } // Returns the exponent bits of this number. - Bits exponent_bits() const { return kExponentBitMask & u_.bits_; } + Bits exponent_bits() const { return kExponentBitMask & bits_; } // Returns the fraction bits of this number. - Bits fraction_bits() const { return kFractionBitMask & u_.bits_; } + Bits fraction_bits() const { return kFractionBitMask & bits_; } // Returns the sign bit of this number. - Bits sign_bit() const { return kSignBitMask & u_.bits_; } + Bits sign_bit() const { return kSignBitMask & bits_; } // Returns true if and only if this is NAN (not a number). bool is_nan() const { @@ -332,23 +332,16 @@ // // - returns false if either number is (or both are) NAN. // - treats really large numbers as almost equal to infinity. - // - thinks +0.0 and -0.0 are 0 DLP's apart. + // - thinks +0.0 and -0.0 are 0 ULP's apart. bool AlmostEquals(const FloatingPoint& rhs) const { // The IEEE standard says that any comparison operation involving // a NAN must return false. if (is_nan() || rhs.is_nan()) return false; - return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_) <= - kMaxUlps; + return DistanceBetweenSignAndMagnitudeNumbers(bits_, rhs.bits_) <= kMaxUlps; } private: - // The data type used to store the actual floating-point number. - union FloatingPointUnion { - RawType value_; // The raw floating-point number. - Bits bits_; // The bits that represent the number. - }; - // Converts an integer from the sign-and-magnitude representation to // the biased representation. More precisely, let N be 2 to the // power of (kBitCount - 1), an integer x is represented by the @@ -364,7 +357,7 @@ // // Read https://en.wikipedia.org/wiki/Signed_number_representations // for more details on signed number representations. - static Bits SignAndMagnitudeToBiased(const Bits& sam) { + static Bits SignAndMagnitudeToBiased(Bits sam) { if (kSignBitMask & sam) { // sam represents a negative number. return ~sam + 1; @@ -376,14 +369,13 @@ // Given two numbers in the sign-and-magnitude representation, // returns the distance between them as an unsigned number. - static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits& sam1, - const Bits& sam2) { + static Bits DistanceBetweenSignAndMagnitudeNumbers(Bits sam1, Bits sam2) { const Bits biased1 = SignAndMagnitudeToBiased(sam1); const Bits biased2 = SignAndMagnitudeToBiased(sam2); return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1); } - FloatingPointUnion u_; + Bits bits_; // The bits that represent the number. }; // Typedefs the instances of the FloatingPoint template class that we
diff --git a/third_party/googletest/googletest/include/gtest/internal/gtest-param-util.h b/third_party/googletest/googletest/include/gtest/internal/gtest-param-util.h index cc7ea53..a092a86 100644 --- a/third_party/googletest/googletest/include/gtest/internal/gtest-param-util.h +++ b/third_party/googletest/googletest/include/gtest/internal/gtest-param-util.h
@@ -39,6 +39,7 @@ #include <ctype.h> #include <cassert> +#include <functional> #include <iterator> #include <map> #include <memory> @@ -529,8 +530,7 @@ // prefix). test_base_name is the name of an individual test without // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is // test suite base name and DoBar is test base name. - void AddTestPattern(const char*, - const char* test_base_name, + void AddTestPattern(const char*, const char* test_base_name, TestMetaFactoryBase<ParamType>* meta_factory, CodeLocation code_location) { tests_.emplace_back( @@ -952,11 +952,11 @@ std::tuple<Gen...> generators_; }; -template <typename From, typename To> +template <typename From, typename To, typename Func> class ParamGeneratorConverter : public ParamGeneratorInterface<To> { public: - ParamGeneratorConverter(ParamGenerator<From> gen) // NOLINT - : generator_(std::move(gen)) {} + ParamGeneratorConverter(ParamGenerator<From> gen, Func converter) // NOLINT + : generator_(std::move(gen)), converter_(std::move(converter)) {} ParamIteratorInterface<To>* Begin() const override { return new Iterator(this, generator_.begin(), generator_.end()); @@ -965,13 +965,21 @@ return new Iterator(this, generator_.end(), generator_.end()); } + // Returns the std::function wrapping the user-supplied converter callable. It + // is used by the iterator (see class Iterator below) to convert the object + // (of type FROM) returned by the ParamGenerator to an object of a type that + // can be static_cast to type TO. + const Func& TypeConverter() const { return converter_; } + private: class Iterator : public ParamIteratorInterface<To> { public: - Iterator(const ParamGeneratorInterface<To>* base, ParamIterator<From> it, + Iterator(const ParamGeneratorConverter* base, ParamIterator<From> it, ParamIterator<From> end) : base_(base), it_(it), end_(end) { - if (it_ != end_) value_ = std::make_shared<To>(static_cast<To>(*it_)); + if (it_ != end_) + value_ = + std::make_shared<To>(static_cast<To>(base->TypeConverter()(*it_))); } ~Iterator() override = default; @@ -980,7 +988,9 @@ } void Advance() override { ++it_; - if (it_ != end_) value_ = std::make_shared<To>(static_cast<To>(*it_)); + if (it_ != end_) + value_ = + std::make_shared<To>(static_cast<To>(base_->TypeConverter()(*it_))); } ParamIteratorInterface<To>* Clone() const override { return new Iterator(*this); @@ -1000,30 +1010,54 @@ private: Iterator(const Iterator& other) = default; - const ParamGeneratorInterface<To>* const base_; + const ParamGeneratorConverter* const base_; ParamIterator<From> it_; ParamIterator<From> end_; std::shared_ptr<To> value_; }; // class ParamGeneratorConverter::Iterator ParamGenerator<From> generator_; + Func converter_; }; // class ParamGeneratorConverter -template <class Gen> +template <class GeneratedT, + typename StdFunction = + std::function<const GeneratedT&(const GeneratedT&)>> class ParamConverterGenerator { public: - ParamConverterGenerator(ParamGenerator<Gen> g) // NOLINT - : generator_(std::move(g)) {} + ParamConverterGenerator(ParamGenerator<GeneratedT> g) // NOLINT + : generator_(std::move(g)), converter_(Identity) {} + + ParamConverterGenerator(ParamGenerator<GeneratedT> g, StdFunction converter) + : generator_(std::move(g)), converter_(std::move(converter)) {} template <typename T> operator ParamGenerator<T>() const { // NOLINT - return ParamGenerator<T>(new ParamGeneratorConverter<Gen, T>(generator_)); + return ParamGenerator<T>( + new ParamGeneratorConverter<GeneratedT, T, StdFunction>(generator_, + converter_)); } private: - ParamGenerator<Gen> generator_; + static const GeneratedT& Identity(const GeneratedT& v) { return v; } + + ParamGenerator<GeneratedT> generator_; + StdFunction converter_; }; +// Template to determine the param type of a single-param std::function. +template <typename T> +struct FuncSingleParamType; +template <typename R, typename P> +struct FuncSingleParamType<std::function<R(P)>> { + using type = std::remove_cv_t<std::remove_reference_t<P>>; +}; + +template <typename T> +struct IsSingleArgStdFunction : public std::false_type {}; +template <typename R, typename P> +struct IsSingleArgStdFunction<std::function<R(P)>> : public std::true_type {}; + } // namespace internal } // namespace testing
diff --git a/third_party/googletest/googletest/include/gtest/internal/gtest-port.h b/third_party/googletest/googletest/include/gtest/internal/gtest-port.h index 4cfc16c..06a5a8e 100644 --- a/third_party/googletest/googletest/include/gtest/internal/gtest-port.h +++ b/third_party/googletest/googletest/include/gtest/internal/gtest-port.h
@@ -198,21 +198,8 @@ // suppressed (constant conditional). // GTEST_INTENTIONAL_CONST_COND_POP_ - finish code section where MSVC C4127 // is suppressed. -// GTEST_INTERNAL_HAS_ANY - for enabling UniversalPrinter<std::any> or -// UniversalPrinter<absl::any> specializations. -// Always defined to 0 or 1. -// GTEST_INTERNAL_HAS_OPTIONAL - for enabling UniversalPrinter<std::optional> -// or -// UniversalPrinter<absl::optional> -// specializations. Always defined to 0 or 1. // GTEST_INTERNAL_HAS_STD_SPAN - for enabling UniversalPrinter<std::span> // specializations. Always defined to 0 or 1 -// GTEST_INTERNAL_HAS_STRING_VIEW - for enabling Matcher<std::string_view> or -// Matcher<absl::string_view> -// specializations. Always defined to 0 or 1. -// GTEST_INTERNAL_HAS_VARIANT - for enabling UniversalPrinter<std::variant> or -// UniversalPrinter<absl::variant> -// specializations. Always defined to 0 or 1. // GTEST_USE_OWN_FLAGFILE_FLAG_ - Always defined to 0 or 1. // GTEST_HAS_CXXABI_H_ - Always defined to 0 or 1. // GTEST_CAN_STREAM_RESULTS_ - Always defined to 0 or 1. @@ -282,10 +269,14 @@ // Detect C++ feature test macros as gracefully as possible. // MSVC >= 19.15, Clang >= 3.4.1, and GCC >= 4.1.2 support feature test macros. -#if GTEST_INTERNAL_CPLUSPLUS_LANG >= 202002L && \ - (!defined(__has_include) || GTEST_INTERNAL_HAS_INCLUDE(<version>)) -#include <version> // C++20 and later -#elif (!defined(__has_include) || GTEST_INTERNAL_HAS_INCLUDE(<ciso646>)) +// +// GCC15 warns that <ciso646> is deprecated in C++17 and suggests using +// <version> instead, even though <version> is not available in C++17 mode prior +// to GCC9. +#if GTEST_INTERNAL_CPLUSPLUS_LANG >= 202002L || \ + GTEST_INTERNAL_HAS_INCLUDE(<version>) +#include <version> // C++20 or <version> support. +#else #include <ciso646> // Pre-C++20 #endif @@ -2331,73 +2322,6 @@ } // namespace internal } // namespace testing -#ifdef GTEST_HAS_ABSL -// Always use absl::any for UniversalPrinter<> specializations if googletest -// is built with absl support. -#define GTEST_INTERNAL_HAS_ANY 1 -#include "absl/types/any.h" -namespace testing { -namespace internal { -using Any = ::absl::any; -} // namespace internal -} // namespace testing -#else -#if defined(__cpp_lib_any) || (GTEST_INTERNAL_HAS_INCLUDE(<any>) && \ - GTEST_INTERNAL_CPLUSPLUS_LANG >= 201703L && \ - (!defined(_MSC_VER) || GTEST_HAS_RTTI)) -// Otherwise for C++17 and higher use std::any for UniversalPrinter<> -// specializations. -#define GTEST_INTERNAL_HAS_ANY 1 -#include <any> -namespace testing { -namespace internal { -using Any = ::std::any; -} // namespace internal -} // namespace testing -// The case where absl is configured NOT to alias std::any is not -// supported. -#endif // __cpp_lib_any -#endif // GTEST_HAS_ABSL - -#ifndef GTEST_INTERNAL_HAS_ANY -#define GTEST_INTERNAL_HAS_ANY 0 -#endif - -#ifdef GTEST_HAS_ABSL -// Always use absl::optional for UniversalPrinter<> specializations if -// googletest is built with absl support. -#define GTEST_INTERNAL_HAS_OPTIONAL 1 -#include "absl/types/optional.h" -namespace testing { -namespace internal { -template <typename T> -using Optional = ::absl::optional<T>; -inline ::absl::nullopt_t Nullopt() { return ::absl::nullopt; } -} // namespace internal -} // namespace testing -#else -#if defined(__cpp_lib_optional) || (GTEST_INTERNAL_HAS_INCLUDE(<optional>) && \ - GTEST_INTERNAL_CPLUSPLUS_LANG >= 201703L) -// Otherwise for C++17 and higher use std::optional for UniversalPrinter<> -// specializations. -#define GTEST_INTERNAL_HAS_OPTIONAL 1 -#include <optional> -namespace testing { -namespace internal { -template <typename T> -using Optional = ::std::optional<T>; -inline ::std::nullopt_t Nullopt() { return ::std::nullopt; } -} // namespace internal -} // namespace testing -// The case where absl is configured NOT to alias std::optional is not -// supported. -#endif // __cpp_lib_optional -#endif // GTEST_HAS_ABSL - -#ifndef GTEST_INTERNAL_HAS_OPTIONAL -#define GTEST_INTERNAL_HAS_OPTIONAL 0 -#endif - #if defined(__cpp_lib_span) || (GTEST_INTERNAL_HAS_INCLUDE(<span>) && \ GTEST_INTERNAL_CPLUSPLUS_LANG >= 202002L) #define GTEST_INTERNAL_HAS_STD_SPAN 1 @@ -2439,38 +2363,6 @@ #define GTEST_INTERNAL_HAS_STRING_VIEW 0 #endif -#ifdef GTEST_HAS_ABSL -// Always use absl::variant for UniversalPrinter<> specializations if googletest -// is built with absl support. -#define GTEST_INTERNAL_HAS_VARIANT 1 -#include "absl/types/variant.h" -namespace testing { -namespace internal { -template <typename... T> -using Variant = ::absl::variant<T...>; -} // namespace internal -} // namespace testing -#else -#if defined(__cpp_lib_variant) || (GTEST_INTERNAL_HAS_INCLUDE(<variant>) && \ - GTEST_INTERNAL_CPLUSPLUS_LANG >= 201703L) -// Otherwise for C++17 and higher use std::variant for UniversalPrinter<> -// specializations. -#define GTEST_INTERNAL_HAS_VARIANT 1 -#include <variant> -namespace testing { -namespace internal { -template <typename... T> -using Variant = ::std::variant<T...>; -} // namespace internal -} // namespace testing -// The case where absl is configured NOT to alias std::variant is not supported. -#endif // __cpp_lib_variant -#endif // GTEST_HAS_ABSL - -#ifndef GTEST_INTERNAL_HAS_VARIANT -#define GTEST_INTERNAL_HAS_VARIANT 0 -#endif - #if (defined(__cpp_lib_three_way_comparison) || \ (GTEST_INTERNAL_HAS_INCLUDE(<compare>) && \ GTEST_INTERNAL_CPLUSPLUS_LANG >= 201907L))
diff --git a/third_party/googletest/googletest/src/gtest-internal-inl.h b/third_party/googletest/googletest/src/gtest-internal-inl.h index cc6f004..6a39b93 100644 --- a/third_party/googletest/googletest/src/gtest-internal-inl.h +++ b/third_party/googletest/googletest/src/gtest-internal-inl.h
@@ -826,6 +826,10 @@ bool catch_exceptions() const { return catch_exceptions_; } private: + // Returns true if a warning should be issued if no tests match the test + // filter flag. + bool ShouldWarnIfNoTestsMatchFilter() const; + struct CompareTestSuitesByPointer { bool operator()(const TestSuite* lhs, const TestSuite* rhs) const { return lhs->name_ < rhs->name_;
diff --git a/third_party/googletest/googletest/src/gtest.cc b/third_party/googletest/googletest/src/gtest.cc index 81096ae..09af151 100644 --- a/third_party/googletest/googletest/src/gtest.cc +++ b/third_party/googletest/googletest/src/gtest.cc
@@ -192,12 +192,17 @@ // The default output file. static const char kDefaultOutputFile[] = "test_detail"; +// These environment variables are set by Bazel. +// https://bazel.build/reference/test-encyclopedia#initial-conditions +// // The environment variable name for the test shard index. static const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; // The environment variable name for the total number of test shards. static const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS"; // The environment variable name for the test shard status file. static const char kTestShardStatusFile[] = "GTEST_SHARD_STATUS_FILE"; +// The environment variable name for the test output warnings file. +static const char kTestWarningsOutputFile[] = "TEST_WARNINGS_OUTPUT_FILE"; namespace internal { @@ -5875,6 +5880,23 @@ static void SetUpEnvironment(Environment* env) { env->SetUp(); } static void TearDownEnvironment(Environment* env) { env->TearDown(); } +// If the environment variable TEST_WARNINGS_OUTPUT_FILE was provided, appends +// `str` to the file, creating the file if necessary. +#if GTEST_HAS_FILE_SYSTEM +static void AppendToTestWarningsOutputFile(const std::string& str) { + const char* const filename = posix::GetEnv(kTestWarningsOutputFile); + if (filename == nullptr) { + return; + } + auto* const file = posix::FOpen(filename, "a"); + if (file == nullptr) { + return; + } + GTEST_CHECK_(fwrite(str.data(), 1, str.size(), file) == str.size()); + GTEST_CHECK_(posix::FClose(file) == 0); +} +#endif // GTEST_HAS_FILE_SYSTEM + // Runs all tests in this UnitTest object, prints the result, and // returns true if all tests are successful. If any exception is // thrown during a test, the test is considered to be failed, but the @@ -5896,12 +5918,26 @@ // user didn't call InitGoogleTest. PostFlagParsingInit(); - if (GTEST_FLAG_GET(fail_if_no_test_linked) && total_test_count() == 0) { + // Handle the case where the program has no tests linked. + // Sometimes this is a programmer mistake, but sometimes it is intended. + if (total_test_count() == 0) { + constexpr char kNoTestLinkedMessage[] = + "This test program does NOT link in any test case."; + constexpr char kNoTestLinkedFatal[] = + "This is INVALID. Please make sure to link in at least one test case."; + constexpr char kNoTestLinkedWarning[] = + "Please make sure this is intended."; + const bool fail_if_no_test_linked = GTEST_FLAG_GET(fail_if_no_test_linked); ColoredPrintf( - GTestColor::kRed, - "This test program does NOT link in any test case. This is INVALID. " - "Please make sure to link in at least one test case.\n"); - return false; + GTestColor::kRed, "%s %s\n", kNoTestLinkedMessage, + fail_if_no_test_linked ? kNoTestLinkedFatal : kNoTestLinkedWarning); + if (fail_if_no_test_linked) { + return false; + } +#if GTEST_HAS_FILE_SYSTEM + AppendToTestWarningsOutputFile(std::string(kNoTestLinkedMessage) + ' ' + + kNoTestLinkedWarning + '\n'); +#endif // GTEST_HAS_FILE_SYSTEM } #if GTEST_HAS_FILE_SYSTEM @@ -6077,6 +6113,17 @@ environments_.clear(); } + // Try to warn the user if no tests matched the test filter. + if (ShouldWarnIfNoTestsMatchFilter()) { + const std::string filter_warning = + std::string("filter \"") + GTEST_FLAG_GET(filter) + + "\" did not match any test; no tests were run\n"; + ColoredPrintf(GTestColor::kRed, "WARNING: %s", filter_warning.c_str()); +#if GTEST_HAS_FILE_SYSTEM + AppendToTestWarningsOutputFile(filter_warning); +#endif // GTEST_HAS_FILE_SYSTEM + } + if (!gtest_is_initialized_before_run_all_tests) { ColoredPrintf( GTestColor::kRed, @@ -6245,6 +6292,30 @@ return num_selected_tests; } +// Returns true if a warning should be issued if no tests match the test filter +// flag. We can't simply count the number of tests that ran because, for +// instance, test sharding and death tests might mean no tests are expected to +// run in this process, but will run in another process. +bool UnitTestImpl::ShouldWarnIfNoTestsMatchFilter() const { + if (total_test_count() == 0) { + // No tests were linked in to program. + // This case is handled by a different warning. + return false; + } + const PositiveAndNegativeUnitTestFilter gtest_flag_filter( + GTEST_FLAG_GET(filter)); + for (auto* test_suite : test_suites_) { + const std::string& test_suite_name = test_suite->name_; + for (TestInfo* test_info : test_suite->test_info_list()) { + const std::string& test_name = test_info->name_; + if (gtest_flag_filter.MatchesTest(test_suite_name, test_name)) { + return false; + } + } + } + return true; +} + // Prints the given C-string on a single line by replacing all '\n' // characters with string "\\n". If the output takes more than // max_length characters, only prints the first max_length characters
diff --git a/third_party/googletest/googletest/test/googletest-fail-if-no-test-linked-test.py b/third_party/googletest/googletest/test/googletest-fail-if-no-test-linked-test.py index 3ecf208..f5854ba 100755 --- a/third_party/googletest/googletest/test/googletest-fail-if-no-test-linked-test.py +++ b/third_party/googletest/googletest/test/googletest-fail-if-no-test-linked-test.py
@@ -31,21 +31,26 @@ """Tests for Google Test's --gtest_fail_if_no_test_linked flag.""" +import os from googletest.test import gtest_test_utils # The command line flag for enabling the fail-if-no-test-linked behavior. FAIL_IF_NO_TEST_LINKED_FLAG = "gtest_fail_if_no_test_linked" +# The environment variable for the test output warnings file. +TEST_WARNINGS_OUTPUT_FILE = "TEST_WARNINGS_OUTPUT_FILE" + class GTestFailIfNoTestLinkedTest(gtest_test_utils.TestCase): """Tests the --gtest_fail_if_no_test_linked flag.""" - def Run(self, program_name, flag=None): + def Run(self, program_name, flag=None, env=None): """Run the given program with the given flag. Args: program_name: Name of the program to run. flag: The command line flag to pass to the program, or None. + env: Dictionary with environment to pass to the subprocess. Returns: True if the program exits with code 0, false otherwise. @@ -55,59 +60,109 @@ args = [exe_path] if flag is not None: args += [flag] - process = gtest_test_utils.Subprocess(args, capture_stderr=False) + process = gtest_test_utils.Subprocess(args, capture_stderr=False, env=env) return process.exited and process.exit_code == 0 def testSucceedsIfNoTestLinkedAndFlagNotSpecified(self): """Tests the behavior of no test linked and flag not specified.""" - self.assertTrue( self.Run("googletest-fail-if-no-test-linked-test-without-test_") ) + def testSucceedsIfNoTestLinkedAndFlagNotSpecifiedWithWarningFile(self): + """Tests that no test linked results in warning file output.""" + + warning_file = os.path.join(gtest_test_utils.GetTempDir(), "NO_TEST_LINKED") + self.assertTrue( + self.Run( + "googletest-fail-if-no-test-linked-test-without-test_", + env={TEST_WARNINGS_OUTPUT_FILE: warning_file}, + ) + ) + warning_file_contents = open(warning_file, "r").read() + self.assertEqual( + warning_file_contents, + "This test program does NOT link in any test case. Please make sure" + " this is intended.\n", + ) + def testFailsIfNoTestLinkedAndFlagSpecified(self): """Tests the behavior of no test linked and flag specified.""" + warning_file = os.path.join( + gtest_test_utils.GetTempDir(), "SHOULD_NOT_EXIST" + ) self.assertFalse( self.Run( "googletest-fail-if-no-test-linked-test-without-test_", f"--{FAIL_IF_NO_TEST_LINKED_FLAG}", + env={TEST_WARNINGS_OUTPUT_FILE: warning_file}, ) ) + with self.assertRaises(FileNotFoundError): + open(warning_file, "r") def testSucceedsIfEnabledTestLinkedAndFlagNotSpecified(self): """Tests the behavior of enabled test linked and flag not specified.""" - self.assertTrue( - self.Run("googletest-fail-if-no-test-linked-test-with-enabled-test_") + warning_file = os.path.join( + gtest_test_utils.GetTempDir(), "SHOULD_NOT_EXIST" ) + self.assertTrue( + self.Run( + "googletest-fail-if-no-test-linked-test-with-enabled-test_", + env={TEST_WARNINGS_OUTPUT_FILE: warning_file}, + ) + ) + with self.assertRaises(FileNotFoundError): + open(warning_file, "r") def testSucceedsIfEnabledTestLinkedAndFlagSpecified(self): """Tests the behavior of enabled test linked and flag specified.""" + warning_file = os.path.join( + gtest_test_utils.GetTempDir(), "SHOULD_NOT_EXIST" + ) self.assertTrue( self.Run( "googletest-fail-if-no-test-linked-test-with-enabled-test_", f"--{FAIL_IF_NO_TEST_LINKED_FLAG}", + env={TEST_WARNINGS_OUTPUT_FILE: warning_file}, ) ) + with self.assertRaises(FileNotFoundError): + open(warning_file, "r") def testSucceedsIfDisabledTestLinkedAndFlagNotSpecified(self): """Tests the behavior of disabled test linked and flag not specified.""" - self.assertTrue( - self.Run("googletest-fail-if-no-test-linked-test-with-disabled-test_") + warning_file = os.path.join( + gtest_test_utils.GetTempDir(), "SHOULD_NOT_EXIST" ) + self.assertTrue( + self.Run( + "googletest-fail-if-no-test-linked-test-with-disabled-test_", + env={TEST_WARNINGS_OUTPUT_FILE: warning_file}, + ) + ) + with self.assertRaises(FileNotFoundError): + open(warning_file, "r") def testSucceedsIfDisabledTestLinkedAndFlagSpecified(self): """Tests the behavior of disabled test linked and flag specified.""" + warning_file = os.path.join( + gtest_test_utils.GetTempDir(), "SHOULD_NOT_EXIST" + ) self.assertTrue( self.Run( "googletest-fail-if-no-test-linked-test-with-disabled-test_", f"--{FAIL_IF_NO_TEST_LINKED_FLAG}", + env={TEST_WARNINGS_OUTPUT_FILE: warning_file}, ) ) + with self.assertRaises(FileNotFoundError): + open(warning_file, "r") if __name__ == "__main__":
diff --git a/third_party/googletest/googletest/test/googletest-filter-unittest.py b/third_party/googletest/googletest/test/googletest-filter-unittest.py index f1f3c7a..a44882a 100755 --- a/third_party/googletest/googletest/test/googletest-filter-unittest.py +++ b/third_party/googletest/googletest/test/googletest-filter-unittest.py
@@ -97,6 +97,9 @@ SHARD_INDEX_ENV_VAR = 'GTEST_SHARD_INDEX' SHARD_STATUS_FILE_ENV_VAR = 'GTEST_SHARD_STATUS_FILE' +# The environment variable for the test warnings output file. +TEST_WARNINGS_OUTPUT_FILE = 'TEST_WARNINGS_OUTPUT_FILE' + # The command line flag for specifying the test filters. FILTER_FLAG = 'gtest_filter' @@ -419,6 +422,22 @@ self.RunAndVerify('BadFilter', []) self.RunAndVerifyAllowingDisabled('BadFilter', []) + def testBadFilterWithWarningFile(self): + """Tests the warning file when a filter that matches nothing.""" + + warning_file = os.path.join( + gtest_test_utils.GetTempDir(), 'testBadFilterWithWarningFile' + ) + extra_env = {TEST_WARNINGS_OUTPUT_FILE: warning_file} + args = ['--%s=%s' % (FILTER_FLAG, 'BadFilter')] + InvokeWithModifiedEnv(extra_env, RunAndReturnOutput, args) + with open(warning_file, 'r') as f: + warning_file_contents = f.read() + self.assertEqual( + warning_file_contents, + 'filter "BadFilter" did not match any test; no tests were run\n', + ) + def testFullName(self): """Tests filtering by full name."""
diff --git a/third_party/googletest/googletest/test/googletest-param-test-test.cc b/third_party/googletest/googletest/test/googletest-param-test-test.cc index c9c5e78..fab977e 100644 --- a/third_party/googletest/googletest/test/googletest-param-test-test.cc +++ b/third_party/googletest/googletest/test/googletest-param-test-test.cc
@@ -35,12 +35,17 @@ #include "test/googletest-param-test-test.h" #include <algorithm> +#include <cstddef> +#include <cstdint> +#include <functional> #include <iostream> #include <list> #include <set> #include <sstream> #include <string> +#include <string_view> #include <tuple> +#include <type_traits> #include <vector> #include "gtest/gtest.h" @@ -583,6 +588,71 @@ EXPECT_TRUE(it == gen.end()); } +TEST(ConvertTest, WithConverterLambdaAndDeducedType) { + const ParamGenerator<ConstructFromT<int8_t>> gen = + ConvertGenerator(Values("0", std::string("1")), [](const std::string& s) { + size_t pos; + int64_t value = std::stoll(s, &pos); + EXPECT_EQ(pos, s.size()); + return value; + }); + + ConstructFromT<int8_t> expected_values[] = {ConstructFromT<int8_t>(0), + ConstructFromT<int8_t>(1)}; + VerifyGenerator(gen, expected_values); +} + +TEST(ConvertTest, WithConverterLambdaAndExplicitType) { + auto convert_generator = ConvertGenerator<std::string>( + Values("0", std::string("1")), [](std::string_view s) { + size_t pos; + int64_t value = std::stoll(std::string(s), &pos); + EXPECT_EQ(pos, s.size()); + return value; + }); + constexpr bool is_correct_type = std::is_same_v< + decltype(convert_generator), + testing::internal::ParamConverterGenerator< + std::string, std::function<int64_t(std::string_view)>>>; + EXPECT_TRUE(is_correct_type); + const ParamGenerator<ConstructFromT<int8_t>> gen = convert_generator; + + ConstructFromT<int8_t> expected_values[] = {ConstructFromT<int8_t>(0), + ConstructFromT<int8_t>(1)}; + VerifyGenerator(gen, expected_values); +} + +TEST(ConvertTest, WithConverterFunctionPointer) { + int64_t (*func_ptr)(const std::string&) = [](const std::string& s) { + size_t pos; + int64_t value = std::stoll(s, &pos); + EXPECT_EQ(pos, s.size()); + return value; + }; + const ParamGenerator<ConstructFromT<int8_t>> gen = + ConvertGenerator(Values("0", std::string("1")), func_ptr); + + ConstructFromT<int8_t> expected_values[] = {ConstructFromT<int8_t>(0), + ConstructFromT<int8_t>(1)}; + VerifyGenerator(gen, expected_values); +} + +TEST(ConvertTest, WithConverterFunctionReference) { + int64_t (*func_ptr)(const std::string&) = [](const std::string& s) { + size_t pos; + int64_t value = std::stoll(s, &pos); + EXPECT_EQ(pos, s.size()); + return value; + }; + int64_t (&func_ref)(const std::string&) = *func_ptr; + const ParamGenerator<ConstructFromT<int8_t>> gen = + ConvertGenerator(Values("0", std::string("1")), func_ref); + + ConstructFromT<int8_t> expected_values[] = {ConstructFromT<int8_t>(0), + ConstructFromT<int8_t>(1)}; + VerifyGenerator(gen, expected_values); +} + // Tests that an generator produces correct sequence after being // assigned from another generator. TEST(ParamGeneratorTest, AssignmentWorks) { @@ -1104,7 +1174,7 @@ class ParameterizedDeathTest : public ::testing::TestWithParam<int> {}; TEST_F(ParameterizedDeathTest, GetParamDiesFromTestF) { - EXPECT_DEATH_IF_SUPPORTED(GetParam(), ".* value-parameterized test .*"); + EXPECT_DEATH_IF_SUPPORTED((void)GetParam(), ".* value-parameterized test .*"); } INSTANTIATE_TEST_SUITE_P(RangeZeroToFive, ParameterizedDerivedTest,
diff --git a/third_party/googletest/googletest/test/googletest-printers-test.cc b/third_party/googletest/googletest/test/googletest-printers-test.cc index 52b2c49..a016e8a 100644 --- a/third_party/googletest/googletest/test/googletest-printers-test.cc +++ b/third_party/googletest/googletest/test/googletest-printers-test.cc
@@ -32,6 +32,7 @@ // This file tests the universal value printer. #include <algorithm> +#include <any> #include <cctype> #include <cstdint> #include <cstring> @@ -42,6 +43,7 @@ #include <list> #include <map> #include <memory> +#include <optional> #include <ostream> #include <set> #include <sstream> @@ -50,6 +52,7 @@ #include <unordered_map> #include <unordered_set> #include <utility> +#include <variant> #include <vector> #include "gtest/gtest-printers.h" @@ -1920,7 +1923,6 @@ EXPECT_EQ("\"a\"", result[1]); } -#if GTEST_INTERNAL_HAS_ANY class PrintAnyTest : public ::testing::Test { protected: template <typename T> @@ -1934,12 +1936,12 @@ }; TEST_F(PrintAnyTest, Empty) { - internal::Any any; + std::any any; EXPECT_EQ("no value", PrintToString(any)); } TEST_F(PrintAnyTest, NonEmpty) { - internal::Any any; + std::any any; constexpr int val1 = 10; const std::string val2 = "content"; @@ -1950,27 +1952,23 @@ EXPECT_EQ("value of type " + ExpectedTypeName<std::string>(), PrintToString(any)); } -#endif // GTEST_INTERNAL_HAS_ANY -#if GTEST_INTERNAL_HAS_OPTIONAL TEST(PrintOptionalTest, Basic) { - EXPECT_EQ("(nullopt)", PrintToString(internal::Nullopt())); - internal::Optional<int> value; + EXPECT_EQ("(nullopt)", PrintToString(std::nullopt)); + std::optional<int> value; EXPECT_EQ("(nullopt)", PrintToString(value)); value = {7}; EXPECT_EQ("(7)", PrintToString(value)); - EXPECT_EQ("(1.1)", PrintToString(internal::Optional<double>{1.1})); - EXPECT_EQ("(\"A\")", PrintToString(internal::Optional<std::string>{"A"})); + EXPECT_EQ("(1.1)", PrintToString(std::optional<double>{1.1})); + EXPECT_EQ("(\"A\")", PrintToString(std::optional<std::string>{"A"})); } -#endif // GTEST_INTERNAL_HAS_OPTIONAL -#if GTEST_INTERNAL_HAS_VARIANT struct NonPrintable { unsigned char contents = 17; }; TEST(PrintOneofTest, Basic) { - using Type = internal::Variant<int, StreamableInGlobal, NonPrintable>; + using Type = std::variant<int, StreamableInGlobal, NonPrintable>; EXPECT_EQ("('int(index = 0)' with value 7)", PrintToString(Type(7))); EXPECT_EQ("('StreamableInGlobal(index = 1)' with value StreamableInGlobal)", PrintToString(Type(StreamableInGlobal{}))); @@ -1979,7 +1977,6 @@ "1-byte object <11>)", PrintToString(Type(NonPrintable{}))); } -#endif // GTEST_INTERNAL_HAS_VARIANT #if GTEST_INTERNAL_HAS_COMPARE_LIB TEST(PrintOrderingTest, Basic) {
diff --git a/third_party/googletest/googletest_deps.bzl b/third_party/googletest/googletest_deps.bzl index d3dd03e..9eb7270 100644 --- a/third_party/googletest/googletest_deps.bzl +++ b/third_party/googletest/googletest_deps.bzl
@@ -17,9 +17,9 @@ if not native.existing_rule("abseil-cpp"): http_archive( name = "abseil-cpp", - sha256 = "16242f394245627e508ec6bb296b433c90f8d914f73b9c026fddb905e27276e8", - strip_prefix = "abseil-cpp-20250127.0", - urls = ["https://github.com/abseil/abseil-cpp/releases/download/20250127.0/abseil-cpp-20250127.0.tar.gz"], + sha256 = "7262daa7c1711406248c10f41026d685e88223bc92817d16fb93c19adb57f669", + strip_prefix = "abseil-cpp-20250512.0", + urls = ["https://github.com/abseil/abseil-cpp/releases/download/20250512.0/abseil-cpp-20250512.0.tar.gz"], ) if not native.existing_rule("fuchsia_sdk"):