diff options
| author | Enji Cooper <ngie@FreeBSD.org> | 2025-09-26 07:39:07 +0000 |
|---|---|---|
| committer | Enji Cooper <ngie@FreeBSD.org> | 2025-09-26 07:39:47 +0000 |
| commit | 3a4c29b5bed4ea20266ad9371fbfdc6bca088f92 (patch) | |
| tree | d8522255b63fc7f4d7183cdaf04e194d7620366f | |
| parent | 14f7077fed7d82046bdcbe347004132f08aba886 (diff) | |
61 files changed, 2684 insertions, 916 deletions
diff --git a/.github/workflows/gtest-ci.yml b/.github/workflows/gtest-ci.yml deleted file mode 100644 index 03a8cc5e287b..000000000000 --- a/.github/workflows/gtest-ci.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: ci - -on: - push: - pull_request: - -env: - BAZEL_CXXOPTS: -std=c++14 - -jobs: - Linux: - runs-on: ubuntu-latest - steps: - - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Tests - run: bazel test --cxxopt=-std=c++14 --features=external_include_paths --test_output=errors ... - - macOS: - runs-on: macos-latest - steps: - - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Tests - run: bazel test --cxxopt=-std=c++14 --features=external_include_paths --test_output=errors ... - - - Windows: - runs-on: windows-latest - steps: - - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Tests - run: bazel test --cxxopt=/std:c++14 --features=external_include_paths --test_output=errors ... diff --git a/.gitignore b/.gitignore index fede02f65093..f0df39db1d7e 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ bazel-genfiles bazel-googletest bazel-out bazel-testlogs +MODULE.bazel.lock # python *.pyc diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 4e7413a4f9a3..000000000000 --- a/.travis.yml +++ /dev/null @@ -1,81 +0,0 @@ -# Build matrix / environment variable are explained on: -# https://docs.travis-ci.com/user/customizing-the-build/ -# This file can be validated on: -# http://lint.travis-ci.org/ - -sudo: false -language: cpp - -# Define the matrix explicitly, manually expanding the combinations of (os, compiler, env). -# It is more tedious, but grants us far more flexibility. -matrix: - include: - - os: linux - compiler: gcc - sudo : true - install: ./ci/install-linux.sh && ./ci/log-config.sh - script: ./ci/build-linux-bazel.sh - - os: linux - compiler: clang - sudo : true - install: ./ci/install-linux.sh && ./ci/log-config.sh - script: ./ci/build-linux-bazel.sh - - os: linux - group: deprecated-2017Q4 - compiler: gcc - install: ./ci/install-linux.sh && ./ci/log-config.sh - script: ./ci/build-linux-autotools.sh - - os: linux - group: deprecated-2017Q4 - compiler: gcc - env: BUILD_TYPE=Debug VERBOSE=1 CXX_FLAGS=-std=c++11 - - os: linux - group: deprecated-2017Q4 - compiler: clang - env: BUILD_TYPE=Debug VERBOSE=1 - - os: linux - group: deprecated-2017Q4 - compiler: clang - env: BUILD_TYPE=Release VERBOSE=1 CXX_FLAGS=-std=c++11 - - os: linux - compiler: clang - env: BUILD_TYPE=Release VERBOSE=1 CXX_FLAGS=-std=c++11 NO_EXCEPTION=ON NO_RTTI=ON COMPILER_IS_GNUCXX=ON - - os: osx - compiler: gcc - env: BUILD_TYPE=Debug VERBOSE=1 - - os: osx - compiler: gcc - env: BUILD_TYPE=Release VERBOSE=1 CXX_FLAGS=-std=c++11 - - os: osx - compiler: clang - env: BUILD_TYPE=Debug VERBOSE=1 - if: type != pull_request - - os: osx - env: BUILD_TYPE=Release VERBOSE=1 CXX_FLAGS=-std=c++11 - if: type != pull_request - -# These are the install and build (script) phases for the most common entries in the matrix. They could be included -# in each entry in the matrix, but that is just repetitive. -install: - - ./ci/install-${TRAVIS_OS_NAME}.sh - - . ./ci/env-${TRAVIS_OS_NAME}.sh - - ./ci/log-config.sh - -script: ./ci/travis.sh - -# For sudo=false builds this section installs the necessary dependencies. -addons: - apt: - # List of whitelisted in travis packages for ubuntu-precise can be found here: - # https://github.com/travis-ci/apt-package-whitelist/blob/master/ubuntu-precise - # List of whitelisted in travis apt-sources: - # https://github.com/travis-ci/apt-source-whitelist/blob/master/ubuntu.json - sources: - - ubuntu-toolchain-r-test - - llvm-toolchain-precise-3.9 - packages: - - g++-4.9 - - clang-3.9 - -notifications: - email: false diff --git a/BUILD.bazel b/BUILD.bazel index e407ae29f44c..53501454ce4f 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -83,6 +83,10 @@ cc_library( ) # 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( @@ -138,19 +142,19 @@ cc_library( }), deps = select({ ":has_absl": [ - "@com_google_absl//absl/container:flat_hash_set", - "@com_google_absl//absl/debugging:failure_signal_handler", - "@com_google_absl//absl/debugging:stacktrace", - "@com_google_absl//absl/debugging:symbolize", - "@com_google_absl//absl/flags:flag", - "@com_google_absl//absl/flags:parse", - "@com_google_absl//absl/flags:reflection", - "@com_google_absl//absl/flags:usage", - "@com_google_absl//absl/strings", - "@com_google_absl//absl/types:any", - "@com_google_absl//absl/types:optional", - "@com_google_absl//absl/types:variant", - "@com_googlesource_code_re2//:re2", + "@abseil-cpp//absl/container:flat_hash_set", + "@abseil-cpp//absl/debugging:failure_signal_handler", + "@abseil-cpp//absl/debugging:stacktrace", + "@abseil-cpp//absl/debugging:symbolize", + "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/flags:parse", + "@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", ], "//conditions:default": [], }) + select({ @@ -167,6 +171,16 @@ cc_library( }), ) +# `gtest`, but testonly. See guidance on `gtest` for when to use this. +alias( + name = "gtest_for_library", + actual = ":gtest", + testonly = True, +) + +# 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/CMakeLists.txt b/CMakeLists.txt index 512e5c3d480f..0567ae7daa32 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,10 @@ # Note: CMake support is community-based. The maintainers do not use CMake # internally. -cmake_minimum_required(VERSION 3.13) +cmake_minimum_required(VERSION 3.16) project(googletest-distribution) -set(GOOGLETEST_VERSION 1.15.2) +set(GOOGLETEST_VERSION 1.17.0) if(NOT CYGWIN AND NOT MSYS AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL QNX) set(CMAKE_CXX_EXTENSIONS OFF) diff --git a/MODULE.bazel b/MODULE.bazel index 61d5e2223512..5cb0b156f40c 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -32,38 +32,45 @@ module( name = "googletest", - version = "1.15.2", + version = "1.17.0", compatibility_level = 1, ) # Only direct dependencies need to be listed below. # Please keep the versions in sync with the versions in the WORKSPACE file. -bazel_dep(name = "abseil-cpp", - version = "20240116.2", - repo_name = "com_google_absl") - -bazel_dep(name = "platforms", - version = "0.0.10") - -bazel_dep(name = "re2", - repo_name = "com_googlesource_code_re2", - version = "2024-07-02") +bazel_dep( + name = "abseil-cpp", + version = "20250127.1", +) +bazel_dep( + name = "platforms", + version = "0.0.11", +) +bazel_dep( + name = "re2", + version = "2024-07-02.bcr.1", +) -bazel_dep(name = "rules_python", - version = "0.34.0", - dev_dependency = True) +bazel_dep( + name = "rules_python", + version = "1.3.0", + dev_dependency = True, +) # https://rules-python.readthedocs.io/en/stable/toolchains.html#library-modules-with-dev-only-python-usage python = use_extension( "@rules_python//python/extensions:python.bzl", "python", - dev_dependency = True + dev_dependency = True, +) +python.toolchain( + ignore_root_user_error = True, + is_default = True, + python_version = "3.12", ) -python.toolchain(python_version = "3.12", - is_default = True, - ignore_root_user_error = True) - -fake_fuchsia_sdk = use_repo_rule("//:fake_fuchsia_sdk.bzl", "fake_fuchsia_sdk") -fake_fuchsia_sdk(name = "fuchsia_sdk") +# See fake_fuchsia_sdk.bzl for instructions on how to override this with a real SDK, if needed. +fuchsia_sdk = use_extension("//:fake_fuchsia_sdk.bzl", "fuchsia_sdk") +fuchsia_sdk.create_fake() +use_repo(fuchsia_sdk, "fuchsia_sdk") diff --git a/README.md b/README.md index f50c670534d5..598cf31242b7 100644 --- a/README.md +++ b/README.md @@ -2,27 +2,18 @@ ### 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.15.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.15.0 +#### Release 1.17.0 -[Release 1.15.0](https://github.com/google/googletest/releases/tag/v1.15.0) is +[Release 1.17.0](https://github.com/google/googletest/releases/tag/v1.17.0) is now available. -The 1.15.x branch requires at least C++14. +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/WORKSPACE b/WORKSPACE index 218e6c2e8c2b..0ae5dee92baf 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -1,4 +1,34 @@ -workspace(name = "com_google_googletest") +# Copyright 2024 Google Inc. +# All Rights Reserved. +# +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +workspace(name = "googletest") load("//:googletest_deps.bzl", "googletest_deps") googletest_deps() @@ -6,13 +36,12 @@ googletest_deps() load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( - name = "rules_python", - sha256 = "d71d2c67e0bce986e1c5a7731b4693226867c45bfe0b7c5e0067228a536fc580", - strip_prefix = "rules_python-0.29.0", - urls = ["https://github.com/bazelbuild/rules_python/releases/download/0.29.0/rules_python-0.29.0.tar.gz"], + name = "rules_python", + 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/0.29.0 +# https://github.com/bazelbuild/rules_python/releases/tag/1.1.0 load("@rules_python//python:repositories.bzl", "py_repositories") py_repositories() @@ -25,8 +54,8 @@ http_archive( 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/ci/linux-presubmit.sh b/ci/linux-presubmit.sh index 6d2b3fb573a0..6491e79844b8 100644 --- a/ci/linux-presubmit.sh +++ b/ci/linux-presubmit.sh @@ -31,51 +31,68 @@ set -euox pipefail -readonly LINUX_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20240523" -readonly LINUX_GCC_FLOOR_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-floor:20230120" +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" if [[ -z ${GTEST_ROOT:-} ]]; then GTEST_ROOT="$(realpath $(dirname ${0})/..)" fi if [[ -z ${STD:-} ]]; then - STD="c++14 c++17 c++20" + STD="c++17 c++20" fi -# Test the CMake build -for cc in /usr/local/bin/gcc /opt/llvm/clang/bin/clang; do - for cmake_off_on in OFF ON; do - time docker run \ - --volume="${GTEST_ROOT}:/src:ro" \ - --tmpfs="/build:exec" \ - --workdir="/build" \ - --rm \ - --env="CC=${cc}" \ - --env=CXXFLAGS="-Werror -Wdeprecated" \ - ${LINUX_LATEST_CONTAINER} \ - /bin/bash -c " - cmake /src \ - -DCMAKE_CXX_STANDARD=14 \ - -Dgtest_build_samples=ON \ - -Dgtest_build_tests=ON \ - -Dgmock_build_tests=ON \ - -Dcxx_no_exception=${cmake_off_on} \ - -Dcxx_no_rtti=${cmake_off_on} && \ - make -j$(nproc) && \ - ctest -j$(nproc) --output-on-failure" - done +# Test CMake + GCC +for cmake_off_on in OFF ON; do + time docker run \ + --volume="${GTEST_ROOT}:/src:ro" \ + --tmpfs="/build:exec" \ + --workdir="/build" \ + --rm \ + --env="CC=/usr/local/bin/gcc" \ + --env=CXXFLAGS="-Werror -Wdeprecated" \ + ${LINUX_LATEST_CONTAINER} \ + /bin/bash -c " + cmake /src \ + -DCMAKE_CXX_STANDARD=17 \ + -Dgtest_build_samples=ON \ + -Dgtest_build_tests=ON \ + -Dgmock_build_tests=ON \ + -Dcxx_no_exception=${cmake_off_on} \ + -Dcxx_no_rtti=${cmake_off_on} && \ + make -j$(nproc) && \ + ctest -j$(nproc) --output-on-failure" +done + +# Test CMake + Clang +for cmake_off_on in OFF ON; do + time docker run \ + --volume="${GTEST_ROOT}:/src:ro" \ + --tmpfs="/build:exec" \ + --workdir="/build" \ + --rm \ + --env="CC=/opt/llvm/clang/bin/clang" \ + --env=CXXFLAGS="-Werror -Wdeprecated --gcc-toolchain=/usr/local" \ + ${LINUX_LATEST_CONTAINER} \ + /bin/bash -c " + cmake /src \ + -DCMAKE_CXX_STANDARD=17 \ + -Dgtest_build_samples=ON \ + -Dgtest_build_tests=ON \ + -Dgmock_build_tests=ON \ + -Dcxx_no_exception=${cmake_off_on} \ + -Dcxx_no_rtti=${cmake_off_on} && \ + make -j$(nproc) && \ + ctest -j$(nproc) --output-on-failure" done # Do one test with an older version of GCC -# TODO(googletest-team): This currently uses Bazel 5. When upgrading to a -# version of Bazel that supports Bzlmod, add --enable_bzlmod=false to keep test -# coverage for the old WORKSPACE dependency management. time docker run \ --volume="${GTEST_ROOT}:/src:ro" \ --workdir="/src" \ --rm \ --env="CC=/usr/local/bin/gcc" \ - --env="BAZEL_CXXOPTS=-std=c++14" \ + --env="BAZEL_CXXOPTS=-std=c++17" \ ${LINUX_GCC_FLOOR_CONTAINER} \ /usr/local/bin/bazel test ... \ --copt="-Wall" \ @@ -83,6 +100,7 @@ time docker run \ --copt="-Wuninitialized" \ --copt="-Wundef" \ --copt="-Wno-error=pragmas" \ + --enable_bzlmod=false \ --features=external_include_paths \ --keep_going \ --show_timestamps \ diff --git a/ci/macos-presubmit.sh b/ci/macos-presubmit.sh index 70eaa74fb490..5370ed60d3d8 100644 --- a/ci/macos-presubmit.sh +++ b/ci/macos-presubmit.sh @@ -31,6 +31,9 @@ set -euox pipefail +# Use Xcode 16.0 +sudo xcode-select -s /Applications/Xcode_16.0.app/Contents/Developer + if [[ -z ${GTEST_ROOT:-} ]]; then GTEST_ROOT="$(realpath $(dirname ${0})/..)" fi @@ -40,20 +43,20 @@ for cmake_off_on in OFF ON; do BUILD_DIR=$(mktemp -d build_dir.XXXXXXXX) cd ${BUILD_DIR} time cmake ${GTEST_ROOT} \ - -DCMAKE_CXX_STANDARD=14 \ + -DCMAKE_CXX_STANDARD=17 \ -Dgtest_build_samples=ON \ -Dgtest_build_tests=ON \ -Dgmock_build_tests=ON \ -Dcxx_no_exception=${cmake_off_on} \ -Dcxx_no_rtti=${cmake_off_on} - time make + time make -j$(nproc) time ctest -j$(nproc) --output-on-failure done # Test the Bazel build # If we are running on Kokoro, check for a versioned Bazel binary. -KOKORO_GFILE_BAZEL_BIN="bazel-7.0.0-darwin-x86_64" +KOKORO_GFILE_BAZEL_BIN="bazel-8.0.0-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} @@ -67,7 +70,7 @@ for absl in 0 1; do --copt="-Wall" \ --copt="-Werror" \ --copt="-Wundef" \ - --cxxopt="-std=c++14" \ + --cxxopt="-std=c++17" \ --define="absl=${absl}" \ --enable_bzlmod=true \ --features=external_include_paths \ diff --git a/ci/windows-presubmit.bat b/ci/windows-presubmit.bat index 1adc1a16ffa8..e2664c538da6 100644 --- a/ci/windows-presubmit.bat +++ b/ci/windows-presubmit.bat @@ -1,6 +1,6 @@ SETLOCAL ENABLEDELAYEDEXPANSION -SET BAZEL_EXE=%KOKORO_GFILE_DIR%\bazel-7.0.0-windows-x86_64.exe +SET BAZEL_EXE=%KOKORO_GFILE_DIR%\bazel-8.0.0-windows-x86_64.exe SET PATH=C:\Python34;%PATH% SET BAZEL_PYTHON=C:\python34\python.exe @@ -11,21 +11,18 @@ SET CTEST_OUTPUT_ON_FAILURE=1 SET CMAKE_BUILD_PARALLEL_LEVEL=16 SET CTEST_PARALLEL_LEVEL=16 -IF EXIST git\googletest ( - CD git\googletest -) ELSE IF EXIST github\googletest ( - CD github\googletest -) - +SET GTEST_ROOT=%~dp0\.. IF %errorlevel% neq 0 EXIT /B 1 :: ---------------------------------------------------------------------------- :: CMake -MKDIR cmake_msvc2022 -CD cmake_msvc2022 +SET CMAKE_BUILD_PATH=cmake_msvc2022 +MKDIR %CMAKE_BUILD_PATH% +CD %CMAKE_BUILD_PATH% -%CMAKE_BIN% .. ^ +%CMAKE_BIN% %GTEST_ROOT% ^ -G "Visual Studio 17 2022" ^ + -DCMAKE_CXX_STANDARD=17 ^ -DPYTHON_EXECUTABLE:FILEPATH=c:\python37\python.exe ^ -DPYTHON_INCLUDE_DIR:PATH=c:\python37\include ^ -DPYTHON_LIBRARY:FILEPATH=c:\python37\lib\site-packages\pip ^ @@ -40,8 +37,8 @@ IF %errorlevel% neq 0 EXIT /B 1 %CTEST_BIN% -C Debug --timeout 600 IF %errorlevel% neq 0 EXIT /B 1 -CD .. -RMDIR /S /Q cmake_msvc2022 +CD %GTEST_ROOT% +RMDIR /S /Q %CMAKE_BUILD_PATH% :: ---------------------------------------------------------------------------- :: Bazel @@ -50,11 +47,26 @@ RMDIR /S /Q cmake_msvc2022 :: because of Windows limitations on path length. :: --output_user_root=C:\tmp causes Bazel to use a shorter path. SET BAZEL_VS=C:\Program Files\Microsoft Visual Studio\2022\Community + +:: C++17 +%BAZEL_EXE% ^ + --output_user_root=C:\tmp ^ + test ... ^ + --compilation_mode=dbg ^ + --copt=/std:c++17 ^ + --copt=/WX ^ + --enable_bzlmod=true ^ + --keep_going ^ + --test_output=errors ^ + --test_tag_filters=-no_test_msvc2017 +IF %errorlevel% neq 0 EXIT /B 1 + +:: C++20 %BAZEL_EXE% ^ --output_user_root=C:\tmp ^ test ... ^ --compilation_mode=dbg ^ - --copt=/std:c++14 ^ + --copt=/std:c++20 ^ --copt=/WX ^ --enable_bzlmod=true ^ --keep_going ^ diff --git a/docs/advanced.md b/docs/advanced.md index 240588a83b4e..9b1220a1e09a 100644 --- a/docs/advanced.md +++ b/docs/advanced.md @@ -286,7 +286,7 @@ For example: ```c++ TEST(SkipTest, DoesSkip) { GTEST_SKIP() << "Skipping single test"; - EXPECT_EQ(0, 1); // Won't fail; it won't be executed + FAIL(); // Won't fail; it won't be executed } class SkipFixture : public ::testing::Test { @@ -298,7 +298,7 @@ class SkipFixture : public ::testing::Test { // Tests for SkipFixture won't be executed. TEST_F(SkipFixture, SkipsOneTest) { - EXPECT_EQ(5, 7); // Won't fail + FAIL(); // Won't fail; it won't be executed } ``` @@ -405,6 +405,51 @@ EXPECT_TRUE(IsCorrectPointIntVector(point_ints)) For more details regarding `AbslStringify()` and its integration with other libraries, see go/abslstringify. +## Regular Expression Syntax + +When built with Bazel and using Abseil, GoogleTest uses the +[RE2](https://github.com/google/re2/wiki/Syntax) syntax. Otherwise, for POSIX +systems (Linux, Cygwin, Mac), GoogleTest uses the +[POSIX extended regular expression](https://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap09.html#tag_09_04) +syntax. To learn about POSIX syntax, you may want to read this +[Wikipedia entry](https://en.wikipedia.org/wiki/Regular_expression#POSIX_extended). + +On Windows, GoogleTest uses its own simple regular expression implementation. It +lacks many features. For example, we don't support union (`"x|y"`), grouping +(`"(xy)"`), brackets (`"[xy]"`), and repetition count (`"x{5,7}"`), among +others. Below is what we do support (`A` denotes a literal character, period +(`.`), or a single `\\ ` escape sequence; `x` and `y` denote regular +expressions.): + +Expression | Meaning +---------- | -------------------------------------------------------------- +`c` | matches any literal character `c` +`\\d` | matches any decimal digit +`\\D` | matches any character that's not a decimal digit +`\\f` | matches `\f` +`\\n` | matches `\n` +`\\r` | matches `\r` +`\\s` | matches any ASCII whitespace, including `\n` +`\\S` | matches any character that's not a whitespace +`\\t` | matches `\t` +`\\v` | matches `\v` +`\\w` | matches any letter, `_`, or decimal digit +`\\W` | matches any character that `\\w` doesn't match +`\\c` | matches any literal character `c`, which must be a punctuation +`.` | matches any single character except `\n` +`A?` | matches 0 or 1 occurrences of `A` +`A*` | matches 0 or many occurrences of `A` +`A+` | matches 1 or many occurrences of `A` +`^` | matches the beginning of a string (not that of each line) +`$` | matches the end of a string (not that of each line) +`xy` | matches `x` followed by `y` + +To help you determine which capability is available on your system, GoogleTest +defines macros to govern which regular expression it is using. The macros are: +`GTEST_USES_SIMPLE_RE=1` or `GTEST_USES_POSIX_RE=1`. If you want your death +tests to work in all cases, you can either `#if` on these macros or use the more +limited syntax only. + ## Death Tests In many applications, there are assertions that can cause application failure if @@ -416,7 +461,7 @@ corruption, security holes, or worse. Hence it is vitally important to test that such assertion statements work as expected. Since these precondition checks cause the processes to die, we call such tests -_death tests_. More generally, any test that checks that a program terminates +*death tests*. More generally, any test that checks that a program terminates (except by throwing an exception) in an expected fashion is also a death test. Note that if a piece of code throws an exception, we don't consider it "death" @@ -462,6 +507,12 @@ verifies that: exit with exit code 0, and * calling `KillProcess()` kills the process with signal `SIGKILL`. +{: .callout .warning} +Warning: If your death test contains mocks and is expecting a specific exit +code, then you must allow the mock objects to be leaked via `Mock::AllowLeak`. +This is because the mock leak detector will exit with its own error code if it +detects a leak. + The test function body may contain other assertions and statements as well, if necessary. @@ -503,51 +554,6 @@ TEST_F(FooDeathTest, DoesThat) { } ``` -### Regular Expression Syntax - -When built with Bazel and using Abseil, GoogleTest uses the -[RE2](https://github.com/google/re2/wiki/Syntax) syntax. Otherwise, for POSIX -systems (Linux, Cygwin, Mac), GoogleTest uses the -[POSIX extended regular expression](https://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap09.html#tag_09_04) -syntax. To learn about POSIX syntax, you may want to read this -[Wikipedia entry](https://en.wikipedia.org/wiki/Regular_expression#POSIX_extended). - -On Windows, GoogleTest uses its own simple regular expression implementation. It -lacks many features. For example, we don't support union (`"x|y"`), grouping -(`"(xy)"`), brackets (`"[xy]"`), and repetition count (`"x{5,7}"`), among -others. Below is what we do support (`A` denotes a literal character, period -(`.`), or a single `\\ ` escape sequence; `x` and `y` denote regular -expressions.): - -Expression | Meaning ----------- | -------------------------------------------------------------- -`c` | matches any literal character `c` -`\\d` | matches any decimal digit -`\\D` | matches any character that's not a decimal digit -`\\f` | matches `\f` -`\\n` | matches `\n` -`\\r` | matches `\r` -`\\s` | matches any ASCII whitespace, including `\n` -`\\S` | matches any character that's not a whitespace -`\\t` | matches `\t` -`\\v` | matches `\v` -`\\w` | matches any letter, `_`, or decimal digit -`\\W` | matches any character that `\\w` doesn't match -`\\c` | matches any literal character `c`, which must be a punctuation -`.` | matches any single character except `\n` -`A?` | matches 0 or 1 occurrences of `A` -`A*` | matches 0 or many occurrences of `A` -`A+` | matches 1 or many occurrences of `A` -`^` | matches the beginning of a string (not that of each line) -`$` | matches the end of a string (not that of each line) -`xy` | matches `x` followed by `y` - -To help you determine which capability is available on your system, GoogleTest -defines macros to govern which regular expression it is using. The macros are: -`GTEST_USES_SIMPLE_RE=1` or `GTEST_USES_POSIX_RE=1`. If you want your death -tests to work in all cases, you can either `#if` on these macros or use the more -limited syntax only. - ### How It Works See [Death Assertions](reference/assertions.md#death) in the Assertions @@ -727,7 +733,7 @@ Some tips on using `SCOPED_TRACE`: ### Propagating Fatal Failures A common pitfall when using `ASSERT_*` and `FAIL*` is not understanding that -when they fail they only abort the _current function_, not the entire test. For +when they fail they only abort the *current function*, not the entire test. For example, the following test will segfault: ```c++ @@ -1923,6 +1929,20 @@ the `--gtest_also_run_disabled_tests` flag or set the You can combine this with the `--gtest_filter` flag to further select which disabled tests to run. +### Enforcing Having At Least One Test Case + +A not uncommon programmer mistake is to write a test program that has no test +case linked in. This can happen, for example, when you put test case definitions +in a library and the library is not marked as "always link". + +To catch such mistakes, run the test program with the +`--gtest_fail_if_no_test_linked` flag or set the `GTEST_FAIL_IF_NO_TEST_LINKED` +environment variable to a value other than `0`. Now the program will fail if no +test case is linked in. + +Note that *any* test case linked in makes the program valid for the purpose of +this check. In particular, even a disabled test case suffices. + ### Repeating the Tests Once in a while you'll run into a test whose result is hit-or-miss. Perhaps it @@ -2382,7 +2402,7 @@ IMPORTANT: The exact format of the JSON document is subject to change. #### Detecting Test Premature Exit -Google Test implements the _premature-exit-file_ protocol for test runners to +Google Test implements the *premature-exit-file* protocol for test runners to catch any kind of unexpected exits of test programs. Upon start, Google Test creates the file which will be automatically deleted after all work has been finished. Then, the test runner can check if this file exists. In case the file diff --git a/docs/faq.md b/docs/faq.md index c7d10b5006ba..4e958384673a 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -511,19 +511,6 @@ However, there are cases where you have to define your own: 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/docs/gmock_cook_book.md b/docs/gmock_cook_book.md index f1b10b472d27..9e59b4cf438c 100644 --- a/docs/gmock_cook_book.md +++ b/docs/gmock_cook_book.md @@ -177,7 +177,7 @@ class StackInterface { template <typename Elem> class MockStack : public StackInterface<Elem> { ... - MOCK_METHOD(int, GetSize, (), (override)); + MOCK_METHOD(int, GetSize, (), (const, override)); MOCK_METHOD(void, Push, (const Elem& x), (override)); }; ``` @@ -936,8 +936,8 @@ casts a matcher `m` to type `Matcher<T>`. To ensure safety, gMock checks that floating-point numbers), the conversion from `T` to `U` is not lossy (in other words, any value representable by `T` can also be represented by `U`); and -3. When `U` is a reference, `T` must also be a reference (as the underlying - matcher may be interested in the address of the `U` value). +3. When `U` is a non-const reference, `T` must also be a reference (as the + underlying matcher may be interested in the address of the `U` value). The code won't compile if any of these conditions isn't met. @@ -3387,9 +3387,9 @@ With this definition, the above assertion will give a better message: #### Using EXPECT_ Statements in Matchers -You can also use `EXPECT_...` (and `ASSERT_...`) statements inside custom -matcher definitions. In many cases, this allows you to write your matcher more -concisely while still providing an informative error message. For example: +You can also use `EXPECT_...` statements inside custom matcher definitions. In +many cases, this allows you to write your matcher more concisely while still +providing an informative error message. For example: ```cpp MATCHER(IsDivisibleBy7, "") { @@ -3419,14 +3419,14 @@ itself, as gMock already prints it for you. #### Argument Types -The type of the value being matched (`arg_type`) is determined by the -context in which you use the matcher and is supplied to you by the compiler, so -you don't need to worry about declaring it (nor can you). This allows the -matcher to be polymorphic. For example, `IsDivisibleBy7()` can be used to match -any type where the value of `(arg % 7) == 0` can be implicitly converted to a -`bool`. In the `Bar(IsDivisibleBy7())` example above, if method `Bar()` takes an -`int`, `arg_type` will be `int`; if it takes an `unsigned long`, `arg_type` will -be `unsigned long`; and so on. +The type of the value being matched (`arg_type`) is determined by the context in +which you use the matcher and is supplied to you by the compiler, so you don't +need to worry about declaring it (nor can you). This allows the matcher to be +polymorphic. For example, `IsDivisibleBy7()` can be used to match any type where +the value of `(arg % 7) == 0` can be implicitly converted to a `bool`. In the +`Bar(IsDivisibleBy7())` example above, if method `Bar()` takes an `int`, +`arg_type` will be `int`; if it takes an `unsigned long`, `arg_type` will be +`unsigned long`; and so on. ### Writing New Parameterized Matchers Quickly @@ -3567,10 +3567,15 @@ just based on the number of parameters). ### 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 @@ instead of `std::ostream*`. ### 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 @@ virtual. 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/docs/primer.md b/docs/primer.md index 61806be6ef86..69d6c6ddcb0f 100644 --- a/docs/primer.md +++ b/docs/primer.md @@ -73,8 +73,8 @@ Meaning Exercise a particular program path with specific input values and verify the results | [TEST()](#simple-tests) | [Test Case][istqb test case] -[istqb test case]: https://glossary.istqb.org/en_US/term/test-case-2 -[istqb test suite]: https://glossary.istqb.org/en_US/term/test-suite-1-3 +[istqb test case]: https://glossary.istqb.org/en_US/term/test-case +[istqb test suite]: https://glossary.istqb.org/en_US/term/test-suite ## Basic Concepts diff --git a/docs/quickstart-bazel.md b/docs/quickstart-bazel.md index 4f693dbe7fd4..5750f026f2af 100644 --- a/docs/quickstart-bazel.md +++ b/docs/quickstart-bazel.md @@ -10,8 +10,8 @@ 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. -* [Bazel](https://bazel.build/), the preferred build system used by the - GoogleTest team. +* [Bazel](https://bazel.build/) 7.0 or higher, the preferred build system used + by the GoogleTest team. See [Supported Platforms](platforms.md) for more information about platforms compatible with GoogleTest. @@ -28,7 +28,7 @@ A [Bazel workspace](https://docs.bazel.build/versions/main/build-ref.html#workspace) is a directory on your filesystem that you use to manage source files for the software you want to build. Each workspace directory has a text file named -`WORKSPACE` which may be empty, or may contain references to external +`MODULE.bazel` which may be empty, or may contain references to external dependencies required to build the outputs. First, create a directory for your workspace: @@ -37,30 +37,20 @@ First, create a directory for your workspace: $ mkdir my_workspace && cd my_workspace ``` -Next, you’ll create the `WORKSPACE` file to specify dependencies. A common and -recommended way to depend on GoogleTest is to use a -[Bazel external dependency](https://docs.bazel.build/versions/main/external.html) -via the -[`http_archive` rule](https://docs.bazel.build/versions/main/repo/http.html#http_archive). -To do this, in the root directory of your workspace (`my_workspace/`), create a -file named `WORKSPACE` with the following contents: +Next, you’ll create the `MODULE.bazel` file to specify dependencies. As of Bazel +7.0, the recommended way to consume GoogleTest is through the +[Bazel Central Registry](https://registry.bazel.build/modules/googletest). To do +this, create a `MODULE.bazel` file in the root directory of your Bazel workspace +with the following content: ``` -load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +# MODULE.bazel -http_archive( - name = "com_google_googletest", - urls = ["https://github.com/google/googletest/archive/5ab508a01f9eb089207ee87fd547d290da39d015.zip"], - strip_prefix = "googletest-5ab508a01f9eb089207ee87fd547d290da39d015", -) +# Choose the most recent version available at +# https://registry.bazel.build/modules/googletest +bazel_dep(name = "googletest", version = "1.15.2") ``` -The above configuration declares a dependency on GoogleTest which is downloaded -as a ZIP archive from GitHub. In the above example, -`5ab508a01f9eb089207ee87fd547d290da39d015` is the Git commit hash of the -GoogleTest version to use; we recommend updating the hash often to point to the -latest version. Use a recent hash on the `main` branch. - Now you're ready to build C++ code that uses GoogleTest. ## Create and run a binary @@ -92,17 +82,20 @@ following contents: ``` cc_test( - name = "hello_test", - size = "small", - srcs = ["hello_test.cc"], - deps = ["@com_google_googletest//:gtest_main"], + name = "hello_test", + size = "small", + srcs = ["hello_test.cc"], + deps = [ + "@googletest//:gtest", + "@googletest//:gtest_main", + ], ) ``` This `cc_test` rule declares the C++ test binary you want to build, and links to -GoogleTest (`//:gtest_main`) using the prefix you specified in the `WORKSPACE` -file (`@com_google_googletest`). For more information about Bazel `BUILD` files, -see the +the GoogleTest library (`@googletest//:gtest"`) and the GoogleTest `main()` +function (`@googletest//:gtest_main`). For more information about Bazel `BUILD` +files, see the [Bazel C++ Tutorial](https://docs.bazel.build/versions/main/tutorial/cpp.html). {: .callout .note} @@ -115,7 +108,7 @@ on supported language versions. Now you can build and run your test: <pre> -<strong>my_workspace$ bazel test --cxxopt=-std=c++14 --test_output=all //:hello_test</strong> +<strong>$ bazel test --cxxopt=-std=c++14 --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/docs/reference/actions.md b/docs/reference/actions.md index ab81a129eff6..0ebdc1e8433c 100644 --- a/docs/reference/actions.md +++ b/docs/reference/actions.md @@ -24,7 +24,8 @@ provided by GoogleTest. All actions are defined in the `::testing` namespace. | :--------------------------------- | :-------------------------------------- | | `Assign(&variable, value)` | Assign `value` to variable. | | `DeleteArg<N>()` | Delete the `N`-th (0-based) argument, which must be a pointer. | -| `SaveArg<N>(pointer)` | Save the `N`-th (0-based) argument to `*pointer`. | +| `SaveArg<N>(pointer)` | Save the `N`-th (0-based) argument to `*pointer` by copy-assignment. | +| `SaveArgByMove<N>(pointer)` | Save the `N`-th (0-based) argument to `*pointer` by move-assignment. | | `SaveArgPointee<N>(pointer)` | Save the value pointed to by the `N`-th (0-based) argument to `*pointer`. | | `SetArgReferee<N>(value)` | Assign `value` to the variable referenced by the `N`-th (0-based) argument. | | `SetArgPointee<N>(value)` | Assign `value` to the variable pointed by the `N`-th (0-based) argument. | diff --git a/docs/reference/assertions.md b/docs/reference/assertions.md index 492ff5ef6937..eeec4a0c489d 100644 --- a/docs/reference/assertions.md +++ b/docs/reference/assertions.md @@ -276,7 +276,8 @@ Units in the Last Place (ULPs). To learn more about ULPs, see the article `ASSERT_FLOAT_EQ(`*`val1`*`,`*`val2`*`)` Verifies that the two `float` values *`val1`* and *`val2`* are approximately -equal, to within 4 ULPs from each other. +equal, to within 4 ULPs from each other. Infinity and the largest finite float +value are considered to be one ULP apart. ### EXPECT_DOUBLE_EQ {#EXPECT_DOUBLE_EQ} @@ -284,7 +285,8 @@ equal, to within 4 ULPs from each other. `ASSERT_DOUBLE_EQ(`*`val1`*`,`*`val2`*`)` Verifies that the two `double` values *`val1`* and *`val2`* are approximately -equal, to within 4 ULPs from each other. +equal, to within 4 ULPs from each other. Infinity and the largest finite double +value are considered to be one ULP apart. ### EXPECT_NEAR {#EXPECT_NEAR} @@ -294,6 +296,11 @@ equal, to within 4 ULPs from each other. Verifies that the difference between *`val1`* and *`val2`* does not exceed the absolute error bound *`abs_error`*. +If *`val`* and *`val2`* are both infinity of the same sign, the difference is +considered to be 0. Otherwise, if either value is infinity, the difference is +considered to be infinity. All non-NaN values (including infinity) are +considered to not exceed an *`abs_error`* of infinity. + ## Exception Assertions {#exceptions} The following assertions verify that a piece of code throws, or does not throw, diff --git a/docs/reference/matchers.md b/docs/reference/matchers.md index 243e3f95164d..8ff9e0bc97ba 100644 --- a/docs/reference/matchers.md +++ b/docs/reference/matchers.md @@ -42,6 +42,8 @@ Matcher | Description | `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). | @@ -171,6 +173,11 @@ messages, you can use: | `Property(&class::property, m)` | `argument.property()` (or `argument->property()` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_. The method `property()` must take no argument and be declared as `const`. | | `Property(property_name, &class::property, m)` | The same as the two-parameter version, but provides a better error message. +{: .callout .warning} +Warning: Don't use `Property()` against member functions that you do not own, +because taking addresses of functions is fragile and generally not part of the +contract of the function. + **Notes:** * You can use `FieldsAre()` to match any type that supports structured @@ -189,10 +196,6 @@ messages, you can use: EXPECT_THAT(s, FieldsAre(42, "aloha")); ``` -* Don't use `Property()` against member functions that you do not own, because - taking addresses of functions is fragile and generally not part of the - contract of the function. - ## Matching the Result of a Function, Functor, or Callback | Matcher | Description | diff --git a/docs/reference/testing.md b/docs/reference/testing.md index 3ed521111787..d7dc5cf9b3df 100644 --- a/docs/reference/testing.md +++ b/docs/reference/testing.md @@ -110,7 +110,7 @@ namespace: | `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 @@ For more information, see 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/fake_fuchsia_sdk.bzl b/fake_fuchsia_sdk.bzl index 2024dc6c4d03..bc5b92734708 100644 --- a/fake_fuchsia_sdk.bzl +++ b/fake_fuchsia_sdk.bzl @@ -1,10 +1,20 @@ """Provides a fake @fuchsia_sdk implementation that's used when the real one isn't available. -This is needed since bazel queries on targets that depend on //:gtest (eg: -`bazel query "deps(set(//googletest/test:gtest_all_test))"`) will fail if @fuchsia_sdk is not -defined when bazel is evaluating the transitive closure of the query target. +GoogleTest can be used with the [Fuchsia](https://fuchsia.dev/) SDK. However, +because the Fuchsia SDK does not yet support bzlmod, GoogleTest's `MODULE.bazel` +file by default provides a "fake" Fuchsia SDK. -See https://github.com/google/googletest/issues/4472. +To override this and use the real Fuchsia SDK, you can add the following to your +project's `MODULE.bazel` file: + + fake_fuchsia_sdk_extension = + use_extension("@com_google_googletest//:fake_fuchsia_sdk.bzl", "fuchsia_sdk") + override_repo(fake_fuchsia_sdk_extension, "fuchsia_sdk") + +NOTE: The `override_repo` built-in is only available in Bazel 8.0 and higher. + +See https://github.com/google/googletest/issues/4472 for more details of why the +fake Fuchsia SDK is needed. """ def _fake_fuchsia_sdk_impl(repo_ctx): @@ -31,3 +41,21 @@ fake_fuchsia_sdk = repository_rule( ), }, ) + +_create_fake = tag_class() + +def _fuchsia_sdk_impl(module_ctx): + create_fake_sdk = False + for mod in module_ctx.modules: + for _ in mod.tags.create_fake: + create_fake_sdk = True + + if create_fake_sdk: + fake_fuchsia_sdk(name = "fuchsia_sdk") + + return module_ctx.extension_metadata(reproducible = True) + +fuchsia_sdk = module_extension( + implementation = _fuchsia_sdk_impl, + tag_classes = {"create_fake": _create_fake}, +) diff --git a/googlemock/include/gmock/gmock-actions.h b/googlemock/include/gmock/gmock-actions.h index cd12996955b6..5fe50e3d8e34 100644 --- a/googlemock/include/gmock/gmock-actions.h +++ b/googlemock/include/gmock/gmock-actions.h @@ -835,6 +835,10 @@ class Action<R(Args...)> { 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 @@ struct WithArgsAction { 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< @@ -1493,6 +1521,7 @@ class DoAllAction<FinalAction> { // providing a call operator because even with a particular set of arguments // they don't have a fixed return type. + // We support conversion to OnceAction whenever the sub-action does. template <typename R, typename... Args, typename std::enable_if< std::is_convertible<FinalAction, OnceAction<R(Args...)>>::value, @@ -1501,6 +1530,21 @@ class DoAllAction<FinalAction> { return std::move(final_action_); } + // We also support conversion to OnceAction whenever the sub-action supports + // conversion to Action (since any Action can also be a OnceAction). + template < + typename R, typename... Args, + typename std::enable_if< + conjunction< + negation< + std::is_convertible<FinalAction, OnceAction<R(Args...)>>>, + std::is_convertible<FinalAction, Action<R(Args...)>>>::value, + int>::type = 0> + operator OnceAction<R(Args...)>() && { // NOLINT + return Action<R(Args...)>(std::move(final_action_)); + } + + // We support conversion to Action whenever the sub-action does. template < typename R, typename... Args, typename std::enable_if< @@ -1580,16 +1624,16 @@ class DoAllAction<InitialAction, OtherActions...> : Base({}, std::forward<U>(other_actions)...), initial_action_(std::forward<T>(initial_action)) {} - template <typename R, typename... Args, - typename std::enable_if< - conjunction< - // Both the initial action and the rest must support - // conversion to OnceAction. - std::is_convertible< - InitialAction, - OnceAction<void(InitialActionArgType<Args>...)>>, - std::is_convertible<Base, OnceAction<R(Args...)>>>::value, - int>::type = 0> + // We support conversion to OnceAction whenever both the initial action and + // the rest support conversion to OnceAction. + template < + typename R, typename... Args, + typename std::enable_if< + conjunction<std::is_convertible< + InitialAction, + OnceAction<void(InitialActionArgType<Args>...)>>, + std::is_convertible<Base, OnceAction<R(Args...)>>>::value, + int>::type = 0> operator OnceAction<R(Args...)>() && { // NOLINT // Return an action that first calls the initial action with arguments // filtered through InitialActionArgType, then forwards arguments directly @@ -1612,12 +1656,34 @@ class DoAllAction<InitialAction, OtherActions...> }; } + // We also support conversion to OnceAction whenever the initial action + // supports conversion to Action (since any Action can also be a OnceAction). + // + // The remaining sub-actions must also be compatible, but we don't need to + // special case them because the base class deals with them. + template < + typename R, typename... Args, + typename std::enable_if< + conjunction< + negation<std::is_convertible< + InitialAction, + OnceAction<void(InitialActionArgType<Args>...)>>>, + std::is_convertible<InitialAction, + Action<void(InitialActionArgType<Args>...)>>, + std::is_convertible<Base, OnceAction<R(Args...)>>>::value, + int>::type = 0> + operator OnceAction<R(Args...)>() && { // NOLINT + return DoAll( + Action<void(InitialActionArgType<Args>...)>(std::move(initial_action_)), + std::move(static_cast<Base&>(*this))); + } + + // We support conversion to Action whenever both the initial action and the + // rest support conversion to Action. template < typename R, typename... Args, typename std::enable_if< conjunction< - // Both the initial action and the rest must support conversion to - // Action. std::is_convertible<const InitialAction&, Action<void(InitialActionArgType<Args>...)>>, std::is_convertible<const Base&, Action<R(Args...)>>>::value, @@ -1682,6 +1748,16 @@ struct SaveArgAction { }; template <size_t k, typename Ptr> +struct SaveArgByMoveAction { + Ptr pointer; + + template <typename... Args> + void operator()(Args&&... args) const { + *pointer = std::move(std::get<k>(std::tie(args...))); + } +}; + +template <size_t k, typename Ptr> struct SaveArgPointeeAction { Ptr pointer; @@ -2031,6 +2107,13 @@ internal::SaveArgAction<k, Ptr> SaveArg(Ptr pointer) { return {pointer}; } +// Action SaveArgByMove<k>(pointer) moves the k-th (0-based) argument of the +// mock function into *pointer. +template <size_t k, typename Ptr> +internal::SaveArgByMoveAction<k, Ptr> SaveArgByMove(Ptr pointer) { + return {pointer}; +} + // Action SaveArgPointee<k>(pointer) saves the value pointed to // by the k-th (0-based) argument of the mock function to *pointer. template <size_t k, typename Ptr> @@ -2174,9 +2257,9 @@ template <typename F, typename Impl> } #define GMOCK_INTERNAL_ARG_UNUSED(i, data, el) \ - , GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED const arg##i##_type& arg##i -#define GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_ \ - GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED const args_type& args GMOCK_PP_REPEAT( \ + , [[maybe_unused]] const arg##i##_type& arg##i +#define GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_ \ + [[maybe_unused]] const args_type& args GMOCK_PP_REPEAT( \ GMOCK_INTERNAL_ARG_UNUSED, , 10) #define GMOCK_INTERNAL_ARG(i, data, el) , const arg##i##_type& arg##i @@ -2241,8 +2324,8 @@ template <typename F, typename Impl> std::shared_ptr<const gmock_Impl> impl_; \ }; \ template <GMOCK_ACTION_TYPENAME_PARAMS_(params)> \ - inline full_name<GMOCK_ACTION_TYPE_PARAMS_(params)> name( \ - GMOCK_ACTION_TYPE_GVALUE_PARAMS_(params)) GTEST_MUST_USE_RESULT_; \ + [[nodiscard]] inline full_name<GMOCK_ACTION_TYPE_PARAMS_(params)> name( \ + GMOCK_ACTION_TYPE_GVALUE_PARAMS_(params)); \ template <GMOCK_ACTION_TYPENAME_PARAMS_(params)> \ inline full_name<GMOCK_ACTION_TYPE_PARAMS_(params)> name( \ GMOCK_ACTION_TYPE_GVALUE_PARAMS_(params)) { \ @@ -2277,7 +2360,7 @@ template <typename F, typename Impl> return_type gmock_PerformImpl(GMOCK_ACTION_ARG_TYPES_AND_NAMES_) const; \ }; \ }; \ - inline name##Action name() GTEST_MUST_USE_RESULT_; \ + [[nodiscard]] inline name##Action name(); \ inline name##Action name() { return name##Action(); } \ template <typename function_type, typename return_type, typename args_type, \ GMOCK_ACTION_TEMPLATE_ARGS_NAMES_> \ diff --git a/googlemock/include/gmock/gmock-matchers.h b/googlemock/include/gmock/gmock-matchers.h index 063ee6ca25e7..aa3a5eb16fcc 100644 --- a/googlemock/include/gmock/gmock-matchers.h +++ b/googlemock/include/gmock/gmock-matchers.h @@ -257,6 +257,7 @@ #include <algorithm> #include <cmath> +#include <cstddef> #include <exception> #include <functional> #include <initializer_list> @@ -408,13 +409,22 @@ class MatcherCastImpl<T, Matcher<U>> { } private: - class Impl : public MatcherInterface<T> { + // If it's possible to implicitly convert a `const T&` to U, then `Impl` can + // take that as input to avoid a copy. Otherwise, such as when `T` is a + // non-const reference type or a type explicitly constructible only from a + // non-const reference, then `Impl` must use `T` as-is (potentially copying). + using ImplArgT = + typename std::conditional<std::is_convertible<const T&, const U&>::value, + const T&, T>::type; + + class Impl : public MatcherInterface<ImplArgT> { public: explicit Impl(const Matcher<U>& source_matcher) : source_matcher_(source_matcher) {} // We delegate the matching logic to the source matcher. - bool MatchAndExplain(T x, MatchResultListener* listener) const override { + bool MatchAndExplain(ImplArgT x, + MatchResultListener* listener) const override { using FromType = typename std::remove_cv<typename std::remove_pointer< typename std::remove_reference<T>::type>::type>::type; using ToType = typename std::remove_cv<typename std::remove_pointer< @@ -431,9 +441,8 @@ class MatcherCastImpl<T, Matcher<U>> { // Do the cast to `U` explicitly if necessary. // Otherwise, let implicit conversions do the trick. - using CastType = - typename std::conditional<std::is_convertible<T&, const U&>::value, - T&, U>::type; + using CastType = typename std::conditional< + std::is_convertible<ImplArgT&, const U&>::value, ImplArgT&, U>::type; return source_matcher_.MatchAndExplain(static_cast<CastType>(x), listener); @@ -528,18 +537,16 @@ inline Matcher<T> SafeMatcherCast(const M& polymorphic_matcher_or_value) { // safely convert a Matcher<U> to a Matcher<T> (i.e. Matcher is // contravariant): just keep a copy of the original Matcher<U>, convert the // argument from type T to U, and then pass it to the underlying Matcher<U>. -// The only exception is when U is a reference and T is not, as the +// The only exception is when U is a non-const reference and T is not, as the // underlying Matcher<U> may be interested in the argument's address, which -// is not preserved in the conversion from T to U. +// cannot be preserved in the conversion from T to U (since a copy of the input +// T argument would be required to provide a non-const reference U). template <typename T, typename U> inline Matcher<T> SafeMatcherCast(const Matcher<U>& matcher) { // Enforce that T can be implicitly converted to U. static_assert(std::is_convertible<const T&, const U&>::value, - "T must be implicitly convertible to U"); - // Enforce that we are not converting a non-reference type T to a reference - // type U. - static_assert(std::is_reference<T>::value || !std::is_reference<U>::value, - "cannot convert non reference arg to reference"); + "T must be implicitly convertible to U (and T must be a " + "non-const reference if U is a non-const reference)"); // In case both T and U are arithmetic types, enforce that the // conversion is not lossy. typedef GTEST_REMOVE_REFERENCE_AND_CONST_(T) RawT; @@ -561,6 +568,11 @@ Matcher<T> A(); // and MUST NOT BE USED IN USER CODE!!! namespace internal { +// Used per go/ranked-overloads for dispatching. +struct Rank0 {}; +struct Rank1 : Rank0 {}; +using HighestRank = Rank1; + // If the explanation is not empty, prints it to the ostream. inline void PrintIfNotEmpty(const std::string& explanation, ::std::ostream* os) { @@ -1300,34 +1312,57 @@ class AllOfMatcherImpl : public MatcherInterface<const T&> { bool MatchAndExplain(const T& x, MatchResultListener* listener) const override { - // If either matcher1_ or matcher2_ doesn't match x, we only need - // to explain why one of them fails. + 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. std::string all_match_result; - - for (size_t i = 0; i < matchers_.size(); ++i) { + for (const Matcher<T>& matcher : matchers_) { StringMatchResultListener slistener; - if (matchers_[i].MatchAndExplain(x, &slistener)) { - if (all_match_result.empty()) { - all_match_result = slistener.str(); + // Return explanation for first failed matcher. + if (!matcher.MatchAndExplain(x, &slistener)) { + const std::string explanation = slistener.str(); + if (!explanation.empty()) { + *listener << explanation; } else { - std::string result = slistener.str(); - if (!result.empty()) { - all_match_result += ", and "; - all_match_result += result; - } + *listener << "which doesn't match (" << Describe(matcher) << ")"; } - } else { - *listener << slistener.str(); return false; } + // Keep track of explanations in case all matchers succeed. + std::string explanation = slistener.str(); + if (explanation.empty()) { + explanation = Describe(matcher); + } + if (all_match_result.empty()) { + all_match_result = explanation; + } else { + if (!explanation.empty()) { + all_match_result += ", and "; + all_match_result += explanation; + } + } } - // Otherwise we need to explain why *both* of them match. *listener << all_match_result; return true; } private: + // Returns matcher description as a string. + std::string Describe(const Matcher<T>& matcher) const { + StringMatchResultListener listener; + matcher.DescribeTo(listener.stream()); + return listener.str(); + } const std::vector<Matcher<T>> matchers_; }; @@ -1405,34 +1440,64 @@ class AnyOfMatcherImpl : public MatcherInterface<const T&> { 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. std::string no_match_result; - - // If either matcher1_ or matcher2_ matches x, we just need to - // explain why *one* of them matches. - for (size_t i = 0; i < matchers_.size(); ++i) { + for (const Matcher<T>& matcher : matchers_) { StringMatchResultListener slistener; - if (matchers_[i].MatchAndExplain(x, &slistener)) { - *listener << slistener.str(); + // Return explanation for first match. + if (matcher.MatchAndExplain(x, &slistener)) { + const std::string explanation = slistener.str(); + if (!explanation.empty()) { + *listener << explanation; + } else { + *listener << "which matches (" << Describe(matcher) << ")"; + } return true; + } + // Keep track of explanations in case there is no match. + std::string explanation = slistener.str(); + if (explanation.empty()) { + explanation = DescribeNegation(matcher); + } + if (no_match_result.empty()) { + no_match_result = explanation; } else { - if (no_match_result.empty()) { - no_match_result = slistener.str(); - } else { - std::string result = slistener.str(); - if (!result.empty()) { - no_match_result += ", and "; - no_match_result += result; - } + if (!explanation.empty()) { + no_match_result += ", and "; + no_match_result += explanation; } } } - // Otherwise we need to explain why *both* of them fail. *listener << no_match_result; return false; } private: + // Returns matcher description as a string. + std::string Describe(const Matcher<T>& matcher) const { + StringMatchResultListener listener; + matcher.DescribeTo(listener.stream()); + return listener.str(); + } + + std::string DescribeNegation(const Matcher<T>& matcher) const { + StringMatchResultListener listener; + matcher.DescribeNegationTo(listener.stream()); + return listener.str(); + } + const std::vector<Matcher<T>> matchers_; }; @@ -1483,7 +1548,7 @@ class SomeOfArrayMatcher { } private: - const ::std::vector<T> matchers_; + const std::vector<std::remove_const_t<T>> matchers_; }; template <typename T> @@ -2051,11 +2116,11 @@ class WhenDynamicCastToMatcher<To&> : public WhenDynamicCastToMatcherBase<To&> { 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), @@ -2099,7 +2164,7 @@ class FieldMatcher { 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 @@ -2235,6 +2300,9 @@ class ResultOfMatcher { class Impl : public MatcherInterface<T> { using ResultType = decltype(CallableTraits<Callable>::template Invoke<T>( std::declval<CallableStorageType>(), std::declval<T>())); + using InnerType = std::conditional_t< + std::is_lvalue_reference<ResultType>::value, + const typename std::remove_reference<ResultType>::type&, ResultType>; public: template <typename M> @@ -2242,7 +2310,7 @@ class ResultOfMatcher { const CallableStorageType& callable, const M& matcher) : result_description_(result_description), callable_(callable), - matcher_(MatcherCast<ResultType>(matcher)) {} + matcher_(MatcherCast<InnerType>(matcher)) {} void DescribeTo(::std::ostream* os) const override { if (result_description_.empty()) { @@ -2272,7 +2340,7 @@ class ResultOfMatcher { // takes a non-const reference as argument. // Also, specifying template argument explicitly is needed because T could // be a non-const reference (e.g. Matcher<Uncopyable&>). - ResultType result = + InnerType result = CallableTraits<Callable>::template Invoke<T>(callable_, obj); return MatchPrintAndExplain(result, matcher_, listener); } @@ -2285,7 +2353,7 @@ class ResultOfMatcher { // use stateful callables with ResultOf(), which doesn't guarantee // how many times the callable will be invoked. mutable CallableStorageType callable_; - const Matcher<ResultType> matcher_; + const Matcher<InnerType> matcher_; }; // class Impl const std::string result_description_; @@ -2806,6 +2874,54 @@ class ContainsMatcherImpl : public QuantifierMatcherImpl<Container> { } }; +// 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> @@ -2920,10 +3036,6 @@ class EachMatcher { const M inner_matcher_; }; -// Use go/ranked-overloads for dispatching. -struct Rank0 {}; -struct Rank1 : Rank0 {}; - namespace pair_getters { using std::get; template <typename T> @@ -2945,6 +3057,52 @@ auto Second(T& x, Rank1) -> decltype((x.second)) { // NOLINT } } // 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 @@ -3152,8 +3310,8 @@ class PairMatcher { }; 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)...); @@ -3255,6 +3413,26 @@ auto UnpackStructImpl(const T& t, std::make_index_sequence<19>, char) { const auto& [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s] = t; return std::tie(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s); } +template <typename T> +auto UnpackStructImpl(const T& u, std::make_index_sequence<20>, char) { + 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); +} #endif // defined(__cpp_structured_bindings) template <size_t I, typename T> @@ -3430,7 +3608,7 @@ class ElementsAreMatcherImpl : public MatcherInterface<Container> { 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 @@ -3446,11 +3624,23 @@ class ElementsAreMatcherImpl : public MatcherInterface<Container> { } 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" @@ -3471,10 +3661,27 @@ class ElementsAreMatcherImpl : public MatcherInterface<Container> { 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; @@ -3769,7 +3976,7 @@ class UnorderedElementsAreArrayMatcher { private: UnorderedMatcherRequire::Flags match_flags_; - ::std::vector<T> matchers_; + std::vector<std::remove_const_t<T>> matchers_; }; // Implements ElementsAreArray(). @@ -3790,7 +3997,7 @@ class ElementsAreArrayMatcher { } private: - const ::std::vector<T> matchers_; + const std::vector<std::remove_const_t<T>> matchers_; }; // Given a 2-tuple matcher tm of type Tuple2Matcher and a value second @@ -3877,6 +4084,21 @@ GTEST_API_ std::string FormatMatcherDescription( bool negation, const char* matcher_name, const std::vector<const char*>& param_names, const Strings& param_values); +// 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) { + // 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()) { + return optional.has_value(); +} + // Implements a matcher that checks the value of a optional<> type variable. template <typename ValueMatcher> class OptionalMatcher { @@ -3909,11 +4131,15 @@ class OptionalMatcher { bool MatchAndExplain(Optional optional, MatchResultListener* listener) const override { - if (!optional) { + if (!IsOptionalEngaged(optional, HighestRank())) { *listener << "which is not engaged"; 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) @@ -4300,6 +4526,42 @@ inline internal::FloatingEqMatcher<double> DoubleNear(double rhs, 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. @@ -4365,7 +4627,7 @@ WhenDynamicCastTo(const Matcher<To>& inner_matcher) { // 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 @@ -4378,7 +4640,7 @@ inline PolymorphicMatcher<internal::FieldMatcher<Class, FieldType>> Field( // 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))); @@ -4388,6 +4650,10 @@ inline PolymorphicMatcher<internal::FieldMatcher<Class, FieldType>> Field( // matches 'matcher'. For example, // Property(&Foo::str, StartsWith("hi")) // matches a Foo object x if and only if x.str() starts with "hi". +// +// Warning: Don't use `Property()` against member functions that you do not +// own, because taking addresses of functions is fragile and generally not part +// of the contract of the function. template <typename Class, typename PropertyType, typename PropertyMatcher> inline PolymorphicMatcher<internal::PropertyMatcher< Class, PropertyType, PropertyType (Class::*)() const>> @@ -4742,9 +5008,10 @@ Pointwise(const TupleMatcher& tuple_matcher, const Container& rhs) { // Supports the Pointwise(m, {a, b, c}) syntax. template <typename TupleMatcher, typename T> -inline internal::PointwiseMatcher<TupleMatcher, std::vector<T>> Pointwise( - const TupleMatcher& tuple_matcher, std::initializer_list<T> rhs) { - return Pointwise(tuple_matcher, std::vector<T>(rhs)); +inline internal::PointwiseMatcher<TupleMatcher, + std::vector<std::remove_const_t<T>>> +Pointwise(const TupleMatcher& tuple_matcher, std::initializer_list<T> rhs) { + return Pointwise(tuple_matcher, std::vector<std::remove_const_t<T>>(rhs)); } // UnorderedPointwise(pair_matcher, rhs) matches an STL-style @@ -4906,7 +5173,7 @@ inline internal::UnorderedElementsAreArrayMatcher<T> IsSupersetOf( // - {1} matches IsSubsetOf({Gt(0), Lt(0)}), as 1 matches Gt(0). // - {1, -1} matches IsSubsetOf({Lt(0), Gt(0)}), as 1 matches Gt(0) and -1 // matches Lt(0). -// - {1, 2} doesn't matches IsSubsetOf({Gt(0), Lt(0)}), even though 1 and 2 both +// - {1, 2} doesn't match IsSubsetOf({Gt(0), Lt(0)}), even though 1 and 2 both // match Gt(0). The reason is that different matchers must be used for // elements in different slots of the container. // @@ -5231,9 +5498,10 @@ inline InnerMatcher AllArgs(const InnerMatcher& matcher) { } // Returns a matcher that matches the value of an optional<> type variable. -// The matcher implementation only uses '!arg' and requires that the optional<> -// type has a 'value_type' member type and that '*arg' is of type 'value_type' -// and is printable using 'PrintToString'. It is compatible with +// The matcher implementation only uses '!arg' (or 'arg.has_value()' if '!arg` +// isn't a valid expression) and requires that the optional<> type has a +// 'value_type' member type and that '*arg' is of type 'value_type' and is +// printable using 'PrintToString'. It is compatible with // std::optional/std::experimental::optional. // Note that to compare an optional type variable against nullopt you should // use Eq(nullopt) and not Eq(Optional(nullopt)). The latter implies that the @@ -5484,8 +5752,7 @@ PolymorphicMatcher<internal::ExceptionMatcherImpl<Err>> ThrowsMessage( template <typename arg_type> \ bool name##Matcher::gmock_Impl<arg_type>::MatchAndExplain( \ const arg_type& arg, \ - GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED ::testing::MatchResultListener* \ - result_listener) const + [[maybe_unused]] ::testing::MatchResultListener* result_listener) const #define MATCHER_P(name, p0, description) \ GMOCK_INTERNAL_MATCHER(name, name##MatcherP, description, (#p0), (p0)) @@ -5570,8 +5837,8 @@ PolymorphicMatcher<internal::ExceptionMatcherImpl<Err>> ThrowsMessage( bool full_name<GMOCK_INTERNAL_MATCHER_TYPE_PARAMS(args)>:: \ gmock_Impl<arg_type>::MatchAndExplain( \ const arg_type& arg, \ - GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED ::testing:: \ - MatchResultListener* result_listener) const + [[maybe_unused]] ::testing::MatchResultListener* result_listener) \ + const #define GMOCK_INTERNAL_MATCHER_TEMPLATE_PARAMS(args) \ GMOCK_PP_TAIL( \ diff --git a/googlemock/include/gmock/gmock-more-actions.h b/googlemock/include/gmock/gmock-more-actions.h index e341d47fca94..eacfdcd9e7e9 100644 --- a/googlemock/include/gmock/gmock-more-actions.h +++ b/googlemock/include/gmock/gmock-more-actions.h @@ -521,9 +521,8 @@ GMOCK_INTERNAL_DECL_##value_params) \ GMOCK_PP_IF(GMOCK_PP_IS_EMPTY(GMOCK_INTERNAL_COUNT_##value_params), \ = default; \ - , \ - : impl_(std::make_shared<gmock_Impl>( \ - GMOCK_INTERNAL_LIST_##value_params)){}) \ + , : impl_(std::make_shared<gmock_Impl>( \ + GMOCK_INTERNAL_LIST_##value_params)){}) \ GMOCK_ACTION_CLASS_(name, value_params)(const GMOCK_ACTION_CLASS_( \ name, value_params) &) noexcept GMOCK_INTERNAL_DEFN_COPY_ \ ##value_params \ @@ -551,10 +550,10 @@ }; \ template <GMOCK_INTERNAL_DECL_##template_params \ GMOCK_INTERNAL_DECL_TYPE_##value_params> \ - GMOCK_ACTION_CLASS_( \ + [[nodiscard]] GMOCK_ACTION_CLASS_( \ name, value_params)<GMOCK_INTERNAL_LIST_##template_params \ GMOCK_INTERNAL_LIST_TYPE_##value_params> \ - name(GMOCK_INTERNAL_DECL_##value_params) GTEST_MUST_USE_RESULT_; \ + name(GMOCK_INTERNAL_DECL_##value_params); \ template <GMOCK_INTERNAL_DECL_##template_params \ GMOCK_INTERNAL_DECL_TYPE_##value_params> \ inline GMOCK_ACTION_CLASS_( \ @@ -601,9 +600,10 @@ template <std::size_t index, typename... Params> struct InvokeArgumentAction { template <typename... Args, typename = typename std::enable_if<(index < sizeof...(Args))>::type> - auto operator()(Args &&...args) const -> decltype(internal::InvokeArgument( - std::get<index>(std::forward_as_tuple(std::forward<Args>(args)...)), - std::declval<const Params &>()...)) { + auto operator()(Args &&...args) const + -> decltype(internal::InvokeArgument( + std::get<index>(std::forward_as_tuple(std::forward<Args>(args)...)), + std::declval<const Params &>()...)) { internal::FlatTuple<Args &&...> args_tuple(FlatTupleConstructTag{}, std::forward<Args>(args)...); return params.Apply([&](const Params &...unpacked_params) { diff --git a/googlemock/include/gmock/gmock-spec-builders.h b/googlemock/include/gmock/gmock-spec-builders.h index 78ca15d05e0f..c4c42b7c59c2 100644 --- a/googlemock/include/gmock/gmock-spec-builders.h +++ b/googlemock/include/gmock/gmock-spec-builders.h @@ -868,7 +868,7 @@ class GTEST_API_ ExpectationBase { Clause last_clause_; mutable bool action_count_checked_; // Under mutex_. mutable Mutex mutex_; // Protects action_count_checked_. -}; // class ExpectationBase +}; // class ExpectationBase template <typename F> class TypedExpectation; @@ -1838,9 +1838,8 @@ R FunctionMocker<R(Args...)>::InvokeWith(ArgumentTuple&& args) // Doing so slows down compilation dramatically because the *constructor* of // std::function<T> is re-instantiated with different template // parameters each time. - const UninterestingCallCleanupHandler report_uninteresting_call = { - reaction, ss - }; + const UninterestingCallCleanupHandler report_uninteresting_call = {reaction, + ss}; return PerformActionAndPrintResult(nullptr, std::move(args), ss.str(), ss); } @@ -1890,8 +1889,7 @@ R FunctionMocker<R(Args...)>::InvokeWith(ArgumentTuple&& args) // std::function<T> is re-instantiated with different template // parameters each time. const FailureCleanupHandler handle_failures = { - ss, why, loc, untyped_expectation, found, is_excessive - }; + ss, why, loc, untyped_expectation, found, is_excessive}; return PerformActionAndPrintResult(untyped_action, std::move(args), ss.str(), ss); diff --git a/googlemock/include/gmock/internal/gmock-internal-utils.h b/googlemock/include/gmock/internal/gmock-internal-utils.h index b7685f573001..8fc1ddc7ab67 100644 --- a/googlemock/include/gmock/internal/gmock-internal-utils.h +++ b/googlemock/include/gmock/internal/gmock-internal-utils.h @@ -467,11 +467,6 @@ struct Function<R(Args...)> { using MakeResultIgnoredValue = IgnoredValue(Args...); }; -#ifdef GTEST_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL -template <typename R, typename... Args> -constexpr size_t Function<R(Args...)>::ArgumentCount; -#endif - // Workaround for MSVC error C2039: 'type': is not a member of 'std' // when std::tuple_element is used. // See: https://github.com/google/googletest/issues/3931 diff --git a/googlemock/include/gmock/internal/gmock-port.h b/googlemock/include/gmock/internal/gmock-port.h index e9d9e32a7a80..42d36d2f12d0 100644 --- a/googlemock/include/gmock/internal/gmock-port.h +++ b/googlemock/include/gmock/internal/gmock-port.h @@ -42,6 +42,7 @@ #include <assert.h> #include <stdlib.h> + #include <cstdint> #include <iostream> diff --git a/googlemock/src/gmock-cardinalities.cc b/googlemock/src/gmock-cardinalities.cc index 92cde3484abf..a7283aaf1c90 100644 --- a/googlemock/src/gmock-cardinalities.cc +++ b/googlemock/src/gmock-cardinalities.cc @@ -53,12 +53,12 @@ class BetweenCardinalityImpl : public CardinalityInterface { : min_(min >= 0 ? min : 0), max_(max >= min_ ? max : min_) { std::stringstream ss; if (min < 0) { - ss << "The invocation lower bound must be >= 0, " - << "but is actually " << min << "."; + ss << "The invocation lower bound must be >= 0, " << "but is actually " + << min << "."; internal::Expect(false, __FILE__, __LINE__, ss.str()); } else if (max < 0) { - ss << "The invocation upper bound must be >= 0, " - << "but is actually " << max << "."; + ss << "The invocation upper bound must be >= 0, " << "but is actually " + << max << "."; internal::Expect(false, __FILE__, __LINE__, ss.str()); } else if (min > max) { ss << "The invocation upper bound (" << max diff --git a/googlemock/test/gmock-actions_test.cc b/googlemock/test/gmock-actions_test.cc index da1675c525d1..46b0e91871c5 100644 --- a/googlemock/test/gmock-actions_test.cc +++ b/googlemock/test/gmock-actions_test.cc @@ -222,8 +222,8 @@ TEST(TypeTraits, IsInvocableRV) { // In C++17 and above, where it's guaranteed that functions can return // non-moveable objects, everything should work fine for non-moveable rsult // types too. -#if defined(GTEST_INTERNAL_CPLUSPLUS_LANG) && \ - GTEST_INTERNAL_CPLUSPLUS_LANG >= 201703L + // TODO(b/396121064) - Fix this test under MSVC +#ifndef _MSC_VER { struct NonMoveable { NonMoveable() = default; @@ -244,7 +244,7 @@ TEST(TypeTraits, IsInvocableRV) { static_assert(!internal::is_callable_r<int, Callable>::value); static_assert(!internal::is_callable_r<NonMoveable, Callable, int>::value); } -#endif // C++17 and above +#endif // _MSC_VER // Nothing should choke when we try to call other arguments besides directly // callable objects, but they should not show up as callable. @@ -441,8 +441,8 @@ TEST(DefaultValueDeathTest, GetReturnsBuiltInDefaultValueWhenUnset) { EXPECT_EQ(0, DefaultValue<int>::Get()); - EXPECT_DEATH_IF_SUPPORTED({ DefaultValue<MyNonDefaultConstructible>::Get(); }, - ""); + EXPECT_DEATH_IF_SUPPORTED( + { DefaultValue<MyNonDefaultConstructible>::Get(); }, ""); } TEST(DefaultValueTest, GetWorksForMoveOnlyIfSet) { @@ -505,8 +505,8 @@ TEST(DefaultValueOfReferenceDeathTest, GetReturnsBuiltInDefaultValueWhenUnset) { EXPECT_FALSE(DefaultValue<MyNonDefaultConstructible&>::IsSet()); EXPECT_DEATH_IF_SUPPORTED({ DefaultValue<int&>::Get(); }, ""); - EXPECT_DEATH_IF_SUPPORTED({ DefaultValue<MyNonDefaultConstructible>::Get(); }, - ""); + EXPECT_DEATH_IF_SUPPORTED( + { DefaultValue<MyNonDefaultConstructible>::Get(); }, ""); } // Tests that ActionInterface can be implemented by defining the @@ -1477,6 +1477,54 @@ TEST(DoAll, SupportsTypeErasedActions) { } } +// A DoAll action should be convertible to a OnceAction, even when its component +// sub-actions are user-provided types that define only an Action conversion +// operator. If they supposed being called more than once then they also support +// being called at most once. +TEST(DoAll, ConvertibleToOnceActionWithUserProvidedActionConversion) { + // Simplest case: only one sub-action. + struct CustomFinal final { + operator Action<int()>() { // NOLINT + return Return(17); + } + + operator Action<int(int, char)>() { // NOLINT + return Return(19); + } + }; + + { + OnceAction<int()> action = DoAll(CustomFinal{}); + EXPECT_EQ(17, std::move(action).Call()); + } + + { + OnceAction<int(int, char)> action = DoAll(CustomFinal{}); + EXPECT_EQ(19, std::move(action).Call(0, 0)); + } + + // It should also work with multiple sub-actions. + struct CustomInitial final { + operator Action<void()>() { // NOLINT + return [] {}; + } + + operator Action<void(int, char)>() { // NOLINT + return [] {}; + } + }; + + { + OnceAction<int()> action = DoAll(CustomInitial{}, CustomFinal{}); + EXPECT_EQ(17, std::move(action).Call()); + } + + { + OnceAction<int(int, char)> action = DoAll(CustomInitial{}, CustomFinal{}); + EXPECT_EQ(19, std::move(action).Call(0, 0)); + } +} + // Tests using WithArgs and with an action that takes 1 argument. TEST(WithArgsTest, OneArg) { Action<bool(double x, int n)> a = WithArgs<1>(Invoke(Unary)); // NOLINT @@ -1597,6 +1645,22 @@ TEST(WithArgsTest, RefQualifiedInnerAction) { 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/googlemock/test/gmock-function-mocker_test.cc b/googlemock/test/gmock-function-mocker_test.cc index f7b31ae33852..cdac79b7e7cc 100644 --- a/googlemock/test/gmock-function-mocker_test.cc +++ b/googlemock/test/gmock-function-mocker_test.cc @@ -325,8 +325,8 @@ TYPED_TEST(FunctionMockerTest, MocksBinaryFunction) { // Tests mocking a decimal function. TYPED_TEST(FunctionMockerTest, MocksDecimalFunction) { - EXPECT_CALL(this->mock_foo_, - Decimal(true, 'a', 0, 0, 1L, A<float>(), Lt(100), 5U, NULL, "hi")) + EXPECT_CALL(this->mock_foo_, Decimal(true, 'a', 0, 0, 1L, A<float>(), Lt(100), + 5U, nullptr, "hi")) .WillOnce(Return(5)); EXPECT_EQ(5, this->foo_->Decimal(true, 'a', 0, 0, 1, 0, 0, 5, nullptr, "hi")); diff --git a/googlemock/test/gmock-matchers-arithmetic_test.cc b/googlemock/test/gmock-matchers-arithmetic_test.cc index f176962855ea..b6c35119e29b 100644 --- a/googlemock/test/gmock-matchers-arithmetic_test.cc +++ b/googlemock/test/gmock-matchers-arithmetic_test.cc @@ -34,9 +34,12 @@ #include <cmath> #include <limits> #include <memory> +#include <ostream> #include <string> +#include "gmock/gmock.h" #include "test/gmock-matchers_test.h" +#include "gtest/gtest.h" // Silence warning C4244: 'initializing': conversion from 'int' to 'short', // possible loss of data and C4100, unreferenced local parameter @@ -396,6 +399,188 @@ TEST(NanSensitiveDoubleNearTest, CanDescribeSelfWithNaNs) { 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; @@ -559,10 +744,9 @@ TEST_P(AllOfTestP, ExplainsResult) { Matcher<int> m; // Successful match. Both matchers need to explain. The second - // matcher doesn't give an explanation, so only the first matcher's - // explanation is printed. + // matcher doesn't give an explanation, so the matcher description is used. m = AllOf(GreaterThan(10), Lt(30)); - EXPECT_EQ("which is 15 more than 10", Explain(m, 25)); + EXPECT_EQ("which is 15 more than 10, and is < 30", Explain(m, 25)); // Successful match. Both matchers need to explain. m = AllOf(GreaterThan(10), GreaterThan(20)); @@ -572,8 +756,9 @@ TEST_P(AllOfTestP, ExplainsResult) { // Successful match. All matchers need to explain. The second // matcher doesn't given an explanation. m = AllOf(GreaterThan(10), Lt(30), GreaterThan(20)); - EXPECT_EQ("which is 15 more than 10, and which is 5 more than 20", - Explain(m, 25)); + EXPECT_EQ( + "which is 15 more than 10, and is < 30, and which is 5 more than 20", + Explain(m, 25)); // Successful match. All matchers need to explain. m = AllOf(GreaterThan(10), GreaterThan(20), GreaterThan(30)); @@ -588,10 +773,10 @@ TEST_P(AllOfTestP, ExplainsResult) { EXPECT_EQ("which is 5 less than 10", Explain(m, 5)); // Failed match. The second matcher, which failed, needs to - // explain. Since it doesn't given an explanation, nothing is + // explain. Since it doesn't given an explanation, the matcher text is // printed. m = AllOf(GreaterThan(10), Lt(30)); - EXPECT_EQ("", Explain(m, 40)); + EXPECT_EQ("which doesn't match (is < 30)", Explain(m, 40)); // Failed match. The second matcher, which failed, needs to // explain. @@ -774,45 +959,43 @@ TEST(AnyOfTest, AnyOfMatcherSafelyCastsMonomorphicMatchers) { TEST_P(AnyOfTestP, ExplainsResult) { Matcher<int> m; - // Failed match. Both matchers need to explain. The second - // matcher doesn't give an explanation, so only the first matcher's - // explanation is printed. + // Failed match. The second matcher have no explanation (description is used). m = AnyOf(GreaterThan(10), Lt(0)); - EXPECT_EQ("which is 5 less than 10", Explain(m, 5)); + EXPECT_EQ("which is 5 less than 10, and isn't < 0", Explain(m, 5)); - // Failed match. Both matchers need to explain. + // Failed match. Both matchers have explanations. m = AnyOf(GreaterThan(10), GreaterThan(20)); EXPECT_EQ("which is 5 less than 10, and which is 15 less than 20", Explain(m, 5)); - // Failed match. All matchers need to explain. The second - // matcher doesn't given an explanation. + // Failed match. The middle matcher have no explanation. m = AnyOf(GreaterThan(10), Gt(20), GreaterThan(30)); - EXPECT_EQ("which is 5 less than 10, and which is 25 less than 30", - Explain(m, 5)); + EXPECT_EQ( + "which is 5 less than 10, and isn't > 20, and which is 25 less than 30", + Explain(m, 5)); - // Failed match. All matchers need to explain. + // Failed match. All three matchers have explanations. m = AnyOf(GreaterThan(10), GreaterThan(20), GreaterThan(30)); EXPECT_EQ( "which is 5 less than 10, and which is 15 less than 20, " "and which is 25 less than 30", Explain(m, 5)); - // Successful match. The first matcher, which succeeded, needs to - // explain. + // Successful match. The first macher succeeded and has explanation. m = AnyOf(GreaterThan(10), GreaterThan(20)); EXPECT_EQ("which is 5 more than 10", Explain(m, 15)); - // Successful match. The second matcher, which succeeded, needs to - // explain. Since it doesn't given an explanation, nothing is - // printed. - m = AnyOf(GreaterThan(10), Lt(30)); - EXPECT_EQ("", Explain(m, 0)); - - // Successful match. The second matcher, which succeeded, needs to - // explain. + // Successful match. The second matcher succeeded and has explanation. m = AnyOf(GreaterThan(30), GreaterThan(20)); EXPECT_EQ("which is 5 more than 20", Explain(m, 25)); + + // Successful match. The first matcher succeeded and has no explanation. + m = AnyOf(Gt(10), Lt(20)); + EXPECT_EQ("which matches (is > 10)", Explain(m, 15)); + + // Successful match. The second matcher succeeded and has no explanation. + m = AnyOf(Gt(30), Gt(20)); + EXPECT_EQ("which matches (is > 20)", Explain(m, 25)); } // The following predicate function and predicate functor are for diff --git a/googlemock/test/gmock-matchers-comparisons_test.cc b/googlemock/test/gmock-matchers-comparisons_test.cc index 5b75b457be04..87eca08f5ad2 100644 --- a/googlemock/test/gmock-matchers-comparisons_test.cc +++ b/googlemock/test/gmock-matchers-comparisons_test.cc @@ -33,17 +33,19 @@ #include <functional> #include <memory> +#include <optional> #include <string> #include <tuple> #include <vector> +#include "gmock/gmock.h" #include "test/gmock-matchers_test.h" +#include "gtest/gtest.h" // Silence warning C4244: 'initializing': conversion from 'int' to 'short', // possible loss of data and C4100, unreferenced local parameter GTEST_DISABLE_MSC_WARNINGS_PUSH_(4244 4100) - namespace testing { namespace gmock_matchers_test { namespace { @@ -410,9 +412,27 @@ class IntValue { int value_; }; +// For testing casting matchers between compatible types. This is similar to +// IntValue, but takes a non-const reference to the value, showing MatcherCast +// works with such types (and doesn't, for example, use a const ref internally). +class MutableIntView { + public: + // An int& can be statically (although not implicitly) cast to a + // MutableIntView. + explicit MutableIntView(int& a_value) : value_(a_value) {} + + int& value() const { return value_; } + + private: + int& value_; +}; + // For testing casting matchers between compatible types. bool IsPositiveIntValue(const IntValue& foo) { return foo.value() > 0; } +// For testing casting matchers between compatible types. +bool IsPositiveMutableIntView(MutableIntView foo) { return foo.value() > 0; } + // Tests that MatcherCast<T>(m) works when m is a Matcher<U> where T // can be statically converted to U. TEST(MatcherCastTest, FromCompatibleType) { @@ -428,14 +448,34 @@ TEST(MatcherCastTest, FromCompatibleType) { // predicate. EXPECT_TRUE(m4.Matches(1)); EXPECT_FALSE(m4.Matches(0)); + + Matcher<MutableIntView> m5 = Truly(IsPositiveMutableIntView); + Matcher<int> m6 = MatcherCast<int>(m5); + // In the following, the arguments 1 and 0 are statically converted to + // MutableIntView objects, and then tested by the IsPositiveMutableIntView() + // predicate. + EXPECT_TRUE(m6.Matches(1)); + EXPECT_FALSE(m6.Matches(0)); } // Tests that MatcherCast<T>(m) works when m is a Matcher<const T&>. TEST(MatcherCastTest, FromConstReferenceToNonReference) { - Matcher<const int&> m1 = Eq(0); + int n = 0; + Matcher<const int&> m1 = Ref(n); Matcher<int> m2 = MatcherCast<int>(m1); - EXPECT_TRUE(m2.Matches(0)); - EXPECT_FALSE(m2.Matches(1)); + int n1 = 0; + EXPECT_TRUE(m2.Matches(n)); + EXPECT_FALSE(m2.Matches(n1)); +} + +// Tests that MatcherCast<T&>(m) works when m is a Matcher<const T&>. +TEST(MatcherCastTest, FromConstReferenceToReference) { + int n = 0; + Matcher<const int&> m1 = Ref(n); + Matcher<int&> m2 = MatcherCast<int&>(m1); + int n1 = 0; + EXPECT_TRUE(m2.Matches(n)); + EXPECT_FALSE(m2.Matches(n1)); } // Tests that MatcherCast<T>(m) works when m is a Matcher<T&>. @@ -444,6 +484,12 @@ TEST(MatcherCastTest, FromReferenceToNonReference) { Matcher<int> m2 = MatcherCast<int>(m1); EXPECT_TRUE(m2.Matches(0)); EXPECT_FALSE(m2.Matches(1)); + + // Of course, reference identity isn't preserved since a copy is required. + int n = 0; + Matcher<int&> m3 = Ref(n); + Matcher<int> m4 = MatcherCast<int>(m3); + EXPECT_FALSE(m4.Matches(n)); } // Tests that MatcherCast<const T&>(m) works when m is a Matcher<T>. @@ -648,6 +694,16 @@ TEST(SafeMatcherCastTest, FromBaseClass) { EXPECT_FALSE(m4.Matches(d2)); } +// Tests that SafeMatcherCast<T>(m) works when m is a Matcher<const T&>. +TEST(SafeMatcherCastTest, FromConstReferenceToNonReference) { + int n = 0; + Matcher<const int&> m1 = Ref(n); + Matcher<int> m2 = SafeMatcherCast<int>(m1); + int n1 = 0; + EXPECT_TRUE(m2.Matches(n)); + EXPECT_FALSE(m2.Matches(n1)); +} + // Tests that SafeMatcherCast<T&>(m) works when m is a Matcher<const T&>. TEST(SafeMatcherCastTest, FromConstReferenceToReference) { int n = 0; @@ -2334,9 +2390,79 @@ TEST(ExplainMatchResultTest, AllOf_True_True) { EXPECT_EQ("which is 0 modulo 2, and which is 0 modulo 3", Explain(m, 6)); } +// Tests that when AllOf() succeeds, but matchers have no explanation, +// the matcher description is used. TEST(ExplainMatchResultTest, AllOf_True_True_2) { const Matcher<int> m = AllOf(Ge(2), Le(3)); - EXPECT_EQ("", Explain(m, 2)); + 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); diff --git a/googlemock/test/gmock-matchers-containers_test.cc b/googlemock/test/gmock-matchers-containers_test.cc index acea4ec357e0..e9f1a02d85d1 100644 --- a/googlemock/test/gmock-matchers-containers_test.cc +++ b/googlemock/test/gmock-matchers-containers_test.cc @@ -33,6 +33,7 @@ #include <algorithm> #include <array> +#include <cstddef> #include <deque> #include <forward_list> #include <iterator> @@ -43,14 +44,14 @@ #include <tuple> #include <vector> +#include "gmock/gmock.h" +#include "test/gmock-matchers_test.h" #include "gtest/gtest.h" // Silence warning C4244: 'initializing': conversion from 'int' to 'short', // possible loss of data and C4100, unreferenced local parameter GTEST_DISABLE_MSC_WARNINGS_PUSH_(4244 4100) -#include "test/gmock-matchers_test.h" - namespace testing { namespace gmock_matchers_test { namespace { @@ -1204,13 +1205,16 @@ TEST(SizeIsTest, ExplainsResult) { vector<int> container; EXPECT_EQ("whose size 0 doesn't match", Explain(m1, container)); EXPECT_EQ("whose size 0 matches", Explain(m2, container)); - EXPECT_EQ("whose size 0 matches", Explain(m3, container)); + EXPECT_EQ("whose size 0 matches, which matches (is equal to 0)", + Explain(m3, container)); EXPECT_EQ("whose size 0 doesn't match", Explain(m4, container)); container.push_back(0); container.push_back(0); EXPECT_EQ("whose size 2 matches", Explain(m1, container)); EXPECT_EQ("whose size 2 doesn't match", Explain(m2, container)); - EXPECT_EQ("whose size 2 doesn't match", Explain(m3, container)); + EXPECT_EQ( + "whose size 2 doesn't match, isn't equal to 0, and isn't equal to 3", + Explain(m3, container)); EXPECT_EQ("whose size 2 matches", Explain(m4, container)); } @@ -1268,10 +1272,11 @@ TEST(WhenSortedByTest, CanDescribeSelf) { 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 @@ -1475,8 +1480,10 @@ TEST_P(BeginEndDistanceIsTestP, ExplainsResult) { Explain(m1, container)); EXPECT_EQ("whose distance between begin() and end() 0 matches", Explain(m2, container)); - EXPECT_EQ("whose distance between begin() and end() 0 matches", - Explain(m3, container)); + EXPECT_EQ( + "whose distance between begin() and end() 0 matches, which matches (is " + "equal to 0)", + Explain(m3, container)); EXPECT_EQ( "whose distance between begin() and end() 0 doesn't match, which is 1 " "less than 1", @@ -1487,8 +1494,10 @@ TEST_P(BeginEndDistanceIsTestP, ExplainsResult) { Explain(m1, container)); EXPECT_EQ("whose distance between begin() and end() 2 doesn't match", Explain(m2, container)); - EXPECT_EQ("whose distance between begin() and end() 2 doesn't match", - Explain(m3, container)); + EXPECT_EQ( + "whose distance between begin() and end() 2 doesn't match, isn't equal " + "to 0, and isn't equal to 3", + Explain(m3, container)); EXPECT_EQ( "whose distance between begin() and end() 2 matches, which is 1 more " "than 1", @@ -1768,6 +1777,295 @@ TEST(IsSubsetOfTest, WorksWithMoveOnly) { 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". @@ -2148,7 +2446,7 @@ TEST_P(EachTestP, ExplainsMatchResultCorrectly) { 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)); @@ -2283,7 +2581,7 @@ TEST(PointwiseTest, MakesCopyOfRhs) { 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. @@ -2411,7 +2709,7 @@ TEST(UnorderedPointwiseTest, MakesCopyOfRhs) { 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. @@ -2662,11 +2960,11 @@ TEST_P(ElementsAreTestP, CanExplainMismatchRightSize) { 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) { @@ -3066,7 +3364,7 @@ TEST(ContainsTest, SetDoesNotMatchWhenElementIsNotInContainer) { 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/googlemock/test/gmock-matchers-misc_test.cc b/googlemock/test/gmock-matchers-misc_test.cc index b8f64587db14..de8b76c69af4 100644 --- a/googlemock/test/gmock-matchers-misc_test.cc +++ b/googlemock/test/gmock-matchers-misc_test.cc @@ -32,6 +32,7 @@ // This file tests some commonly used argument matchers. #include <array> +#include <cstdint> #include <memory> #include <ostream> #include <string> @@ -39,14 +40,14 @@ #include <utility> #include <vector> +#include "gmock/gmock.h" +#include "test/gmock-matchers_test.h" #include "gtest/gtest.h" // Silence warning C4244: 'initializing': conversion from 'int' to 'short', // possible loss of data and C4100, unreferenced local parameter GTEST_DISABLE_MSC_WARNINGS_PUSH_(4244 4100) -#include "test/gmock-matchers_test.h" - namespace testing { namespace gmock_matchers_test { namespace { @@ -674,6 +675,8 @@ TEST_P(MatcherTupleTestP, ExplainsMatchFailure) { // explanation. } +#if GTEST_HAS_TYPED_TEST + // Sample optional type implementation with minimal requirements for use with // Optional matcher. template <typename T> @@ -691,38 +694,94 @@ class SampleOptional { bool has_value_; }; -TEST(OptionalTest, DescribesSelf) { - const Matcher<SampleOptional<int>> m = Optional(Eq(1)); +// Sample optional type implementation with alternative minimal requirements for +// use with Optional matcher. In particular, while it doesn't have a bool +// conversion operator, it does have a has_value() method. +template <typename T> +class SampleOptionalWithoutBoolConversion { + public: + using value_type = T; + explicit SampleOptionalWithoutBoolConversion(T value) + : value_(std::move(value)), has_value_(true) {} + SampleOptionalWithoutBoolConversion() : value_(), has_value_(false) {} + bool has_value() const { return has_value_; } + const T& operator*() const { return value_; } + + private: + T value_; + bool has_value_; +}; + +template <typename T> +class OptionalTest : public testing::Test {}; + +using OptionalTestTypes = + testing::Types<SampleOptional<int>, + SampleOptionalWithoutBoolConversion<int>>; + +TYPED_TEST_SUITE(OptionalTest, OptionalTestTypes); + +TYPED_TEST(OptionalTest, DescribesSelf) { + const Matcher<TypeParam> m = Optional(Eq(1)); EXPECT_EQ("value is equal to 1", Describe(m)); } -TEST(OptionalTest, ExplainsSelf) { - const Matcher<SampleOptional<int>> m = Optional(Eq(1)); - EXPECT_EQ("whose value 1 matches", Explain(m, SampleOptional<int>(1))); - EXPECT_EQ("whose value 2 doesn't match", Explain(m, SampleOptional<int>(2))); +TYPED_TEST(OptionalTest, ExplainsSelf) { + const Matcher<TypeParam> m = Optional(Eq(1)); + EXPECT_EQ("whose value 1 matches", Explain(m, TypeParam(1))); + EXPECT_EQ("whose value 2 doesn't match", Explain(m, TypeParam(2))); } -TEST(OptionalTest, MatchesNonEmptyOptional) { - const Matcher<SampleOptional<int>> m1 = Optional(1); - const Matcher<SampleOptional<int>> m2 = Optional(Eq(2)); - const Matcher<SampleOptional<int>> m3 = Optional(Lt(3)); - SampleOptional<int> opt(1); +TYPED_TEST(OptionalTest, MatchesNonEmptyOptional) { + const Matcher<TypeParam> m1 = Optional(1); + const Matcher<TypeParam> m2 = Optional(Eq(2)); + const Matcher<TypeParam> m3 = Optional(Lt(3)); + TypeParam opt(1); EXPECT_TRUE(m1.Matches(opt)); EXPECT_FALSE(m2.Matches(opt)); EXPECT_TRUE(m3.Matches(opt)); } -TEST(OptionalTest, DoesNotMatchNullopt) { - const Matcher<SampleOptional<int>> m = Optional(1); - SampleOptional<int> empty; +TYPED_TEST(OptionalTest, DoesNotMatchNullopt) { + const Matcher<TypeParam> m = Optional(1); + TypeParam empty; EXPECT_FALSE(m.Matches(empty)); } -TEST(OptionalTest, WorksWithMoveOnly) { - Matcher<SampleOptional<std::unique_ptr<int>>> m = Optional(Eq(nullptr)); - EXPECT_TRUE(m.Matches(SampleOptional<std::unique_ptr<int>>(nullptr))); +TYPED_TEST(OptionalTest, ComposesWithMonomorphicMatchersTakingReferences) { + const Matcher<const int&> eq1 = Eq(1); + const Matcher<const int&> eq2 = Eq(2); + TypeParam opt(1); + EXPECT_THAT(opt, Optional(eq1)); + EXPECT_THAT(opt, Optional(Not(eq2))); + EXPECT_THAT(opt, Optional(AllOf(eq1, Not(eq2)))); +} + +TYPED_TEST(OptionalTest, ComposesWithMonomorphicMatchersRequiringConversion) { + const Matcher<int64_t> eq1 = Eq(1); + const Matcher<int64_t> eq2 = Eq(2); + TypeParam opt(1); + EXPECT_THAT(opt, Optional(eq1)); + EXPECT_THAT(opt, Optional(Not(eq2))); + EXPECT_THAT(opt, Optional(AllOf(eq1, Not(eq2)))); +} + +template <typename T> +class MoveOnlyOptionalTest : public testing::Test {}; + +using MoveOnlyOptionalTestTypes = + testing::Types<SampleOptional<std::unique_ptr<int>>, + SampleOptionalWithoutBoolConversion<std::unique_ptr<int>>>; + +TYPED_TEST_SUITE(MoveOnlyOptionalTest, MoveOnlyOptionalTestTypes); + +TYPED_TEST(MoveOnlyOptionalTest, WorksWithMoveOnly) { + Matcher<TypeParam> m = Optional(Eq(nullptr)); + EXPECT_TRUE(m.Matches(TypeParam(nullptr))); } +#endif // GTEST_HAS_TYPED_TEST + class SampleVariantIntString { public: SampleVariantIntString(int i) : i_(i), has_int_(true) {} @@ -1576,10 +1635,10 @@ TEST_P(AnyOfArrayTestP, ExplainsMatchResultCorrectly) { const Matcher<int> m1 = AnyOfArray(v1); const Matcher<int> m2 = AnyOfArray(v2); EXPECT_EQ("", Explain(m0, 0)); - EXPECT_EQ("", Explain(m1, 1)); - EXPECT_EQ("", Explain(m1, 2)); - EXPECT_EQ("", Explain(m2, 3)); - EXPECT_EQ("", Explain(m2, 4)); + EXPECT_EQ("which matches (is equal to 1)", Explain(m1, 1)); + EXPECT_EQ("isn't equal to 1", Explain(m1, 2)); + EXPECT_EQ("which matches (is equal to 3)", Explain(m2, 3)); + EXPECT_EQ("isn't equal to 2, and isn't equal to 3", Explain(m2, 4)); EXPECT_EQ("()", Describe(m0)); EXPECT_EQ("(is equal to 1)", Describe(m1)); EXPECT_EQ("(is equal to 2) or (is equal to 3)", Describe(m2)); diff --git a/googlemock/test/gmock-more-actions_test.cc b/googlemock/test/gmock-more-actions_test.cc index 354a79b192c8..5b8b566f4c9f 100644 --- a/googlemock/test/gmock-more-actions_test.cc +++ b/googlemock/test/gmock-more-actions_test.cc @@ -59,6 +59,7 @@ using testing::Invoke; using testing::ReturnArg; using testing::ReturnPointee; using testing::SaveArg; +using testing::SaveArgByMove; using testing::SaveArgPointee; using testing::SetArgReferee; using testing::Unused; @@ -492,6 +493,34 @@ TEST(SaveArgActionTest, WorksForCompatibleType) { EXPECT_EQ('a', result); } +struct MoveOnly { + explicit MoveOnly(int v) : i(v) {} + MoveOnly(MoveOnly&& o) { + i = o.i; + o.i = -1; + } + MoveOnly& operator=(MoveOnly&& o) { + i = o.i; + o.i = -1; + return *this; + } + int i; +}; + +TEST(SaveArgByMoveActionTest, WorksForSameType) { + MoveOnly result{0}; + const Action<void(MoveOnly v)> a1 = SaveArgByMove<0>(&result); + a1.Perform(std::make_tuple(MoveOnly{5})); + EXPECT_EQ(5, result.i); +} + +TEST(SaveArgByMoveActionTest, WorksForCompatibleType) { + MoveOnly result{0}; + const Action<void(bool, MoveOnly)> a1 = SaveArgByMove<1>(&result); + a1.Perform(std::make_tuple(true, MoveOnly{7})); + EXPECT_EQ(7, result.i); +} + TEST(SaveArgPointeeActionTest, WorksForSameType) { int result = 0; const int value = 5; @@ -756,34 +785,34 @@ TEST(InvokeArgumentTest, Functor6) { // Tests using InvokeArgument with a 7-ary function. TEST(InvokeArgumentTest, Function7) { - Action<std::string(std::string(*)(const char*, const char*, const char*, - const char*, const char*, const char*, - const char*))> + Action<std::string(std::string (*)(const char*, const char*, const char*, + const char*, const char*, const char*, + const char*))> a = InvokeArgument<0>("1", "2", "3", "4", "5", "6", "7"); EXPECT_EQ("1234567", a.Perform(std::make_tuple(&Concat7))); } // Tests using InvokeArgument with a 8-ary function. TEST(InvokeArgumentTest, Function8) { - Action<std::string(std::string(*)(const char*, const char*, const char*, - const char*, const char*, const char*, - const char*, const char*))> + Action<std::string(std::string (*)(const char*, const char*, const char*, + const char*, const char*, const char*, + const char*, const char*))> a = InvokeArgument<0>("1", "2", "3", "4", "5", "6", "7", "8"); EXPECT_EQ("12345678", a.Perform(std::make_tuple(&Concat8))); } // Tests using InvokeArgument with a 9-ary function. TEST(InvokeArgumentTest, Function9) { - Action<std::string(std::string(*)(const char*, const char*, const char*, - const char*, const char*, const char*, - const char*, const char*, const char*))> + Action<std::string(std::string (*)(const char*, const char*, const char*, + const char*, const char*, const char*, + const char*, const char*, const char*))> a = InvokeArgument<0>("1", "2", "3", "4", "5", "6", "7", "8", "9"); EXPECT_EQ("123456789", a.Perform(std::make_tuple(&Concat9))); } // Tests using InvokeArgument with a 10-ary function. TEST(InvokeArgumentTest, Function10) { - Action<std::string(std::string(*)( + Action<std::string(std::string (*)( const char*, const char*, const char*, const char*, const char*, const char*, const char*, const char*, const char*, const char*))> a = InvokeArgument<0>("1", "2", "3", "4", "5", "6", "7", "8", "9", "0"); diff --git a/googlemock/test/gmock-pp_test.cc b/googlemock/test/gmock-pp_test.cc index 5d1566e38853..e447f7651d3c 100644 --- a/googlemock/test/gmock-pp_test.cc +++ b/googlemock/test/gmock-pp_test.cc @@ -70,7 +70,7 @@ static_assert(GMOCK_PP_INTERNAL_VAR_TEST(x, y) == 2, ""); static_assert(GMOCK_PP_INTERNAL_VAR_TEST(silly) == 1, ""); static_assert(GMOCK_PP_INTERNAL_VAR_TEST(x, y, z) == 3, ""); -// TODO(iserna): The following asserts fail in --config=lexan. +// TODO(iserna): The following asserts fail in --config=windows. #define GMOCK_PP_INTERNAL_IS_EMPTY_TEST_1 static_assert(GMOCK_PP_IS_EMPTY(GMOCK_PP_INTERNAL_IS_EMPTY_TEST_1), ""); static_assert(GMOCK_PP_IS_EMPTY(), ""); diff --git a/googlemock/test/gmock-spec-builders_test.cc b/googlemock/test/gmock-spec-builders_test.cc index aaf88d74ee79..9e68aa0cbeca 100644 --- a/googlemock/test/gmock-spec-builders_test.cc +++ b/googlemock/test/gmock-spec-builders_test.cc @@ -804,9 +804,8 @@ TEST(ExpectCallTest, InfersCardinality1WhenThereIsWillRepeatedly) { "to be called at least once"); } -#if defined(GTEST_INTERNAL_CPLUSPLUS_LANG) && \ - GTEST_INTERNAL_CPLUSPLUS_LANG >= 201703L - +// TODO(b/396121064) - Fix this test under MSVC +#ifndef _MSC_VER // It should be possible to return a non-moveable type from a mock action in // C++17 and above, where it's guaranteed that such a type can be initialized // from a prvalue returned from a function. @@ -847,7 +846,7 @@ TEST(ExpectCallTest, NonMoveableType) { EXPECT_EQ(17, mock.AsStdFunction()().x); } -#endif // C++17 and above +#endif // _MSC_VER // Tests that the n-th action is taken for the n-th matching // invocation. diff --git a/googlemock/test/gmock_link_test.h b/googlemock/test/gmock_link_test.h index cf0a985b6320..cb5179b2f83b 100644 --- a/googlemock/test/gmock_link_test.h +++ b/googlemock/test/gmock_link_test.h @@ -186,8 +186,8 @@ using testing::SetErrnoAndReturn; #endif #if GTEST_HAS_EXCEPTIONS -using testing::Throw; using testing::Rethrow; +using testing::Throw; #endif using testing::ContainsRegex; diff --git a/googletest/README.md b/googletest/README.md index a7d9aa32589f..a760759eb0a5 100644 --- a/googletest/README.md +++ b/googletest/README.md @@ -25,7 +25,7 @@ When building GoogleTest as a standalone project, the typical workflow starts with ``` -git clone https://github.com/google/googletest.git -b v1.15.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 @@ match the project in which it is included. #### 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. diff --git a/googletest/cmake/internal_utils.cmake b/googletest/cmake/internal_utils.cmake index 580ac1cbc381..7ca256a76b75 100644 --- a/googletest/cmake/internal_utils.cmake +++ b/googletest/cmake/internal_utils.cmake @@ -195,7 +195,7 @@ function(cxx_library_with_type name type cxx_flags) target_link_libraries(${name} PUBLIC Threads::Threads) endif() - target_compile_features(${name} PUBLIC cxx_std_14) + target_compile_features(${name} PUBLIC cxx_std_17) endfunction() ######################################################################## diff --git a/googletest/include/gtest/gtest-assertion-result.h b/googletest/include/gtest/gtest-assertion-result.h index 74eb2b1f3c71..954e7c40f3af 100644 --- a/googletest/include/gtest/gtest-assertion-result.h +++ b/googletest/include/gtest/gtest-assertion-result.h @@ -129,6 +129,13 @@ namespace testing { // // Expected: Foo() is even // Actual: it's 5 +// + +// Returned AssertionResult objects may not be ignored. +// Note: Disabled for SWIG as it doesn't parse attributes correctly. +#if !defined(SWIG) +class [[nodiscard]] AssertionResult; +#endif // !SWIG class GTEST_API_ AssertionResult { public: diff --git a/googletest/include/gtest/gtest-matchers.h b/googletest/include/gtest/gtest-matchers.h index eae210e99dda..78160f0e418d 100644 --- a/googletest/include/gtest/gtest-matchers.h +++ b/googletest/include/gtest/gtest-matchers.h @@ -67,10 +67,10 @@ namespace testing { // To implement a matcher Foo for type T, define: // 1. a class FooMatcherMatcher that implements the matcher interface: // using is_gtest_matcher = void; -// bool MatchAndExplain(const T&, std::ostream*); +// bool MatchAndExplain(const T&, std::ostream*) const; // (MatchResultListener* can also be used instead of std::ostream*) -// void DescribeTo(std::ostream*); -// void DescribeNegationTo(std::ostream*); +// void DescribeTo(std::ostream*) const; +// void DescribeNegationTo(std::ostream*) const; // // 2. a factory function that creates a Matcher<T> object from a // FooMatcherMatcher. diff --git a/googletest/include/gtest/gtest-param-test.h b/googletest/include/gtest/gtest-param-test.h index 55ee088b93fb..9e023f96dc60 100644 --- a/googletest/include/gtest/gtest-param-test.h +++ b/googletest/include/gtest/gtest-param-test.h @@ -174,6 +174,7 @@ TEST_P(DerivedTest, DoesBlah) { #endif // 0 +#include <functional> #include <iterator> #include <utility> @@ -413,7 +414,8 @@ internal::CartesianProductHolder<Generator...> Combine(const Generator&... g) { // 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 @@ internal::CartesianProductHolder<Generator...> Combine(const Generator&... g) { // 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) \ @@ -469,7 +526,7 @@ internal::ParamConverterGenerator<T> ConvertGenerator( ::testing::internal::CodeLocation(__FILE__, __LINE__)); \ return 0; \ } \ - GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED static int gtest_registering_dummy_; \ + [[maybe_unused]] static int gtest_registering_dummy_; \ }; \ int GTEST_TEST_CLASS_NAME_(test_suite_name, \ test_name)::gtest_registering_dummy_ = \ @@ -493,39 +550,38 @@ internal::ParamConverterGenerator<T> ConvertGenerator( #define GTEST_GET_FIRST_(first, ...) first #define GTEST_GET_SECOND_(first, second, ...) second -#define INSTANTIATE_TEST_SUITE_P(prefix, test_suite_name, ...) \ - static ::testing::internal::ParamGenerator<test_suite_name::ParamType> \ - gtest_##prefix##test_suite_name##_EvalGenerator_() { \ - return GTEST_EXPAND_(GTEST_GET_FIRST_(__VA_ARGS__, DUMMY_PARAM_)); \ - } \ - static ::std::string gtest_##prefix##test_suite_name##_EvalGenerateName_( \ - const ::testing::TestParamInfo<test_suite_name::ParamType>& info) { \ - if (::testing::internal::AlwaysFalse()) { \ - ::testing::internal::TestNotEmpty(GTEST_EXPAND_(GTEST_GET_SECOND_( \ - __VA_ARGS__, \ - ::testing::internal::DefaultParamName<test_suite_name::ParamType>, \ - DUMMY_PARAM_))); \ - auto t = std::make_tuple(__VA_ARGS__); \ - static_assert(std::tuple_size<decltype(t)>::value <= 2, \ - "Too Many Args!"); \ - } \ - return ((GTEST_EXPAND_(GTEST_GET_SECOND_( \ - __VA_ARGS__, \ - ::testing::internal::DefaultParamName<test_suite_name::ParamType>, \ - DUMMY_PARAM_))))(info); \ - } \ - GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED static int \ - gtest_##prefix##test_suite_name##_dummy_ = \ - ::testing::UnitTest::GetInstance() \ - ->parameterized_test_registry() \ - .GetTestSuitePatternHolder<test_suite_name>( \ - GTEST_STRINGIFY_(test_suite_name), \ - ::testing::internal::CodeLocation(__FILE__, __LINE__)) \ - ->AddTestSuiteInstantiation( \ - GTEST_STRINGIFY_(prefix), \ - >est_##prefix##test_suite_name##_EvalGenerator_, \ - >est_##prefix##test_suite_name##_EvalGenerateName_, \ - __FILE__, __LINE__) +#define INSTANTIATE_TEST_SUITE_P(prefix, test_suite_name, ...) \ + static ::testing::internal::ParamGenerator<test_suite_name::ParamType> \ + gtest_##prefix##test_suite_name##_EvalGenerator_() { \ + return GTEST_EXPAND_(GTEST_GET_FIRST_(__VA_ARGS__, DUMMY_PARAM_)); \ + } \ + static ::std::string gtest_##prefix##test_suite_name##_EvalGenerateName_( \ + const ::testing::TestParamInfo<test_suite_name::ParamType>& info) { \ + if (::testing::internal::AlwaysFalse()) { \ + ::testing::internal::TestNotEmpty(GTEST_EXPAND_(GTEST_GET_SECOND_( \ + __VA_ARGS__, \ + ::testing::internal::DefaultParamName<test_suite_name::ParamType>, \ + DUMMY_PARAM_))); \ + auto t = std::make_tuple(__VA_ARGS__); \ + static_assert(std::tuple_size<decltype(t)>::value <= 2, \ + "Too Many Args!"); \ + } \ + return ((GTEST_EXPAND_(GTEST_GET_SECOND_( \ + __VA_ARGS__, \ + ::testing::internal::DefaultParamName<test_suite_name::ParamType>, \ + DUMMY_PARAM_))))(info); \ + } \ + [[maybe_unused]] static int gtest_##prefix##test_suite_name##_dummy_ = \ + ::testing::UnitTest::GetInstance() \ + ->parameterized_test_registry() \ + .GetTestSuitePatternHolder<test_suite_name>( \ + GTEST_STRINGIFY_(test_suite_name), \ + ::testing::internal::CodeLocation(__FILE__, __LINE__)) \ + ->AddTestSuiteInstantiation( \ + GTEST_STRINGIFY_(prefix), \ + >est_##prefix##test_suite_name##_EvalGenerator_, \ + >est_##prefix##test_suite_name##_EvalGenerateName_, __FILE__, \ + __LINE__) // Allow Marking a Parameterized test class as not needing to be instantiated. #define GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(T) \ diff --git a/googletest/include/gtest/gtest-printers.h b/googletest/include/gtest/gtest-printers.h index b2822bcde23c..198a7693493a 100644 --- a/googletest/include/gtest/gtest-printers.h +++ b/googletest/include/gtest/gtest-printers.h @@ -126,6 +126,10 @@ #include <span> // NOLINT #endif // GTEST_INTERNAL_HAS_STD_SPAN +#if GTEST_INTERNAL_HAS_COMPARE_LIB +#include <compare> // NOLINT +#endif // GTEST_INTERNAL_HAS_COMPARE_LIB + namespace testing { // Definitions in the internal* namespaces are subject to change without notice. @@ -782,6 +786,41 @@ void PrintTo(const std::shared_ptr<T>& ptr, std::ostream* os) { (PrintSmartPointer<T>)(ptr, os, 0); } +#if GTEST_INTERNAL_HAS_COMPARE_LIB +template <typename T> +void PrintOrderingHelper(T ordering, std::ostream* os) { + if (ordering == T::less) { + *os << "(less)"; + } else if (ordering == T::greater) { + *os << "(greater)"; + } else if (ordering == T::equivalent) { + *os << "(equivalent)"; + } else { + *os << "(unknown ordering)"; + } +} + +inline void PrintTo(std::strong_ordering ordering, std::ostream* os) { + if (ordering == std::strong_ordering::equal) { + *os << "(equal)"; + } else { + PrintOrderingHelper(ordering, os); + } +} + +inline void PrintTo(std::partial_ordering ordering, std::ostream* os) { + if (ordering == std::partial_ordering::unordered) { + *os << "(unordered)"; + } else { + PrintOrderingHelper(ordering, os); + } +} + +inline void PrintTo(std::weak_ordering ordering, std::ostream* os) { + PrintOrderingHelper(ordering, os); +} +#endif + // Helper function for printing a tuple. T must be instantiated with // a tuple type. template <typename T> diff --git a/googletest/include/gtest/gtest-typed-test.h b/googletest/include/gtest/gtest-typed-test.h index 305b0b50dd4c..442e00bd3478 100644 --- a/googletest/include/gtest/gtest-typed-test.h +++ b/googletest/include/gtest/gtest-typed-test.h @@ -194,34 +194,33 @@ INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes); typedef ::testing::internal::NameGeneratorSelector<__VA_ARGS__>::type \ GTEST_NAME_GENERATOR_(CaseName) -#define TYPED_TEST(CaseName, TestName) \ - static_assert(sizeof(GTEST_STRINGIFY_(TestName)) > 1, \ - "test-name must not be empty"); \ - template <typename gtest_TypeParam_> \ - class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \ - : public CaseName<gtest_TypeParam_> { \ - private: \ - typedef CaseName<gtest_TypeParam_> TestFixture; \ - typedef gtest_TypeParam_ TypeParam; \ - void TestBody() override; \ - }; \ - GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED static bool \ - gtest_##CaseName##_##TestName##_registered_ = \ - ::testing::internal::TypeParameterizedTest< \ - CaseName, \ - ::testing::internal::TemplateSel<GTEST_TEST_CLASS_NAME_( \ - CaseName, TestName)>, \ - GTEST_TYPE_PARAMS_( \ - CaseName)>::Register("", \ - ::testing::internal::CodeLocation( \ - __FILE__, __LINE__), \ - GTEST_STRINGIFY_(CaseName), \ - GTEST_STRINGIFY_(TestName), 0, \ - ::testing::internal::GenerateNames< \ - GTEST_NAME_GENERATOR_(CaseName), \ - GTEST_TYPE_PARAMS_(CaseName)>()); \ - template <typename gtest_TypeParam_> \ - void GTEST_TEST_CLASS_NAME_(CaseName, \ +#define TYPED_TEST(CaseName, TestName) \ + static_assert(sizeof(GTEST_STRINGIFY_(TestName)) > 1, \ + "test-name must not be empty"); \ + template <typename gtest_TypeParam_> \ + class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \ + : public CaseName<gtest_TypeParam_> { \ + private: \ + typedef CaseName<gtest_TypeParam_> TestFixture; \ + typedef gtest_TypeParam_ TypeParam; \ + void TestBody() override; \ + }; \ + [[maybe_unused]] static bool gtest_##CaseName##_##TestName##_registered_ = \ + ::testing::internal::TypeParameterizedTest< \ + CaseName, \ + ::testing::internal::TemplateSel<GTEST_TEST_CLASS_NAME_(CaseName, \ + TestName)>, \ + GTEST_TYPE_PARAMS_( \ + CaseName)>::Register("", \ + ::testing::internal::CodeLocation( \ + __FILE__, __LINE__), \ + GTEST_STRINGIFY_(CaseName), \ + GTEST_STRINGIFY_(TestName), 0, \ + ::testing::internal::GenerateNames< \ + GTEST_NAME_GENERATOR_(CaseName), \ + GTEST_TYPE_PARAMS_(CaseName)>()); \ + template <typename gtest_TypeParam_> \ + void GTEST_TEST_CLASS_NAME_(CaseName, \ TestName)<gtest_TypeParam_>::TestBody() // Legacy API is deprecated but still available @@ -268,23 +267,22 @@ INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes); TYPED_TEST_SUITE_P #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ -#define TYPED_TEST_P(SuiteName, TestName) \ - namespace GTEST_SUITE_NAMESPACE_(SuiteName) { \ - template <typename gtest_TypeParam_> \ - class TestName : public SuiteName<gtest_TypeParam_> { \ - private: \ - typedef SuiteName<gtest_TypeParam_> TestFixture; \ - typedef gtest_TypeParam_ TypeParam; \ - void TestBody() override; \ - }; \ - GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED static bool \ - gtest_##TestName##_defined_ = \ - GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).AddTestName( \ - __FILE__, __LINE__, GTEST_STRINGIFY_(SuiteName), \ - GTEST_STRINGIFY_(TestName)); \ - } \ - template <typename gtest_TypeParam_> \ - void GTEST_SUITE_NAMESPACE_( \ +#define TYPED_TEST_P(SuiteName, TestName) \ + namespace GTEST_SUITE_NAMESPACE_(SuiteName) { \ + template <typename gtest_TypeParam_> \ + class TestName : public SuiteName<gtest_TypeParam_> { \ + private: \ + typedef SuiteName<gtest_TypeParam_> TestFixture; \ + typedef gtest_TypeParam_ TypeParam; \ + void TestBody() override; \ + }; \ + [[maybe_unused]] static bool gtest_##TestName##_defined_ = \ + GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).AddTestName( \ + __FILE__, __LINE__, GTEST_STRINGIFY_(SuiteName), \ + GTEST_STRINGIFY_(TestName)); \ + } \ + template <typename gtest_TypeParam_> \ + void GTEST_SUITE_NAMESPACE_( \ SuiteName)::TestName<gtest_TypeParam_>::TestBody() // Note: this won't work correctly if the trailing arguments are macros. @@ -292,8 +290,8 @@ INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes); namespace GTEST_SUITE_NAMESPACE_(SuiteName) { \ typedef ::testing::internal::Templates<__VA_ARGS__> gtest_AllTests_; \ } \ - GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED static const char* const \ - GTEST_REGISTERED_TEST_NAMES_(SuiteName) = \ + [[maybe_unused]] static const char* const GTEST_REGISTERED_TEST_NAMES_( \ + SuiteName) = \ GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).VerifyRegisteredTestNames( \ GTEST_STRINGIFY_(SuiteName), __FILE__, __LINE__, #__VA_ARGS__) @@ -305,24 +303,22 @@ INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes); REGISTER_TYPED_TEST_SUITE_P #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ -#define INSTANTIATE_TYPED_TEST_SUITE_P(Prefix, SuiteName, Types, ...) \ - static_assert(sizeof(GTEST_STRINGIFY_(Prefix)) > 1, \ - "test-suit-prefix must not be empty"); \ - GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED static bool \ - gtest_##Prefix##_##SuiteName = \ - ::testing::internal::TypeParameterizedTestSuite< \ - SuiteName, GTEST_SUITE_NAMESPACE_(SuiteName)::gtest_AllTests_, \ - ::testing::internal::GenerateTypeList<Types>::type>:: \ - Register( \ - GTEST_STRINGIFY_(Prefix), \ - ::testing::internal::CodeLocation(__FILE__, __LINE__), \ - >EST_TYPED_TEST_SUITE_P_STATE_(SuiteName), \ - GTEST_STRINGIFY_(SuiteName), \ - GTEST_REGISTERED_TEST_NAMES_(SuiteName), \ - ::testing::internal::GenerateNames< \ - ::testing::internal::NameGeneratorSelector< \ - __VA_ARGS__>::type, \ - ::testing::internal::GenerateTypeList<Types>::type>()) +#define INSTANTIATE_TYPED_TEST_SUITE_P(Prefix, SuiteName, Types, ...) \ + static_assert(sizeof(GTEST_STRINGIFY_(Prefix)) > 1, \ + "test-suit-prefix must not be empty"); \ + [[maybe_unused]] static bool gtest_##Prefix##_##SuiteName = \ + ::testing::internal::TypeParameterizedTestSuite< \ + SuiteName, GTEST_SUITE_NAMESPACE_(SuiteName)::gtest_AllTests_, \ + ::testing::internal::GenerateTypeList<Types>::type>:: \ + Register(GTEST_STRINGIFY_(Prefix), \ + ::testing::internal::CodeLocation(__FILE__, __LINE__), \ + >EST_TYPED_TEST_SUITE_P_STATE_(SuiteName), \ + GTEST_STRINGIFY_(SuiteName), \ + GTEST_REGISTERED_TEST_NAMES_(SuiteName), \ + ::testing::internal::GenerateNames< \ + ::testing::internal::NameGeneratorSelector< \ + __VA_ARGS__>::type, \ + ::testing::internal::GenerateTypeList<Types>::type>()) // Legacy API is deprecated but still available #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_ diff --git a/googletest/include/gtest/gtest.h b/googletest/include/gtest/gtest.h index c89966952033..7be0caaf515c 100644 --- a/googletest/include/gtest/gtest.h +++ b/googletest/include/gtest/gtest.h @@ -1123,7 +1123,7 @@ class GTEST_API_ UnitTest { // This method can only be called from the main thread. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. - int Run() GTEST_MUST_USE_RESULT_; + [[nodiscard]] int Run(); // Returns the working directory when the first TEST() or TEST_F() // was executed. The UnitTest object owns the string. @@ -2329,7 +2329,7 @@ TestInfo* RegisterTest(const char* test_suite_name, const char* test_name, // // This function was formerly a macro; thus, it is in the global // namespace and has an all-caps name. -int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_; +[[nodiscard]] int RUN_ALL_TESTS(); inline int RUN_ALL_TESTS() { return ::testing::UnitTest::GetInstance()->Run(); } diff --git a/googletest/include/gtest/internal/gtest-internal.h b/googletest/include/gtest/internal/gtest-internal.h index 7e55dc605cb9..808d89be9143 100644 --- a/googletest/include/gtest/internal/gtest-internal.h +++ b/googletest/include/gtest/internal/gtest-internal.h @@ -290,17 +290,17 @@ class FloatingPoint { // 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 @@ class FloatingPoint { // 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 @@ class FloatingPoint { // // - 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 @@ class FloatingPoint { // // 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 @@ class FloatingPoint { // 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 @@ -894,11 +886,6 @@ class HasDebugStringAndShortDebugString { HasDebugStringType::value && HasShortDebugStringType::value; }; -#ifdef GTEST_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL -template <typename T> -constexpr bool HasDebugStringAndShortDebugString<T>::value; -#endif - // When the compiler sees expression IsContainerTest<C>(0), if C is an // STL-style container class, the first overload of IsContainerTest // will be viable (since both C::iterator* and C::const_iterator* are @@ -1241,30 +1228,40 @@ class FlatTuple // Utility functions to be called with static_assert to induce deprecation // warnings. -GTEST_INTERNAL_DEPRECATED( +[[deprecated( "INSTANTIATE_TEST_CASE_P is deprecated, please use " - "INSTANTIATE_TEST_SUITE_P") -constexpr bool InstantiateTestCase_P_IsDeprecated() { return true; } + "INSTANTIATE_TEST_SUITE_P")]] +constexpr bool InstantiateTestCase_P_IsDeprecated() { + return true; +} -GTEST_INTERNAL_DEPRECATED( +[[deprecated( "TYPED_TEST_CASE_P is deprecated, please use " - "TYPED_TEST_SUITE_P") -constexpr bool TypedTestCase_P_IsDeprecated() { return true; } + "TYPED_TEST_SUITE_P")]] +constexpr bool TypedTestCase_P_IsDeprecated() { + return true; +} -GTEST_INTERNAL_DEPRECATED( +[[deprecated( "TYPED_TEST_CASE is deprecated, please use " - "TYPED_TEST_SUITE") -constexpr bool TypedTestCaseIsDeprecated() { return true; } + "TYPED_TEST_SUITE")]] +constexpr bool TypedTestCaseIsDeprecated() { + return true; +} -GTEST_INTERNAL_DEPRECATED( +[[deprecated( "REGISTER_TYPED_TEST_CASE_P is deprecated, please use " - "REGISTER_TYPED_TEST_SUITE_P") -constexpr bool RegisterTypedTestCase_P_IsDeprecated() { return true; } + "REGISTER_TYPED_TEST_SUITE_P")]] +constexpr bool RegisterTypedTestCase_P_IsDeprecated() { + return true; +} -GTEST_INTERNAL_DEPRECATED( +[[deprecated( "INSTANTIATE_TYPED_TEST_CASE_P is deprecated, please use " - "INSTANTIATE_TYPED_TEST_SUITE_P") -constexpr bool InstantiateTypedTestCase_P_IsDeprecated() { return true; } + "INSTANTIATE_TYPED_TEST_SUITE_P")]] +constexpr bool InstantiateTypedTestCase_P_IsDeprecated() { + return true; +} } // namespace internal } // namespace testing @@ -1501,8 +1498,7 @@ class NeverThrown { \ private: \ void TestBody() override; \ - GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED static ::testing::TestInfo* const \ - test_info_; \ + [[maybe_unused]] static ::testing::TestInfo* const test_info_; \ }; \ \ ::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_suite_name, \ diff --git a/googletest/include/gtest/internal/gtest-param-util.h b/googletest/include/gtest/internal/gtest-param-util.h index cc7ea531738c..a092a86adab2 100644 --- a/googletest/include/gtest/internal/gtest-param-util.h +++ b/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 @@ class ParameterizedTestSuiteInfo : public ParameterizedTestSuiteInfoBase { // 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 @@ class CartesianProductHolder { 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 @@ class ParamGeneratorConverter : public ParamGeneratorInterface<To> { 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 @@ class ParamGeneratorConverter : public ParamGeneratorInterface<To> { } 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 @@ class ParamGeneratorConverter : public ParamGeneratorInterface<To> { 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/googletest/include/gtest/internal/gtest-port.h b/googletest/include/gtest/internal/gtest-port.h index 8d27c2c4f72f..25b7d194dba4 100644 --- a/googletest/include/gtest/internal/gtest-port.h +++ b/googletest/include/gtest/internal/gtest-port.h @@ -194,7 +194,6 @@ // // Macros for basic C++ coding: // GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning. -// GTEST_MUST_USE_RESULT_ - declares that a function's result must be used. // GTEST_INTENTIONAL_CONST_COND_PUSH_ - start code section where MSVC C4127 is // suppressed (constant conditional). // GTEST_INTENTIONAL_CONST_COND_POP_ - finish code section where MSVC C4127 @@ -260,11 +259,6 @@ // BoolFromGTestEnv() - parses a bool environment variable. // Int32FromGTestEnv() - parses an int32_t environment variable. // StringFromGTestEnv() - parses a string environment variable. -// -// Deprecation warnings: -// GTEST_INTERNAL_DEPRECATED(message) - attribute marking a function as -// deprecated; calling a marked function -// should generate a compiler warning // The definition of GTEST_INTERNAL_CPLUSPLUS_LANG comes first because it can // potentially be used as an #include guard. @@ -275,8 +269,8 @@ #endif #if !defined(GTEST_INTERNAL_CPLUSPLUS_LANG) || \ - GTEST_INTERNAL_CPLUSPLUS_LANG < 201402L -#error C++ versions less than C++14 are not supported. + GTEST_INTERNAL_CPLUSPLUS_LANG < 201703L +#error C++ versions less than C++17 are not supported. #endif // MSVC >= 19.11 (VS 2017 Update 3) supports __has_include. @@ -288,10 +282,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 @@ -772,25 +770,6 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; #define GTEST_HAVE_FEATURE_(x) 0 #endif -// Use this annotation after a variable or parameter declaration to tell the -// compiler the variable/parameter may be used. -// Example: -// -// GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED int foo = bar(); -// -// This can be removed once we only support only C++17 or newer and -// [[maybe_unused]] is available on all supported platforms. -#if GTEST_INTERNAL_HAVE_CPP_ATTRIBUTE(maybe_unused) -#define GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED [[maybe_unused]] -#elif GTEST_HAVE_ATTRIBUTE_(unused) -// This is inferior to [[maybe_unused]] as it can produce a -// -Wused-but-marked-unused warning on optionally used symbols, but it is all we -// have. -#define GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED __attribute__((__unused__)) -#else -#define GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED -#endif - // Use this annotation before a function that takes a printf format string. #if GTEST_HAVE_ATTRIBUTE_(format) && defined(__MINGW_PRINTF_FORMAT) // MinGW has two different printf implementations. Ensure the format macro @@ -805,17 +784,6 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION; #define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) #endif -// Tell the compiler to warn about unused return values for functions declared -// with this macro. The macro should be used on function declarations -// following the argument list: -// -// Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_; -#if GTEST_HAVE_ATTRIBUTE_(warn_unused_result) -#define GTEST_MUST_USE_RESULT_ __attribute__((warn_unused_result)) -#else -#define GTEST_MUST_USE_RESULT_ -#endif - // MS C++ compiler emits warning when a conditional expression is compile time // constant. In some contexts this warning is false positive and needs to be // suppressed. Use the following two macros in such cases: @@ -2367,26 +2335,6 @@ const char* StringFromGTestEnv(const char* flag, const char* default_val); } // namespace internal } // namespace testing -#if !defined(GTEST_INTERNAL_DEPRECATED) - -// Internal Macro to mark an API deprecated, for googletest usage only -// Usage: class GTEST_INTERNAL_DEPRECATED(message) MyClass or -// GTEST_INTERNAL_DEPRECATED(message) <return_type> myFunction(); Every usage of -// a deprecated entity will trigger a warning when compiled with -// `-Wdeprecated-declarations` option (clang, gcc, any __GNUC__ compiler). -// For msvc /W3 option will need to be used -// Note that for 'other' compilers this macro evaluates to nothing to prevent -// compilations errors. -#if defined(_MSC_VER) -#define GTEST_INTERNAL_DEPRECATED(message) __declspec(deprecated(message)) -#elif defined(__GNUC__) -#define GTEST_INTERNAL_DEPRECATED(message) __attribute__((deprecated(message))) -#else -#define GTEST_INTERNAL_DEPRECATED(message) -#endif - -#endif // !defined(GTEST_INTERNAL_DEPRECATED) - #ifdef GTEST_HAS_ABSL // Always use absl::any for UniversalPrinter<> specializations if googletest // is built with absl support. @@ -2527,10 +2475,12 @@ using Variant = ::std::variant<T...>; #define GTEST_INTERNAL_HAS_VARIANT 0 #endif -#if (defined(__cpp_constexpr) && !defined(__cpp_inline_variables)) || \ - (defined(GTEST_INTERNAL_CPLUSPLUS_LANG) && \ - GTEST_INTERNAL_CPLUSPLUS_LANG < 201703L) -#define GTEST_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL 1 +#if (defined(__cpp_lib_three_way_comparison) || \ + (GTEST_INTERNAL_HAS_INCLUDE(<compare>) && \ + GTEST_INTERNAL_CPLUSPLUS_LANG >= 201907L)) +#define GTEST_INTERNAL_HAS_COMPARE_LIB 1 +#else +#define GTEST_INTERNAL_HAS_COMPARE_LIB 0 #endif #endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ diff --git a/googletest/src/gtest-internal-inl.h b/googletest/src/gtest-internal-inl.h index cc6f00488f96..6a39b93be132 100644 --- a/googletest/src/gtest-internal-inl.h +++ b/googletest/src/gtest-internal-inl.h @@ -826,6 +826,10 @@ class GTEST_API_ UnitTestImpl { 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/googletest/src/gtest.cc b/googletest/src/gtest.cc index 6662a13ce145..09af15179f1f 100644 --- a/googletest/src/gtest.cc +++ b/googletest/src/gtest.cc @@ -192,12 +192,17 @@ static const char kDefaultOutputFormat[] = "xml"; // 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 { @@ -259,6 +264,12 @@ GTEST_DEFINE_bool_( "True if and only if a test failure should stop further test execution."); GTEST_DEFINE_bool_( + fail_if_no_test_linked, + testing::internal::BoolFromGTestEnv("fail_if_no_test_linked", false), + "True if and only if the test should fail if no test case (including " + "disabled test cases) is linked."); + +GTEST_DEFINE_bool_( also_run_disabled_tests, testing::internal::BoolFromGTestEnv("also_run_disabled_tests", false), "Run disabled tests too, in addition to the tests normally being run."); @@ -1660,10 +1671,25 @@ std::string GetBoolAssertionFailureMessage( return msg.GetString(); } -// Helper function for implementing ASSERT_NEAR. +// Helper function for implementing ASSERT_NEAR. Treats infinity as a specific +// value, such that comparing infinity to infinity is equal, the distance +// between -infinity and +infinity is infinity, and infinity <= infinity is +// true. AssertionResult DoubleNearPredFormat(const char* expr1, const char* expr2, const char* abs_error_expr, double val1, double val2, double abs_error) { + // We want to return success when the two values are infinity and at least + // one of the following is true: + // * The values are the same-signed infinity. + // * The error limit itself is infinity. + // This is done here so that we don't end up with a NaN when calculating the + // difference in values. + if (std::isinf(val1) && std::isinf(val2) && + (std::signbit(val1) == std::signbit(val2) || + (abs_error > 0.0 && std::isinf(abs_error)))) { + return AssertionSuccess(); + } + const double diff = fabs(val1 - val2); if (diff <= abs_error) return AssertionSuccess(); @@ -3974,6 +4000,12 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { static void OutputXmlTestSuiteForTestResult(::std::ostream* stream, const TestResult& result); + // Streams a test case XML stanza containing the given test result. + // + // Requires: result.Failed() + static void OutputXmlTestCaseForTestResult(::std::ostream* stream, + const TestResult& result); + // Streams an XML representation of a TestResult object. static void OutputXmlTestResult(::std::ostream* stream, const TestResult& result); @@ -3991,16 +4023,11 @@ class XmlUnitTestResultPrinter : public EmptyTestEventListener { static void PrintXmlUnitTest(::std::ostream* stream, const UnitTest& unit_test); - // Produces a string representing the test properties in a result as space - // delimited XML attributes based on the property key="value" pairs. - // When the std::string is not empty, it includes a space at the beginning, - // to delimit this attribute from prior attributes. - static std::string TestPropertiesAsXmlAttributes(const TestResult& result); - // Streams an XML representation of the test properties of a TestResult // object. static void OutputXmlTestProperties(std::ostream* stream, - const TestResult& result); + const TestResult& result, + const std::string& indent); // The output file. const std::string output_file_; @@ -4221,6 +4248,15 @@ void XmlUnitTestResultPrinter::OutputXmlTestSuiteForTestResult( FormatEpochTimeInMillisAsIso8601(result.start_timestamp())); *stream << ">"; + OutputXmlTestCaseForTestResult(stream, result); + + // Complete the test suite. + *stream << " </testsuite>\n"; +} + +// Streams a test case XML stanza containing the given test result. +void XmlUnitTestResultPrinter::OutputXmlTestCaseForTestResult( + ::std::ostream* stream, const TestResult& result) { // Output the boilerplate for a minimal test case with a single test. *stream << " <testcase"; OutputXmlAttribute(stream, "testcase", "name", ""); @@ -4235,9 +4271,6 @@ void XmlUnitTestResultPrinter::OutputXmlTestSuiteForTestResult( // Output the actual test result. OutputXmlTestResult(stream, result); - - // Complete the test suite. - *stream << " </testsuite>\n"; } // Prints an XML representation of a TestInfo object. @@ -4328,7 +4361,7 @@ void XmlUnitTestResultPrinter::OutputXmlTestResult(::std::ostream* stream, if (failures == 0 && skips == 0) { *stream << ">\n"; } - OutputXmlTestProperties(stream, result); + OutputXmlTestProperties(stream, result, /*indent=*/" "); *stream << " </testcase>\n"; } } @@ -4357,13 +4390,18 @@ void XmlUnitTestResultPrinter::PrintXmlTestSuite(std::ostream* stream, OutputXmlAttribute( stream, kTestsuite, "timestamp", FormatEpochTimeInMillisAsIso8601(test_suite.start_timestamp())); - *stream << TestPropertiesAsXmlAttributes(test_suite.ad_hoc_test_result()); } *stream << ">\n"; + OutputXmlTestProperties(stream, test_suite.ad_hoc_test_result(), + /*indent=*/" "); for (int i = 0; i < test_suite.total_test_count(); ++i) { if (test_suite.GetTestInfo(i)->is_reportable()) OutputXmlTestInfo(stream, test_suite.name(), *test_suite.GetTestInfo(i)); } + if (test_suite.ad_hoc_test_result().Failed()) { + OutputXmlTestCaseForTestResult(stream, test_suite.ad_hoc_test_result()); + } + *stream << " </" << kTestsuite << ">\n"; } @@ -4393,11 +4431,12 @@ void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream, OutputXmlAttribute(stream, kTestsuites, "random_seed", StreamableToString(unit_test.random_seed())); } - *stream << TestPropertiesAsXmlAttributes(unit_test.ad_hoc_test_result()); OutputXmlAttribute(stream, kTestsuites, "name", "AllTests"); *stream << ">\n"; + OutputXmlTestProperties(stream, unit_test.ad_hoc_test_result(), + /*indent=*/" "); for (int i = 0; i < unit_test.total_test_suite_count(); ++i) { if (unit_test.GetTestSuite(i)->reportable_test_count() > 0) PrintXmlTestSuite(stream, *unit_test.GetTestSuite(i)); @@ -4434,21 +4473,8 @@ void XmlUnitTestResultPrinter::PrintXmlTestsList( *stream << "</" << kTestsuites << ">\n"; } -// Produces a string representing the test properties in a result as space -// delimited XML attributes based on the property key="value" pairs. -std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( - const TestResult& result) { - Message attributes; - for (int i = 0; i < result.test_property_count(); ++i) { - const TestProperty& property = result.GetTestProperty(i); - attributes << " " << property.key() << "=" << "\"" - << EscapeXmlAttribute(property.value()) << "\""; - } - return attributes.GetString(); -} - void XmlUnitTestResultPrinter::OutputXmlTestProperties( - std::ostream* stream, const TestResult& result) { + std::ostream* stream, const TestResult& result, const std::string& indent) { const std::string kProperties = "properties"; const std::string kProperty = "property"; @@ -4456,15 +4482,15 @@ void XmlUnitTestResultPrinter::OutputXmlTestProperties( return; } - *stream << " <" << kProperties << ">\n"; + *stream << indent << "<" << kProperties << ">\n"; for (int i = 0; i < result.test_property_count(); ++i) { const TestProperty& property = result.GetTestProperty(i); - *stream << " <" << kProperty; + *stream << indent << " <" << kProperty; *stream << " name=\"" << EscapeXmlAttribute(property.key()) << "\""; *stream << " value=\"" << EscapeXmlAttribute(property.value()) << "\""; *stream << "/>\n"; } - *stream << " </" << kProperties << ">\n"; + *stream << indent << "</" << kProperties << ">\n"; } // End XmlUnitTestResultPrinter @@ -4503,6 +4529,12 @@ class JsonUnitTestResultPrinter : public EmptyTestEventListener { static void OutputJsonTestSuiteForTestResult(::std::ostream* stream, const TestResult& result); + // Streams a test case JSON stanza containing the given test result. + // + // Requires: result.Failed() + static void OutputJsonTestCaseForTestResult(::std::ostream* stream, + const TestResult& result); + // Streams a JSON representation of a TestResult object. static void OutputJsonTestResult(::std::ostream* stream, const TestResult& result); @@ -4673,6 +4705,15 @@ void JsonUnitTestResultPrinter::OutputJsonTestSuiteForTestResult( } *stream << Indent(6) << "\"testsuite\": [\n"; + OutputJsonTestCaseForTestResult(stream, result); + + // Finish the test suite. + *stream << "\n" << Indent(6) << "]\n" << Indent(4) << "}"; +} + +// Streams a test case JSON stanza containing the given test result. +void JsonUnitTestResultPrinter::OutputJsonTestCaseForTestResult( + ::std::ostream* stream, const TestResult& result) { // Output the boilerplate for a new test case. *stream << Indent(8) << "{\n"; OutputJsonKey(stream, "testcase", "name", "", Indent(10)); @@ -4689,9 +4730,6 @@ void JsonUnitTestResultPrinter::OutputJsonTestSuiteForTestResult( // Output the actual test result. OutputJsonTestResult(stream, result); - - // Finish the test suite. - *stream << "\n" << Indent(6) << "]\n" << Indent(4) << "}"; } // Prints a JSON representation of a TestInfo object. @@ -4836,6 +4874,16 @@ void JsonUnitTestResultPrinter::PrintJsonTestSuite( OutputJsonTestInfo(stream, test_suite.name(), *test_suite.GetTestInfo(i)); } } + + // If there was a failure in the test suite setup or teardown include that in + // the output. + if (test_suite.ad_hoc_test_result().Failed()) { + if (comma) { + *stream << ",\n"; + } + OutputJsonTestCaseForTestResult(stream, test_suite.ad_hoc_test_result()); + } + *stream << "\n" << kIndent << "]\n" << Indent(4) << "}"; } @@ -5832,6 +5880,23 @@ TestSuite* UnitTestImpl::GetTestSuite( 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 @@ -5853,6 +5918,28 @@ bool UnitTestImpl::RunAllTests() { // user didn't call InitGoogleTest. PostFlagParsingInit(); + // 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, "%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 // Even if sharding is not on, test runners may want to use the // GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding @@ -6026,6 +6113,17 @@ bool UnitTestImpl::RunAllTests() { 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, @@ -6194,6 +6292,30 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { 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 @@ -6640,6 +6762,7 @@ static bool ParseGoogleTestFlag(const char* const arg) { GTEST_INTERNAL_PARSE_FLAG(death_test_style); GTEST_INTERNAL_PARSE_FLAG(death_test_use_fork); GTEST_INTERNAL_PARSE_FLAG(fail_fast); + GTEST_INTERNAL_PARSE_FLAG(fail_if_no_test_linked); GTEST_INTERNAL_PARSE_FLAG(filter); GTEST_INTERNAL_PARSE_FLAG(internal_run_death_test); GTEST_INTERNAL_PARSE_FLAG(list_tests); diff --git a/googletest/test/BUILD.bazel b/googletest/test/BUILD.bazel index 1890b6ff9ed9..c561ef8b91c3 100644 --- a/googletest/test/BUILD.bazel +++ b/googletest/test/BUILD.bazel @@ -45,36 +45,38 @@ cc_test( "gtest-*.cc", "googletest-*.cc", "*.h", - "googletest/include/gtest/**/*.h", ], exclude = [ - "gtest-unittest-api_test.cc", - "googletest/src/gtest-all.cc", - "gtest_all_test.cc", - "gtest-death-test_ex_test.cc", - "gtest-listener_test.cc", - "gtest-unittest-api_test.cc", - "googletest-param-test-test.cc", - "googletest-param-test2-test.cc", + # go/keep-sorted start + "googletest-break-on-failure-unittest_.cc", "googletest-catch-exceptions-test_.cc", "googletest-color-test_.cc", + "googletest-death-test_ex_test.cc", "googletest-env-var-test_.cc", + "googletest-fail-if-no-test-linked-test-with-disabled-test_.cc", + "googletest-fail-if-no-test-linked-test-with-enabled-test_.cc", "googletest-failfast-unittest_.cc", "googletest-filter-unittest_.cc", "googletest-global-environment-unittest_.cc", - "googletest-break-on-failure-unittest_.cc", + "googletest-list-tests-unittest_.cc", "googletest-listener-test.cc", "googletest-message-test.cc", "googletest-output-test_.cc", - "googletest-list-tests-unittest_.cc", - "googletest-shuffle-test_.cc", - "googletest-setuptestsuite-test_.cc", - "googletest-uninitialized-test_.cc", - "googletest-death-test_ex_test.cc", - "googletest-param-test-test", - "googletest-throw-on-failure-test_.cc", "googletest-param-test-invalid-name1-test_.cc", "googletest-param-test-invalid-name2-test_.cc", + "googletest-param-test-test", + "googletest-param-test-test.cc", + "googletest-param-test2-test.cc", + "googletest-setuptestsuite-test_.cc", + "googletest-shuffle-test_.cc", + "googletest-throw-on-failure-test_.cc", + "googletest-uninitialized-test_.cc", + "googletest/src/gtest-all.cc", + "gtest-death-test_ex_test.cc", + "gtest-listener_test.cc", + "gtest-unittest-api_test.cc", + "gtest_all_test.cc", + # go/keep-sorted end ], ) + select({ "//:windows": [], @@ -324,6 +326,26 @@ cc_binary( deps = ["//:gtest"], ) +cc_binary( + name = "googletest-fail-if-no-test-linked-test-without-test_", + testonly = 1, + deps = ["//:gtest_main"], +) + +cc_binary( + name = "googletest-fail-if-no-test-linked-test-with-disabled-test_", + testonly = 1, + srcs = ["googletest-fail-if-no-test-linked-test-with-disabled-test_.cc"], + deps = ["//:gtest_main"], +) + +cc_binary( + name = "googletest-fail-if-no-test-linked-test-with-enabled-test_", + testonly = 1, + srcs = ["googletest-fail-if-no-test-linked-test-with-enabled-test_.cc"], + deps = ["//:gtest_main"], +) + cc_test( name = "gtest_skip_test", size = "small", @@ -364,6 +386,18 @@ py_test( deps = [":gtest_test_utils"], ) +py_test( + name = "googletest-fail-if-no-test-linked-test", + size = "small", + srcs = ["googletest-fail-if-no-test-linked-test.py"], + data = [ + ":googletest-fail-if-no-test-linked-test-with-disabled-test_", + ":googletest-fail-if-no-test-linked-test-with-enabled-test_", + ":googletest-fail-if-no-test-linked-test-without-test_", + ], + deps = [":gtest_test_utils"], +) + cc_binary( name = "googletest-shuffle-test_", srcs = ["googletest-shuffle-test_.cc"], diff --git a/googletest/test/googletest-filter-unittest.py b/googletest/test/googletest-filter-unittest.py index f1f3c7a513be..a44882a6da67 100755 --- a/googletest/test/googletest-filter-unittest.py +++ b/googletest/test/googletest-filter-unittest.py @@ -97,6 +97,9 @@ TOTAL_SHARDS_ENV_VAR = 'GTEST_TOTAL_SHARDS' 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 @@ class GTestFilterUnitTest(gtest_test_utils.TestCase): 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/googletest/test/googletest-json-output-unittest.py b/googletest/test/googletest-json-output-unittest.py index d3338e3d2f90..c75051c800fb 100644 --- a/googletest/test/googletest-json-output-unittest.py +++ b/googletest/test/googletest-json-output-unittest.py @@ -57,7 +57,7 @@ else: STACK_TRACE_TEMPLATE = '\n' EXPECTED_NON_EMPTY = { - 'tests': 26, + 'tests': 28, 'failures': 5, 'disabled': 2, 'errors': 0, @@ -323,12 +323,14 @@ EXPECTED_NON_EMPTY = { 'time': '*', 'timestamp': '*', 'SetUpTestSuite': 'yes', + 'SetUpTestSuite (with whitespace)': 'yes and yes', 'TearDownTestSuite': 'aye', + 'TearDownTestSuite (with whitespace)': 'aye and aye', 'testsuite': [ { 'name': 'OneProperty', 'file': 'gtest_xml_output_unittest_.cc', - 'line': 121, + 'line': 125, 'status': 'RUN', 'result': 'COMPLETED', 'time': '*', @@ -339,7 +341,7 @@ EXPECTED_NON_EMPTY = { { 'name': 'IntValuedProperty', 'file': 'gtest_xml_output_unittest_.cc', - 'line': 125, + 'line': 129, 'status': 'RUN', 'result': 'COMPLETED', 'time': '*', @@ -350,7 +352,7 @@ EXPECTED_NON_EMPTY = { { 'name': 'ThreeProperties', 'file': 'gtest_xml_output_unittest_.cc', - 'line': 129, + 'line': 133, 'status': 'RUN', 'result': 'COMPLETED', 'time': '*', @@ -363,7 +365,7 @@ EXPECTED_NON_EMPTY = { { 'name': 'TwoValuesForOneKeyUsesLastValue', 'file': 'gtest_xml_output_unittest_.cc', - 'line': 135, + 'line': 139, 'status': 'RUN', 'result': 'COMPLETED', 'time': '*', @@ -385,7 +387,7 @@ EXPECTED_NON_EMPTY = { { 'name': 'RecordProperty', 'file': 'gtest_xml_output_unittest_.cc', - 'line': 140, + 'line': 144, 'status': 'RUN', 'result': 'COMPLETED', 'time': '*', @@ -396,7 +398,7 @@ EXPECTED_NON_EMPTY = { { 'name': 'ExternalUtilityThatCallsRecordIntValuedProperty', 'file': 'gtest_xml_output_unittest_.cc', - 'line': 153, + 'line': 157, 'status': 'RUN', 'result': 'COMPLETED', 'time': '*', @@ -409,7 +411,7 @@ EXPECTED_NON_EMPTY = { 'ExternalUtilityThatCallsRecordStringValuedProperty' ), 'file': 'gtest_xml_output_unittest_.cc', - 'line': 157, + 'line': 161, 'status': 'RUN', 'result': 'COMPLETED', 'time': '*', @@ -420,6 +422,83 @@ EXPECTED_NON_EMPTY = { ], }, { + 'name': 'SetupFailTest', + 'tests': 1, + 'failures': 0, + 'disabled': 0, + 'errors': 0, + 'time': '*', + 'timestamp': '*', + 'testsuite': [ + { + 'name': 'NoopPassingTest', + 'file': 'gtest_xml_output_unittest_.cc', + 'line': 172, + 'status': 'RUN', + 'result': 'SKIPPED', + 'timestamp': '*', + 'time': '*', + 'classname': 'SetupFailTest', + 'skipped': [ + {'message': 'gtest_xml_output_unittest_.cc:*\n'} + ], + }, + { + 'name': '', + 'status': 'RUN', + 'result': 'COMPLETED', + 'timestamp': '*', + 'time': '*', + 'classname': '', + 'failures': [{ + 'failure': ( + 'gtest_xml_output_unittest_.cc:*\nExpected equality' + ' of these values:\n 1\n 2' + + STACK_TRACE_TEMPLATE + ), + 'type': '', + }], + }, + ], + }, + { + 'name': 'TearDownFailTest', + 'tests': 1, + 'failures': 0, + 'disabled': 0, + 'errors': 0, + 'timestamp': '*', + 'time': '*', + 'testsuite': [ + { + 'name': 'NoopPassingTest', + 'file': 'gtest_xml_output_unittest_.cc', + 'line': 179, + 'status': 'RUN', + 'result': 'COMPLETED', + 'timestamp': '*', + 'time': '*', + 'classname': 'TearDownFailTest', + }, + { + 'name': '', + 'status': 'RUN', + 'result': 'COMPLETED', + 'timestamp': '*', + 'time': '*', + 'classname': '', + 'failures': [{ + 'failure': ( + 'gtest_xml_output_unittest_.cc:*\nExpected equality' + ' of these values:\n 1\n 2' + + STACK_TRACE_TEMPLATE + ), + 'type': '', + }], + }, + ], + }, + { 'name': 'TypedTest/0', 'tests': 1, 'failures': 0, @@ -431,7 +510,7 @@ EXPECTED_NON_EMPTY = { 'name': 'HasTypeParamAttribute', 'type_param': 'int', 'file': 'gtest_xml_output_unittest_.cc', - 'line': 173, + 'line': 193, 'status': 'RUN', 'result': 'COMPLETED', 'time': '*', @@ -451,7 +530,7 @@ EXPECTED_NON_EMPTY = { 'name': 'HasTypeParamAttribute', 'type_param': 'long', 'file': 'gtest_xml_output_unittest_.cc', - 'line': 173, + 'line': 193, 'status': 'RUN', 'result': 'COMPLETED', 'time': '*', @@ -471,7 +550,7 @@ EXPECTED_NON_EMPTY = { 'name': 'HasTypeParamAttribute', 'type_param': 'int', 'file': 'gtest_xml_output_unittest_.cc', - 'line': 180, + 'line': 200, 'status': 'RUN', 'result': 'COMPLETED', 'time': '*', @@ -491,7 +570,7 @@ EXPECTED_NON_EMPTY = { 'name': 'HasTypeParamAttribute', 'type_param': 'long', 'file': 'gtest_xml_output_unittest_.cc', - 'line': 180, + 'line': 200, 'status': 'RUN', 'result': 'COMPLETED', 'time': '*', @@ -512,7 +591,7 @@ EXPECTED_NON_EMPTY = { 'name': 'HasValueParamAttribute/0', 'value_param': '33', 'file': 'gtest_xml_output_unittest_.cc', - 'line': 164, + 'line': 184, 'status': 'RUN', 'result': 'COMPLETED', 'time': '*', @@ -523,7 +602,7 @@ EXPECTED_NON_EMPTY = { 'name': 'HasValueParamAttribute/1', 'value_param': '42', 'file': 'gtest_xml_output_unittest_.cc', - 'line': 164, + 'line': 184, 'status': 'RUN', 'result': 'COMPLETED', 'time': '*', @@ -534,7 +613,7 @@ EXPECTED_NON_EMPTY = { 'name': 'AnotherTestThatHasValueParamAttribute/0', 'value_param': '33', 'file': 'gtest_xml_output_unittest_.cc', - 'line': 165, + 'line': 185, 'status': 'RUN', 'result': 'COMPLETED', 'time': '*', @@ -545,7 +624,7 @@ EXPECTED_NON_EMPTY = { 'name': 'AnotherTestThatHasValueParamAttribute/1', 'value_param': '42', 'file': 'gtest_xml_output_unittest_.cc', - 'line': 165, + 'line': 185, 'status': 'RUN', 'result': 'COMPLETED', 'time': '*', diff --git a/googletest/test/googletest-param-test-test.cc b/googletest/test/googletest-param-test-test.cc index c9c5e78e49f4..bc1306019783 100644 --- a/googletest/test/googletest-param-test-test.cc +++ b/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 @@ TEST(ConvertTest, NonDefaultConstructAssign) { 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) { diff --git a/googletest/test/googletest-printers-test.cc b/googletest/test/googletest-printers-test.cc index d5061bef26d7..52b2c497d740 100644 --- a/googletest/test/googletest-printers-test.cc +++ b/googletest/test/googletest-printers-test.cc @@ -64,6 +64,10 @@ #include <span> // NOLINT #endif // GTEST_INTERNAL_HAS_STD_SPAN +#if GTEST_INTERNAL_HAS_COMPARE_LIB +#include <compare> // NOLINT +#endif // GTEST_INTERNAL_HAS_COMPARE_LIB + // Some user-defined types for testing the universal value printer. // An anonymous enum type. @@ -117,6 +121,9 @@ class UnprintableTemplateInGlobal { // A user-defined streamable type in the global namespace. class StreamableInGlobal { public: + StreamableInGlobal() = default; + StreamableInGlobal(const StreamableInGlobal&) = default; + StreamableInGlobal& operator=(const StreamableInGlobal&) = default; virtual ~StreamableInGlobal() = default; }; @@ -568,6 +575,8 @@ TEST(PrintU8StringTest, Null) { } // Tests that u8 strings are escaped properly. +// TODO(b/396121064) - Fix this test under MSVC +#ifndef _MSC_VER TEST(PrintU8StringTest, EscapesProperly) { const char8_t* p = u8"'\"?\\\a\b\f\n\r\t\v\x7F\xFF hello 世界"; EXPECT_EQ(PrintPointer(p) + @@ -575,7 +584,8 @@ TEST(PrintU8StringTest, EscapesProperly) { "hello \\xE4\\xB8\\x96\\xE7\\x95\\x8C\"", Print(p)); } -#endif +#endif // _MSC_VER +#endif // __cpp_lib_char8_t // const char16_t*. TEST(PrintU16StringTest, Const) { @@ -1970,6 +1980,26 @@ TEST(PrintOneofTest, Basic) { PrintToString(Type(NonPrintable{}))); } #endif // GTEST_INTERNAL_HAS_VARIANT + +#if GTEST_INTERNAL_HAS_COMPARE_LIB +TEST(PrintOrderingTest, Basic) { + EXPECT_EQ("(less)", PrintToString(std::strong_ordering::less)); + EXPECT_EQ("(greater)", PrintToString(std::strong_ordering::greater)); + // equal == equivalent for strong_ordering. + EXPECT_EQ("(equal)", PrintToString(std::strong_ordering::equivalent)); + EXPECT_EQ("(equal)", PrintToString(std::strong_ordering::equal)); + + EXPECT_EQ("(less)", PrintToString(std::weak_ordering::less)); + EXPECT_EQ("(greater)", PrintToString(std::weak_ordering::greater)); + EXPECT_EQ("(equivalent)", PrintToString(std::weak_ordering::equivalent)); + + EXPECT_EQ("(less)", PrintToString(std::partial_ordering::less)); + EXPECT_EQ("(greater)", PrintToString(std::partial_ordering::greater)); + EXPECT_EQ("(equivalent)", PrintToString(std::partial_ordering::equivalent)); + EXPECT_EQ("(unordered)", PrintToString(std::partial_ordering::unordered)); +} +#endif + namespace { class string_ref; diff --git a/googletest/test/googletest-setuptestsuite-test_.cc b/googletest/test/googletest-setuptestsuite-test_.cc index d20899f56866..f4c43ccb2fac 100644 --- a/googletest/test/googletest-setuptestsuite-test_.cc +++ b/googletest/test/googletest-setuptestsuite-test_.cc @@ -31,14 +31,14 @@ class SetupFailTest : public ::testing::Test { protected: - static void SetUpTestSuite() { ASSERT_EQ("", "SET_UP_FAIL"); } + static void SetUpTestSuite() { ASSERT_STREQ("", "SET_UP_FAIL"); } }; TEST_F(SetupFailTest, NoopPassingTest) {} class TearDownFailTest : public ::testing::Test { protected: - static void TearDownTestSuite() { ASSERT_EQ("", "TEAR_DOWN_FAIL"); } + static void TearDownTestSuite() { ASSERT_STREQ("", "TEAR_DOWN_FAIL"); } }; TEST_F(TearDownFailTest, NoopPassingTest) {} diff --git a/googletest/test/gtest_unittest.cc b/googletest/test/gtest_unittest.cc index 5ded865074df..559d34c013d0 100644 --- a/googletest/test/gtest_unittest.cc +++ b/googletest/test/gtest_unittest.cc @@ -2163,7 +2163,7 @@ class UnitTestRecordPropertyTestEnvironment : public Environment { }; // This will test property recording outside of any test or test case. -GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED static Environment* record_property_env = +[[maybe_unused]] static Environment* record_property_env = AddGlobalTestEnvironment(new UnitTestRecordPropertyTestEnvironment); // This group of tests is for predicate assertions (ASSERT_PRED*, etc) @@ -2870,6 +2870,8 @@ TEST_F(FloatTest, LargeDiff) { // This ensures that no overflow occurs when comparing numbers whose // absolute value is very large. TEST_F(FloatTest, Infinity) { + EXPECT_FLOAT_EQ(values_.infinity, values_.infinity); + EXPECT_FLOAT_EQ(-values_.infinity, -values_.infinity); EXPECT_FLOAT_EQ(values_.infinity, values_.close_to_infinity); EXPECT_FLOAT_EQ(-values_.infinity, -values_.close_to_infinity); EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(values_.infinity, -values_.infinity), @@ -2894,6 +2896,11 @@ TEST_F(FloatTest, NaN) { EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(v.nan1, v.nan1), "v.nan1"); EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(v.nan1, v.nan2), "v.nan2"); EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(1.0, v.nan1), "v.nan1"); + EXPECT_NONFATAL_FAILURE(EXPECT_NEAR(1.0f, v.nan1, 1.0f), "v.nan1"); + EXPECT_NONFATAL_FAILURE(EXPECT_NEAR(1.0f, v.nan1, v.infinity), "v.nan1"); + EXPECT_NONFATAL_FAILURE(EXPECT_NEAR(v.infinity, v.nan1, 1.0f), "v.nan1"); + EXPECT_NONFATAL_FAILURE(EXPECT_NEAR(v.infinity, v.nan1, v.infinity), + "v.nan1"); EXPECT_FATAL_FAILURE(ASSERT_FLOAT_EQ(v.nan1, v.infinity), "v.infinity"); } @@ -2917,11 +2924,28 @@ TEST_F(FloatTest, Commutative) { // Tests EXPECT_NEAR. TEST_F(FloatTest, EXPECT_NEAR) { + static const FloatTest::TestValues& v = this->values_; + EXPECT_NEAR(-1.0f, -1.1f, 0.2f); EXPECT_NEAR(2.0f, 3.0f, 1.0f); + EXPECT_NEAR(v.infinity, v.infinity, 0.0f); + EXPECT_NEAR(-v.infinity, -v.infinity, 0.0f); + EXPECT_NEAR(0.0f, 1.0f, v.infinity); + EXPECT_NEAR(v.infinity, -v.infinity, v.infinity); + EXPECT_NEAR(-v.infinity, v.infinity, v.infinity); EXPECT_NONFATAL_FAILURE(EXPECT_NEAR(1.0f, 1.5f, 0.25f), // NOLINT "The difference between 1.0f and 1.5f is 0.5, " "which exceeds 0.25f"); + EXPECT_NONFATAL_FAILURE(EXPECT_NEAR(v.infinity, -v.infinity, 0.0f), // NOLINT + "The difference between v.infinity and -v.infinity " + "is inf, which exceeds 0.0f"); + EXPECT_NONFATAL_FAILURE(EXPECT_NEAR(-v.infinity, v.infinity, 0.0f), // NOLINT + "The difference between -v.infinity and v.infinity " + "is inf, which exceeds 0.0f"); + EXPECT_NONFATAL_FAILURE( + EXPECT_NEAR(v.infinity, v.close_to_infinity, v.further_from_infinity), + "The difference between v.infinity and v.close_to_infinity is inf, which " + "exceeds v.further_from_infinity"); } // Tests ASSERT_NEAR. @@ -3028,6 +3052,8 @@ TEST_F(DoubleTest, LargeDiff) { // This ensures that no overflow occurs when comparing numbers whose // absolute value is very large. TEST_F(DoubleTest, Infinity) { + EXPECT_DOUBLE_EQ(values_.infinity, values_.infinity); + EXPECT_DOUBLE_EQ(-values_.infinity, -values_.infinity); EXPECT_DOUBLE_EQ(values_.infinity, values_.close_to_infinity); EXPECT_DOUBLE_EQ(-values_.infinity, -values_.close_to_infinity); EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(values_.infinity, -values_.infinity), @@ -3047,6 +3073,12 @@ TEST_F(DoubleTest, NaN) { EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(v.nan1, v.nan1), "v.nan1"); EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(v.nan1, v.nan2), "v.nan2"); EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(1.0, v.nan1), "v.nan1"); + EXPECT_NONFATAL_FAILURE(EXPECT_NEAR(1.0, v.nan1, 1.0), "v.nan1"); + EXPECT_NONFATAL_FAILURE(EXPECT_NEAR(1.0, v.nan1, v.infinity), "v.nan1"); + EXPECT_NONFATAL_FAILURE(EXPECT_NEAR(v.infinity, v.nan1, 1.0), "v.nan1"); + EXPECT_NONFATAL_FAILURE(EXPECT_NEAR(v.infinity, v.nan1, v.infinity), + "v.nan1"); + EXPECT_FATAL_FAILURE(ASSERT_DOUBLE_EQ(v.nan1, v.infinity), "v.infinity"); } @@ -3069,11 +3101,28 @@ TEST_F(DoubleTest, Commutative) { // Tests EXPECT_NEAR. TEST_F(DoubleTest, EXPECT_NEAR) { + static const DoubleTest::TestValues& v = this->values_; + EXPECT_NEAR(-1.0, -1.1, 0.2); EXPECT_NEAR(2.0, 3.0, 1.0); + EXPECT_NEAR(v.infinity, v.infinity, 0.0); + EXPECT_NEAR(-v.infinity, -v.infinity, 0.0); + EXPECT_NEAR(0.0, 1.0, v.infinity); + EXPECT_NEAR(v.infinity, -v.infinity, v.infinity); + EXPECT_NEAR(-v.infinity, v.infinity, v.infinity); EXPECT_NONFATAL_FAILURE(EXPECT_NEAR(1.0, 1.5, 0.25), // NOLINT "The difference between 1.0 and 1.5 is 0.5, " "which exceeds 0.25"); + EXPECT_NONFATAL_FAILURE(EXPECT_NEAR(v.infinity, -v.infinity, 0.0), + "The difference between v.infinity and -v.infinity " + "is inf, which exceeds 0.0"); + EXPECT_NONFATAL_FAILURE(EXPECT_NEAR(-v.infinity, v.infinity, 0.0), + "The difference between -v.infinity and v.infinity " + "is inf, which exceeds 0.0"); + EXPECT_NONFATAL_FAILURE( + EXPECT_NEAR(v.infinity, v.close_to_infinity, v.further_from_infinity), + "The difference between v.infinity and v.close_to_infinity is inf, which " + "exceeds v.further_from_infinity"); // At this magnitude adjacent doubles are 512.0 apart, so this triggers a // slightly different failure reporting path. EXPECT_NONFATAL_FAILURE( @@ -6705,9 +6754,8 @@ TEST(ColoredOutputTest, UsesColorsWhenTermSupportsColors) { // Verifies that StaticAssertTypeEq works in a namespace scope. -GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED static bool dummy1 = - StaticAssertTypeEq<bool, bool>(); -GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED static bool dummy2 = +[[maybe_unused]] static bool dummy1 = StaticAssertTypeEq<bool, bool>(); +[[maybe_unused]] static bool dummy2 = StaticAssertTypeEq<const int, const int>(); // Verifies that StaticAssertTypeEq works in a class. diff --git a/googletest/test/gtest_xml_output_unittest.py b/googletest/test/gtest_xml_output_unittest.py index c3fea2c0a3a1..87a7683a90c6 100755 --- a/googletest/test/gtest_xml_output_unittest.py +++ b/googletest/test/gtest_xml_output_unittest.py @@ -29,14 +29,14 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -"""Unit test for the gtest_xml_output module""" +"""Unit test for the gtest_xml_output module.""" import datetime import errno import os import re import sys -from xml.dom import minidom, Node +from xml.dom import minidom from googletest.test import gtest_test_utils from googletest.test import gtest_xml_test_utils @@ -67,7 +67,10 @@ else: sys.argv.remove(NO_STACKTRACE_SUPPORT_FLAG) EXPECTED_NON_EMPTY_XML = """<?xml version="1.0" encoding="UTF-8"?> -<testsuites tests="26" failures="5" disabled="2" errors="0" time="*" timestamp="*" name="AllTests" ad_hoc_property="42"> +<testsuites tests="28" failures="5" disabled="2" errors="0" time="*" timestamp="*" name="AllTests"> + <properties> + <property name="ad_hoc_property" value="42"/> + </properties> <testsuite name="SuccessfulTest" tests="1" failures="0" disabled="0" skipped="0" errors="0" time="*" timestamp="*"> <testcase name="Succeeds" file="gtest_xml_output_unittest_.cc" line="53" status="run" result="completed" time="*" timestamp="*" classname="SuccessfulTest"/> </testsuite> @@ -132,64 +135,91 @@ It is good practice to tell why you skip a test. </testcase> </testsuite> - <testsuite name="PropertyRecordingTest" tests="4" failures="0" disabled="0" skipped="0" errors="0" time="*" timestamp="*" SetUpTestSuite="yes" TearDownTestSuite="aye"> - <testcase name="OneProperty" file="gtest_xml_output_unittest_.cc" line="121" status="run" result="completed" time="*" timestamp="*" classname="PropertyRecordingTest"> + <testsuite name="PropertyRecordingTest" tests="4" failures="0" disabled="0" skipped="0" errors="0" time="*" timestamp="*"> + <properties> + <property name="SetUpTestSuite" value="yes"/> + <property name="SetUpTestSuite (with whitespace)" value="yes and yes"/> + <property name="TearDownTestSuite" value="aye"/> + <property name="TearDownTestSuite (with whitespace)" value="aye and aye"/> + </properties> + <testcase name="OneProperty" file="gtest_xml_output_unittest_.cc" line="125" status="run" result="completed" time="*" timestamp="*" classname="PropertyRecordingTest"> <properties> <property name="key_1" value="1"/> </properties> </testcase> - <testcase name="IntValuedProperty" file="gtest_xml_output_unittest_.cc" line="125" status="run" result="completed" time="*" timestamp="*" classname="PropertyRecordingTest"> + <testcase name="IntValuedProperty" file="gtest_xml_output_unittest_.cc" line="129" status="run" result="completed" time="*" timestamp="*" classname="PropertyRecordingTest"> <properties> <property name="key_int" value="1"/> </properties> </testcase> - <testcase name="ThreeProperties" file="gtest_xml_output_unittest_.cc" line="129" status="run" result="completed" time="*" timestamp="*" classname="PropertyRecordingTest"> + <testcase name="ThreeProperties" file="gtest_xml_output_unittest_.cc" line="133" status="run" result="completed" time="*" timestamp="*" classname="PropertyRecordingTest"> <properties> <property name="key_1" value="1"/> <property name="key_2" value="2"/> <property name="key_3" value="3"/> </properties> </testcase> - <testcase name="TwoValuesForOneKeyUsesLastValue" file="gtest_xml_output_unittest_.cc" line="135" status="run" result="completed" time="*" timestamp="*" classname="PropertyRecordingTest"> + <testcase name="TwoValuesForOneKeyUsesLastValue" file="gtest_xml_output_unittest_.cc" line="139" status="run" result="completed" time="*" timestamp="*" classname="PropertyRecordingTest"> <properties> <property name="key_1" value="2"/> </properties> </testcase> </testsuite> <testsuite name="NoFixtureTest" tests="3" failures="0" disabled="0" skipped="0" errors="0" time="*" timestamp="*"> - <testcase name="RecordProperty" file="gtest_xml_output_unittest_.cc" line="140" status="run" result="completed" time="*" timestamp="*" classname="NoFixtureTest"> + <testcase name="RecordProperty" file="gtest_xml_output_unittest_.cc" line="144" status="run" result="completed" time="*" timestamp="*" classname="NoFixtureTest"> <properties> <property name="key" value="1"/> </properties> </testcase> - <testcase name="ExternalUtilityThatCallsRecordIntValuedProperty" file="gtest_xml_output_unittest_.cc" line="153" status="run" result="completed" time="*" timestamp="*" classname="NoFixtureTest"> + <testcase name="ExternalUtilityThatCallsRecordIntValuedProperty" file="gtest_xml_output_unittest_.cc" line="157" status="run" result="completed" time="*" timestamp="*" classname="NoFixtureTest"> <properties> <property name="key_for_utility_int" value="1"/> </properties> </testcase> - <testcase name="ExternalUtilityThatCallsRecordStringValuedProperty" file="gtest_xml_output_unittest_.cc" line="157" status="run" result="completed" time="*" timestamp="*" classname="NoFixtureTest"> + <testcase name="ExternalUtilityThatCallsRecordStringValuedProperty" file="gtest_xml_output_unittest_.cc" line="161" status="run" result="completed" time="*" timestamp="*" classname="NoFixtureTest"> <properties> <property name="key_for_utility_string" value="1"/> </properties> </testcase> </testsuite> + <testsuite name="SetupFailTest" tests="1" failures="0" disabled="0" skipped="1" errors="0" time="*" timestamp="*"> + <testcase name="NoopPassingTest" file="gtest_xml_output_unittest_.cc" line="172" status="run" result="skipped" time="*" timestamp="*" classname="SetupFailTest"> + <skipped message="gtest_xml_output_unittest_.cc:*
"><![CDATA[gtest_xml_output_unittest_.cc:* +]]></skipped> + </testcase> + <testcase name="" status="run" result="completed" classname="" time="*" timestamp="*"> + <failure message="gtest_xml_output_unittest_.cc:*
Expected equality of these values:
 1
 2%(stack_entity)s" type=""><![CDATA[gtest_xml_output_unittest_.cc:* +Expected equality of these values: + 1 + 2%(stack)s]]></failure> + </testcase> + </testsuite> + <testsuite name="TearDownFailTest" tests="1" failures="0" disabled="0" skipped="0" errors="0" time="*" timestamp="*"> + <testcase name="NoopPassingTest" file="gtest_xml_output_unittest_.cc" line="179" status="run" result="completed" time="*" timestamp="*" classname="TearDownFailTest"/> + <testcase name="" status="run" result="completed" classname="" time="*" timestamp="*"> + <failure message="gtest_xml_output_unittest_.cc:*
Expected equality of these values:
 1
 2%(stack_entity)s" type=""><![CDATA[gtest_xml_output_unittest_.cc:* +Expected equality of these values: + 1 + 2%(stack)s]]></failure> + </testcase> + </testsuite> <testsuite name="Single/ValueParamTest" tests="4" failures="0" disabled="0" skipped="0" errors="0" time="*" timestamp="*"> - <testcase name="HasValueParamAttribute/0" file="gtest_xml_output_unittest_.cc" line="164" value_param="33" status="run" result="completed" time="*" timestamp="*" classname="Single/ValueParamTest" /> - <testcase name="HasValueParamAttribute/1" file="gtest_xml_output_unittest_.cc" line="164" value_param="42" status="run" result="completed" time="*" timestamp="*" classname="Single/ValueParamTest" /> - <testcase name="AnotherTestThatHasValueParamAttribute/0" file="gtest_xml_output_unittest_.cc" line="165" value_param="33" status="run" result="completed" time="*" timestamp="*" classname="Single/ValueParamTest" /> - <testcase name="AnotherTestThatHasValueParamAttribute/1" file="gtest_xml_output_unittest_.cc" line="165" value_param="42" status="run" result="completed" time="*" timestamp="*" classname="Single/ValueParamTest" /> + <testcase name="HasValueParamAttribute/0" file="gtest_xml_output_unittest_.cc" line="184" value_param="33" status="run" result="completed" time="*" timestamp="*" classname="Single/ValueParamTest" /> + <testcase name="HasValueParamAttribute/1" file="gtest_xml_output_unittest_.cc" line="184" value_param="42" status="run" result="completed" time="*" timestamp="*" classname="Single/ValueParamTest" /> + <testcase name="AnotherTestThatHasValueParamAttribute/0" file="gtest_xml_output_unittest_.cc" line="185" value_param="33" status="run" result="completed" time="*" timestamp="*" classname="Single/ValueParamTest" /> + <testcase name="AnotherTestThatHasValueParamAttribute/1" file="gtest_xml_output_unittest_.cc" line="185" value_param="42" status="run" result="completed" time="*" timestamp="*" classname="Single/ValueParamTest" /> </testsuite> <testsuite name="TypedTest/0" tests="1" failures="0" disabled="0" skipped="0" errors="0" time="*" timestamp="*"> - <testcase name="HasTypeParamAttribute" file="gtest_xml_output_unittest_.cc" line="173" type_param="*" status="run" result="completed" time="*" timestamp="*" classname="TypedTest/0" /> + <testcase name="HasTypeParamAttribute" file="gtest_xml_output_unittest_.cc" line="193" type_param="*" status="run" result="completed" time="*" timestamp="*" classname="TypedTest/0" /> </testsuite> <testsuite name="TypedTest/1" tests="1" failures="0" disabled="0" skipped="0" errors="0" time="*" timestamp="*"> - <testcase name="HasTypeParamAttribute" file="gtest_xml_output_unittest_.cc" line="173" type_param="*" status="run" result="completed" time="*" timestamp="*" classname="TypedTest/1" /> + <testcase name="HasTypeParamAttribute" file="gtest_xml_output_unittest_.cc" line="193" type_param="*" status="run" result="completed" time="*" timestamp="*" classname="TypedTest/1" /> </testsuite> <testsuite name="Single/TypeParameterizedTestSuite/0" tests="1" failures="0" disabled="0" skipped="0" errors="0" time="*" timestamp="*"> - <testcase name="HasTypeParamAttribute" file="gtest_xml_output_unittest_.cc" line="180" type_param="*" status="run" result="completed" time="*" timestamp="*" classname="Single/TypeParameterizedTestSuite/0" /> + <testcase name="HasTypeParamAttribute" file="gtest_xml_output_unittest_.cc" line="200" type_param="*" status="run" result="completed" time="*" timestamp="*" classname="Single/TypeParameterizedTestSuite/0" /> </testsuite> <testsuite name="Single/TypeParameterizedTestSuite/1" tests="1" failures="0" disabled="0" skipped="0" errors="0" time="*" timestamp="*"> - <testcase name="HasTypeParamAttribute" file="gtest_xml_output_unittest_.cc" line="180" type_param="*" status="run" result="completed" time="*" timestamp="*" classname="Single/TypeParameterizedTestSuite/1" /> + <testcase name="HasTypeParamAttribute" file="gtest_xml_output_unittest_.cc" line="200" type_param="*" status="run" result="completed" time="*" timestamp="*" classname="Single/TypeParameterizedTestSuite/1" /> </testsuite> </testsuites>""" % { 'stack': STACK_TRACE_TEMPLATE, @@ -197,8 +227,10 @@ It is good practice to tell why you skip a test. } EXPECTED_FILTERED_TEST_XML = """<?xml version="1.0" encoding="UTF-8"?> -<testsuites tests="1" failures="0" disabled="0" errors="0" time="*" - timestamp="*" name="AllTests" ad_hoc_property="42"> +<testsuites tests="1" failures="0" disabled="0" errors="0" time="*" timestamp="*" name="AllTests"> + <properties> + <property name="ad_hoc_property" value="42"/> + </properties> <testsuite name="SuccessfulTest" tests="1" failures="0" disabled="0" skipped="0" errors="0" time="*" timestamp="*"> <testcase name="Succeeds" file="gtest_xml_output_unittest_.cc" line="53" status="run" result="completed" time="*" timestamp="*" classname="SuccessfulTest"/> @@ -206,19 +238,28 @@ EXPECTED_FILTERED_TEST_XML = """<?xml version="1.0" encoding="UTF-8"?> </testsuites>""" EXPECTED_SHARDED_TEST_XML = """<?xml version="1.0" encoding="UTF-8"?> -<testsuites tests="3" failures="0" disabled="0" errors="0" time="*" timestamp="*" name="AllTests" ad_hoc_property="42"> +<testsuites tests="3" failures="0" disabled="0" errors="0" time="*" timestamp="*" name="AllTests"> + <properties> + <property name="ad_hoc_property" value="42"/> + </properties> <testsuite name="SuccessfulTest" tests="1" failures="0" disabled="0" skipped="0" errors="0" time="*" timestamp="*"> <testcase name="Succeeds" file="gtest_xml_output_unittest_.cc" line="53" status="run" result="completed" time="*" timestamp="*" classname="SuccessfulTest"/> </testsuite> - <testsuite name="PropertyRecordingTest" tests="1" failures="0" disabled="0" skipped="0" errors="0" time="*" timestamp="*" SetUpTestSuite="yes" TearDownTestSuite="aye"> - <testcase name="IntValuedProperty" file="gtest_xml_output_unittest_.cc" line="125" status="run" result="completed" time="*" timestamp="*" classname="PropertyRecordingTest"> + <testsuite name="PropertyRecordingTest" tests="1" failures="0" disabled="0" skipped="0" errors="0" time="*" timestamp="*"> + <properties> + <property name="SetUpTestSuite" value="yes"/> + <property name="SetUpTestSuite (with whitespace)" value="yes and yes"/> + <property name="TearDownTestSuite" value="aye"/> + <property name="TearDownTestSuite (with whitespace)" value="aye and aye"/> + </properties> + <testcase name="IntValuedProperty" file="gtest_xml_output_unittest_.cc" line="129" status="run" result="completed" time="*" timestamp="*" classname="PropertyRecordingTest"> <properties> <property name="key_int" value="1"/> </properties> </testcase> </testsuite> - <testsuite name="Single/ValueParamTest" tests="1" failures="0" disabled="0" skipped="0" errors="0" time="*" timestamp="*"> - <testcase name="HasValueParamAttribute/0" file="gtest_xml_output_unittest_.cc" line="164" value_param="33" status="run" result="completed" time="*" timestamp="*" classname="Single/ValueParamTest" /> + <testsuite name="Single/TypeParameterizedTestSuite/0" tests="1" failures="0" disabled="0" skipped="0" errors="0" time="*" timestamp="*"> + <testcase name="HasTypeParamAttribute" type_param="*" file="gtest_xml_output_unittest_.cc" line="200" status="run" result="completed" time="*" timestamp="*" classname="Single/TypeParameterizedTestSuite/0" /> </testsuite> </testsuites>""" diff --git a/googletest/test/gtest_xml_output_unittest_.cc b/googletest/test/gtest_xml_output_unittest_.cc index 0ab33022e06a..fe196b630b08 100644 --- a/googletest/test/gtest_xml_output_unittest_.cc +++ b/googletest/test/gtest_xml_output_unittest_.cc @@ -112,8 +112,12 @@ TEST(InvalidCharactersTest, InvalidCharactersInMessage) { class PropertyRecordingTest : public Test { public: - static void SetUpTestSuite() { RecordProperty("SetUpTestSuite", "yes"); } + static void SetUpTestSuite() { + RecordProperty("SetUpTestSuite (with whitespace)", "yes and yes"); + RecordProperty("SetUpTestSuite", "yes"); + } static void TearDownTestSuite() { + RecordProperty("TearDownTestSuite (with whitespace)", "aye and aye"); RecordProperty("TearDownTestSuite", "aye"); } }; @@ -158,6 +162,22 @@ TEST(NoFixtureTest, ExternalUtilityThatCallsRecordStringValuedProperty) { ExternalUtilityThatCallsRecordProperty("key_for_utility_string", "1"); } +// Ensures that SetUpTestSuite and TearDownTestSuite failures are reported in +// the XML output. +class SetupFailTest : public ::testing::Test { + protected: + static void SetUpTestSuite() { ASSERT_EQ(1, 2); } +}; + +TEST_F(SetupFailTest, NoopPassingTest) {} + +class TearDownFailTest : public ::testing::Test { + protected: + static void TearDownTestSuite() { ASSERT_EQ(1, 2); } +}; + +TEST_F(TearDownFailTest, NoopPassingTest) {} + // Verifies that the test parameter value is output in the 'value_param' // XML attribute for value-parameterized tests. class ValueParamTest : public TestWithParam<int> {}; diff --git a/googletest_deps.bzl b/googletest_deps.bzl index 65fc48c364ed..cadc244e85d3 100644 --- a/googletest_deps.bzl +++ b/googletest_deps.bzl @@ -6,20 +6,20 @@ load("//:fake_fuchsia_sdk.bzl", "fake_fuchsia_sdk") def googletest_deps(): """Loads common dependencies needed to use the googletest library.""" - if not native.existing_rule("com_googlesource_code_re2"): + if not native.existing_rule("re2"): http_archive( - name = "com_googlesource_code_re2", + name = "re2", sha256 = "eb2df807c781601c14a260a507a5bb4509be1ee626024cb45acbd57cb9d4032b", strip_prefix = "re2-2024-07-02", urls = ["https://github.com/google/re2/releases/download/2024-07-02/re2-2024-07-02.tar.gz"], ) - if not native.existing_rule("com_google_absl"): + if not native.existing_rule("abseil-cpp"): http_archive( - name = "com_google_absl", - sha256 = "733726b8c3a6d39a4120d7e45ea8b41a434cdacde401cba500f14236c49b39dc", - strip_prefix = "abseil-cpp-20240116.2", - urls = ["https://github.com/abseil/abseil-cpp/releases/download/20240116.2/abseil-cpp-20240116.2.tar.gz"], + name = "abseil-cpp", + sha256 = "b396401fd29e2e679cace77867481d388c807671dc2acc602a0259eeb79b7811", + strip_prefix = "abseil-cpp-20250127.1", + urls = ["https://github.com/abseil/abseil-cpp/releases/download/20250127.1/abseil-cpp-20250127.1.tar.gz"], ) if not native.existing_rule("fuchsia_sdk"): |
