mirror of
https://git.mirrors.martin98.com/https://github.com/google/googletest.git
synced 2025-08-01 21:20:37 +08:00
Compare commits
40 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
e9092b12dc | ||
![]() |
7427a6b5e3 | ||
![]() |
7da55820cc | ||
![]() |
3abc68be30 | ||
![]() |
09ffd00153 | ||
![]() |
6aa03e6774 | ||
![]() |
16d4f8eff6 | ||
![]() |
bac6a8fd8a | ||
![]() |
fa8438ae6b | ||
![]() |
571930618f | ||
![]() |
9f79a9597a | ||
![]() |
8b8ef3ff0d | ||
![]() |
90a4152114 | ||
![]() |
04ee1b4f2a | ||
![]() |
54915d462b | ||
![]() |
59c924bc47 | ||
![]() |
00b2154e8e | ||
![]() |
cd430b47a5 | ||
![]() |
155b337c93 | ||
![]() |
e90fe24856 | ||
![]() |
50a9511f50 | ||
![]() |
52204f78f9 | ||
![]() |
2ae29b52fd | ||
![]() |
c2ceb2b09b | ||
![]() |
e7b26b7246 | ||
![]() |
3af834740f | ||
![]() |
4902ea2d7c | ||
![]() |
4ee4b17bf5 | ||
![]() |
0bdccf4aa2 | ||
![]() |
e88cb95b92 | ||
![]() |
24a9e940d4 | ||
![]() |
72189081ca | ||
![]() |
144d335538 | ||
![]() |
e5669fdffc | ||
![]() |
54501746a6 | ||
![]() |
3fbe4db9a3 | ||
![]() |
a6ce08abf7 | ||
![]() |
c00fd25b71 | ||
![]() |
4a00a24fff | ||
![]() |
a866428a78 |
19
BUILD.bazel
19
BUILD.bazel
@ -83,6 +83,10 @@ cc_library(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Google Test including Google Mock
|
# 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(
|
cc_library(
|
||||||
name = "gtest",
|
name = "gtest",
|
||||||
srcs = glob(
|
srcs = glob(
|
||||||
@ -147,10 +151,7 @@ cc_library(
|
|||||||
"@abseil-cpp//absl/flags:reflection",
|
"@abseil-cpp//absl/flags:reflection",
|
||||||
"@abseil-cpp//absl/flags:usage",
|
"@abseil-cpp//absl/flags:usage",
|
||||||
"@abseil-cpp//absl/strings",
|
"@abseil-cpp//absl/strings",
|
||||||
"@abseil-cpp//absl/types:any",
|
"@re2",
|
||||||
"@abseil-cpp//absl/types:optional",
|
|
||||||
"@abseil-cpp//absl/types:variant",
|
|
||||||
"@re2//:re2",
|
|
||||||
],
|
],
|
||||||
"//conditions:default": [],
|
"//conditions:default": [],
|
||||||
}) + select({
|
}) + select({
|
||||||
@ -167,6 +168,16 @@ cc_library(
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# `gtest`, but testonly. See guidance on `gtest` for when to use this.
|
||||||
|
alias(
|
||||||
|
name = "gtest_for_library",
|
||||||
|
testonly = True,
|
||||||
|
actual = ":gtest",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Implements main() for tests using gtest. Prefer to depend on `gtest` as well
|
||||||
|
# to ensure compliance with the layering_check Bazel feature where only the
|
||||||
|
# direct hdrs values are available.
|
||||||
cc_library(
|
cc_library(
|
||||||
name = "gtest_main",
|
name = "gtest_main",
|
||||||
srcs = ["googlemock/src/gmock_main.cc"],
|
srcs = ["googlemock/src/gmock_main.cc"],
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
# Note: CMake support is community-based. The maintainers do not use CMake
|
# Note: CMake support is community-based. The maintainers do not use CMake
|
||||||
# internally.
|
# internally.
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
project(googletest-distribution)
|
project(googletest-distribution)
|
||||||
set(GOOGLETEST_VERSION 1.15.2)
|
set(GOOGLETEST_VERSION 1.16.0)
|
||||||
|
|
||||||
if(NOT CYGWIN AND NOT MSYS AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL QNX)
|
if(NOT CYGWIN AND NOT MSYS AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL QNX)
|
||||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||||
|
@ -41,20 +41,20 @@ module(
|
|||||||
|
|
||||||
bazel_dep(
|
bazel_dep(
|
||||||
name = "abseil-cpp",
|
name = "abseil-cpp",
|
||||||
version = "20250127.0",
|
version = "20250512.0",
|
||||||
)
|
)
|
||||||
bazel_dep(
|
bazel_dep(
|
||||||
name = "platforms",
|
name = "platforms",
|
||||||
version = "0.0.10",
|
version = "0.0.11",
|
||||||
)
|
)
|
||||||
bazel_dep(
|
bazel_dep(
|
||||||
name = "re2",
|
name = "re2",
|
||||||
version = "2024-07-02",
|
version = "2024-07-02.bcr.1",
|
||||||
)
|
)
|
||||||
|
|
||||||
bazel_dep(
|
bazel_dep(
|
||||||
name = "rules_python",
|
name = "rules_python",
|
||||||
version = "1.1.0",
|
version = "1.3.0",
|
||||||
dev_dependency = True,
|
dev_dependency = True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
16
README.md
16
README.md
@ -2,27 +2,19 @@
|
|||||||
|
|
||||||
### Announcements
|
### 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.2`).
|
|
||||||
|
|
||||||
#### Documentation Updates
|
#### Documentation Updates
|
||||||
|
|
||||||
Our documentation is now live on GitHub Pages at
|
Our documentation is now live on GitHub Pages at
|
||||||
https://google.github.io/googletest/. We recommend browsing the documentation on
|
https://google.github.io/googletest/. We recommend browsing the documentation on
|
||||||
GitHub Pages rather than directly in the repository.
|
GitHub Pages rather than directly in the repository.
|
||||||
|
|
||||||
#### Release 1.15.2
|
#### Release 1.17.0
|
||||||
|
|
||||||
[Release 1.15.2](https://github.com/google/googletest/releases/tag/v1.15.2) is
|
[Release 1.17.0](https://github.com/google/googletest/releases/tag/v1.17.0) is
|
||||||
now available.
|
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
|
#### Continuous Integration
|
||||||
|
|
||||||
|
12
WORKSPACE
12
WORKSPACE
@ -37,9 +37,9 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
|||||||
|
|
||||||
http_archive(
|
http_archive(
|
||||||
name = "rules_python",
|
name = "rules_python",
|
||||||
sha256 = "9c6e26911a79fbf510a8f06d8eedb40f412023cf7fa6d1461def27116bff022c",
|
sha256 = "2cc26bbd53854ceb76dd42a834b1002cd4ba7f8df35440cf03482e045affc244",
|
||||||
strip_prefix = "rules_python-1.1.0",
|
strip_prefix = "rules_python-1.3.0",
|
||||||
url = "https://github.com/bazelbuild/rules_python/releases/download/1.1.0/rules_python-1.1.0.tar.gz",
|
url = "https://github.com/bazelbuild/rules_python/releases/download/1.3.0/rules_python-1.3.0.tar.gz",
|
||||||
)
|
)
|
||||||
# https://github.com/bazelbuild/rules_python/releases/tag/1.1.0
|
# https://github.com/bazelbuild/rules_python/releases/tag/1.1.0
|
||||||
load("@rules_python//python:repositories.bzl", "py_repositories")
|
load("@rules_python//python:repositories.bzl", "py_repositories")
|
||||||
@ -54,8 +54,8 @@ http_archive(
|
|||||||
http_archive(
|
http_archive(
|
||||||
name = "platforms",
|
name = "platforms",
|
||||||
urls = [
|
urls = [
|
||||||
"https://mirror.bazel.build/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.10/platforms-0.0.10.tar.gz",
|
"https://github.com/bazelbuild/platforms/releases/download/0.0.11/platforms-0.0.11.tar.gz",
|
||||||
],
|
],
|
||||||
sha256 = "218efe8ee736d26a3572663b374a253c012b716d8af0c07e842e82f238a0a7ee",
|
sha256 = "29742e87275809b5e598dc2f04d86960cc7a55b3067d97221c9abbc9926bff0f",
|
||||||
)
|
)
|
||||||
|
@ -31,62 +31,91 @@
|
|||||||
|
|
||||||
set -euox pipefail
|
set -euox pipefail
|
||||||
|
|
||||||
readonly LINUX_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20241218"
|
readonly LINUX_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20250430"
|
||||||
readonly LINUX_GCC_FLOOR_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-floor:20250205"
|
readonly LINUX_GCC_FLOOR_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-floor:20250430"
|
||||||
|
|
||||||
if [[ -z ${GTEST_ROOT:-} ]]; then
|
if [[ -z ${GTEST_ROOT:-} ]]; then
|
||||||
GTEST_ROOT="$(realpath $(dirname ${0})/..)"
|
GTEST_ROOT="$(realpath $(dirname ${0})/..)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -z ${STD:-} ]]; then
|
# Use Bazel Vendor mode to reduce reliance on external dependencies.
|
||||||
STD="c++14 c++17 c++20"
|
# See https://bazel.build/external/vendor and the Dockerfile for
|
||||||
|
# an explaination of how this works.
|
||||||
|
if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -f "${KOKORO_GFILE_DIR}/distdir/googletest_vendor.tar.gz" ]]; then
|
||||||
|
DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly --env=BAZEL_VENDOR_ARCHIVE=/distdir/googletest_vendor.tar.gz ${DOCKER_EXTRA_ARGS:-}"
|
||||||
|
BAZEL_EXTRA_ARGS="--vendor_dir=/googletest_vendor ${BAZEL_EXTRA_ARGS:-}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Test the CMake build
|
if [[ -z ${STD:-} ]]; then
|
||||||
for cc in /usr/local/bin/gcc /opt/llvm/clang/bin/clang; do
|
STD="c++17 c++20 c++23"
|
||||||
for cmake_off_on in OFF ON; do
|
fi
|
||||||
time docker run \
|
|
||||||
--volume="${GTEST_ROOT}:/src:ro" \
|
# Test CMake + GCC
|
||||||
--tmpfs="/build:exec" \
|
for cmake_off_on in OFF ON; do
|
||||||
--workdir="/build" \
|
time docker run \
|
||||||
--rm \
|
--volume="${GTEST_ROOT}:/src:ro" \
|
||||||
--env="CC=${cc}" \
|
--tmpfs="/build:exec" \
|
||||||
--env=CXXFLAGS="-Werror -Wdeprecated" \
|
--workdir="/build" \
|
||||||
${LINUX_LATEST_CONTAINER} \
|
--rm \
|
||||||
/bin/bash -c "
|
--env="CC=/usr/local/bin/gcc" \
|
||||||
cmake /src \
|
--env=CXXFLAGS="-Werror -Wdeprecated" \
|
||||||
-DCMAKE_CXX_STANDARD=14 \
|
${LINUX_LATEST_CONTAINER} \
|
||||||
-Dgtest_build_samples=ON \
|
/bin/bash -c "
|
||||||
-Dgtest_build_tests=ON \
|
cmake /src \
|
||||||
-Dgmock_build_tests=ON \
|
-DCMAKE_CXX_STANDARD=17 \
|
||||||
-Dcxx_no_exception=${cmake_off_on} \
|
-Dgtest_build_samples=ON \
|
||||||
-Dcxx_no_rtti=${cmake_off_on} && \
|
-Dgtest_build_tests=ON \
|
||||||
make -j$(nproc) && \
|
-Dgmock_build_tests=ON \
|
||||||
ctest -j$(nproc) --output-on-failure"
|
-Dcxx_no_exception=${cmake_off_on} \
|
||||||
done
|
-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
|
done
|
||||||
|
|
||||||
# Do one test with an older version of GCC
|
# 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 \
|
time docker run \
|
||||||
--volume="${GTEST_ROOT}:/src:ro" \
|
--volume="${GTEST_ROOT}:/src:ro" \
|
||||||
--workdir="/src" \
|
--workdir="/src" \
|
||||||
--rm \
|
--rm \
|
||||||
--env="CC=/usr/local/bin/gcc" \
|
--env="CC=/usr/local/bin/gcc" \
|
||||||
--env="BAZEL_CXXOPTS=-std=c++14" \
|
--env="BAZEL_CXXOPTS=-std=c++17" \
|
||||||
|
${DOCKER_EXTRA_ARGS:-} \
|
||||||
${LINUX_GCC_FLOOR_CONTAINER} \
|
${LINUX_GCC_FLOOR_CONTAINER} \
|
||||||
|
/bin/bash --login -c "
|
||||||
/usr/local/bin/bazel test ... \
|
/usr/local/bin/bazel test ... \
|
||||||
--copt="-Wall" \
|
--copt=\"-Wall\" \
|
||||||
--copt="-Werror" \
|
--copt=\"-Werror\" \
|
||||||
--copt="-Wuninitialized" \
|
--copt=\"-Wuninitialized\" \
|
||||||
--copt="-Wundef" \
|
--copt=\"-Wundef\" \
|
||||||
--copt="-Wno-error=pragmas" \
|
--copt=\"-Wno-error=pragmas\" \
|
||||||
|
--enable_bzlmod=false \
|
||||||
--features=external_include_paths \
|
--features=external_include_paths \
|
||||||
--keep_going \
|
--keep_going \
|
||||||
--show_timestamps \
|
--show_timestamps \
|
||||||
--test_output=errors
|
--test_output=errors \
|
||||||
|
${BAZEL_EXTRA_ARGS:-}"
|
||||||
|
|
||||||
# Test GCC
|
# Test GCC
|
||||||
for std in ${STD}; do
|
for std in ${STD}; do
|
||||||
@ -97,18 +126,21 @@ for std in ${STD}; do
|
|||||||
--rm \
|
--rm \
|
||||||
--env="CC=/usr/local/bin/gcc" \
|
--env="CC=/usr/local/bin/gcc" \
|
||||||
--env="BAZEL_CXXOPTS=-std=${std}" \
|
--env="BAZEL_CXXOPTS=-std=${std}" \
|
||||||
|
${DOCKER_EXTRA_ARGS:-} \
|
||||||
${LINUX_LATEST_CONTAINER} \
|
${LINUX_LATEST_CONTAINER} \
|
||||||
/usr/local/bin/bazel test ... \
|
/bin/bash --login -c "
|
||||||
--copt="-Wall" \
|
/usr/local/bin/bazel test ... \
|
||||||
--copt="-Werror" \
|
--copt=\"-Wall\" \
|
||||||
--copt="-Wuninitialized" \
|
--copt=\"-Werror\" \
|
||||||
--copt="-Wundef" \
|
--copt=\"-Wuninitialized\" \
|
||||||
--define="absl=${absl}" \
|
--copt=\"-Wundef\" \
|
||||||
--enable_bzlmod=true \
|
--define=\"absl=${absl}\" \
|
||||||
--features=external_include_paths \
|
--enable_bzlmod=true \
|
||||||
--keep_going \
|
--features=external_include_paths \
|
||||||
--show_timestamps \
|
--keep_going \
|
||||||
--test_output=errors
|
--show_timestamps \
|
||||||
|
--test_output=errors \
|
||||||
|
${BAZEL_EXTRA_ARGS:-}"
|
||||||
done
|
done
|
||||||
done
|
done
|
||||||
|
|
||||||
@ -121,19 +153,22 @@ for std in ${STD}; do
|
|||||||
--rm \
|
--rm \
|
||||||
--env="CC=/opt/llvm/clang/bin/clang" \
|
--env="CC=/opt/llvm/clang/bin/clang" \
|
||||||
--env="BAZEL_CXXOPTS=-std=${std}" \
|
--env="BAZEL_CXXOPTS=-std=${std}" \
|
||||||
|
${DOCKER_EXTRA_ARGS:-} \
|
||||||
${LINUX_LATEST_CONTAINER} \
|
${LINUX_LATEST_CONTAINER} \
|
||||||
/usr/local/bin/bazel test ... \
|
/bin/bash --login -c "
|
||||||
--copt="--gcc-toolchain=/usr/local" \
|
/usr/local/bin/bazel test ... \
|
||||||
--copt="-Wall" \
|
--copt=\"--gcc-toolchain=/usr/local\" \
|
||||||
--copt="-Werror" \
|
--copt=\"-Wall\" \
|
||||||
--copt="-Wuninitialized" \
|
--copt=\"-Werror\" \
|
||||||
--copt="-Wundef" \
|
--copt=\"-Wuninitialized\" \
|
||||||
--define="absl=${absl}" \
|
--copt=\"-Wundef\" \
|
||||||
--enable_bzlmod=true \
|
--define=\"absl=${absl}\" \
|
||||||
--features=external_include_paths \
|
--enable_bzlmod=true \
|
||||||
--keep_going \
|
--features=external_include_paths \
|
||||||
--linkopt="--gcc-toolchain=/usr/local" \
|
--keep_going \
|
||||||
--show_timestamps \
|
--linkopt=\"--gcc-toolchain=/usr/local\" \
|
||||||
--test_output=errors
|
--show_timestamps \
|
||||||
|
--test_output=errors \
|
||||||
|
${BAZEL_EXTRA_ARGS:-}"
|
||||||
done
|
done
|
||||||
done
|
done
|
||||||
|
@ -31,6 +31,9 @@
|
|||||||
|
|
||||||
set -euox pipefail
|
set -euox pipefail
|
||||||
|
|
||||||
|
# Use Xcode 16.0
|
||||||
|
sudo xcode-select -s /Applications/Xcode_16.0.app/Contents/Developer
|
||||||
|
|
||||||
if [[ -z ${GTEST_ROOT:-} ]]; then
|
if [[ -z ${GTEST_ROOT:-} ]]; then
|
||||||
GTEST_ROOT="$(realpath $(dirname ${0})/..)"
|
GTEST_ROOT="$(realpath $(dirname ${0})/..)"
|
||||||
fi
|
fi
|
||||||
@ -40,20 +43,20 @@ for cmake_off_on in OFF ON; do
|
|||||||
BUILD_DIR=$(mktemp -d build_dir.XXXXXXXX)
|
BUILD_DIR=$(mktemp -d build_dir.XXXXXXXX)
|
||||||
cd ${BUILD_DIR}
|
cd ${BUILD_DIR}
|
||||||
time cmake ${GTEST_ROOT} \
|
time cmake ${GTEST_ROOT} \
|
||||||
-DCMAKE_CXX_STANDARD=14 \
|
-DCMAKE_CXX_STANDARD=17 \
|
||||||
-Dgtest_build_samples=ON \
|
-Dgtest_build_samples=ON \
|
||||||
-Dgtest_build_tests=ON \
|
-Dgtest_build_tests=ON \
|
||||||
-Dgmock_build_tests=ON \
|
-Dgmock_build_tests=ON \
|
||||||
-Dcxx_no_exception=${cmake_off_on} \
|
-Dcxx_no_exception=${cmake_off_on} \
|
||||||
-Dcxx_no_rtti=${cmake_off_on}
|
-Dcxx_no_rtti=${cmake_off_on}
|
||||||
time make
|
time make -j$(nproc)
|
||||||
time ctest -j$(nproc) --output-on-failure
|
time ctest -j$(nproc) --output-on-failure
|
||||||
done
|
done
|
||||||
|
|
||||||
# Test the Bazel build
|
# Test the Bazel build
|
||||||
|
|
||||||
# If we are running on Kokoro, check for a versioned Bazel binary.
|
# 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.2.1-darwin-x86_64"
|
||||||
if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -f ${KOKORO_GFILE_DIR}/${KOKORO_GFILE_BAZEL_BIN} ]]; then
|
if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -f ${KOKORO_GFILE_DIR}/${KOKORO_GFILE_BAZEL_BIN} ]]; then
|
||||||
BAZEL_BIN="${KOKORO_GFILE_DIR}/${KOKORO_GFILE_BAZEL_BIN}"
|
BAZEL_BIN="${KOKORO_GFILE_DIR}/${KOKORO_GFILE_BAZEL_BIN}"
|
||||||
chmod +x ${BAZEL_BIN}
|
chmod +x ${BAZEL_BIN}
|
||||||
@ -61,17 +64,24 @@ else
|
|||||||
BAZEL_BIN="bazel"
|
BAZEL_BIN="bazel"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Use Bazel Vendor mode to reduce reliance on external dependencies.
|
||||||
|
if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -f "${KOKORO_GFILE_DIR}/distdir/googletest_vendor.tar.gz" ]]; then
|
||||||
|
tar -xf "${KOKORO_GFILE_DIR}/distdir/googletest_vendor.tar.gz" -C "${TMP}/"
|
||||||
|
BAZEL_EXTRA_ARGS="--vendor_dir=\"${TMP}/googletest_vendor\" ${BAZEL_EXTRA_ARGS:-}"
|
||||||
|
fi
|
||||||
|
|
||||||
cd ${GTEST_ROOT}
|
cd ${GTEST_ROOT}
|
||||||
for absl in 0 1; do
|
for absl in 0 1; do
|
||||||
${BAZEL_BIN} test ... \
|
${BAZEL_BIN} test ... \
|
||||||
--copt="-Wall" \
|
--copt="-Wall" \
|
||||||
--copt="-Werror" \
|
--copt="-Werror" \
|
||||||
--copt="-Wundef" \
|
--copt="-Wundef" \
|
||||||
--cxxopt="-std=c++14" \
|
--cxxopt="-std=c++17" \
|
||||||
--define="absl=${absl}" \
|
--define="absl=${absl}" \
|
||||||
--enable_bzlmod=true \
|
--enable_bzlmod=true \
|
||||||
--features=external_include_paths \
|
--features=external_include_paths \
|
||||||
--keep_going \
|
--keep_going \
|
||||||
--show_timestamps \
|
--show_timestamps \
|
||||||
--test_output=errors
|
--test_output=errors \
|
||||||
|
${BAZEL_EXTRA_ARGS:-}
|
||||||
done
|
done
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
SETLOCAL ENABLEDELAYEDEXPANSION
|
SETLOCAL ENABLEDELAYEDEXPANSION
|
||||||
|
|
||||||
SET BAZEL_EXE=%KOKORO_GFILE_DIR%\bazel-7.0.0-windows-x86_64.exe
|
SET BAZEL_EXE=%KOKORO_GFILE_DIR%\bazel-8.2.1-windows-x86_64.exe
|
||||||
|
|
||||||
SET PATH=C:\Python34;%PATH%
|
SET PATH=C:\Python34;%PATH%
|
||||||
SET BAZEL_PYTHON=C:\python34\python.exe
|
SET BAZEL_PYTHON=C:\python34\python.exe
|
||||||
@ -11,21 +11,18 @@ SET CTEST_OUTPUT_ON_FAILURE=1
|
|||||||
SET CMAKE_BUILD_PARALLEL_LEVEL=16
|
SET CMAKE_BUILD_PARALLEL_LEVEL=16
|
||||||
SET CTEST_PARALLEL_LEVEL=16
|
SET CTEST_PARALLEL_LEVEL=16
|
||||||
|
|
||||||
IF EXIST git\googletest (
|
SET GTEST_ROOT=%~dp0\..
|
||||||
CD git\googletest
|
|
||||||
) ELSE IF EXIST github\googletest (
|
|
||||||
CD github\googletest
|
|
||||||
)
|
|
||||||
|
|
||||||
IF %errorlevel% neq 0 EXIT /B 1
|
IF %errorlevel% neq 0 EXIT /B 1
|
||||||
|
|
||||||
:: ----------------------------------------------------------------------------
|
:: ----------------------------------------------------------------------------
|
||||||
:: CMake
|
:: CMake
|
||||||
MKDIR cmake_msvc2022
|
SET CMAKE_BUILD_PATH=cmake_msvc2022
|
||||||
CD cmake_msvc2022
|
MKDIR %CMAKE_BUILD_PATH%
|
||||||
|
CD %CMAKE_BUILD_PATH%
|
||||||
|
|
||||||
%CMAKE_BIN% .. ^
|
%CMAKE_BIN% %GTEST_ROOT% ^
|
||||||
-G "Visual Studio 17 2022" ^
|
-G "Visual Studio 17 2022" ^
|
||||||
|
-DCMAKE_CXX_STANDARD=17 ^
|
||||||
-DPYTHON_EXECUTABLE:FILEPATH=c:\python37\python.exe ^
|
-DPYTHON_EXECUTABLE:FILEPATH=c:\python37\python.exe ^
|
||||||
-DPYTHON_INCLUDE_DIR:PATH=c:\python37\include ^
|
-DPYTHON_INCLUDE_DIR:PATH=c:\python37\include ^
|
||||||
-DPYTHON_LIBRARY:FILEPATH=c:\python37\lib\site-packages\pip ^
|
-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
|
%CTEST_BIN% -C Debug --timeout 600
|
||||||
IF %errorlevel% neq 0 EXIT /B 1
|
IF %errorlevel% neq 0 EXIT /B 1
|
||||||
|
|
||||||
CD ..
|
CD %GTEST_ROOT%
|
||||||
RMDIR /S /Q cmake_msvc2022
|
RMDIR /S /Q %CMAKE_BUILD_PATH%
|
||||||
|
|
||||||
:: ----------------------------------------------------------------------------
|
:: ----------------------------------------------------------------------------
|
||||||
:: Bazel
|
:: Bazel
|
||||||
@ -50,14 +47,39 @@ RMDIR /S /Q cmake_msvc2022
|
|||||||
:: because of Windows limitations on path length.
|
:: because of Windows limitations on path length.
|
||||||
:: --output_user_root=C:\tmp causes Bazel to use a shorter path.
|
:: --output_user_root=C:\tmp causes Bazel to use a shorter path.
|
||||||
SET BAZEL_VS=C:\Program Files\Microsoft Visual Studio\2022\Community
|
SET BAZEL_VS=C:\Program Files\Microsoft Visual Studio\2022\Community
|
||||||
|
|
||||||
|
:: Use Bazel Vendor mode to reduce reliance on external dependencies.
|
||||||
|
IF EXIST "%KOKORO_GFILE_DIR%\distdir\googletest_vendor.tar.gz" (
|
||||||
|
tar --force-local -xf "%KOKORO_GFILE_DIR%\distdir\googletest_vendor.tar.gz" -C c:
|
||||||
|
SET VENDOR_FLAG=--vendor_dir=c:\googletest_vendor
|
||||||
|
) ELSE (
|
||||||
|
SET VENDOR_FLAG=
|
||||||
|
)
|
||||||
|
|
||||||
|
:: C++17
|
||||||
%BAZEL_EXE% ^
|
%BAZEL_EXE% ^
|
||||||
--output_user_root=C:\tmp ^
|
--output_user_root=C:\tmp ^
|
||||||
test ... ^
|
test ... ^
|
||||||
--compilation_mode=dbg ^
|
--compilation_mode=dbg ^
|
||||||
--copt=/std:c++14 ^
|
--copt=/std:c++17 ^
|
||||||
--copt=/WX ^
|
--copt=/WX ^
|
||||||
--enable_bzlmod=true ^
|
--enable_bzlmod=true ^
|
||||||
--keep_going ^
|
--keep_going ^
|
||||||
--test_output=errors ^
|
--test_output=errors ^
|
||||||
--test_tag_filters=-no_test_msvc2017
|
--test_tag_filters=-no_test_msvc2017 ^
|
||||||
|
%VENDOR_FLAG%
|
||||||
|
IF %errorlevel% neq 0 EXIT /B 1
|
||||||
|
|
||||||
|
:: C++20
|
||||||
|
%BAZEL_EXE% ^
|
||||||
|
--output_user_root=C:\tmp ^
|
||||||
|
test ... ^
|
||||||
|
--compilation_mode=dbg ^
|
||||||
|
--copt=/std:c++20 ^
|
||||||
|
--copt=/WX ^
|
||||||
|
--enable_bzlmod=true ^
|
||||||
|
--keep_going ^
|
||||||
|
--test_output=errors ^
|
||||||
|
--test_tag_filters=-no_test_msvc2017 ^
|
||||||
|
%VENDOR_FLAG%
|
||||||
IF %errorlevel% neq 0 EXIT /B 1
|
IF %errorlevel% neq 0 EXIT /B 1
|
||||||
|
@ -7,15 +7,15 @@
|
|||||||
|
|
||||||
{% seo %}
|
{% seo %}
|
||||||
<link rel="stylesheet" href="{{ "/assets/css/style.css?v=" | append: site.github.build_revision | relative_url }}">
|
<link rel="stylesheet" href="{{ "/assets/css/style.css?v=" | append: site.github.build_revision | relative_url }}">
|
||||||
|
<!-- Google tag (gtag.js) -->
|
||||||
|
<script async src="https://www.googletagmanager.com/gtag/js?id=G-9PTP6FW1M5"></script>
|
||||||
<script>
|
<script>
|
||||||
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
|
window.dataLayer = window.dataLayer || [];
|
||||||
ga('create', 'UA-197576187-1', { 'storage': 'none' });
|
function gtag(){dataLayer.push(arguments);}
|
||||||
ga('set', 'referrer', document.referrer.split('?')[0]);
|
gtag('js', new Date());
|
||||||
ga('set', 'location', window.location.href.split('?')[0]);
|
|
||||||
ga('set', 'anonymizeIp', true);
|
gtag('config', 'G-9PTP6FW1M5');
|
||||||
ga('send', 'pageview');
|
|
||||||
</script>
|
</script>
|
||||||
<script async src='https://www.google-analytics.com/analytics.js'></script>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="sidebar">
|
<div class="sidebar">
|
||||||
|
@ -1471,10 +1471,7 @@ To test them, we use the following special techniques:
|
|||||||
|
|
||||||
Another way to test private members is to refactor them into an
|
Another way to test private members is to refactor them into an
|
||||||
implementation class, which is then declared in a `*-internal.h` file. Your
|
implementation class, which is then declared in a `*-internal.h` file. Your
|
||||||
clients aren't allowed to include this header but your tests can. Such is
|
clients aren't allowed to include this header but your tests can.
|
||||||
called the
|
|
||||||
[Pimpl](https://www.gamedev.net/articles/programming/general-and-gameplay-programming/the-c-pimpl-r1794/)
|
|
||||||
(Private Implementation) idiom.
|
|
||||||
|
|
||||||
Or, you can declare an individual test as a friend of your class by adding
|
Or, you can declare an individual test as a friend of your class by adding
|
||||||
this line in the class body:
|
this line in the class body:
|
||||||
@ -1929,6 +1926,20 @@ the `--gtest_also_run_disabled_tests` flag or set the
|
|||||||
You can combine this with the `--gtest_filter` flag to further select which
|
You can combine this with the `--gtest_filter` flag to further select which
|
||||||
disabled tests to run.
|
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
|
### Repeating the Tests
|
||||||
|
|
||||||
Once in a while you'll run into a test whose result is hit-or-miss. Perhaps it
|
Once in a while you'll run into a test whose result is hit-or-miss. Perhaps it
|
||||||
|
13
docs/faq.md
13
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
|
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`.)
|
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`?
|
## 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
|
GoogleTest does not interleave tests from different test suites. That is, it
|
||||||
|
@ -3567,10 +3567,15 @@ just based on the number of parameters).
|
|||||||
|
|
||||||
### Writing New Monomorphic Matchers
|
### Writing New Monomorphic Matchers
|
||||||
|
|
||||||
A matcher of argument type `T` implements the matcher interface for `T` and does
|
A matcher of type `testing::Matcher<T>` implements the matcher interface for `T`
|
||||||
two things: it tests whether a value of type `T` matches the matcher, and can
|
and does two things: it tests whether a value of type `T` matches the matcher,
|
||||||
describe what kind of values it matches. The latter ability is used for
|
and can describe what kind of values it matches. The latter ability is used for
|
||||||
generating readable error messages when expectations are violated.
|
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:
|
A matcher of `T` must declare a typedef like:
|
||||||
|
|
||||||
@ -3662,8 +3667,16 @@ instead of `std::ostream*`.
|
|||||||
|
|
||||||
### Writing New Polymorphic Matchers
|
### Writing New Polymorphic Matchers
|
||||||
|
|
||||||
Expanding what we learned above to *polymorphic* matchers is now just as simple
|
Unlike a monomorphic matcher, which can only be used to match a value of a
|
||||||
as adding templates in the right place.
|
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
|
```cpp
|
||||||
|
|
||||||
@ -3789,6 +3802,26 @@ virtual.
|
|||||||
Like in a monomorphic matcher, you may explain the match result by streaming
|
Like in a monomorphic matcher, you may explain the match result by streaming
|
||||||
additional information to the `listener` argument in `MatchAndExplain()`.
|
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
|
### Writing New Cardinalities
|
||||||
|
|
||||||
A cardinality is used in `Times()` to tell gMock how many times you expect a
|
A cardinality is used in `Times()` to tell gMock how many times you expect a
|
||||||
|
@ -9,7 +9,7 @@ we recommend this tutorial as a starting point.
|
|||||||
To complete this tutorial, you'll need:
|
To complete this tutorial, you'll need:
|
||||||
|
|
||||||
* A compatible operating system (e.g. Linux, macOS, Windows).
|
* A compatible operating system (e.g. Linux, macOS, Windows).
|
||||||
* A compatible C++ compiler that supports at least C++14.
|
* A compatible C++ compiler that supports at least C++17.
|
||||||
* [Bazel](https://bazel.build/) 7.0 or higher, the preferred build system used
|
* [Bazel](https://bazel.build/) 7.0 or higher, the preferred build system used
|
||||||
by the GoogleTest team.
|
by the GoogleTest team.
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ with the following content:
|
|||||||
|
|
||||||
# Choose the most recent version available at
|
# Choose the most recent version available at
|
||||||
# https://registry.bazel.build/modules/googletest
|
# https://registry.bazel.build/modules/googletest
|
||||||
bazel_dep(name = "googletest", version = "1.15.2")
|
bazel_dep(name = "googletest", version = "1.17.0")
|
||||||
```
|
```
|
||||||
|
|
||||||
Now you're ready to build C++ code that uses GoogleTest.
|
Now you're ready to build C++ code that uses GoogleTest.
|
||||||
@ -99,16 +99,16 @@ files, see the
|
|||||||
[Bazel C++ Tutorial](https://docs.bazel.build/versions/main/tutorial/cpp.html).
|
[Bazel C++ Tutorial](https://docs.bazel.build/versions/main/tutorial/cpp.html).
|
||||||
|
|
||||||
{: .callout .note}
|
{: .callout .note}
|
||||||
NOTE: In the example below, we assume Clang or GCC and set `--cxxopt=-std=c++14`
|
NOTE: In the example below, we assume Clang or GCC and set `--cxxopt=-std=c++17`
|
||||||
to ensure that GoogleTest is compiled as C++14 instead of the compiler's default
|
to ensure that GoogleTest is compiled as C++17 instead of the compiler's default
|
||||||
setting (which could be C++11). For MSVC, the equivalent would be
|
setting. For MSVC, the equivalent would be `--cxxopt=/std:c++17`. See
|
||||||
`--cxxopt=/std:c++14`. See [Supported Platforms](platforms.md) for more details
|
[Supported Platforms](platforms.md) for more details on supported language
|
||||||
on supported language versions.
|
versions.
|
||||||
|
|
||||||
Now you can build and run your test:
|
Now you can build and run your test:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
<strong>$ bazel test --cxxopt=-std=c++14 --test_output=all //:hello_test</strong>
|
<strong>$ bazel test --cxxopt=-std=c++17 --test_output=all //:hello_test</strong>
|
||||||
INFO: Analyzed target //:hello_test (26 packages loaded, 362 targets configured).
|
INFO: Analyzed target //:hello_test (26 packages loaded, 362 targets configured).
|
||||||
INFO: Found 1 test target...
|
INFO: Found 1 test target...
|
||||||
INFO: From Testing //:hello_test:
|
INFO: From Testing //:hello_test:
|
||||||
|
@ -10,7 +10,7 @@ this tutorial as a starting point. If your project uses Bazel, see the
|
|||||||
To complete this tutorial, you'll need:
|
To complete this tutorial, you'll need:
|
||||||
|
|
||||||
* A compatible operating system (e.g. Linux, macOS, Windows).
|
* A compatible operating system (e.g. Linux, macOS, Windows).
|
||||||
* A compatible C++ compiler that supports at least C++14.
|
* A compatible C++ compiler that supports at least C++17.
|
||||||
* [CMake](https://cmake.org/) and a compatible build tool for building the
|
* [CMake](https://cmake.org/) and a compatible build tool for building the
|
||||||
project.
|
project.
|
||||||
* Compatible build tools include
|
* Compatible build tools include
|
||||||
@ -52,8 +52,8 @@ To do this, in your project directory (`my_project`), create a file named
|
|||||||
cmake_minimum_required(VERSION 3.14)
|
cmake_minimum_required(VERSION 3.14)
|
||||||
project(my_project)
|
project(my_project)
|
||||||
|
|
||||||
# GoogleTest requires at least C++14
|
# GoogleTest requires at least C++17
|
||||||
set(CMAKE_CXX_STANDARD 14)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
|
@ -24,7 +24,8 @@ provided by GoogleTest. All actions are defined in the `::testing` namespace.
|
|||||||
| :--------------------------------- | :-------------------------------------- |
|
| :--------------------------------- | :-------------------------------------- |
|
||||||
| `Assign(&variable, value)` | Assign `value` to variable. |
|
| `Assign(&variable, value)` | Assign `value` to variable. |
|
||||||
| `DeleteArg<N>()` | Delete the `N`-th (0-based) argument, which must be a pointer. |
|
| `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`. |
|
| `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. |
|
| `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. |
|
| `SetArgPointee<N>(value)` | Assign `value` to the variable pointed by the `N`-th (0-based) argument. |
|
||||||
@ -47,8 +48,8 @@ functor, or lambda.
|
|||||||
| `InvokeWithoutArgs(object_pointer, &class::method)` | Invoke the method on the object, which takes no arguments. |
|
| `InvokeWithoutArgs(object_pointer, &class::method)` | Invoke the method on the object, which takes no arguments. |
|
||||||
| `InvokeArgument<N>(arg1, arg2, ..., argk)` | Invoke the mock function's `N`-th (0-based) argument, which must be a function or a functor, with the `k` arguments. |
|
| `InvokeArgument<N>(arg1, arg2, ..., argk)` | Invoke the mock function's `N`-th (0-based) argument, which must be a function or a functor, with the `k` arguments. |
|
||||||
|
|
||||||
The return value of the invoked function is used as the return value of the
|
The return value of the invoked function (except `InvokeArgument`) is used as
|
||||||
action.
|
the return value of the action.
|
||||||
|
|
||||||
When defining a callable to be used with `Invoke*()`, you can declare any unused
|
When defining a callable to be used with `Invoke*()`, you can declare any unused
|
||||||
parameters as `Unused`:
|
parameters as `Unused`:
|
||||||
|
@ -42,6 +42,8 @@ Matcher | Description
|
|||||||
| `Lt(value)` | `argument < value` |
|
| `Lt(value)` | `argument < value` |
|
||||||
| `Ne(value)` | `argument != value` |
|
| `Ne(value)` | `argument != value` |
|
||||||
| `IsFalse()` | `argument` evaluates to `false` in a Boolean context. |
|
| `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. |
|
| `IsTrue()` | `argument` evaluates to `true` in a Boolean context. |
|
||||||
| `IsNull()` | `argument` is a `NULL` pointer (raw or smart). |
|
| `IsNull()` | `argument` is a `NULL` pointer (raw or smart). |
|
||||||
| `NotNull()` | `argument` is a non-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(&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.
|
| `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:**
|
**Notes:**
|
||||||
|
|
||||||
* You can use `FieldsAre()` to match any type that supports structured
|
* 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"));
|
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
|
## Matching the Result of a Function, Functor, or Callback
|
||||||
|
|
||||||
| Matcher | Description |
|
| Matcher | Description |
|
||||||
|
@ -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)`. |
|
| `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}`. |
|
| `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`. |
|
| `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
|
The optional last argument *`name_generator`* is a function or functor that
|
||||||
generates custom test name suffixes based on the test parameters. The function
|
generates custom test name suffixes based on the test parameters. The function
|
||||||
@ -137,6 +137,103 @@ For more information, see
|
|||||||
See also
|
See also
|
||||||
[`GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST`](#GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST).
|
[`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 {#TYPED_TEST_SUITE}
|
||||||
|
|
||||||
`TYPED_TEST_SUITE(`*`TestFixtureName`*`,`*`Types`*`)`
|
`TYPED_TEST_SUITE(`*`TestFixtureName`*`,`*`Types`*`)`
|
||||||
|
@ -835,6 +835,10 @@ class Action<R(Args...)> {
|
|||||||
Result operator()(const InArgs&...) const {
|
Result operator()(const InArgs&...) const {
|
||||||
return function_impl();
|
return function_impl();
|
||||||
}
|
}
|
||||||
|
template <typename... InArgs>
|
||||||
|
Result operator()(const InArgs&...) {
|
||||||
|
return function_impl();
|
||||||
|
}
|
||||||
|
|
||||||
FunctionImpl function_impl;
|
FunctionImpl function_impl;
|
||||||
};
|
};
|
||||||
@ -1451,6 +1455,30 @@ struct WithArgsAction {
|
|||||||
return OA{std::move(inner_action)};
|
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 <
|
template <
|
||||||
typename R, typename... Args,
|
typename R, typename... Args,
|
||||||
typename std::enable_if<
|
typename std::enable_if<
|
||||||
@ -1703,9 +1731,8 @@ template <size_t k>
|
|||||||
struct ReturnArgAction {
|
struct ReturnArgAction {
|
||||||
template <typename... Args,
|
template <typename... Args,
|
||||||
typename = typename std::enable_if<(k < sizeof...(Args))>::type>
|
typename = typename std::enable_if<(k < sizeof...(Args))>::type>
|
||||||
auto operator()(Args&&... args) const
|
auto operator()(Args&&... args) const -> decltype(std::get<k>(
|
||||||
-> decltype(std::get<k>(
|
std::forward_as_tuple(std::forward<Args>(args)...))) {
|
||||||
std::forward_as_tuple(std::forward<Args>(args)...))) {
|
|
||||||
return std::get<k>(std::forward_as_tuple(std::forward<Args>(args)...));
|
return std::get<k>(std::forward_as_tuple(std::forward<Args>(args)...));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1720,6 +1747,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>
|
template <size_t k, typename Ptr>
|
||||||
struct SaveArgPointeeAction {
|
struct SaveArgPointeeAction {
|
||||||
Ptr pointer;
|
Ptr pointer;
|
||||||
@ -2070,6 +2107,13 @@ internal::SaveArgAction<k, Ptr> SaveArg(Ptr pointer) {
|
|||||||
return {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
|
// Action SaveArgPointee<k>(pointer) saves the value pointed to
|
||||||
// by the k-th (0-based) argument of the mock function to *pointer.
|
// by the k-th (0-based) argument of the mock function to *pointer.
|
||||||
template <size_t k, typename Ptr>
|
template <size_t k, typename Ptr>
|
||||||
@ -2213,9 +2257,9 @@ template <typename F, typename Impl>
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define GMOCK_INTERNAL_ARG_UNUSED(i, data, el) \
|
#define GMOCK_INTERNAL_ARG_UNUSED(i, data, el) \
|
||||||
, GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED const arg##i##_type& arg##i
|
, [[maybe_unused]] const arg##i##_type& arg##i
|
||||||
#define GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_ \
|
#define GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_ \
|
||||||
GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED const args_type& args GMOCK_PP_REPEAT( \
|
[[maybe_unused]] const args_type& args GMOCK_PP_REPEAT( \
|
||||||
GMOCK_INTERNAL_ARG_UNUSED, , 10)
|
GMOCK_INTERNAL_ARG_UNUSED, , 10)
|
||||||
|
|
||||||
#define GMOCK_INTERNAL_ARG(i, data, el) , const arg##i##_type& arg##i
|
#define GMOCK_INTERNAL_ARG(i, data, el) , const arg##i##_type& arg##i
|
||||||
@ -2280,8 +2324,8 @@ template <typename F, typename Impl>
|
|||||||
std::shared_ptr<const gmock_Impl> impl_; \
|
std::shared_ptr<const gmock_Impl> impl_; \
|
||||||
}; \
|
}; \
|
||||||
template <GMOCK_ACTION_TYPENAME_PARAMS_(params)> \
|
template <GMOCK_ACTION_TYPENAME_PARAMS_(params)> \
|
||||||
inline full_name<GMOCK_ACTION_TYPE_PARAMS_(params)> name( \
|
[[nodiscard]] inline full_name<GMOCK_ACTION_TYPE_PARAMS_(params)> name( \
|
||||||
GMOCK_ACTION_TYPE_GVALUE_PARAMS_(params)) GTEST_MUST_USE_RESULT_; \
|
GMOCK_ACTION_TYPE_GVALUE_PARAMS_(params)); \
|
||||||
template <GMOCK_ACTION_TYPENAME_PARAMS_(params)> \
|
template <GMOCK_ACTION_TYPENAME_PARAMS_(params)> \
|
||||||
inline full_name<GMOCK_ACTION_TYPE_PARAMS_(params)> name( \
|
inline full_name<GMOCK_ACTION_TYPE_PARAMS_(params)> name( \
|
||||||
GMOCK_ACTION_TYPE_GVALUE_PARAMS_(params)) { \
|
GMOCK_ACTION_TYPE_GVALUE_PARAMS_(params)) { \
|
||||||
@ -2316,7 +2360,7 @@ template <typename F, typename Impl>
|
|||||||
return_type gmock_PerformImpl(GMOCK_ACTION_ARG_TYPES_AND_NAMES_) const; \
|
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(); } \
|
inline name##Action name() { return name##Action(); } \
|
||||||
template <typename function_type, typename return_type, typename args_type, \
|
template <typename function_type, typename return_type, typename args_type, \
|
||||||
GMOCK_ACTION_TEMPLATE_ARGS_NAMES_> \
|
GMOCK_ACTION_TEMPLATE_ARGS_NAMES_> \
|
||||||
|
@ -257,6 +257,7 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <cstddef>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
@ -1311,6 +1312,15 @@ class AllOfMatcherImpl : public MatcherInterface<const T&> {
|
|||||||
|
|
||||||
bool MatchAndExplain(const T& x,
|
bool MatchAndExplain(const T& x,
|
||||||
MatchResultListener* listener) const override {
|
MatchResultListener* listener) const override {
|
||||||
|
if (!listener->IsInterested()) {
|
||||||
|
// Fast path to avoid unnecessary formatting.
|
||||||
|
for (const Matcher<T>& matcher : matchers_) {
|
||||||
|
if (!matcher.Matches(x)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
// This method uses matcher's explanation when explaining the result.
|
// This method uses matcher's explanation when explaining the result.
|
||||||
// However, if matcher doesn't provide one, this method uses matcher's
|
// However, if matcher doesn't provide one, this method uses matcher's
|
||||||
// description.
|
// description.
|
||||||
@ -1430,6 +1440,15 @@ class AnyOfMatcherImpl : public MatcherInterface<const T&> {
|
|||||||
|
|
||||||
bool MatchAndExplain(const T& x,
|
bool MatchAndExplain(const T& x,
|
||||||
MatchResultListener* listener) const override {
|
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.
|
// This method uses matcher's explanation when explaining the result.
|
||||||
// However, if matcher doesn't provide one, this method uses matcher's
|
// However, if matcher doesn't provide one, this method uses matcher's
|
||||||
// description.
|
// description.
|
||||||
@ -2097,11 +2116,11 @@ class WhenDynamicCastToMatcher<To&> : public WhenDynamicCastToMatcherBase<To&> {
|
|||||||
template <typename Class, typename FieldType>
|
template <typename Class, typename FieldType>
|
||||||
class FieldMatcher {
|
class FieldMatcher {
|
||||||
public:
|
public:
|
||||||
FieldMatcher(FieldType Class::*field,
|
FieldMatcher(FieldType Class::* field,
|
||||||
const Matcher<const FieldType&>& matcher)
|
const Matcher<const FieldType&>& matcher)
|
||||||
: field_(field), matcher_(matcher), whose_field_("whose given field ") {}
|
: 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)
|
const Matcher<const FieldType&>& matcher)
|
||||||
: field_(field),
|
: field_(field),
|
||||||
matcher_(matcher),
|
matcher_(matcher),
|
||||||
@ -2145,7 +2164,7 @@ class FieldMatcher {
|
|||||||
return MatchAndExplainImpl(std::false_type(), *p, listener);
|
return MatchAndExplainImpl(std::false_type(), *p, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
const FieldType Class::*field_;
|
const FieldType Class::* field_;
|
||||||
const Matcher<const FieldType&> matcher_;
|
const Matcher<const FieldType&> matcher_;
|
||||||
|
|
||||||
// Contains either "whose given field " if the name of the field is unknown
|
// Contains either "whose given field " if the name of the field is unknown
|
||||||
@ -2855,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.
|
// Implements Each(element_matcher) for the given argument type Container.
|
||||||
// Symmetric to ContainsMatcherImpl.
|
// Symmetric to ContainsMatcherImpl.
|
||||||
template <typename Container>
|
template <typename Container>
|
||||||
@ -2990,6 +3057,52 @@ auto Second(T& x, Rank1) -> decltype((x.second)) { // NOLINT
|
|||||||
}
|
}
|
||||||
} // namespace pair_getters
|
} // 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.
|
// Implements Key(inner_matcher) for the given argument pair type.
|
||||||
// Key(inner_matcher) matches an std::pair whose 'first' field matches
|
// 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
|
// inner_matcher. For example, Contains(Key(Ge(5))) can be used to match an
|
||||||
@ -3197,8 +3310,8 @@ class PairMatcher {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, size_t... I>
|
template <typename T, size_t... I>
|
||||||
auto UnpackStructImpl(const T& t, std::index_sequence<I...>,
|
auto UnpackStructImpl(const T& t, std::index_sequence<I...>, int)
|
||||||
int) -> decltype(std::tie(get<I>(t)...)) {
|
-> decltype(std::tie(get<I>(t)...)) {
|
||||||
static_assert(std::tuple_size<T>::value == sizeof...(I),
|
static_assert(std::tuple_size<T>::value == sizeof...(I),
|
||||||
"Number of arguments doesn't match the number of fields.");
|
"Number of arguments doesn't match the number of fields.");
|
||||||
return std::tie(get<I>(t)...);
|
return std::tie(get<I>(t)...);
|
||||||
@ -3305,6 +3418,29 @@ 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;
|
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);
|
return std::tie(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t);
|
||||||
}
|
}
|
||||||
|
template <typename T>
|
||||||
|
auto UnpackStructImpl(const T& in, std::make_index_sequence<21>, char) {
|
||||||
|
const auto& [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u] =
|
||||||
|
in;
|
||||||
|
return std::tie(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t,
|
||||||
|
u);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
auto UnpackStructImpl(const T& in, std::make_index_sequence<22>, char) {
|
||||||
|
const auto& [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u,
|
||||||
|
v] = in;
|
||||||
|
return std::tie(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u,
|
||||||
|
v);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
auto UnpackStructImpl(const T& in, std::make_index_sequence<23>, char) {
|
||||||
|
const auto& [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v,
|
||||||
|
w] = in;
|
||||||
|
return std::tie(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u,
|
||||||
|
v, w);
|
||||||
|
}
|
||||||
#endif // defined(__cpp_structured_bindings)
|
#endif // defined(__cpp_structured_bindings)
|
||||||
|
|
||||||
template <size_t I, typename T>
|
template <size_t I, typename T>
|
||||||
@ -3480,7 +3616,7 @@ class ElementsAreMatcherImpl : public MatcherInterface<Container> {
|
|||||||
StlContainerReference stl_container = View::ConstReference(container);
|
StlContainerReference stl_container = View::ConstReference(container);
|
||||||
auto it = stl_container.begin();
|
auto it = stl_container.begin();
|
||||||
size_t exam_pos = 0;
|
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
|
// 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
|
// the end of either the elements or the matchers, or until we find a
|
||||||
@ -3496,11 +3632,23 @@ class ElementsAreMatcherImpl : public MatcherInterface<Container> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!match) {
|
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;
|
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
|
// Find how many elements the actual container has. We avoid
|
||||||
// calling size() s.t. this code works for stream-like "containers"
|
// calling size() s.t. this code works for stream-like "containers"
|
||||||
@ -3521,10 +3669,27 @@ class ElementsAreMatcherImpl : public MatcherInterface<Container> {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mismatch_found) {
|
if (unmatched_found) {
|
||||||
// The element count matches, but the exam_pos-th element doesn't match.
|
// The element count matches, but the exam_pos-th element doesn't match.
|
||||||
if (listener_interested) {
|
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());
|
PrintIfNotEmpty(explanations[exam_pos], listener->stream());
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -3930,15 +4095,15 @@ GTEST_API_ std::string FormatMatcherDescription(
|
|||||||
// Overloads to support `OptionalMatcher` being used with a type that either
|
// Overloads to support `OptionalMatcher` being used with a type that either
|
||||||
// supports implicit conversion to bool or a `has_value()` method.
|
// supports implicit conversion to bool or a `has_value()` method.
|
||||||
template <typename Optional>
|
template <typename Optional>
|
||||||
auto IsOptionalEngaged(const Optional& optional,
|
auto IsOptionalEngaged(const Optional& optional, Rank1)
|
||||||
Rank1) -> decltype(!!optional) {
|
-> decltype(!!optional) {
|
||||||
// The use of double-negation here is to preserve historical behavior where
|
// The use of double-negation here is to preserve historical behavior where
|
||||||
// the matcher used `operator!` rather than directly using `operator bool`.
|
// the matcher used `operator!` rather than directly using `operator bool`.
|
||||||
return !static_cast<bool>(!optional);
|
return !static_cast<bool>(!optional);
|
||||||
}
|
}
|
||||||
template <typename Optional>
|
template <typename Optional>
|
||||||
auto IsOptionalEngaged(const Optional& optional,
|
auto IsOptionalEngaged(const Optional& optional, Rank0)
|
||||||
Rank0) -> decltype(!optional.has_value()) {
|
-> decltype(!optional.has_value()) {
|
||||||
return optional.has_value();
|
return optional.has_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3979,6 +4144,10 @@ class OptionalMatcher {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const ValueType& value = *optional;
|
const ValueType& value = *optional;
|
||||||
|
if (!listener->IsInterested()) {
|
||||||
|
// Fast path to avoid unnecessary generation of match explanation.
|
||||||
|
return value_matcher_.Matches(value);
|
||||||
|
}
|
||||||
StringMatchResultListener value_listener;
|
StringMatchResultListener value_listener;
|
||||||
const bool match = value_matcher_.MatchAndExplain(value, &value_listener);
|
const bool match = value_matcher_.MatchAndExplain(value, &value_listener);
|
||||||
*listener << "whose value " << PrintToString(value)
|
*listener << "whose value " << PrintToString(value)
|
||||||
@ -4365,6 +4534,42 @@ inline internal::FloatingEqMatcher<double> DoubleNear(double rhs,
|
|||||||
return internal::FloatingEqMatcher<double>(rhs, false, max_abs_error);
|
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
|
// 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, up to the specified max absolute error bound, including NaN values when
|
||||||
// rhs is NaN. The max absolute error bound must be non-negative.
|
// rhs is NaN. The max absolute error bound must be non-negative.
|
||||||
@ -4430,7 +4635,7 @@ WhenDynamicCastTo(const Matcher<To>& inner_matcher) {
|
|||||||
// matches a Foo object x if and only if x.number >= 5.
|
// matches a Foo object x if and only if x.number >= 5.
|
||||||
template <typename Class, typename FieldType, typename FieldMatcher>
|
template <typename Class, typename FieldType, typename FieldMatcher>
|
||||||
inline PolymorphicMatcher<internal::FieldMatcher<Class, FieldType>> Field(
|
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>(
|
return MakePolymorphicMatcher(internal::FieldMatcher<Class, FieldType>(
|
||||||
field, MatcherCast<const FieldType&>(matcher)));
|
field, MatcherCast<const FieldType&>(matcher)));
|
||||||
// The call to MatcherCast() is required for supporting inner
|
// The call to MatcherCast() is required for supporting inner
|
||||||
@ -4443,7 +4648,7 @@ inline PolymorphicMatcher<internal::FieldMatcher<Class, FieldType>> Field(
|
|||||||
// messages.
|
// messages.
|
||||||
template <typename Class, typename FieldType, typename FieldMatcher>
|
template <typename Class, typename FieldType, typename FieldMatcher>
|
||||||
inline PolymorphicMatcher<internal::FieldMatcher<Class, FieldType>> Field(
|
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) {
|
const FieldMatcher& matcher) {
|
||||||
return MakePolymorphicMatcher(internal::FieldMatcher<Class, FieldType>(
|
return MakePolymorphicMatcher(internal::FieldMatcher<Class, FieldType>(
|
||||||
field_name, field, MatcherCast<const FieldType&>(matcher)));
|
field_name, field, MatcherCast<const FieldType&>(matcher)));
|
||||||
@ -4453,6 +4658,10 @@ inline PolymorphicMatcher<internal::FieldMatcher<Class, FieldType>> Field(
|
|||||||
// matches 'matcher'. For example,
|
// matches 'matcher'. For example,
|
||||||
// Property(&Foo::str, StartsWith("hi"))
|
// Property(&Foo::str, StartsWith("hi"))
|
||||||
// matches a Foo object x if and only if x.str() starts with "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>
|
template <typename Class, typename PropertyType, typename PropertyMatcher>
|
||||||
inline PolymorphicMatcher<internal::PropertyMatcher<
|
inline PolymorphicMatcher<internal::PropertyMatcher<
|
||||||
Class, PropertyType, PropertyType (Class::*)() const>>
|
Class, PropertyType, PropertyType (Class::*)() const>>
|
||||||
@ -5551,8 +5760,7 @@ PolymorphicMatcher<internal::ExceptionMatcherImpl<Err>> ThrowsMessage(
|
|||||||
template <typename arg_type> \
|
template <typename arg_type> \
|
||||||
bool name##Matcher::gmock_Impl<arg_type>::MatchAndExplain( \
|
bool name##Matcher::gmock_Impl<arg_type>::MatchAndExplain( \
|
||||||
const arg_type& arg, \
|
const arg_type& arg, \
|
||||||
GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED ::testing::MatchResultListener* \
|
[[maybe_unused]] ::testing::MatchResultListener* result_listener) const
|
||||||
result_listener) const
|
|
||||||
|
|
||||||
#define MATCHER_P(name, p0, description) \
|
#define MATCHER_P(name, p0, description) \
|
||||||
GMOCK_INTERNAL_MATCHER(name, name##MatcherP, description, (#p0), (p0))
|
GMOCK_INTERNAL_MATCHER(name, name##MatcherP, description, (#p0), (p0))
|
||||||
@ -5637,8 +5845,8 @@ PolymorphicMatcher<internal::ExceptionMatcherImpl<Err>> ThrowsMessage(
|
|||||||
bool full_name<GMOCK_INTERNAL_MATCHER_TYPE_PARAMS(args)>:: \
|
bool full_name<GMOCK_INTERNAL_MATCHER_TYPE_PARAMS(args)>:: \
|
||||||
gmock_Impl<arg_type>::MatchAndExplain( \
|
gmock_Impl<arg_type>::MatchAndExplain( \
|
||||||
const arg_type& arg, \
|
const arg_type& arg, \
|
||||||
GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED ::testing:: \
|
[[maybe_unused]] ::testing::MatchResultListener* result_listener) \
|
||||||
MatchResultListener* result_listener) const
|
const
|
||||||
|
|
||||||
#define GMOCK_INTERNAL_MATCHER_TEMPLATE_PARAMS(args) \
|
#define GMOCK_INTERNAL_MATCHER_TEMPLATE_PARAMS(args) \
|
||||||
GMOCK_PP_TAIL( \
|
GMOCK_PP_TAIL( \
|
||||||
|
@ -521,9 +521,8 @@
|
|||||||
GMOCK_INTERNAL_DECL_##value_params) \
|
GMOCK_INTERNAL_DECL_##value_params) \
|
||||||
GMOCK_PP_IF(GMOCK_PP_IS_EMPTY(GMOCK_INTERNAL_COUNT_##value_params), \
|
GMOCK_PP_IF(GMOCK_PP_IS_EMPTY(GMOCK_INTERNAL_COUNT_##value_params), \
|
||||||
= default; \
|
= default; \
|
||||||
, \
|
, : impl_(std::make_shared<gmock_Impl>( \
|
||||||
: impl_(std::make_shared<gmock_Impl>( \
|
GMOCK_INTERNAL_LIST_##value_params)){}) \
|
||||||
GMOCK_INTERNAL_LIST_##value_params)){}) \
|
|
||||||
GMOCK_ACTION_CLASS_(name, value_params)(const GMOCK_ACTION_CLASS_( \
|
GMOCK_ACTION_CLASS_(name, value_params)(const GMOCK_ACTION_CLASS_( \
|
||||||
name, value_params) &) noexcept GMOCK_INTERNAL_DEFN_COPY_ \
|
name, value_params) &) noexcept GMOCK_INTERNAL_DEFN_COPY_ \
|
||||||
##value_params \
|
##value_params \
|
||||||
@ -551,10 +550,10 @@
|
|||||||
}; \
|
}; \
|
||||||
template <GMOCK_INTERNAL_DECL_##template_params \
|
template <GMOCK_INTERNAL_DECL_##template_params \
|
||||||
GMOCK_INTERNAL_DECL_TYPE_##value_params> \
|
GMOCK_INTERNAL_DECL_TYPE_##value_params> \
|
||||||
GMOCK_ACTION_CLASS_( \
|
[[nodiscard]] GMOCK_ACTION_CLASS_( \
|
||||||
name, value_params)<GMOCK_INTERNAL_LIST_##template_params \
|
name, value_params)<GMOCK_INTERNAL_LIST_##template_params \
|
||||||
GMOCK_INTERNAL_LIST_TYPE_##value_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 \
|
template <GMOCK_INTERNAL_DECL_##template_params \
|
||||||
GMOCK_INTERNAL_DECL_TYPE_##value_params> \
|
GMOCK_INTERNAL_DECL_TYPE_##value_params> \
|
||||||
inline GMOCK_ACTION_CLASS_( \
|
inline GMOCK_ACTION_CLASS_( \
|
||||||
|
@ -467,11 +467,6 @@ struct Function<R(Args...)> {
|
|||||||
using MakeResultIgnoredValue = IgnoredValue(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'
|
// Workaround for MSVC error C2039: 'type': is not a member of 'std'
|
||||||
// when std::tuple_element is used.
|
// when std::tuple_element is used.
|
||||||
// See: https://github.com/google/googletest/issues/3931
|
// See: https://github.com/google/googletest/issues/3931
|
||||||
|
@ -188,7 +188,7 @@ TEST(TypeTraits, IsInvocableRV) {
|
|||||||
struct C {
|
struct C {
|
||||||
int operator()() const { return 0; }
|
int operator()() const { return 0; }
|
||||||
void operator()(int) & {}
|
void operator()(int) & {}
|
||||||
std::string operator()(int) && { return ""; };
|
std::string operator()(int) && { return ""; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// The first overload is callable for const and non-const rvalues and lvalues.
|
// The first overload is callable for const and non-const rvalues and lvalues.
|
||||||
@ -222,8 +222,8 @@ TEST(TypeTraits, IsInvocableRV) {
|
|||||||
// In C++17 and above, where it's guaranteed that functions can return
|
// In C++17 and above, where it's guaranteed that functions can return
|
||||||
// non-moveable objects, everything should work fine for non-moveable rsult
|
// non-moveable objects, everything should work fine for non-moveable rsult
|
||||||
// types too.
|
// types too.
|
||||||
#if defined(GTEST_INTERNAL_CPLUSPLUS_LANG) && \
|
// TODO(b/396121064) - Fix this test under MSVC
|
||||||
GTEST_INTERNAL_CPLUSPLUS_LANG >= 201703L
|
#ifndef _MSC_VER
|
||||||
{
|
{
|
||||||
struct NonMoveable {
|
struct NonMoveable {
|
||||||
NonMoveable() = default;
|
NonMoveable() = default;
|
||||||
@ -244,7 +244,7 @@ TEST(TypeTraits, IsInvocableRV) {
|
|||||||
static_assert(!internal::is_callable_r<int, Callable>::value);
|
static_assert(!internal::is_callable_r<int, Callable>::value);
|
||||||
static_assert(!internal::is_callable_r<NonMoveable, Callable, int>::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
|
// Nothing should choke when we try to call other arguments besides directly
|
||||||
// callable objects, but they should not show up as callable.
|
// callable objects, but they should not show up as callable.
|
||||||
@ -1645,6 +1645,22 @@ TEST(WithArgsTest, RefQualifiedInnerAction) {
|
|||||||
EXPECT_EQ(19, mock.AsStdFunction()(0, 17));
|
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
|
#ifndef GTEST_OS_WINDOWS_MOBILE
|
||||||
|
|
||||||
class SetErrnoAndReturnTest : public testing::Test {
|
class SetErrnoAndReturnTest : public testing::Test {
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <ostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "gmock/gmock.h"
|
#include "gmock/gmock.h"
|
||||||
@ -398,6 +399,188 @@ TEST(NanSensitiveDoubleNearTest, CanDescribeSelfWithNaNs) {
|
|||||||
EXPECT_EQ("are an almost-equal pair", Describe(m));
|
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.
|
// Tests that Not(m) matches any value that doesn't match m.
|
||||||
TEST(NotTest, NegatesMatcher) {
|
TEST(NotTest, NegatesMatcher) {
|
||||||
Matcher<int> m;
|
Matcher<int> m;
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -2396,6 +2397,74 @@ TEST(ExplainMatchResultTest, AllOf_True_True_2) {
|
|||||||
EXPECT_EQ("is >= 2, and is <= 3", 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);
|
INSTANTIATE_GTEST_MATCHER_TEST_P(ExplainmatcherResultTest);
|
||||||
|
|
||||||
TEST_P(ExplainmatcherResultTestP, MonomorphicMatcher) {
|
TEST_P(ExplainmatcherResultTestP, MonomorphicMatcher) {
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <cstddef>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <forward_list>
|
#include <forward_list>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
@ -1271,10 +1272,11 @@ TEST(WhenSortedByTest, CanDescribeSelf) {
|
|||||||
|
|
||||||
TEST(WhenSortedByTest, ExplainsMatchResult) {
|
TEST(WhenSortedByTest, ExplainsMatchResult) {
|
||||||
const int a[] = {2, 1};
|
const int a[] = {2, 1};
|
||||||
EXPECT_EQ("which is { 1, 2 } when sorted, whose element #0 doesn't match",
|
EXPECT_EQ(
|
||||||
Explain(WhenSortedBy(less<int>(), ElementsAre(2, 3)), a));
|
Explain(WhenSortedBy(less<int>(), ElementsAre(2, 3)), a),
|
||||||
EXPECT_EQ("which is { 1, 2 } when sorted",
|
"which is { 1, 2 } when sorted, whose element #0 (1) isn't equal to 2");
|
||||||
Explain(WhenSortedBy(less<int>(), ElementsAre(1, 2)), a));
|
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
|
// WhenSorted() is a simple wrapper on WhenSortedBy(). Hence we don't
|
||||||
@ -1775,6 +1777,295 @@ TEST(IsSubsetOfTest, WorksWithMoveOnly) {
|
|||||||
helper.Call(MakeUniquePtrs({2}));
|
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
|
// Tests using ElementsAre() and ElementsAreArray() with stream-like
|
||||||
// "containers".
|
// "containers".
|
||||||
|
|
||||||
@ -2155,7 +2446,7 @@ TEST_P(EachTestP, ExplainsMatchResultCorrectly) {
|
|||||||
Matcher<set<int>> m = Each(2);
|
Matcher<set<int>> m = Each(2);
|
||||||
EXPECT_EQ("", Explain(m, a));
|
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};
|
const int b[1] = {1};
|
||||||
EXPECT_EQ("", Explain(n, b));
|
EXPECT_EQ("", Explain(n, b));
|
||||||
@ -2290,7 +2581,7 @@ TEST(PointwiseTest, MakesCopyOfRhs) {
|
|||||||
rhs.push_back(4);
|
rhs.push_back(4);
|
||||||
|
|
||||||
int lhs[] = {1, 2};
|
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);
|
EXPECT_THAT(lhs, m);
|
||||||
|
|
||||||
// Changing rhs now shouldn't affect m, which made a copy of rhs.
|
// Changing rhs now shouldn't affect m, which made a copy of rhs.
|
||||||
@ -2418,7 +2709,7 @@ TEST(UnorderedPointwiseTest, MakesCopyOfRhs) {
|
|||||||
rhs.push_back(4);
|
rhs.push_back(4);
|
||||||
|
|
||||||
int lhs[] = {2, 1};
|
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);
|
EXPECT_THAT(lhs, m);
|
||||||
|
|
||||||
// Changing rhs now shouldn't affect m, which made a copy of rhs.
|
// Changing rhs now shouldn't affect m, which made a copy of rhs.
|
||||||
@ -2669,11 +2960,11 @@ TEST_P(ElementsAreTestP, CanExplainMismatchRightSize) {
|
|||||||
vector<int> v;
|
vector<int> v;
|
||||||
v.push_back(2);
|
v.push_back(2);
|
||||||
v.push_back(1);
|
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;
|
v[0] = 1;
|
||||||
EXPECT_EQ("whose element #1 doesn't match, which is 4 less than 5",
|
EXPECT_EQ(Explain(m, v),
|
||||||
Explain(m, v));
|
"whose element #1 (1) is <= 5, which is 4 less than 5");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ElementsAreTest, MatchesOneElementVector) {
|
TEST(ElementsAreTest, MatchesOneElementVector) {
|
||||||
@ -3073,7 +3364,7 @@ TEST(ContainsTest, SetDoesNotMatchWhenElementIsNotInContainer) {
|
|||||||
|
|
||||||
TEST_P(ContainsTestP, ExplainsMatchResultCorrectly) {
|
TEST_P(ContainsTestP, ExplainsMatchResultCorrectly) {
|
||||||
const int a[2] = {1, 2};
|
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));
|
EXPECT_EQ("whose element #1 matches", Explain(m, a));
|
||||||
|
|
||||||
m = Contains(3);
|
m = Contains(3);
|
||||||
|
@ -59,6 +59,7 @@ using testing::Invoke;
|
|||||||
using testing::ReturnArg;
|
using testing::ReturnArg;
|
||||||
using testing::ReturnPointee;
|
using testing::ReturnPointee;
|
||||||
using testing::SaveArg;
|
using testing::SaveArg;
|
||||||
|
using testing::SaveArgByMove;
|
||||||
using testing::SaveArgPointee;
|
using testing::SaveArgPointee;
|
||||||
using testing::SetArgReferee;
|
using testing::SetArgReferee;
|
||||||
using testing::Unused;
|
using testing::Unused;
|
||||||
@ -492,6 +493,34 @@ TEST(SaveArgActionTest, WorksForCompatibleType) {
|
|||||||
EXPECT_EQ('a', result);
|
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) {
|
TEST(SaveArgPointeeActionTest, WorksForSameType) {
|
||||||
int result = 0;
|
int result = 0;
|
||||||
const int value = 5;
|
const int value = 5;
|
||||||
@ -756,34 +785,34 @@ TEST(InvokeArgumentTest, Functor6) {
|
|||||||
|
|
||||||
// Tests using InvokeArgument with a 7-ary function.
|
// Tests using InvokeArgument with a 7-ary function.
|
||||||
TEST(InvokeArgumentTest, Function7) {
|
TEST(InvokeArgumentTest, Function7) {
|
||||||
Action<std::string(std::string(*)(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*,
|
||||||
const char*))>
|
const char*))>
|
||||||
a = InvokeArgument<0>("1", "2", "3", "4", "5", "6", "7");
|
a = InvokeArgument<0>("1", "2", "3", "4", "5", "6", "7");
|
||||||
EXPECT_EQ("1234567", a.Perform(std::make_tuple(&Concat7)));
|
EXPECT_EQ("1234567", a.Perform(std::make_tuple(&Concat7)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests using InvokeArgument with a 8-ary function.
|
// Tests using InvokeArgument with a 8-ary function.
|
||||||
TEST(InvokeArgumentTest, Function8) {
|
TEST(InvokeArgumentTest, Function8) {
|
||||||
Action<std::string(std::string(*)(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*,
|
||||||
const char*, const char*))>
|
const char*, const char*))>
|
||||||
a = InvokeArgument<0>("1", "2", "3", "4", "5", "6", "7", "8");
|
a = InvokeArgument<0>("1", "2", "3", "4", "5", "6", "7", "8");
|
||||||
EXPECT_EQ("12345678", a.Perform(std::make_tuple(&Concat8)));
|
EXPECT_EQ("12345678", a.Perform(std::make_tuple(&Concat8)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests using InvokeArgument with a 9-ary function.
|
// Tests using InvokeArgument with a 9-ary function.
|
||||||
TEST(InvokeArgumentTest, Function9) {
|
TEST(InvokeArgumentTest, Function9) {
|
||||||
Action<std::string(std::string(*)(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*,
|
||||||
const char*, const char*, const char*))>
|
const char*, const char*, const char*))>
|
||||||
a = InvokeArgument<0>("1", "2", "3", "4", "5", "6", "7", "8", "9");
|
a = InvokeArgument<0>("1", "2", "3", "4", "5", "6", "7", "8", "9");
|
||||||
EXPECT_EQ("123456789", a.Perform(std::make_tuple(&Concat9)));
|
EXPECT_EQ("123456789", a.Perform(std::make_tuple(&Concat9)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests using InvokeArgument with a 10-ary function.
|
// Tests using InvokeArgument with a 10-ary function.
|
||||||
TEST(InvokeArgumentTest, Function10) {
|
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*,
|
||||||
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");
|
a = InvokeArgument<0>("1", "2", "3", "4", "5", "6", "7", "8", "9", "0");
|
||||||
|
@ -804,9 +804,8 @@ TEST(ExpectCallTest, InfersCardinality1WhenThereIsWillRepeatedly) {
|
|||||||
"to be called at least once");
|
"to be called at least once");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(GTEST_INTERNAL_CPLUSPLUS_LANG) && \
|
// TODO(b/396121064) - Fix this test under MSVC
|
||||||
GTEST_INTERNAL_CPLUSPLUS_LANG >= 201703L
|
#ifndef _MSC_VER
|
||||||
|
|
||||||
// It should be possible to return a non-moveable type from a mock action in
|
// 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
|
// C++17 and above, where it's guaranteed that such a type can be initialized
|
||||||
// from a prvalue returned from a function.
|
// from a prvalue returned from a function.
|
||||||
@ -847,7 +846,7 @@ TEST(ExpectCallTest, NonMoveableType) {
|
|||||||
EXPECT_EQ(17, mock.AsStdFunction()().x);
|
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
|
// Tests that the n-th action is taken for the n-th matching
|
||||||
// invocation.
|
// invocation.
|
||||||
|
@ -132,9 +132,6 @@ if(GTEST_HAS_ABSL)
|
|||||||
absl::flags_reflection
|
absl::flags_reflection
|
||||||
absl::flags_usage
|
absl::flags_usage
|
||||||
absl::strings
|
absl::strings
|
||||||
absl::any
|
|
||||||
absl::optional
|
|
||||||
absl::variant
|
|
||||||
re2::re2
|
re2::re2
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
@ -25,7 +25,7 @@ When building GoogleTest as a standalone project, the typical workflow starts
|
|||||||
with
|
with
|
||||||
|
|
||||||
```
|
```
|
||||||
git clone https://github.com/google/googletest.git -b v1.15.2
|
git clone https://github.com/google/googletest.git -b v1.17.0
|
||||||
cd googletest # Main directory of the cloned repository.
|
cd googletest # Main directory of the cloned repository.
|
||||||
mkdir build # Create a directory to hold the build output.
|
mkdir build # Create a directory to hold the build output.
|
||||||
cd build
|
cd build
|
||||||
@ -124,9 +124,9 @@ match the project in which it is included.
|
|||||||
|
|
||||||
#### C++ Standard Version
|
#### 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
|
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
|
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
|
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.
|
adding it to the options for cmake via the`-DCMAKE_CXX_FLAGS` option.
|
||||||
@ -145,9 +145,9 @@ We list the most frequently used macros below. For a complete list, see file
|
|||||||
### Multi-threaded Tests
|
### Multi-threaded Tests
|
||||||
|
|
||||||
GoogleTest is thread-safe where the pthread library is available. After
|
GoogleTest is thread-safe where the pthread library is available. After
|
||||||
`#include <gtest/gtest.h>`, you can check the
|
`#include <gtest/gtest.h>`, you can check the `GTEST_IS_THREADSAFE` macro to see
|
||||||
`GTEST_IS_THREADSAFE` macro to see whether this is the case (yes if the macro is
|
whether this is the case (yes if the macro is `#defined` to 1, no if it's
|
||||||
`#defined` to 1, no if it's undefined.).
|
undefined.).
|
||||||
|
|
||||||
If GoogleTest doesn't correctly detect whether pthread is available in your
|
If GoogleTest doesn't correctly detect whether pthread is available in your
|
||||||
environment, you can force it with
|
environment, you can force it with
|
||||||
|
@ -195,7 +195,7 @@ function(cxx_library_with_type name type cxx_flags)
|
|||||||
target_link_libraries(${name} PUBLIC Threads::Threads)
|
target_link_libraries(${name} PUBLIC Threads::Threads)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_compile_features(${name} PUBLIC cxx_std_14)
|
target_compile_features(${name} PUBLIC cxx_std_17)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
|
@ -129,6 +129,13 @@ namespace testing {
|
|||||||
//
|
//
|
||||||
// Expected: Foo() is even
|
// Expected: Foo() is even
|
||||||
// Actual: it's 5
|
// 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 {
|
class GTEST_API_ AssertionResult {
|
||||||
public:
|
public:
|
||||||
|
@ -174,6 +174,7 @@ TEST_P(DerivedTest, DoesBlah) {
|
|||||||
|
|
||||||
#endif // 0
|
#endif // 0
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
@ -413,7 +414,8 @@ internal::CartesianProductHolder<Generator...> Combine(const Generator&... g) {
|
|||||||
// Synopsis:
|
// Synopsis:
|
||||||
// ConvertGenerator<T>(gen)
|
// ConvertGenerator<T>(gen)
|
||||||
// - returns a generator producing the same elements as generated by gen, but
|
// - 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
|
// It is useful when using the Combine() function to get the generated
|
||||||
// parameters in a custom type instead of std::tuple
|
// parameters in a custom type instead of std::tuple
|
||||||
@ -441,10 +443,65 @@ internal::CartesianProductHolder<Generator...> Combine(const Generator&... g) {
|
|||||||
// Combine(Values("cat", "dog"),
|
// Combine(Values("cat", "dog"),
|
||||||
// Values(BLACK, WHITE))));
|
// Values(BLACK, WHITE))));
|
||||||
//
|
//
|
||||||
template <typename T>
|
template <typename RequestedT>
|
||||||
internal::ParamConverterGenerator<T> ConvertGenerator(
|
internal::ParamConverterGenerator<RequestedT> ConvertGenerator(
|
||||||
internal::ParamGenerator<T> gen) {
|
internal::ParamGenerator<RequestedT> gen) {
|
||||||
return internal::ParamConverterGenerator<T>(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) \
|
#define TEST_P(test_suite_name, test_name) \
|
||||||
@ -469,7 +526,7 @@ internal::ParamConverterGenerator<T> ConvertGenerator(
|
|||||||
::testing::internal::CodeLocation(__FILE__, __LINE__)); \
|
::testing::internal::CodeLocation(__FILE__, __LINE__)); \
|
||||||
return 0; \
|
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, \
|
int GTEST_TEST_CLASS_NAME_(test_suite_name, \
|
||||||
test_name)::gtest_registering_dummy_ = \
|
test_name)::gtest_registering_dummy_ = \
|
||||||
@ -493,39 +550,38 @@ internal::ParamConverterGenerator<T> ConvertGenerator(
|
|||||||
#define GTEST_GET_FIRST_(first, ...) first
|
#define GTEST_GET_FIRST_(first, ...) first
|
||||||
#define GTEST_GET_SECOND_(first, second, ...) second
|
#define GTEST_GET_SECOND_(first, second, ...) second
|
||||||
|
|
||||||
#define INSTANTIATE_TEST_SUITE_P(prefix, test_suite_name, ...) \
|
#define INSTANTIATE_TEST_SUITE_P(prefix, test_suite_name, ...) \
|
||||||
static ::testing::internal::ParamGenerator<test_suite_name::ParamType> \
|
static ::testing::internal::ParamGenerator<test_suite_name::ParamType> \
|
||||||
gtest_##prefix##test_suite_name##_EvalGenerator_() { \
|
gtest_##prefix##test_suite_name##_EvalGenerator_() { \
|
||||||
return GTEST_EXPAND_(GTEST_GET_FIRST_(__VA_ARGS__, DUMMY_PARAM_)); \
|
return GTEST_EXPAND_(GTEST_GET_FIRST_(__VA_ARGS__, DUMMY_PARAM_)); \
|
||||||
} \
|
} \
|
||||||
static ::std::string gtest_##prefix##test_suite_name##_EvalGenerateName_( \
|
static ::std::string gtest_##prefix##test_suite_name##_EvalGenerateName_( \
|
||||||
const ::testing::TestParamInfo<test_suite_name::ParamType>& info) { \
|
const ::testing::TestParamInfo<test_suite_name::ParamType>& info) { \
|
||||||
if (::testing::internal::AlwaysFalse()) { \
|
if (::testing::internal::AlwaysFalse()) { \
|
||||||
::testing::internal::TestNotEmpty(GTEST_EXPAND_(GTEST_GET_SECOND_( \
|
::testing::internal::TestNotEmpty(GTEST_EXPAND_(GTEST_GET_SECOND_( \
|
||||||
__VA_ARGS__, \
|
__VA_ARGS__, \
|
||||||
::testing::internal::DefaultParamName<test_suite_name::ParamType>, \
|
::testing::internal::DefaultParamName<test_suite_name::ParamType>, \
|
||||||
DUMMY_PARAM_))); \
|
DUMMY_PARAM_))); \
|
||||||
auto t = std::make_tuple(__VA_ARGS__); \
|
auto t = std::make_tuple(__VA_ARGS__); \
|
||||||
static_assert(std::tuple_size<decltype(t)>::value <= 2, \
|
static_assert(std::tuple_size<decltype(t)>::value <= 2, \
|
||||||
"Too Many Args!"); \
|
"Too Many Args!"); \
|
||||||
} \
|
} \
|
||||||
return ((GTEST_EXPAND_(GTEST_GET_SECOND_( \
|
return ((GTEST_EXPAND_(GTEST_GET_SECOND_( \
|
||||||
__VA_ARGS__, \
|
__VA_ARGS__, \
|
||||||
::testing::internal::DefaultParamName<test_suite_name::ParamType>, \
|
::testing::internal::DefaultParamName<test_suite_name::ParamType>, \
|
||||||
DUMMY_PARAM_))))(info); \
|
DUMMY_PARAM_))))(info); \
|
||||||
} \
|
} \
|
||||||
GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED static int \
|
[[maybe_unused]] static int gtest_##prefix##test_suite_name##_dummy_ = \
|
||||||
gtest_##prefix##test_suite_name##_dummy_ = \
|
::testing::UnitTest::GetInstance() \
|
||||||
::testing::UnitTest::GetInstance() \
|
->parameterized_test_registry() \
|
||||||
->parameterized_test_registry() \
|
.GetTestSuitePatternHolder<test_suite_name>( \
|
||||||
.GetTestSuitePatternHolder<test_suite_name>( \
|
GTEST_STRINGIFY_(test_suite_name), \
|
||||||
GTEST_STRINGIFY_(test_suite_name), \
|
::testing::internal::CodeLocation(__FILE__, __LINE__)) \
|
||||||
::testing::internal::CodeLocation(__FILE__, __LINE__)) \
|
->AddTestSuiteInstantiation( \
|
||||||
->AddTestSuiteInstantiation( \
|
GTEST_STRINGIFY_(prefix), \
|
||||||
GTEST_STRINGIFY_(prefix), \
|
>est_##prefix##test_suite_name##_EvalGenerator_, \
|
||||||
>est_##prefix##test_suite_name##_EvalGenerator_, \
|
>est_##prefix##test_suite_name##_EvalGenerateName_, __FILE__, \
|
||||||
>est_##prefix##test_suite_name##_EvalGenerateName_, \
|
__LINE__)
|
||||||
__FILE__, __LINE__)
|
|
||||||
|
|
||||||
// Allow Marking a Parameterized test class as not needing to be instantiated.
|
// Allow Marking a Parameterized test class as not needing to be instantiated.
|
||||||
#define GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(T) \
|
#define GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(T) \
|
||||||
|
@ -104,15 +104,19 @@
|
|||||||
#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
|
#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
|
||||||
#define GOOGLETEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
|
#define GOOGLETEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
|
||||||
|
|
||||||
|
#include <any>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
#include <ostream> // NOLINT
|
#include <ostream> // NOLINT
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <variant>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#ifdef GTEST_HAS_ABSL
|
#ifdef GTEST_HAS_ABSL
|
||||||
@ -245,8 +249,8 @@ struct StreamPrinter {
|
|||||||
// ADL (possibly involving implicit conversions).
|
// ADL (possibly involving implicit conversions).
|
||||||
// (Use SFINAE via return type, because it seems GCC < 12 doesn't handle name
|
// (Use SFINAE via return type, because it seems GCC < 12 doesn't handle name
|
||||||
// lookup properly when we do it in the template parameter list.)
|
// lookup properly when we do it in the template parameter list.)
|
||||||
static auto PrintValue(const T& value,
|
static auto PrintValue(const T& value, ::std::ostream* os)
|
||||||
::std::ostream* os) -> decltype((void)(*os << value)) {
|
-> decltype((void)(*os << value)) {
|
||||||
// Call streaming operator found by ADL, possibly with implicit conversions
|
// Call streaming operator found by ADL, possibly with implicit conversions
|
||||||
// of the arguments.
|
// of the arguments.
|
||||||
*os << value;
|
*os << value;
|
||||||
@ -521,11 +525,15 @@ GTEST_API_ void PrintTo(wchar_t wc, ::std::ostream* os);
|
|||||||
|
|
||||||
GTEST_API_ void PrintTo(char32_t c, ::std::ostream* os);
|
GTEST_API_ void PrintTo(char32_t c, ::std::ostream* os);
|
||||||
inline void PrintTo(char16_t c, ::std::ostream* os) {
|
inline void PrintTo(char16_t c, ::std::ostream* os) {
|
||||||
PrintTo(ImplicitCast_<char32_t>(c), os);
|
// TODO(b/418738869): Incorrect for values not representing valid codepoints.
|
||||||
|
// Also see https://github.com/google/googletest/issues/4762.
|
||||||
|
PrintTo(static_cast<char32_t>(c), os);
|
||||||
}
|
}
|
||||||
#ifdef __cpp_lib_char8_t
|
#ifdef __cpp_lib_char8_t
|
||||||
inline void PrintTo(char8_t c, ::std::ostream* os) {
|
inline void PrintTo(char8_t c, ::std::ostream* os) {
|
||||||
PrintTo(ImplicitCast_<char32_t>(c), os);
|
// TODO(b/418738869): Incorrect for values not representing valid codepoints.
|
||||||
|
// Also see https://github.com/google/googletest/issues/4762.
|
||||||
|
PrintTo(static_cast<char32_t>(c), os);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -695,44 +703,63 @@ void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overloads for ::std::string.
|
// Overloads for ::std::string and ::std::string_view
|
||||||
GTEST_API_ void PrintStringTo(const ::std::string& s, ::std::ostream* os);
|
GTEST_API_ void PrintStringTo(::std::string_view s, ::std::ostream* os);
|
||||||
inline void PrintTo(const ::std::string& s, ::std::ostream* os) {
|
inline void PrintTo(const ::std::string& s, ::std::ostream* os) {
|
||||||
PrintStringTo(s, os);
|
PrintStringTo(s, os);
|
||||||
}
|
}
|
||||||
|
inline void PrintTo(::std::string_view s, ::std::ostream* os) {
|
||||||
|
PrintStringTo(s, os);
|
||||||
|
}
|
||||||
|
|
||||||
// Overloads for ::std::u8string
|
// Overloads for ::std::u8string and ::std::u8string_view
|
||||||
#ifdef __cpp_lib_char8_t
|
#ifdef __cpp_lib_char8_t
|
||||||
GTEST_API_ void PrintU8StringTo(const ::std::u8string& s, ::std::ostream* os);
|
GTEST_API_ void PrintU8StringTo(::std::u8string_view s, ::std::ostream* os);
|
||||||
inline void PrintTo(const ::std::u8string& s, ::std::ostream* os) {
|
inline void PrintTo(const ::std::u8string& s, ::std::ostream* os) {
|
||||||
PrintU8StringTo(s, os);
|
PrintU8StringTo(s, os);
|
||||||
}
|
}
|
||||||
|
inline void PrintTo(::std::u8string_view s, ::std::ostream* os) {
|
||||||
|
PrintU8StringTo(s, os);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Overloads for ::std::u16string
|
// Overloads for ::std::u16string and ::std::u16string_view
|
||||||
GTEST_API_ void PrintU16StringTo(const ::std::u16string& s, ::std::ostream* os);
|
GTEST_API_ void PrintU16StringTo(::std::u16string_view s, ::std::ostream* os);
|
||||||
inline void PrintTo(const ::std::u16string& s, ::std::ostream* os) {
|
inline void PrintTo(const ::std::u16string& s, ::std::ostream* os) {
|
||||||
PrintU16StringTo(s, os);
|
PrintU16StringTo(s, os);
|
||||||
}
|
}
|
||||||
|
inline void PrintTo(::std::u16string_view s, ::std::ostream* os) {
|
||||||
|
PrintU16StringTo(s, os);
|
||||||
|
}
|
||||||
|
|
||||||
// Overloads for ::std::u32string
|
// Overloads for ::std::u32string and ::std::u32string_view
|
||||||
GTEST_API_ void PrintU32StringTo(const ::std::u32string& s, ::std::ostream* os);
|
GTEST_API_ void PrintU32StringTo(::std::u32string_view s, ::std::ostream* os);
|
||||||
inline void PrintTo(const ::std::u32string& s, ::std::ostream* os) {
|
inline void PrintTo(const ::std::u32string& s, ::std::ostream* os) {
|
||||||
PrintU32StringTo(s, os);
|
PrintU32StringTo(s, os);
|
||||||
}
|
}
|
||||||
|
inline void PrintTo(::std::u32string_view s, ::std::ostream* os) {
|
||||||
|
PrintU32StringTo(s, os);
|
||||||
|
}
|
||||||
|
|
||||||
// Overloads for ::std::wstring.
|
// Overloads for ::std::wstring and ::std::wstring_view
|
||||||
#if GTEST_HAS_STD_WSTRING
|
#if GTEST_HAS_STD_WSTRING
|
||||||
GTEST_API_ void PrintWideStringTo(const ::std::wstring& s, ::std::ostream* os);
|
GTEST_API_ void PrintWideStringTo(::std::wstring_view s, ::std::ostream* os);
|
||||||
inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) {
|
inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) {
|
||||||
PrintWideStringTo(s, os);
|
PrintWideStringTo(s, os);
|
||||||
}
|
}
|
||||||
|
inline void PrintTo(::std::wstring_view s, ::std::ostream* os) {
|
||||||
|
PrintWideStringTo(s, os);
|
||||||
|
}
|
||||||
#endif // GTEST_HAS_STD_WSTRING
|
#endif // GTEST_HAS_STD_WSTRING
|
||||||
|
|
||||||
#if GTEST_INTERNAL_HAS_STRING_VIEW
|
#if GTEST_INTERNAL_HAS_STRING_VIEW
|
||||||
// Overload for internal::StringView.
|
// Overload for internal::StringView. Needed for build configurations where
|
||||||
|
// internal::StringView is an alias for absl::string_view, but absl::string_view
|
||||||
|
// is a distinct type from std::string_view.
|
||||||
|
template <int&... ExplicitArgumentBarrier, typename T = internal::StringView,
|
||||||
|
std::enable_if_t<!std::is_same_v<T, ::std::string_view>, int> = 0>
|
||||||
inline void PrintTo(internal::StringView sp, ::std::ostream* os) {
|
inline void PrintTo(internal::StringView sp, ::std::ostream* os) {
|
||||||
PrintTo(::std::string(sp), os);
|
PrintStringTo(sp, os);
|
||||||
}
|
}
|
||||||
#endif // GTEST_INTERNAL_HAS_STRING_VIEW
|
#endif // GTEST_INTERNAL_HAS_STRING_VIEW
|
||||||
|
|
||||||
@ -890,14 +917,11 @@ class UniversalPrinter {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
class UniversalPrinter<const T> : public UniversalPrinter<T> {};
|
class UniversalPrinter<const T> : public UniversalPrinter<T> {};
|
||||||
|
|
||||||
#if GTEST_INTERNAL_HAS_ANY
|
// Printer for std::any
|
||||||
|
|
||||||
// Printer for std::any / absl::any
|
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
class UniversalPrinter<Any> {
|
class UniversalPrinter<std::any> {
|
||||||
public:
|
public:
|
||||||
static void Print(const Any& value, ::std::ostream* os) {
|
static void Print(const std::any& value, ::std::ostream* os) {
|
||||||
if (value.has_value()) {
|
if (value.has_value()) {
|
||||||
*os << "value of type " << GetTypeName(value);
|
*os << "value of type " << GetTypeName(value);
|
||||||
} else {
|
} else {
|
||||||
@ -906,7 +930,7 @@ class UniversalPrinter<Any> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static std::string GetTypeName(const Any& value) {
|
static std::string GetTypeName(const std::any& value) {
|
||||||
#if GTEST_HAS_RTTI
|
#if GTEST_HAS_RTTI
|
||||||
return internal::GetTypeName(value.type());
|
return internal::GetTypeName(value.type());
|
||||||
#else
|
#else
|
||||||
@ -916,16 +940,11 @@ class UniversalPrinter<Any> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // GTEST_INTERNAL_HAS_ANY
|
// Printer for std::optional
|
||||||
|
|
||||||
#if GTEST_INTERNAL_HAS_OPTIONAL
|
|
||||||
|
|
||||||
// Printer for std::optional / absl::optional
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class UniversalPrinter<Optional<T>> {
|
class UniversalPrinter<std::optional<T>> {
|
||||||
public:
|
public:
|
||||||
static void Print(const Optional<T>& value, ::std::ostream* os) {
|
static void Print(const std::optional<T>& value, ::std::ostream* os) {
|
||||||
*os << '(';
|
*os << '(';
|
||||||
if (!value) {
|
if (!value) {
|
||||||
*os << "nullopt";
|
*os << "nullopt";
|
||||||
@ -937,29 +956,18 @@ class UniversalPrinter<Optional<T>> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
class UniversalPrinter<decltype(Nullopt())> {
|
class UniversalPrinter<std::nullopt_t> {
|
||||||
public:
|
public:
|
||||||
static void Print(decltype(Nullopt()), ::std::ostream* os) {
|
static void Print(std::nullopt_t, ::std::ostream* os) { *os << "(nullopt)"; }
|
||||||
*os << "(nullopt)";
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // GTEST_INTERNAL_HAS_OPTIONAL
|
// Printer for std::variant
|
||||||
|
|
||||||
#if GTEST_INTERNAL_HAS_VARIANT
|
|
||||||
|
|
||||||
// Printer for std::variant / absl::variant
|
|
||||||
|
|
||||||
template <typename... T>
|
template <typename... T>
|
||||||
class UniversalPrinter<Variant<T...>> {
|
class UniversalPrinter<std::variant<T...>> {
|
||||||
public:
|
public:
|
||||||
static void Print(const Variant<T...>& value, ::std::ostream* os) {
|
static void Print(const std::variant<T...>& value, ::std::ostream* os) {
|
||||||
*os << '(';
|
*os << '(';
|
||||||
#ifdef GTEST_HAS_ABSL
|
|
||||||
absl::visit(Visitor{os, value.index()}, value);
|
|
||||||
#else
|
|
||||||
std::visit(Visitor{os, value.index()}, value);
|
std::visit(Visitor{os, value.index()}, value);
|
||||||
#endif // GTEST_HAS_ABSL
|
|
||||||
*os << ')';
|
*os << ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -976,8 +984,6 @@ class UniversalPrinter<Variant<T...>> {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // GTEST_INTERNAL_HAS_VARIANT
|
|
||||||
|
|
||||||
// UniversalPrintArray(begin, len, os) prints an array of 'len'
|
// UniversalPrintArray(begin, len, os) prints an array of 'len'
|
||||||
// elements, starting at address 'begin'.
|
// elements, starting at address 'begin'.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -194,34 +194,33 @@ INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes);
|
|||||||
typedef ::testing::internal::NameGeneratorSelector<__VA_ARGS__>::type \
|
typedef ::testing::internal::NameGeneratorSelector<__VA_ARGS__>::type \
|
||||||
GTEST_NAME_GENERATOR_(CaseName)
|
GTEST_NAME_GENERATOR_(CaseName)
|
||||||
|
|
||||||
#define TYPED_TEST(CaseName, TestName) \
|
#define TYPED_TEST(CaseName, TestName) \
|
||||||
static_assert(sizeof(GTEST_STRINGIFY_(TestName)) > 1, \
|
static_assert(sizeof(GTEST_STRINGIFY_(TestName)) > 1, \
|
||||||
"test-name must not be empty"); \
|
"test-name must not be empty"); \
|
||||||
template <typename gtest_TypeParam_> \
|
template <typename gtest_TypeParam_> \
|
||||||
class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \
|
class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \
|
||||||
: public CaseName<gtest_TypeParam_> { \
|
: public CaseName<gtest_TypeParam_> { \
|
||||||
private: \
|
private: \
|
||||||
typedef CaseName<gtest_TypeParam_> TestFixture; \
|
typedef CaseName<gtest_TypeParam_> TestFixture; \
|
||||||
typedef gtest_TypeParam_ TypeParam; \
|
typedef gtest_TypeParam_ TypeParam; \
|
||||||
void TestBody() override; \
|
void TestBody() override; \
|
||||||
}; \
|
}; \
|
||||||
GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED static bool \
|
[[maybe_unused]] static bool gtest_##CaseName##_##TestName##_registered_ = \
|
||||||
gtest_##CaseName##_##TestName##_registered_ = \
|
::testing::internal::TypeParameterizedTest< \
|
||||||
::testing::internal::TypeParameterizedTest< \
|
CaseName, \
|
||||||
CaseName, \
|
::testing::internal::TemplateSel<GTEST_TEST_CLASS_NAME_(CaseName, \
|
||||||
::testing::internal::TemplateSel<GTEST_TEST_CLASS_NAME_( \
|
TestName)>, \
|
||||||
CaseName, TestName)>, \
|
GTEST_TYPE_PARAMS_( \
|
||||||
GTEST_TYPE_PARAMS_( \
|
CaseName)>::Register("", \
|
||||||
CaseName)>::Register("", \
|
::testing::internal::CodeLocation( \
|
||||||
::testing::internal::CodeLocation( \
|
__FILE__, __LINE__), \
|
||||||
__FILE__, __LINE__), \
|
GTEST_STRINGIFY_(CaseName), \
|
||||||
GTEST_STRINGIFY_(CaseName), \
|
GTEST_STRINGIFY_(TestName), 0, \
|
||||||
GTEST_STRINGIFY_(TestName), 0, \
|
::testing::internal::GenerateNames< \
|
||||||
::testing::internal::GenerateNames< \
|
GTEST_NAME_GENERATOR_(CaseName), \
|
||||||
GTEST_NAME_GENERATOR_(CaseName), \
|
GTEST_TYPE_PARAMS_(CaseName)>()); \
|
||||||
GTEST_TYPE_PARAMS_(CaseName)>()); \
|
template <typename gtest_TypeParam_> \
|
||||||
template <typename gtest_TypeParam_> \
|
void GTEST_TEST_CLASS_NAME_(CaseName, \
|
||||||
void GTEST_TEST_CLASS_NAME_(CaseName, \
|
|
||||||
TestName)<gtest_TypeParam_>::TestBody()
|
TestName)<gtest_TypeParam_>::TestBody()
|
||||||
|
|
||||||
// Legacy API is deprecated but still available
|
// Legacy API is deprecated but still available
|
||||||
@ -268,23 +267,22 @@ INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes);
|
|||||||
TYPED_TEST_SUITE_P
|
TYPED_TEST_SUITE_P
|
||||||
#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
|
#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
|
||||||
|
|
||||||
#define TYPED_TEST_P(SuiteName, TestName) \
|
#define TYPED_TEST_P(SuiteName, TestName) \
|
||||||
namespace GTEST_SUITE_NAMESPACE_(SuiteName) { \
|
namespace GTEST_SUITE_NAMESPACE_(SuiteName) { \
|
||||||
template <typename gtest_TypeParam_> \
|
template <typename gtest_TypeParam_> \
|
||||||
class TestName : public SuiteName<gtest_TypeParam_> { \
|
class TestName : public SuiteName<gtest_TypeParam_> { \
|
||||||
private: \
|
private: \
|
||||||
typedef SuiteName<gtest_TypeParam_> TestFixture; \
|
typedef SuiteName<gtest_TypeParam_> TestFixture; \
|
||||||
typedef gtest_TypeParam_ TypeParam; \
|
typedef gtest_TypeParam_ TypeParam; \
|
||||||
void TestBody() override; \
|
void TestBody() override; \
|
||||||
}; \
|
}; \
|
||||||
GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED static bool \
|
[[maybe_unused]] static bool gtest_##TestName##_defined_ = \
|
||||||
gtest_##TestName##_defined_ = \
|
GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).AddTestName( \
|
||||||
GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).AddTestName( \
|
__FILE__, __LINE__, GTEST_STRINGIFY_(SuiteName), \
|
||||||
__FILE__, __LINE__, GTEST_STRINGIFY_(SuiteName), \
|
GTEST_STRINGIFY_(TestName)); \
|
||||||
GTEST_STRINGIFY_(TestName)); \
|
} \
|
||||||
} \
|
template <typename gtest_TypeParam_> \
|
||||||
template <typename gtest_TypeParam_> \
|
void GTEST_SUITE_NAMESPACE_( \
|
||||||
void GTEST_SUITE_NAMESPACE_( \
|
|
||||||
SuiteName)::TestName<gtest_TypeParam_>::TestBody()
|
SuiteName)::TestName<gtest_TypeParam_>::TestBody()
|
||||||
|
|
||||||
// Note: this won't work correctly if the trailing arguments are macros.
|
// 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) { \
|
namespace GTEST_SUITE_NAMESPACE_(SuiteName) { \
|
||||||
typedef ::testing::internal::Templates<__VA_ARGS__> gtest_AllTests_; \
|
typedef ::testing::internal::Templates<__VA_ARGS__> gtest_AllTests_; \
|
||||||
} \
|
} \
|
||||||
GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED static const char* const \
|
[[maybe_unused]] static const char* const GTEST_REGISTERED_TEST_NAMES_( \
|
||||||
GTEST_REGISTERED_TEST_NAMES_(SuiteName) = \
|
SuiteName) = \
|
||||||
GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).VerifyRegisteredTestNames( \
|
GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).VerifyRegisteredTestNames( \
|
||||||
GTEST_STRINGIFY_(SuiteName), __FILE__, __LINE__, #__VA_ARGS__)
|
GTEST_STRINGIFY_(SuiteName), __FILE__, __LINE__, #__VA_ARGS__)
|
||||||
|
|
||||||
@ -305,24 +303,22 @@ INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes);
|
|||||||
REGISTER_TYPED_TEST_SUITE_P
|
REGISTER_TYPED_TEST_SUITE_P
|
||||||
#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
|
#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
|
||||||
|
|
||||||
#define INSTANTIATE_TYPED_TEST_SUITE_P(Prefix, SuiteName, Types, ...) \
|
#define INSTANTIATE_TYPED_TEST_SUITE_P(Prefix, SuiteName, Types, ...) \
|
||||||
static_assert(sizeof(GTEST_STRINGIFY_(Prefix)) > 1, \
|
static_assert(sizeof(GTEST_STRINGIFY_(Prefix)) > 1, \
|
||||||
"test-suit-prefix must not be empty"); \
|
"test-suit-prefix must not be empty"); \
|
||||||
GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED static bool \
|
[[maybe_unused]] static bool gtest_##Prefix##_##SuiteName = \
|
||||||
gtest_##Prefix##_##SuiteName = \
|
::testing::internal::TypeParameterizedTestSuite< \
|
||||||
::testing::internal::TypeParameterizedTestSuite< \
|
SuiteName, GTEST_SUITE_NAMESPACE_(SuiteName)::gtest_AllTests_, \
|
||||||
SuiteName, GTEST_SUITE_NAMESPACE_(SuiteName)::gtest_AllTests_, \
|
::testing::internal::GenerateTypeList<Types>::type>:: \
|
||||||
::testing::internal::GenerateTypeList<Types>::type>:: \
|
Register(GTEST_STRINGIFY_(Prefix), \
|
||||||
Register( \
|
::testing::internal::CodeLocation(__FILE__, __LINE__), \
|
||||||
GTEST_STRINGIFY_(Prefix), \
|
>EST_TYPED_TEST_SUITE_P_STATE_(SuiteName), \
|
||||||
::testing::internal::CodeLocation(__FILE__, __LINE__), \
|
GTEST_STRINGIFY_(SuiteName), \
|
||||||
>EST_TYPED_TEST_SUITE_P_STATE_(SuiteName), \
|
GTEST_REGISTERED_TEST_NAMES_(SuiteName), \
|
||||||
GTEST_STRINGIFY_(SuiteName), \
|
::testing::internal::GenerateNames< \
|
||||||
GTEST_REGISTERED_TEST_NAMES_(SuiteName), \
|
::testing::internal::NameGeneratorSelector< \
|
||||||
::testing::internal::GenerateNames< \
|
__VA_ARGS__>::type, \
|
||||||
::testing::internal::NameGeneratorSelector< \
|
::testing::internal::GenerateTypeList<Types>::type>())
|
||||||
__VA_ARGS__>::type, \
|
|
||||||
::testing::internal::GenerateTypeList<Types>::type>())
|
|
||||||
|
|
||||||
// Legacy API is deprecated but still available
|
// Legacy API is deprecated but still available
|
||||||
#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
|
#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
|
||||||
|
@ -1123,7 +1123,7 @@ class GTEST_API_ UnitTest {
|
|||||||
// This method can only be called from the main thread.
|
// This method can only be called from the main thread.
|
||||||
//
|
//
|
||||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
|
// 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()
|
// Returns the working directory when the first TEST() or TEST_F()
|
||||||
// was executed. The UnitTest object owns the string.
|
// was executed. The UnitTest object owns the string.
|
||||||
@ -1693,7 +1693,7 @@ class WithParamInterface {
|
|||||||
|
|
||||||
// The current parameter value. Is also available in the test fixture's
|
// The current parameter value. Is also available in the test fixture's
|
||||||
// constructor.
|
// constructor.
|
||||||
static const ParamType& GetParam() {
|
[[nodiscard]] static const ParamType& GetParam() {
|
||||||
GTEST_CHECK_(parameter_ != nullptr)
|
GTEST_CHECK_(parameter_ != nullptr)
|
||||||
<< "GetParam() can only be called inside a value-parameterized test "
|
<< "GetParam() can only be called inside a value-parameterized test "
|
||||||
<< "-- did you intend to write TEST_P instead of TEST_F?";
|
<< "-- did you intend to write TEST_P instead of TEST_F?";
|
||||||
@ -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
|
// This function was formerly a macro; thus, it is in the global
|
||||||
// namespace and has an all-caps name.
|
// 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(); }
|
inline int RUN_ALL_TESTS() { return ::testing::UnitTest::GetInstance()->Run(); }
|
||||||
|
|
||||||
|
@ -290,17 +290,17 @@ class FloatingPoint {
|
|||||||
// around may change its bits, although the new value is guaranteed
|
// around may change its bits, although the new value is guaranteed
|
||||||
// to be also a NAN. Therefore, don't expect this constructor to
|
// to be also a NAN. Therefore, don't expect this constructor to
|
||||||
// preserve the bits in x when x is a NAN.
|
// 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
|
// Static methods
|
||||||
|
|
||||||
// Reinterprets a bit pattern as a floating-point number.
|
// Reinterprets a bit pattern as a floating-point number.
|
||||||
//
|
//
|
||||||
// This function is needed to test the AlmostEquals() method.
|
// This function is needed to test the AlmostEquals() method.
|
||||||
static RawType ReinterpretBits(const Bits bits) {
|
static RawType ReinterpretBits(Bits bits) {
|
||||||
FloatingPoint fp(0);
|
RawType fp;
|
||||||
fp.u_.bits_ = bits;
|
memcpy(&fp, &bits, sizeof(fp));
|
||||||
return fp.u_.value_;
|
return fp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the floating-point number that represent positive infinity.
|
// Returns the floating-point number that represent positive infinity.
|
||||||
@ -309,16 +309,16 @@ class FloatingPoint {
|
|||||||
// Non-static methods
|
// Non-static methods
|
||||||
|
|
||||||
// Returns the bits that represents this number.
|
// 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.
|
// 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.
|
// 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.
|
// 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).
|
// Returns true if and only if this is NAN (not a number).
|
||||||
bool is_nan() const {
|
bool is_nan() const {
|
||||||
@ -332,23 +332,16 @@ class FloatingPoint {
|
|||||||
//
|
//
|
||||||
// - returns false if either number is (or both are) NAN.
|
// - returns false if either number is (or both are) NAN.
|
||||||
// - treats really large numbers as almost equal to infinity.
|
// - 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 {
|
bool AlmostEquals(const FloatingPoint& rhs) const {
|
||||||
// The IEEE standard says that any comparison operation involving
|
// The IEEE standard says that any comparison operation involving
|
||||||
// a NAN must return false.
|
// a NAN must return false.
|
||||||
if (is_nan() || rhs.is_nan()) return false;
|
if (is_nan() || rhs.is_nan()) return false;
|
||||||
|
|
||||||
return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_) <=
|
return DistanceBetweenSignAndMagnitudeNumbers(bits_, rhs.bits_) <= kMaxUlps;
|
||||||
kMaxUlps;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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
|
// Converts an integer from the sign-and-magnitude representation to
|
||||||
// the biased representation. More precisely, let N be 2 to the
|
// the biased representation. More precisely, let N be 2 to the
|
||||||
// power of (kBitCount - 1), an integer x is represented by 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
|
// Read https://en.wikipedia.org/wiki/Signed_number_representations
|
||||||
// for more details on signed number representations.
|
// for more details on signed number representations.
|
||||||
static Bits SignAndMagnitudeToBiased(const Bits& sam) {
|
static Bits SignAndMagnitudeToBiased(Bits sam) {
|
||||||
if (kSignBitMask & sam) {
|
if (kSignBitMask & sam) {
|
||||||
// sam represents a negative number.
|
// sam represents a negative number.
|
||||||
return ~sam + 1;
|
return ~sam + 1;
|
||||||
@ -376,14 +369,13 @@ class FloatingPoint {
|
|||||||
|
|
||||||
// Given two numbers in the sign-and-magnitude representation,
|
// Given two numbers in the sign-and-magnitude representation,
|
||||||
// returns the distance between them as an unsigned number.
|
// returns the distance between them as an unsigned number.
|
||||||
static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits& sam1,
|
static Bits DistanceBetweenSignAndMagnitudeNumbers(Bits sam1, Bits sam2) {
|
||||||
const Bits& sam2) {
|
|
||||||
const Bits biased1 = SignAndMagnitudeToBiased(sam1);
|
const Bits biased1 = SignAndMagnitudeToBiased(sam1);
|
||||||
const Bits biased2 = SignAndMagnitudeToBiased(sam2);
|
const Bits biased2 = SignAndMagnitudeToBiased(sam2);
|
||||||
return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1);
|
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
|
// Typedefs the instances of the FloatingPoint template class that we
|
||||||
@ -894,11 +886,6 @@ class HasDebugStringAndShortDebugString {
|
|||||||
HasDebugStringType::value && HasShortDebugStringType::value;
|
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
|
// When the compiler sees expression IsContainerTest<C>(0), if C is an
|
||||||
// STL-style container class, the first overload of IsContainerTest
|
// STL-style container class, the first overload of IsContainerTest
|
||||||
// will be viable (since both C::iterator* and C::const_iterator* are
|
// 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
|
// Utility functions to be called with static_assert to induce deprecation
|
||||||
// warnings.
|
// warnings.
|
||||||
GTEST_INTERNAL_DEPRECATED(
|
[[deprecated(
|
||||||
"INSTANTIATE_TEST_CASE_P is deprecated, please use "
|
"INSTANTIATE_TEST_CASE_P is deprecated, please use "
|
||||||
"INSTANTIATE_TEST_SUITE_P")
|
"INSTANTIATE_TEST_SUITE_P")]]
|
||||||
constexpr bool InstantiateTestCase_P_IsDeprecated() { return true; }
|
constexpr bool InstantiateTestCase_P_IsDeprecated() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
GTEST_INTERNAL_DEPRECATED(
|
[[deprecated(
|
||||||
"TYPED_TEST_CASE_P is deprecated, please use "
|
"TYPED_TEST_CASE_P is deprecated, please use "
|
||||||
"TYPED_TEST_SUITE_P")
|
"TYPED_TEST_SUITE_P")]]
|
||||||
constexpr bool TypedTestCase_P_IsDeprecated() { return true; }
|
constexpr bool TypedTestCase_P_IsDeprecated() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
GTEST_INTERNAL_DEPRECATED(
|
[[deprecated(
|
||||||
"TYPED_TEST_CASE is deprecated, please use "
|
"TYPED_TEST_CASE is deprecated, please use "
|
||||||
"TYPED_TEST_SUITE")
|
"TYPED_TEST_SUITE")]]
|
||||||
constexpr bool TypedTestCaseIsDeprecated() { return true; }
|
constexpr bool TypedTestCaseIsDeprecated() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
GTEST_INTERNAL_DEPRECATED(
|
[[deprecated(
|
||||||
"REGISTER_TYPED_TEST_CASE_P is deprecated, please use "
|
"REGISTER_TYPED_TEST_CASE_P is deprecated, please use "
|
||||||
"REGISTER_TYPED_TEST_SUITE_P")
|
"REGISTER_TYPED_TEST_SUITE_P")]]
|
||||||
constexpr bool RegisterTypedTestCase_P_IsDeprecated() { return true; }
|
constexpr bool RegisterTypedTestCase_P_IsDeprecated() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
GTEST_INTERNAL_DEPRECATED(
|
[[deprecated(
|
||||||
"INSTANTIATE_TYPED_TEST_CASE_P is deprecated, please use "
|
"INSTANTIATE_TYPED_TEST_CASE_P is deprecated, please use "
|
||||||
"INSTANTIATE_TYPED_TEST_SUITE_P")
|
"INSTANTIATE_TYPED_TEST_SUITE_P")]]
|
||||||
constexpr bool InstantiateTypedTestCase_P_IsDeprecated() { return true; }
|
constexpr bool InstantiateTypedTestCase_P_IsDeprecated() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace testing
|
} // namespace testing
|
||||||
@ -1501,8 +1498,7 @@ class NeverThrown {
|
|||||||
\
|
\
|
||||||
private: \
|
private: \
|
||||||
void TestBody() override; \
|
void TestBody() override; \
|
||||||
GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED static ::testing::TestInfo* const \
|
[[maybe_unused]] static ::testing::TestInfo* const test_info_; \
|
||||||
test_info_; \
|
|
||||||
}; \
|
}; \
|
||||||
\
|
\
|
||||||
::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_suite_name, \
|
::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_suite_name, \
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <functional>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -529,8 +530,7 @@ class ParameterizedTestSuiteInfo : public ParameterizedTestSuiteInfoBase {
|
|||||||
// prefix). test_base_name is the name of an individual test without
|
// prefix). test_base_name is the name of an individual test without
|
||||||
// parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is
|
// parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is
|
||||||
// test suite base name and DoBar is test base name.
|
// test suite base name and DoBar is test base name.
|
||||||
void AddTestPattern(const char*,
|
void AddTestPattern(const char*, const char* test_base_name,
|
||||||
const char* test_base_name,
|
|
||||||
TestMetaFactoryBase<ParamType>* meta_factory,
|
TestMetaFactoryBase<ParamType>* meta_factory,
|
||||||
CodeLocation code_location) {
|
CodeLocation code_location) {
|
||||||
tests_.emplace_back(
|
tests_.emplace_back(
|
||||||
@ -952,11 +952,11 @@ class CartesianProductHolder {
|
|||||||
std::tuple<Gen...> generators_;
|
std::tuple<Gen...> generators_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename From, typename To>
|
template <typename From, typename To, typename Func>
|
||||||
class ParamGeneratorConverter : public ParamGeneratorInterface<To> {
|
class ParamGeneratorConverter : public ParamGeneratorInterface<To> {
|
||||||
public:
|
public:
|
||||||
ParamGeneratorConverter(ParamGenerator<From> gen) // NOLINT
|
ParamGeneratorConverter(ParamGenerator<From> gen, Func converter) // NOLINT
|
||||||
: generator_(std::move(gen)) {}
|
: generator_(std::move(gen)), converter_(std::move(converter)) {}
|
||||||
|
|
||||||
ParamIteratorInterface<To>* Begin() const override {
|
ParamIteratorInterface<To>* Begin() const override {
|
||||||
return new Iterator(this, generator_.begin(), generator_.end());
|
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());
|
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:
|
private:
|
||||||
class Iterator : public ParamIteratorInterface<To> {
|
class Iterator : public ParamIteratorInterface<To> {
|
||||||
public:
|
public:
|
||||||
Iterator(const ParamGeneratorInterface<To>* base, ParamIterator<From> it,
|
Iterator(const ParamGeneratorConverter* base, ParamIterator<From> it,
|
||||||
ParamIterator<From> end)
|
ParamIterator<From> end)
|
||||||
: base_(base), it_(it), end_(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;
|
~Iterator() override = default;
|
||||||
|
|
||||||
@ -980,7 +988,9 @@ class ParamGeneratorConverter : public ParamGeneratorInterface<To> {
|
|||||||
}
|
}
|
||||||
void Advance() override {
|
void Advance() override {
|
||||||
++it_;
|
++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 {
|
ParamIteratorInterface<To>* Clone() const override {
|
||||||
return new Iterator(*this);
|
return new Iterator(*this);
|
||||||
@ -1000,30 +1010,54 @@ class ParamGeneratorConverter : public ParamGeneratorInterface<To> {
|
|||||||
private:
|
private:
|
||||||
Iterator(const Iterator& other) = default;
|
Iterator(const Iterator& other) = default;
|
||||||
|
|
||||||
const ParamGeneratorInterface<To>* const base_;
|
const ParamGeneratorConverter* const base_;
|
||||||
ParamIterator<From> it_;
|
ParamIterator<From> it_;
|
||||||
ParamIterator<From> end_;
|
ParamIterator<From> end_;
|
||||||
std::shared_ptr<To> value_;
|
std::shared_ptr<To> value_;
|
||||||
}; // class ParamGeneratorConverter::Iterator
|
}; // class ParamGeneratorConverter::Iterator
|
||||||
|
|
||||||
ParamGenerator<From> generator_;
|
ParamGenerator<From> generator_;
|
||||||
|
Func converter_;
|
||||||
}; // class ParamGeneratorConverter
|
}; // class ParamGeneratorConverter
|
||||||
|
|
||||||
template <class Gen>
|
template <class GeneratedT,
|
||||||
|
typename StdFunction =
|
||||||
|
std::function<const GeneratedT&(const GeneratedT&)>>
|
||||||
class ParamConverterGenerator {
|
class ParamConverterGenerator {
|
||||||
public:
|
public:
|
||||||
ParamConverterGenerator(ParamGenerator<Gen> g) // NOLINT
|
ParamConverterGenerator(ParamGenerator<GeneratedT> g) // NOLINT
|
||||||
: generator_(std::move(g)) {}
|
: generator_(std::move(g)), converter_(Identity) {}
|
||||||
|
|
||||||
|
ParamConverterGenerator(ParamGenerator<GeneratedT> g, StdFunction converter)
|
||||||
|
: generator_(std::move(g)), converter_(std::move(converter)) {}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
operator ParamGenerator<T>() const { // NOLINT
|
operator ParamGenerator<T>() const { // NOLINT
|
||||||
return ParamGenerator<T>(new ParamGeneratorConverter<Gen, T>(generator_));
|
return ParamGenerator<T>(
|
||||||
|
new ParamGeneratorConverter<GeneratedT, T, StdFunction>(generator_,
|
||||||
|
converter_));
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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 internal
|
||||||
} // namespace testing
|
} // namespace testing
|
||||||
|
|
||||||
|
@ -194,26 +194,12 @@
|
|||||||
//
|
//
|
||||||
// Macros for basic C++ coding:
|
// Macros for basic C++ coding:
|
||||||
// GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning.
|
// 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
|
// GTEST_INTENTIONAL_CONST_COND_PUSH_ - start code section where MSVC C4127 is
|
||||||
// suppressed (constant conditional).
|
// suppressed (constant conditional).
|
||||||
// GTEST_INTENTIONAL_CONST_COND_POP_ - finish code section where MSVC C4127
|
// GTEST_INTENTIONAL_CONST_COND_POP_ - finish code section where MSVC C4127
|
||||||
// is suppressed.
|
// is suppressed.
|
||||||
// GTEST_INTERNAL_HAS_ANY - for enabling UniversalPrinter<std::any> or
|
|
||||||
// UniversalPrinter<absl::any> specializations.
|
|
||||||
// Always defined to 0 or 1.
|
|
||||||
// GTEST_INTERNAL_HAS_OPTIONAL - for enabling UniversalPrinter<std::optional>
|
|
||||||
// or
|
|
||||||
// UniversalPrinter<absl::optional>
|
|
||||||
// specializations. Always defined to 0 or 1.
|
|
||||||
// GTEST_INTERNAL_HAS_STD_SPAN - for enabling UniversalPrinter<std::span>
|
// GTEST_INTERNAL_HAS_STD_SPAN - for enabling UniversalPrinter<std::span>
|
||||||
// specializations. Always defined to 0 or 1
|
// specializations. Always defined to 0 or 1
|
||||||
// GTEST_INTERNAL_HAS_STRING_VIEW - for enabling Matcher<std::string_view> or
|
|
||||||
// Matcher<absl::string_view>
|
|
||||||
// specializations. Always defined to 0 or 1.
|
|
||||||
// GTEST_INTERNAL_HAS_VARIANT - for enabling UniversalPrinter<std::variant> or
|
|
||||||
// UniversalPrinter<absl::variant>
|
|
||||||
// specializations. Always defined to 0 or 1.
|
|
||||||
// GTEST_USE_OWN_FLAGFILE_FLAG_ - Always defined to 0 or 1.
|
// GTEST_USE_OWN_FLAGFILE_FLAG_ - Always defined to 0 or 1.
|
||||||
// GTEST_HAS_CXXABI_H_ - Always defined to 0 or 1.
|
// GTEST_HAS_CXXABI_H_ - Always defined to 0 or 1.
|
||||||
// GTEST_CAN_STREAM_RESULTS_ - Always defined to 0 or 1.
|
// GTEST_CAN_STREAM_RESULTS_ - Always defined to 0 or 1.
|
||||||
@ -260,11 +246,6 @@
|
|||||||
// BoolFromGTestEnv() - parses a bool environment variable.
|
// BoolFromGTestEnv() - parses a bool environment variable.
|
||||||
// Int32FromGTestEnv() - parses an int32_t environment variable.
|
// Int32FromGTestEnv() - parses an int32_t environment variable.
|
||||||
// StringFromGTestEnv() - parses a string 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
|
// The definition of GTEST_INTERNAL_CPLUSPLUS_LANG comes first because it can
|
||||||
// potentially be used as an #include guard.
|
// potentially be used as an #include guard.
|
||||||
@ -275,8 +256,8 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(GTEST_INTERNAL_CPLUSPLUS_LANG) || \
|
#if !defined(GTEST_INTERNAL_CPLUSPLUS_LANG) || \
|
||||||
GTEST_INTERNAL_CPLUSPLUS_LANG < 201402L
|
GTEST_INTERNAL_CPLUSPLUS_LANG < 201703L
|
||||||
#error C++ versions less than C++14 are not supported.
|
#error C++ versions less than C++17 are not supported.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// MSVC >= 19.11 (VS 2017 Update 3) supports __has_include.
|
// MSVC >= 19.11 (VS 2017 Update 3) supports __has_include.
|
||||||
@ -288,10 +269,14 @@
|
|||||||
|
|
||||||
// Detect C++ feature test macros as gracefully as possible.
|
// 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.
|
// 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>))
|
// GCC15 warns that <ciso646> is deprecated in C++17 and suggests using
|
||||||
#include <version> // C++20 and later
|
// <version> instead, even though <version> is not available in C++17 mode prior
|
||||||
#elif (!defined(__has_include) || GTEST_INTERNAL_HAS_INCLUDE(<ciso646>))
|
// 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
|
#include <ciso646> // Pre-C++20
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -772,25 +757,6 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION;
|
|||||||
#define GTEST_HAVE_FEATURE_(x) 0
|
#define GTEST_HAVE_FEATURE_(x) 0
|
||||||
#endif
|
#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.
|
// Use this annotation before a function that takes a printf format string.
|
||||||
#if GTEST_HAVE_ATTRIBUTE_(format) && defined(__MINGW_PRINTF_FORMAT)
|
#if GTEST_HAVE_ATTRIBUTE_(format) && defined(__MINGW_PRINTF_FORMAT)
|
||||||
// MinGW has two different printf implementations. Ensure the format macro
|
// MinGW has two different printf implementations. Ensure the format macro
|
||||||
@ -805,17 +771,6 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION;
|
|||||||
#define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check)
|
#define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check)
|
||||||
#endif
|
#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
|
// 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
|
// constant. In some contexts this warning is false positive and needs to be
|
||||||
// suppressed. Use the following two macros in such cases:
|
// suppressed. Use the following two macros in such cases:
|
||||||
@ -2367,93 +2322,6 @@ const char* StringFromGTestEnv(const char* flag, const char* default_val);
|
|||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace testing
|
} // 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.
|
|
||||||
#define GTEST_INTERNAL_HAS_ANY 1
|
|
||||||
#include "absl/types/any.h"
|
|
||||||
namespace testing {
|
|
||||||
namespace internal {
|
|
||||||
using Any = ::absl::any;
|
|
||||||
} // namespace internal
|
|
||||||
} // namespace testing
|
|
||||||
#else
|
|
||||||
#if defined(__cpp_lib_any) || (GTEST_INTERNAL_HAS_INCLUDE(<any>) && \
|
|
||||||
GTEST_INTERNAL_CPLUSPLUS_LANG >= 201703L && \
|
|
||||||
(!defined(_MSC_VER) || GTEST_HAS_RTTI))
|
|
||||||
// Otherwise for C++17 and higher use std::any for UniversalPrinter<>
|
|
||||||
// specializations.
|
|
||||||
#define GTEST_INTERNAL_HAS_ANY 1
|
|
||||||
#include <any>
|
|
||||||
namespace testing {
|
|
||||||
namespace internal {
|
|
||||||
using Any = ::std::any;
|
|
||||||
} // namespace internal
|
|
||||||
} // namespace testing
|
|
||||||
// The case where absl is configured NOT to alias std::any is not
|
|
||||||
// supported.
|
|
||||||
#endif // __cpp_lib_any
|
|
||||||
#endif // GTEST_HAS_ABSL
|
|
||||||
|
|
||||||
#ifndef GTEST_INTERNAL_HAS_ANY
|
|
||||||
#define GTEST_INTERNAL_HAS_ANY 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef GTEST_HAS_ABSL
|
|
||||||
// Always use absl::optional for UniversalPrinter<> specializations if
|
|
||||||
// googletest is built with absl support.
|
|
||||||
#define GTEST_INTERNAL_HAS_OPTIONAL 1
|
|
||||||
#include "absl/types/optional.h"
|
|
||||||
namespace testing {
|
|
||||||
namespace internal {
|
|
||||||
template <typename T>
|
|
||||||
using Optional = ::absl::optional<T>;
|
|
||||||
inline ::absl::nullopt_t Nullopt() { return ::absl::nullopt; }
|
|
||||||
} // namespace internal
|
|
||||||
} // namespace testing
|
|
||||||
#else
|
|
||||||
#if defined(__cpp_lib_optional) || (GTEST_INTERNAL_HAS_INCLUDE(<optional>) && \
|
|
||||||
GTEST_INTERNAL_CPLUSPLUS_LANG >= 201703L)
|
|
||||||
// Otherwise for C++17 and higher use std::optional for UniversalPrinter<>
|
|
||||||
// specializations.
|
|
||||||
#define GTEST_INTERNAL_HAS_OPTIONAL 1
|
|
||||||
#include <optional>
|
|
||||||
namespace testing {
|
|
||||||
namespace internal {
|
|
||||||
template <typename T>
|
|
||||||
using Optional = ::std::optional<T>;
|
|
||||||
inline ::std::nullopt_t Nullopt() { return ::std::nullopt; }
|
|
||||||
} // namespace internal
|
|
||||||
} // namespace testing
|
|
||||||
// The case where absl is configured NOT to alias std::optional is not
|
|
||||||
// supported.
|
|
||||||
#endif // __cpp_lib_optional
|
|
||||||
#endif // GTEST_HAS_ABSL
|
|
||||||
|
|
||||||
#ifndef GTEST_INTERNAL_HAS_OPTIONAL
|
|
||||||
#define GTEST_INTERNAL_HAS_OPTIONAL 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__cpp_lib_span) || (GTEST_INTERNAL_HAS_INCLUDE(<span>) && \
|
#if defined(__cpp_lib_span) || (GTEST_INTERNAL_HAS_INCLUDE(<span>) && \
|
||||||
GTEST_INTERNAL_CPLUSPLUS_LANG >= 202002L)
|
GTEST_INTERNAL_CPLUSPLUS_LANG >= 202002L)
|
||||||
#define GTEST_INTERNAL_HAS_STD_SPAN 1
|
#define GTEST_INTERNAL_HAS_STD_SPAN 1
|
||||||
@ -2495,44 +2363,6 @@ using StringView = ::std::string_view;
|
|||||||
#define GTEST_INTERNAL_HAS_STRING_VIEW 0
|
#define GTEST_INTERNAL_HAS_STRING_VIEW 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef GTEST_HAS_ABSL
|
|
||||||
// Always use absl::variant for UniversalPrinter<> specializations if googletest
|
|
||||||
// is built with absl support.
|
|
||||||
#define GTEST_INTERNAL_HAS_VARIANT 1
|
|
||||||
#include "absl/types/variant.h"
|
|
||||||
namespace testing {
|
|
||||||
namespace internal {
|
|
||||||
template <typename... T>
|
|
||||||
using Variant = ::absl::variant<T...>;
|
|
||||||
} // namespace internal
|
|
||||||
} // namespace testing
|
|
||||||
#else
|
|
||||||
#if defined(__cpp_lib_variant) || (GTEST_INTERNAL_HAS_INCLUDE(<variant>) && \
|
|
||||||
GTEST_INTERNAL_CPLUSPLUS_LANG >= 201703L)
|
|
||||||
// Otherwise for C++17 and higher use std::variant for UniversalPrinter<>
|
|
||||||
// specializations.
|
|
||||||
#define GTEST_INTERNAL_HAS_VARIANT 1
|
|
||||||
#include <variant>
|
|
||||||
namespace testing {
|
|
||||||
namespace internal {
|
|
||||||
template <typename... T>
|
|
||||||
using Variant = ::std::variant<T...>;
|
|
||||||
} // namespace internal
|
|
||||||
} // namespace testing
|
|
||||||
// The case where absl is configured NOT to alias std::variant is not supported.
|
|
||||||
#endif // __cpp_lib_variant
|
|
||||||
#endif // GTEST_HAS_ABSL
|
|
||||||
|
|
||||||
#ifndef GTEST_INTERNAL_HAS_VARIANT
|
|
||||||
#define GTEST_INTERNAL_HAS_VARIANT 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if (defined(__cpp_constexpr) && !defined(__cpp_inline_variables)) || \
|
|
||||||
(defined(GTEST_INTERNAL_CPLUSPLUS_LANG) && \
|
|
||||||
GTEST_INTERNAL_CPLUSPLUS_LANG < 201703L)
|
|
||||||
#define GTEST_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if (defined(__cpp_lib_three_way_comparison) || \
|
#if (defined(__cpp_lib_three_way_comparison) || \
|
||||||
(GTEST_INTERNAL_HAS_INCLUDE(<compare>) && \
|
(GTEST_INTERNAL_HAS_INCLUDE(<compare>) && \
|
||||||
GTEST_INTERNAL_CPLUSPLUS_LANG >= 201907L))
|
GTEST_INTERNAL_CPLUSPLUS_LANG >= 201907L))
|
||||||
|
@ -826,6 +826,10 @@ class GTEST_API_ UnitTestImpl {
|
|||||||
bool catch_exceptions() const { return catch_exceptions_; }
|
bool catch_exceptions() const { return catch_exceptions_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Returns true if a warning should be issued if no tests match the test
|
||||||
|
// filter flag.
|
||||||
|
bool ShouldWarnIfNoTestsMatchFilter() const;
|
||||||
|
|
||||||
struct CompareTestSuitesByPointer {
|
struct CompareTestSuitesByPointer {
|
||||||
bool operator()(const TestSuite* lhs, const TestSuite* rhs) const {
|
bool operator()(const TestSuite* lhs, const TestSuite* rhs) const {
|
||||||
return lhs->name_ < rhs->name_;
|
return lhs->name_ < rhs->name_;
|
||||||
|
@ -50,7 +50,7 @@
|
|||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <ios>
|
#include <ios>
|
||||||
#include <ostream> // NOLINT
|
#include <ostream> // NOLINT
|
||||||
#include <string>
|
#include <string_view>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
#include "gtest/internal/gtest-port.h"
|
#include "gtest/internal/gtest-port.h"
|
||||||
@ -333,14 +333,14 @@ void PrintTo(__int128_t v, ::std::ostream* os) {
|
|||||||
|
|
||||||
// Prints the given array of characters to the ostream. CharType must be either
|
// Prints the given array of characters to the ostream. CharType must be either
|
||||||
// char, char8_t, char16_t, char32_t, or wchar_t.
|
// char, char8_t, char16_t, char32_t, or wchar_t.
|
||||||
// The array starts at begin, the length is len, it may include '\0' characters
|
// The array starts at begin (which may be nullptr) and contains len characters.
|
||||||
// and may not be NUL-terminated.
|
// The array may include '\0' characters and may not be NUL-terminated.
|
||||||
template <typename CharType>
|
template <typename CharType>
|
||||||
GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
|
GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
|
||||||
GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
|
GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
|
||||||
GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ static CharFormat
|
GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ static CharFormat
|
||||||
PrintCharsAsStringTo(const CharType* begin, size_t len, ostream* os) {
|
PrintCharsAsStringTo(const CharType* begin, size_t len, ostream* os) {
|
||||||
const char* const quote_prefix = GetCharWidthPrefix(*begin);
|
const char* const quote_prefix = GetCharWidthPrefix(CharType());
|
||||||
*os << quote_prefix << "\"";
|
*os << quote_prefix << "\"";
|
||||||
bool is_previous_hex = false;
|
bool is_previous_hex = false;
|
||||||
CharFormat print_format = kAsIs;
|
CharFormat print_format = kAsIs;
|
||||||
@ -516,13 +516,13 @@ bool IsValidUTF8(const char* str, size_t length) {
|
|||||||
void ConditionalPrintAsText(const char* str, size_t length, ostream* os) {
|
void ConditionalPrintAsText(const char* str, size_t length, ostream* os) {
|
||||||
if (!ContainsUnprintableControlCodes(str, length) &&
|
if (!ContainsUnprintableControlCodes(str, length) &&
|
||||||
IsValidUTF8(str, length)) {
|
IsValidUTF8(str, length)) {
|
||||||
*os << "\n As Text: \"" << str << "\"";
|
*os << "\n As Text: \"" << ::std::string_view(str, length) << "\"";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
void PrintStringTo(const ::std::string& s, ostream* os) {
|
void PrintStringTo(::std::string_view s, ostream* os) {
|
||||||
if (PrintCharsAsStringTo(s.data(), s.size(), os) == kHexEscape) {
|
if (PrintCharsAsStringTo(s.data(), s.size(), os) == kHexEscape) {
|
||||||
if (GTEST_FLAG_GET(print_utf8)) {
|
if (GTEST_FLAG_GET(print_utf8)) {
|
||||||
ConditionalPrintAsText(s.data(), s.size(), os);
|
ConditionalPrintAsText(s.data(), s.size(), os);
|
||||||
@ -531,21 +531,21 @@ void PrintStringTo(const ::std::string& s, ostream* os) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cpp_lib_char8_t
|
#ifdef __cpp_lib_char8_t
|
||||||
void PrintU8StringTo(const ::std::u8string& s, ostream* os) {
|
void PrintU8StringTo(::std::u8string_view s, ostream* os) {
|
||||||
PrintCharsAsStringTo(s.data(), s.size(), os);
|
PrintCharsAsStringTo(s.data(), s.size(), os);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void PrintU16StringTo(const ::std::u16string& s, ostream* os) {
|
void PrintU16StringTo(::std::u16string_view s, ostream* os) {
|
||||||
PrintCharsAsStringTo(s.data(), s.size(), os);
|
PrintCharsAsStringTo(s.data(), s.size(), os);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrintU32StringTo(const ::std::u32string& s, ostream* os) {
|
void PrintU32StringTo(::std::u32string_view s, ostream* os) {
|
||||||
PrintCharsAsStringTo(s.data(), s.size(), os);
|
PrintCharsAsStringTo(s.data(), s.size(), os);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if GTEST_HAS_STD_WSTRING
|
#if GTEST_HAS_STD_WSTRING
|
||||||
void PrintWideStringTo(const ::std::wstring& s, ostream* os) {
|
void PrintWideStringTo(::std::wstring_view s, ostream* os) {
|
||||||
PrintCharsAsStringTo(s.data(), s.size(), os);
|
PrintCharsAsStringTo(s.data(), s.size(), os);
|
||||||
}
|
}
|
||||||
#endif // GTEST_HAS_STD_WSTRING
|
#endif // GTEST_HAS_STD_WSTRING
|
||||||
|
@ -192,12 +192,17 @@ static const char kDefaultOutputFormat[] = "xml";
|
|||||||
// The default output file.
|
// The default output file.
|
||||||
static const char kDefaultOutputFile[] = "test_detail";
|
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.
|
// The environment variable name for the test shard index.
|
||||||
static const char kTestShardIndex[] = "GTEST_SHARD_INDEX";
|
static const char kTestShardIndex[] = "GTEST_SHARD_INDEX";
|
||||||
// The environment variable name for the total number of test shards.
|
// The environment variable name for the total number of test shards.
|
||||||
static const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS";
|
static const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS";
|
||||||
// The environment variable name for the test shard status file.
|
// The environment variable name for the test shard status file.
|
||||||
static const char kTestShardStatusFile[] = "GTEST_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 {
|
namespace internal {
|
||||||
|
|
||||||
@ -258,6 +263,12 @@ GTEST_DEFINE_bool_(
|
|||||||
testing::GetDefaultFailFast()),
|
testing::GetDefaultFailFast()),
|
||||||
"True if and only if a test failure should stop further test execution.");
|
"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_(
|
GTEST_DEFINE_bool_(
|
||||||
also_run_disabled_tests,
|
also_run_disabled_tests,
|
||||||
testing::internal::BoolFromGTestEnv("also_run_disabled_tests", false),
|
testing::internal::BoolFromGTestEnv("also_run_disabled_tests", false),
|
||||||
@ -1477,17 +1488,17 @@ class Hunk {
|
|||||||
// Print a unified diff header for one hunk.
|
// Print a unified diff header for one hunk.
|
||||||
// The format is
|
// The format is
|
||||||
// "@@ -<left_start>,<left_length> +<right_start>,<right_length> @@"
|
// "@@ -<left_start>,<left_length> +<right_start>,<right_length> @@"
|
||||||
// where the left/right parts are omitted if unnecessary.
|
// where the left/right lengths are omitted if unnecessary.
|
||||||
void PrintHeader(std::ostream* ss) const {
|
void PrintHeader(std::ostream* ss) const {
|
||||||
*ss << "@@ ";
|
size_t left_length = removes_ + common_;
|
||||||
if (removes_) {
|
size_t right_length = adds_ + common_;
|
||||||
*ss << "-" << left_start_ << "," << (removes_ + common_);
|
*ss << "@@ " << "-" << left_start_;
|
||||||
|
if (left_length != 1) {
|
||||||
|
*ss << "," << left_length;
|
||||||
}
|
}
|
||||||
if (removes_ && adds_) {
|
*ss << " " << "+" << right_start_;
|
||||||
*ss << " ";
|
if (right_length != 1) {
|
||||||
}
|
*ss << "," << right_length;
|
||||||
if (adds_) {
|
|
||||||
*ss << "+" << right_start_ << "," << (adds_ + common_);
|
|
||||||
}
|
}
|
||||||
*ss << " @@\n";
|
*ss << " @@\n";
|
||||||
}
|
}
|
||||||
@ -5869,6 +5880,23 @@ TestSuite* UnitTestImpl::GetTestSuite(
|
|||||||
static void SetUpEnvironment(Environment* env) { env->SetUp(); }
|
static void SetUpEnvironment(Environment* env) { env->SetUp(); }
|
||||||
static void TearDownEnvironment(Environment* env) { env->TearDown(); }
|
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
|
// Runs all tests in this UnitTest object, prints the result, and
|
||||||
// returns true if all tests are successful. If any exception is
|
// returns true if all tests are successful. If any exception is
|
||||||
// thrown during a test, the test is considered to be failed, but the
|
// thrown during a test, the test is considered to be failed, but the
|
||||||
@ -5890,6 +5918,28 @@ bool UnitTestImpl::RunAllTests() {
|
|||||||
// user didn't call InitGoogleTest.
|
// user didn't call InitGoogleTest.
|
||||||
PostFlagParsingInit();
|
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
|
#if GTEST_HAS_FILE_SYSTEM
|
||||||
// Even if sharding is not on, test runners may want to use the
|
// 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
|
// GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding
|
||||||
@ -6063,6 +6113,17 @@ bool UnitTestImpl::RunAllTests() {
|
|||||||
environments_.clear();
|
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) {
|
if (!gtest_is_initialized_before_run_all_tests) {
|
||||||
ColoredPrintf(
|
ColoredPrintf(
|
||||||
GTestColor::kRed,
|
GTestColor::kRed,
|
||||||
@ -6231,6 +6292,30 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) {
|
|||||||
return num_selected_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'
|
// Prints the given C-string on a single line by replacing all '\n'
|
||||||
// characters with string "\\n". If the output takes more than
|
// characters with string "\\n". If the output takes more than
|
||||||
// max_length characters, only prints the first max_length characters
|
// max_length characters, only prints the first max_length characters
|
||||||
@ -6677,6 +6762,7 @@ static bool ParseGoogleTestFlag(const char* const arg) {
|
|||||||
GTEST_INTERNAL_PARSE_FLAG(death_test_style);
|
GTEST_INTERNAL_PARSE_FLAG(death_test_style);
|
||||||
GTEST_INTERNAL_PARSE_FLAG(death_test_use_fork);
|
GTEST_INTERNAL_PARSE_FLAG(death_test_use_fork);
|
||||||
GTEST_INTERNAL_PARSE_FLAG(fail_fast);
|
GTEST_INTERNAL_PARSE_FLAG(fail_fast);
|
||||||
|
GTEST_INTERNAL_PARSE_FLAG(fail_if_no_test_linked);
|
||||||
GTEST_INTERNAL_PARSE_FLAG(filter);
|
GTEST_INTERNAL_PARSE_FLAG(filter);
|
||||||
GTEST_INTERNAL_PARSE_FLAG(internal_run_death_test);
|
GTEST_INTERNAL_PARSE_FLAG(internal_run_death_test);
|
||||||
GTEST_INTERNAL_PARSE_FLAG(list_tests);
|
GTEST_INTERNAL_PARSE_FLAG(list_tests);
|
||||||
|
@ -47,33 +47,36 @@ cc_test(
|
|||||||
"*.h",
|
"*.h",
|
||||||
],
|
],
|
||||||
exclude = [
|
exclude = [
|
||||||
"gtest-unittest-api_test.cc",
|
# go/keep-sorted start
|
||||||
"googletest/src/gtest-all.cc",
|
"googletest-break-on-failure-unittest_.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",
|
|
||||||
"googletest-catch-exceptions-test_.cc",
|
"googletest-catch-exceptions-test_.cc",
|
||||||
"googletest-color-test_.cc",
|
"googletest-color-test_.cc",
|
||||||
|
"googletest-death-test_ex_test.cc",
|
||||||
"googletest-env-var-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-failfast-unittest_.cc",
|
||||||
"googletest-filter-unittest_.cc",
|
"googletest-filter-unittest_.cc",
|
||||||
"googletest-global-environment-unittest_.cc",
|
"googletest-global-environment-unittest_.cc",
|
||||||
"googletest-break-on-failure-unittest_.cc",
|
"googletest-list-tests-unittest_.cc",
|
||||||
"googletest-listener-test.cc",
|
"googletest-listener-test.cc",
|
||||||
"googletest-message-test.cc",
|
"googletest-message-test.cc",
|
||||||
"googletest-output-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-name1-test_.cc",
|
||||||
"googletest-param-test-invalid-name2-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({
|
) + select({
|
||||||
"//:windows": [],
|
"//:windows": [],
|
||||||
@ -323,6 +326,26 @@ cc_binary(
|
|||||||
deps = ["//:gtest"],
|
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(
|
cc_test(
|
||||||
name = "gtest_skip_test",
|
name = "gtest_skip_test",
|
||||||
size = "small",
|
size = "small",
|
||||||
@ -363,6 +386,18 @@ py_test(
|
|||||||
deps = [":gtest_test_utils"],
|
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(
|
cc_binary(
|
||||||
name = "googletest-shuffle-test_",
|
name = "googletest-shuffle-test_",
|
||||||
srcs = ["googletest-shuffle-test_.cc"],
|
srcs = ["googletest-shuffle-test_.cc"],
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
// Copyright 2025, 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.
|
||||||
|
|
||||||
|
// Unit test for Google Test's --gtest_fail_if_no_test_linked flag.
|
||||||
|
//
|
||||||
|
// This program will be invoked from a Python test.
|
||||||
|
// Don't run it directly.
|
||||||
|
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
// A dummy test that is disabled.
|
||||||
|
TEST(SomeTest, DISABLED_Test1) {}
|
@ -0,0 +1,38 @@
|
|||||||
|
// Copyright 2025, 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.
|
||||||
|
|
||||||
|
// Unit test for Google Test's --gtest_fail_if_no_test_linked flag.
|
||||||
|
//
|
||||||
|
// This program will be invoked from a Python test.
|
||||||
|
// Don't run it directly.
|
||||||
|
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
// A dummy test that is enabled.
|
||||||
|
TEST(SomeTest, Test1) {}
|
169
googletest/test/googletest-fail-if-no-test-linked-test.py
Executable file
169
googletest/test/googletest-fail-if-no-test-linked-test.py
Executable file
@ -0,0 +1,169 @@
|
|||||||
|
#!/usr/bin/env python3 # pylint: disable=g-interpreter-mismatch
|
||||||
|
#
|
||||||
|
# Copyright 2025, 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.
|
||||||
|
|
||||||
|
"""Tests for Google Test's --gtest_fail_if_no_test_linked flag."""
|
||||||
|
|
||||||
|
import os
|
||||||
|
from googletest.test import gtest_test_utils
|
||||||
|
|
||||||
|
# The command line flag for enabling the fail-if-no-test-linked behavior.
|
||||||
|
FAIL_IF_NO_TEST_LINKED_FLAG = "gtest_fail_if_no_test_linked"
|
||||||
|
|
||||||
|
# The environment variable for the test output warnings file.
|
||||||
|
TEST_WARNINGS_OUTPUT_FILE = "TEST_WARNINGS_OUTPUT_FILE"
|
||||||
|
|
||||||
|
|
||||||
|
class GTestFailIfNoTestLinkedTest(gtest_test_utils.TestCase):
|
||||||
|
"""Tests the --gtest_fail_if_no_test_linked flag."""
|
||||||
|
|
||||||
|
def Run(self, program_name, flag=None, env=None):
|
||||||
|
"""Run the given program with the given flag.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
program_name: Name of the program to run.
|
||||||
|
flag: The command line flag to pass to the program, or None.
|
||||||
|
env: Dictionary with environment to pass to the subprocess.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if the program exits with code 0, false otherwise.
|
||||||
|
"""
|
||||||
|
|
||||||
|
exe_path = gtest_test_utils.GetTestExecutablePath(program_name)
|
||||||
|
args = [exe_path]
|
||||||
|
if flag is not None:
|
||||||
|
args += [flag]
|
||||||
|
process = gtest_test_utils.Subprocess(args, capture_stderr=False, env=env)
|
||||||
|
return process.exited and process.exit_code == 0
|
||||||
|
|
||||||
|
def testSucceedsIfNoTestLinkedAndFlagNotSpecified(self):
|
||||||
|
"""Tests the behavior of no test linked and flag not specified."""
|
||||||
|
self.assertTrue(
|
||||||
|
self.Run("googletest-fail-if-no-test-linked-test-without-test_")
|
||||||
|
)
|
||||||
|
|
||||||
|
def testSucceedsIfNoTestLinkedAndFlagNotSpecifiedWithWarningFile(self):
|
||||||
|
"""Tests that no test linked results in warning file output."""
|
||||||
|
|
||||||
|
warning_file = os.path.join(gtest_test_utils.GetTempDir(), "NO_TEST_LINKED")
|
||||||
|
self.assertTrue(
|
||||||
|
self.Run(
|
||||||
|
"googletest-fail-if-no-test-linked-test-without-test_",
|
||||||
|
env={TEST_WARNINGS_OUTPUT_FILE: warning_file},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
warning_file_contents = open(warning_file, "r").read()
|
||||||
|
self.assertEqual(
|
||||||
|
warning_file_contents,
|
||||||
|
"This test program does NOT link in any test case. Please make sure"
|
||||||
|
" this is intended.\n",
|
||||||
|
)
|
||||||
|
|
||||||
|
def testFailsIfNoTestLinkedAndFlagSpecified(self):
|
||||||
|
"""Tests the behavior of no test linked and flag specified."""
|
||||||
|
|
||||||
|
warning_file = os.path.join(
|
||||||
|
gtest_test_utils.GetTempDir(), "SHOULD_NOT_EXIST"
|
||||||
|
)
|
||||||
|
self.assertFalse(
|
||||||
|
self.Run(
|
||||||
|
"googletest-fail-if-no-test-linked-test-without-test_",
|
||||||
|
f"--{FAIL_IF_NO_TEST_LINKED_FLAG}",
|
||||||
|
env={TEST_WARNINGS_OUTPUT_FILE: warning_file},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
with self.assertRaises(FileNotFoundError):
|
||||||
|
open(warning_file, "r")
|
||||||
|
|
||||||
|
def testSucceedsIfEnabledTestLinkedAndFlagNotSpecified(self):
|
||||||
|
"""Tests the behavior of enabled test linked and flag not specified."""
|
||||||
|
|
||||||
|
warning_file = os.path.join(
|
||||||
|
gtest_test_utils.GetTempDir(), "SHOULD_NOT_EXIST"
|
||||||
|
)
|
||||||
|
self.assertTrue(
|
||||||
|
self.Run(
|
||||||
|
"googletest-fail-if-no-test-linked-test-with-enabled-test_",
|
||||||
|
env={TEST_WARNINGS_OUTPUT_FILE: warning_file},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
with self.assertRaises(FileNotFoundError):
|
||||||
|
open(warning_file, "r")
|
||||||
|
|
||||||
|
def testSucceedsIfEnabledTestLinkedAndFlagSpecified(self):
|
||||||
|
"""Tests the behavior of enabled test linked and flag specified."""
|
||||||
|
|
||||||
|
warning_file = os.path.join(
|
||||||
|
gtest_test_utils.GetTempDir(), "SHOULD_NOT_EXIST"
|
||||||
|
)
|
||||||
|
self.assertTrue(
|
||||||
|
self.Run(
|
||||||
|
"googletest-fail-if-no-test-linked-test-with-enabled-test_",
|
||||||
|
f"--{FAIL_IF_NO_TEST_LINKED_FLAG}",
|
||||||
|
env={TEST_WARNINGS_OUTPUT_FILE: warning_file},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
with self.assertRaises(FileNotFoundError):
|
||||||
|
open(warning_file, "r")
|
||||||
|
|
||||||
|
def testSucceedsIfDisabledTestLinkedAndFlagNotSpecified(self):
|
||||||
|
"""Tests the behavior of disabled test linked and flag not specified."""
|
||||||
|
|
||||||
|
warning_file = os.path.join(
|
||||||
|
gtest_test_utils.GetTempDir(), "SHOULD_NOT_EXIST"
|
||||||
|
)
|
||||||
|
self.assertTrue(
|
||||||
|
self.Run(
|
||||||
|
"googletest-fail-if-no-test-linked-test-with-disabled-test_",
|
||||||
|
env={TEST_WARNINGS_OUTPUT_FILE: warning_file},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
with self.assertRaises(FileNotFoundError):
|
||||||
|
open(warning_file, "r")
|
||||||
|
|
||||||
|
def testSucceedsIfDisabledTestLinkedAndFlagSpecified(self):
|
||||||
|
"""Tests the behavior of disabled test linked and flag specified."""
|
||||||
|
|
||||||
|
warning_file = os.path.join(
|
||||||
|
gtest_test_utils.GetTempDir(), "SHOULD_NOT_EXIST"
|
||||||
|
)
|
||||||
|
self.assertTrue(
|
||||||
|
self.Run(
|
||||||
|
"googletest-fail-if-no-test-linked-test-with-disabled-test_",
|
||||||
|
f"--{FAIL_IF_NO_TEST_LINKED_FLAG}",
|
||||||
|
env={TEST_WARNINGS_OUTPUT_FILE: warning_file},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
with self.assertRaises(FileNotFoundError):
|
||||||
|
open(warning_file, "r")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
gtest_test_utils.Main()
|
@ -97,6 +97,9 @@ TOTAL_SHARDS_ENV_VAR = 'GTEST_TOTAL_SHARDS'
|
|||||||
SHARD_INDEX_ENV_VAR = 'GTEST_SHARD_INDEX'
|
SHARD_INDEX_ENV_VAR = 'GTEST_SHARD_INDEX'
|
||||||
SHARD_STATUS_FILE_ENV_VAR = 'GTEST_SHARD_STATUS_FILE'
|
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.
|
# The command line flag for specifying the test filters.
|
||||||
FILTER_FLAG = 'gtest_filter'
|
FILTER_FLAG = 'gtest_filter'
|
||||||
|
|
||||||
@ -419,6 +422,22 @@ class GTestFilterUnitTest(gtest_test_utils.TestCase):
|
|||||||
self.RunAndVerify('BadFilter', [])
|
self.RunAndVerify('BadFilter', [])
|
||||||
self.RunAndVerifyAllowingDisabled('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):
|
def testFullName(self):
|
||||||
"""Tests filtering by full name."""
|
"""Tests filtering by full name."""
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ Expected equality of these values:
|
|||||||
Which is: "\"Line\0 1\"\nLine 2"
|
Which is: "\"Line\0 1\"\nLine 2"
|
||||||
"Line 2"
|
"Line 2"
|
||||||
With diff:
|
With diff:
|
||||||
@@ -1,2 @@
|
@@ -1,2 +1 @@
|
||||||
-\"Line\0 1\"
|
-\"Line\0 1\"
|
||||||
Line 2
|
Line 2
|
||||||
|
|
||||||
|
@ -35,12 +35,17 @@
|
|||||||
#include "test/googletest-param-test-test.h"
|
#include "test/googletest-param-test-test.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <functional>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
#include <type_traits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
@ -583,6 +588,71 @@ TEST(ConvertTest, NonDefaultConstructAssign) {
|
|||||||
EXPECT_TRUE(it == gen.end());
|
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
|
// Tests that an generator produces correct sequence after being
|
||||||
// assigned from another generator.
|
// assigned from another generator.
|
||||||
TEST(ParamGeneratorTest, AssignmentWorks) {
|
TEST(ParamGeneratorTest, AssignmentWorks) {
|
||||||
@ -1104,7 +1174,7 @@ TEST_P(ParameterizedDerivedTest, SeesSequence) {
|
|||||||
class ParameterizedDeathTest : public ::testing::TestWithParam<int> {};
|
class ParameterizedDeathTest : public ::testing::TestWithParam<int> {};
|
||||||
|
|
||||||
TEST_F(ParameterizedDeathTest, GetParamDiesFromTestF) {
|
TEST_F(ParameterizedDeathTest, GetParamDiesFromTestF) {
|
||||||
EXPECT_DEATH_IF_SUPPORTED(GetParam(), ".* value-parameterized test .*");
|
EXPECT_DEATH_IF_SUPPORTED((void)GetParam(), ".* value-parameterized test .*");
|
||||||
}
|
}
|
||||||
|
|
||||||
INSTANTIATE_TEST_SUITE_P(RangeZeroToFive, ParameterizedDerivedTest,
|
INSTANTIATE_TEST_SUITE_P(RangeZeroToFive, ParameterizedDerivedTest,
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
// This file tests the universal value printer.
|
// This file tests the universal value printer.
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <any>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@ -42,14 +43,17 @@
|
|||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <variant>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "gtest/gtest-printers.h"
|
#include "gtest/gtest-printers.h"
|
||||||
@ -62,7 +66,7 @@
|
|||||||
|
|
||||||
#if GTEST_INTERNAL_HAS_STD_SPAN
|
#if GTEST_INTERNAL_HAS_STD_SPAN
|
||||||
#include <span> // NOLINT
|
#include <span> // NOLINT
|
||||||
#endif // GTEST_INTERNAL_HAS_STD_SPAN
|
#endif // GTEST_INTERNAL_HAS_STD_SPAN
|
||||||
|
|
||||||
#if GTEST_INTERNAL_HAS_COMPARE_LIB
|
#if GTEST_INTERNAL_HAS_COMPARE_LIB
|
||||||
#include <compare> // NOLINT
|
#include <compare> // NOLINT
|
||||||
@ -121,6 +125,9 @@ class UnprintableTemplateInGlobal {
|
|||||||
// A user-defined streamable type in the global namespace.
|
// A user-defined streamable type in the global namespace.
|
||||||
class StreamableInGlobal {
|
class StreamableInGlobal {
|
||||||
public:
|
public:
|
||||||
|
StreamableInGlobal() = default;
|
||||||
|
StreamableInGlobal(const StreamableInGlobal&) = default;
|
||||||
|
StreamableInGlobal& operator=(const StreamableInGlobal&) = default;
|
||||||
virtual ~StreamableInGlobal() = default;
|
virtual ~StreamableInGlobal() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -572,6 +579,8 @@ TEST(PrintU8StringTest, Null) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Tests that u8 strings are escaped properly.
|
// Tests that u8 strings are escaped properly.
|
||||||
|
// TODO(b/396121064) - Fix this test under MSVC
|
||||||
|
#ifndef _MSC_VER
|
||||||
TEST(PrintU8StringTest, EscapesProperly) {
|
TEST(PrintU8StringTest, EscapesProperly) {
|
||||||
const char8_t* p = u8"'\"?\\\a\b\f\n\r\t\v\x7F\xFF hello 世界";
|
const char8_t* p = u8"'\"?\\\a\b\f\n\r\t\v\x7F\xFF hello 世界";
|
||||||
EXPECT_EQ(PrintPointer(p) +
|
EXPECT_EQ(PrintPointer(p) +
|
||||||
@ -579,7 +588,8 @@ TEST(PrintU8StringTest, EscapesProperly) {
|
|||||||
"hello \\xE4\\xB8\\x96\\xE7\\x95\\x8C\"",
|
"hello \\xE4\\xB8\\x96\\xE7\\x95\\x8C\"",
|
||||||
Print(p));
|
Print(p));
|
||||||
}
|
}
|
||||||
#endif
|
#endif // _MSC_VER
|
||||||
|
#endif // __cpp_lib_char8_t
|
||||||
|
|
||||||
// const char16_t*.
|
// const char16_t*.
|
||||||
TEST(PrintU16StringTest, Const) {
|
TEST(PrintU16StringTest, Const) {
|
||||||
@ -790,7 +800,7 @@ struct Foo {
|
|||||||
TEST(PrintPointerTest, MemberVariablePointer) {
|
TEST(PrintPointerTest, MemberVariablePointer) {
|
||||||
EXPECT_TRUE(HasPrefix(Print(&Foo::value),
|
EXPECT_TRUE(HasPrefix(Print(&Foo::value),
|
||||||
Print(sizeof(&Foo::value)) + "-byte object "));
|
Print(sizeof(&Foo::value)) + "-byte object "));
|
||||||
int Foo::*p = NULL; // NOLINT
|
int Foo::* p = NULL; // NOLINT
|
||||||
EXPECT_TRUE(HasPrefix(Print(p), Print(sizeof(p)) + "-byte object "));
|
EXPECT_TRUE(HasPrefix(Print(p), Print(sizeof(p)) + "-byte object "));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -917,7 +927,7 @@ TEST(PrintArrayTest, BigArray) {
|
|||||||
PrintArrayHelper(a));
|
PrintArrayHelper(a));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests printing ::string and ::std::string.
|
// Tests printing ::std::string and ::string_view.
|
||||||
|
|
||||||
// ::std::string.
|
// ::std::string.
|
||||||
TEST(PrintStringTest, StringInStdNamespace) {
|
TEST(PrintStringTest, StringInStdNamespace) {
|
||||||
@ -927,6 +937,13 @@ TEST(PrintStringTest, StringInStdNamespace) {
|
|||||||
Print(str));
|
Print(str));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(PrintStringTest, StringViewInStdNamespace) {
|
||||||
|
const char s[] = "'\"?\\\a\b\f\n\0\r\t\v\x7F\xFF a";
|
||||||
|
const ::std::string_view str(s, sizeof(s));
|
||||||
|
EXPECT_EQ("\"'\\\"?\\\\\\a\\b\\f\\n\\0\\r\\t\\v\\x7F\\xFF a\\0\"",
|
||||||
|
Print(str));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(PrintStringTest, StringAmbiguousHex) {
|
TEST(PrintStringTest, StringAmbiguousHex) {
|
||||||
// "\x6BANANA" is ambiguous, it can be interpreted as starting with either of:
|
// "\x6BANANA" is ambiguous, it can be interpreted as starting with either of:
|
||||||
// '\x6', '\x6B', or '\x6BA'.
|
// '\x6', '\x6B', or '\x6BA'.
|
||||||
@ -944,7 +961,7 @@ TEST(PrintStringTest, StringAmbiguousHex) {
|
|||||||
EXPECT_EQ("\"!\\x5-!\"", Print(::std::string("!\x5-!")));
|
EXPECT_EQ("\"!\\x5-!\"", Print(::std::string("!\x5-!")));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests printing ::std::wstring.
|
// Tests printing ::std::wstring and ::std::wstring_view.
|
||||||
#if GTEST_HAS_STD_WSTRING
|
#if GTEST_HAS_STD_WSTRING
|
||||||
// ::std::wstring.
|
// ::std::wstring.
|
||||||
TEST(PrintWideStringTest, StringInStdNamespace) {
|
TEST(PrintWideStringTest, StringInStdNamespace) {
|
||||||
@ -956,6 +973,15 @@ TEST(PrintWideStringTest, StringInStdNamespace) {
|
|||||||
Print(str));
|
Print(str));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(PrintWideStringTest, StringViewInStdNamespace) {
|
||||||
|
const wchar_t s[] = L"'\"?\\\a\b\f\n\0\r\t\v\xD3\x576\x8D3\xC74D a";
|
||||||
|
const ::std::wstring_view str(s, sizeof(s) / sizeof(wchar_t));
|
||||||
|
EXPECT_EQ(
|
||||||
|
"L\"'\\\"?\\\\\\a\\b\\f\\n\\0\\r\\t\\v"
|
||||||
|
"\\xD3\\x576\\x8D3\\xC74D a\\0\"",
|
||||||
|
Print(str));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(PrintWideStringTest, StringAmbiguousHex) {
|
TEST(PrintWideStringTest, StringAmbiguousHex) {
|
||||||
// same for wide strings.
|
// same for wide strings.
|
||||||
EXPECT_EQ("L\"0\\x12\" L\"3\"", Print(::std::wstring(L"0\x12"
|
EXPECT_EQ("L\"0\\x12\" L\"3\"", Print(::std::wstring(L"0\x12"
|
||||||
@ -974,6 +1000,12 @@ TEST(PrintStringTest, U8String) {
|
|||||||
EXPECT_EQ(str, str); // Verify EXPECT_EQ compiles with this type.
|
EXPECT_EQ(str, str); // Verify EXPECT_EQ compiles with this type.
|
||||||
EXPECT_EQ("u8\"Hello, \\xE4\\xB8\\x96\\xE7\\x95\\x8C\"", Print(str));
|
EXPECT_EQ("u8\"Hello, \\xE4\\xB8\\x96\\xE7\\x95\\x8C\"", Print(str));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(PrintStringTest, U8StringView) {
|
||||||
|
std::u8string_view str = u8"Hello, 世界";
|
||||||
|
EXPECT_EQ(str, str); // Verify EXPECT_EQ compiles with this type.
|
||||||
|
EXPECT_EQ("u8\"Hello, \\xE4\\xB8\\x96\\xE7\\x95\\x8C\"", Print(str));
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
TEST(PrintStringTest, U16String) {
|
TEST(PrintStringTest, U16String) {
|
||||||
@ -982,12 +1014,24 @@ TEST(PrintStringTest, U16String) {
|
|||||||
EXPECT_EQ("u\"Hello, \\x4E16\\x754C\"", Print(str));
|
EXPECT_EQ("u\"Hello, \\x4E16\\x754C\"", Print(str));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(PrintStringTest, U16StringView) {
|
||||||
|
std::u16string_view str = u"Hello, 世界";
|
||||||
|
EXPECT_EQ(str, str); // Verify EXPECT_EQ compiles with this type.
|
||||||
|
EXPECT_EQ("u\"Hello, \\x4E16\\x754C\"", Print(str));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(PrintStringTest, U32String) {
|
TEST(PrintStringTest, U32String) {
|
||||||
std::u32string str = U"Hello, 🗺️";
|
std::u32string str = U"Hello, 🗺️";
|
||||||
EXPECT_EQ(str, str); // Verify EXPECT_EQ compiles with this type
|
EXPECT_EQ(str, str); // Verify EXPECT_EQ compiles with this type
|
||||||
EXPECT_EQ("U\"Hello, \\x1F5FA\\xFE0F\"", Print(str));
|
EXPECT_EQ("U\"Hello, \\x1F5FA\\xFE0F\"", Print(str));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(PrintStringTest, U32StringView) {
|
||||||
|
std::u32string_view str = U"Hello, 🗺️";
|
||||||
|
EXPECT_EQ(str, str); // Verify EXPECT_EQ compiles with this type
|
||||||
|
EXPECT_EQ("U\"Hello, \\x1F5FA\\xFE0F\"", Print(str));
|
||||||
|
}
|
||||||
|
|
||||||
// Tests printing types that support generic streaming (i.e. streaming
|
// Tests printing types that support generic streaming (i.e. streaming
|
||||||
// to std::basic_ostream<Char, CharTraits> for any valid Char and
|
// to std::basic_ostream<Char, CharTraits> for any valid Char and
|
||||||
// CharTraits types).
|
// CharTraits types).
|
||||||
@ -1447,7 +1491,7 @@ TEST(PrintReferenceTest, HandlesMemberFunctionPointer) {
|
|||||||
// Tests that the universal printer prints a member variable pointer
|
// Tests that the universal printer prints a member variable pointer
|
||||||
// passed by reference.
|
// passed by reference.
|
||||||
TEST(PrintReferenceTest, HandlesMemberVariablePointer) {
|
TEST(PrintReferenceTest, HandlesMemberVariablePointer) {
|
||||||
int Foo::*p = &Foo::value; // NOLINT
|
int Foo::* p = &Foo::value; // NOLINT
|
||||||
EXPECT_TRUE(HasPrefix(PrintByRef(p), "@" + PrintPointer(&p) + " " +
|
EXPECT_TRUE(HasPrefix(PrintByRef(p), "@" + PrintPointer(&p) + " " +
|
||||||
Print(sizeof(p)) + "-byte object "));
|
Print(sizeof(p)) + "-byte object "));
|
||||||
}
|
}
|
||||||
@ -1885,6 +1929,22 @@ TEST(UniversalPrintTest, SmartPointers) {
|
|||||||
PrintToString(std::shared_ptr<void>(p.get(), [](void*) {})));
|
PrintToString(std::shared_ptr<void>(p.get(), [](void*) {})));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(UniversalPrintTest, StringViewNonZeroTerminated) {
|
||||||
|
// Craft a non-ASCII UTF-8 input (to trigger a special path in
|
||||||
|
// `ConditionalPrintAsText`). Use array notation instead of the string
|
||||||
|
// literal syntax, to avoid placing a terminating 0 at the end of the input.
|
||||||
|
const char s[] = {'\357', '\243', '\242', 'X'};
|
||||||
|
// Only include the first 3 bytes in the `string_view` and leave the last one
|
||||||
|
// ('X') outside. This way, if the code tries to use `str.data()` with
|
||||||
|
// `strlen` instead of `str.size()`, it will include 'X' and cause a visible
|
||||||
|
// difference (in addition to ASAN tests detecting a buffer overflow due to
|
||||||
|
// the missing 0 at the end).
|
||||||
|
const ::std::string_view str(s, 3);
|
||||||
|
::std::stringstream ss;
|
||||||
|
UniversalPrint(str, &ss);
|
||||||
|
EXPECT_EQ("\"\\xEF\\xA3\\xA2\"\n As Text: \"\xEF\xA3\xA2\"", ss.str());
|
||||||
|
}
|
||||||
|
|
||||||
TEST(UniversalTersePrintTupleFieldsToStringsTestWithStd, PrintsEmptyTuple) {
|
TEST(UniversalTersePrintTupleFieldsToStringsTestWithStd, PrintsEmptyTuple) {
|
||||||
Strings result = UniversalTersePrintTupleFieldsToStrings(::std::make_tuple());
|
Strings result = UniversalTersePrintTupleFieldsToStrings(::std::make_tuple());
|
||||||
EXPECT_EQ(0u, result.size());
|
EXPECT_EQ(0u, result.size());
|
||||||
@ -1914,7 +1974,6 @@ TEST(UniversalTersePrintTupleFieldsToStringsTestWithStd, PrintsTersely) {
|
|||||||
EXPECT_EQ("\"a\"", result[1]);
|
EXPECT_EQ("\"a\"", result[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if GTEST_INTERNAL_HAS_ANY
|
|
||||||
class PrintAnyTest : public ::testing::Test {
|
class PrintAnyTest : public ::testing::Test {
|
||||||
protected:
|
protected:
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -1928,12 +1987,12 @@ class PrintAnyTest : public ::testing::Test {
|
|||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(PrintAnyTest, Empty) {
|
TEST_F(PrintAnyTest, Empty) {
|
||||||
internal::Any any;
|
std::any any;
|
||||||
EXPECT_EQ("no value", PrintToString(any));
|
EXPECT_EQ("no value", PrintToString(any));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(PrintAnyTest, NonEmpty) {
|
TEST_F(PrintAnyTest, NonEmpty) {
|
||||||
internal::Any any;
|
std::any any;
|
||||||
constexpr int val1 = 10;
|
constexpr int val1 = 10;
|
||||||
const std::string val2 = "content";
|
const std::string val2 = "content";
|
||||||
|
|
||||||
@ -1944,27 +2003,23 @@ TEST_F(PrintAnyTest, NonEmpty) {
|
|||||||
EXPECT_EQ("value of type " + ExpectedTypeName<std::string>(),
|
EXPECT_EQ("value of type " + ExpectedTypeName<std::string>(),
|
||||||
PrintToString(any));
|
PrintToString(any));
|
||||||
}
|
}
|
||||||
#endif // GTEST_INTERNAL_HAS_ANY
|
|
||||||
|
|
||||||
#if GTEST_INTERNAL_HAS_OPTIONAL
|
|
||||||
TEST(PrintOptionalTest, Basic) {
|
TEST(PrintOptionalTest, Basic) {
|
||||||
EXPECT_EQ("(nullopt)", PrintToString(internal::Nullopt()));
|
EXPECT_EQ("(nullopt)", PrintToString(std::nullopt));
|
||||||
internal::Optional<int> value;
|
std::optional<int> value;
|
||||||
EXPECT_EQ("(nullopt)", PrintToString(value));
|
EXPECT_EQ("(nullopt)", PrintToString(value));
|
||||||
value = {7};
|
value = {7};
|
||||||
EXPECT_EQ("(7)", PrintToString(value));
|
EXPECT_EQ("(7)", PrintToString(value));
|
||||||
EXPECT_EQ("(1.1)", PrintToString(internal::Optional<double>{1.1}));
|
EXPECT_EQ("(1.1)", PrintToString(std::optional<double>{1.1}));
|
||||||
EXPECT_EQ("(\"A\")", PrintToString(internal::Optional<std::string>{"A"}));
|
EXPECT_EQ("(\"A\")", PrintToString(std::optional<std::string>{"A"}));
|
||||||
}
|
}
|
||||||
#endif // GTEST_INTERNAL_HAS_OPTIONAL
|
|
||||||
|
|
||||||
#if GTEST_INTERNAL_HAS_VARIANT
|
|
||||||
struct NonPrintable {
|
struct NonPrintable {
|
||||||
unsigned char contents = 17;
|
unsigned char contents = 17;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST(PrintOneofTest, Basic) {
|
TEST(PrintOneofTest, Basic) {
|
||||||
using Type = internal::Variant<int, StreamableInGlobal, NonPrintable>;
|
using Type = std::variant<int, StreamableInGlobal, NonPrintable>;
|
||||||
EXPECT_EQ("('int(index = 0)' with value 7)", PrintToString(Type(7)));
|
EXPECT_EQ("('int(index = 0)' with value 7)", PrintToString(Type(7)));
|
||||||
EXPECT_EQ("('StreamableInGlobal(index = 1)' with value StreamableInGlobal)",
|
EXPECT_EQ("('StreamableInGlobal(index = 1)' with value StreamableInGlobal)",
|
||||||
PrintToString(Type(StreamableInGlobal{})));
|
PrintToString(Type(StreamableInGlobal{})));
|
||||||
@ -1973,7 +2028,6 @@ TEST(PrintOneofTest, Basic) {
|
|||||||
"1-byte object <11>)",
|
"1-byte object <11>)",
|
||||||
PrintToString(Type(NonPrintable{})));
|
PrintToString(Type(NonPrintable{})));
|
||||||
}
|
}
|
||||||
#endif // GTEST_INTERNAL_HAS_VARIANT
|
|
||||||
|
|
||||||
#if GTEST_INTERNAL_HAS_COMPARE_LIB
|
#if GTEST_INTERNAL_HAS_COMPARE_LIB
|
||||||
TEST(PrintOrderingTest, Basic) {
|
TEST(PrintOrderingTest, Basic) {
|
||||||
|
@ -31,14 +31,14 @@
|
|||||||
|
|
||||||
class SetupFailTest : public ::testing::Test {
|
class SetupFailTest : public ::testing::Test {
|
||||||
protected:
|
protected:
|
||||||
static void SetUpTestSuite() { ASSERT_EQ("", "SET_UP_FAIL"); }
|
static void SetUpTestSuite() { ASSERT_STREQ("", "SET_UP_FAIL"); }
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(SetupFailTest, NoopPassingTest) {}
|
TEST_F(SetupFailTest, NoopPassingTest) {}
|
||||||
|
|
||||||
class TearDownFailTest : public ::testing::Test {
|
class TearDownFailTest : public ::testing::Test {
|
||||||
protected:
|
protected:
|
||||||
static void TearDownTestSuite() { ASSERT_EQ("", "TEAR_DOWN_FAIL"); }
|
static void TearDownTestSuite() { ASSERT_STREQ("", "TEAR_DOWN_FAIL"); }
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(TearDownFailTest, NoopPassingTest) {}
|
TEST_F(TearDownFailTest, NoopPassingTest) {}
|
||||||
|
@ -2163,7 +2163,7 @@ class UnitTestRecordPropertyTestEnvironment : public Environment {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// This will test property recording outside of any test or test case.
|
// 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);
|
AddGlobalTestEnvironment(new UnitTestRecordPropertyTestEnvironment);
|
||||||
|
|
||||||
// This group of tests is for predicate assertions (ASSERT_PRED*, etc)
|
// This group of tests is for predicate assertions (ASSERT_PRED*, etc)
|
||||||
@ -3579,13 +3579,13 @@ TEST(EditDistance, TestSuites) {
|
|||||||
{__LINE__, "A", "A", " ", ""},
|
{__LINE__, "A", "A", " ", ""},
|
||||||
{__LINE__, "ABCDE", "ABCDE", " ", ""},
|
{__LINE__, "ABCDE", "ABCDE", " ", ""},
|
||||||
// Simple adds.
|
// Simple adds.
|
||||||
{__LINE__, "X", "XA", " +", "@@ +1,2 @@\n X\n+A\n"},
|
{__LINE__, "X", "XA", " +", "@@ -1 +1,2 @@\n X\n+A\n"},
|
||||||
{__LINE__, "X", "XABCD", " ++++", "@@ +1,5 @@\n X\n+A\n+B\n+C\n+D\n"},
|
{__LINE__, "X", "XABCD", " ++++", "@@ -1 +1,5 @@\n X\n+A\n+B\n+C\n+D\n"},
|
||||||
// Simple removes.
|
// Simple removes.
|
||||||
{__LINE__, "XA", "X", " -", "@@ -1,2 @@\n X\n-A\n"},
|
{__LINE__, "XA", "X", " -", "@@ -1,2 +1 @@\n X\n-A\n"},
|
||||||
{__LINE__, "XABCD", "X", " ----", "@@ -1,5 @@\n X\n-A\n-B\n-C\n-D\n"},
|
{__LINE__, "XABCD", "X", " ----", "@@ -1,5 +1 @@\n X\n-A\n-B\n-C\n-D\n"},
|
||||||
// Simple replaces.
|
// Simple replaces.
|
||||||
{__LINE__, "A", "a", "/", "@@ -1,1 +1,1 @@\n-A\n+a\n"},
|
{__LINE__, "A", "a", "/", "@@ -1 +1 @@\n-A\n+a\n"},
|
||||||
{__LINE__, "ABCD", "abcd", "////",
|
{__LINE__, "ABCD", "abcd", "////",
|
||||||
"@@ -1,4 +1,4 @@\n-A\n-B\n-C\n-D\n+a\n+b\n+c\n+d\n"},
|
"@@ -1,4 +1,4 @@\n-A\n-B\n-C\n-D\n+a\n+b\n+c\n+d\n"},
|
||||||
// Path finding.
|
// Path finding.
|
||||||
@ -6754,9 +6754,8 @@ TEST(ColoredOutputTest, UsesColorsWhenTermSupportsColors) {
|
|||||||
|
|
||||||
// Verifies that StaticAssertTypeEq works in a namespace scope.
|
// Verifies that StaticAssertTypeEq works in a namespace scope.
|
||||||
|
|
||||||
GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED static bool dummy1 =
|
[[maybe_unused]] static bool dummy1 = StaticAssertTypeEq<bool, bool>();
|
||||||
StaticAssertTypeEq<bool, bool>();
|
[[maybe_unused]] static bool dummy2 =
|
||||||
GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED static bool dummy2 =
|
|
||||||
StaticAssertTypeEq<const int, const int>();
|
StaticAssertTypeEq<const int, const int>();
|
||||||
|
|
||||||
// Verifies that StaticAssertTypeEq works in a class.
|
// Verifies that StaticAssertTypeEq works in a class.
|
||||||
|
@ -17,9 +17,9 @@ def googletest_deps():
|
|||||||
if not native.existing_rule("abseil-cpp"):
|
if not native.existing_rule("abseil-cpp"):
|
||||||
http_archive(
|
http_archive(
|
||||||
name = "abseil-cpp",
|
name = "abseil-cpp",
|
||||||
sha256 = "16242f394245627e508ec6bb296b433c90f8d914f73b9c026fddb905e27276e8",
|
sha256 = "7262daa7c1711406248c10f41026d685e88223bc92817d16fb93c19adb57f669",
|
||||||
strip_prefix = "abseil-cpp-20250127.0",
|
strip_prefix = "abseil-cpp-20250512.0",
|
||||||
urls = ["https://github.com/abseil/abseil-cpp/releases/download/20250127.0/abseil-cpp-20250127.0.tar.gz"],
|
urls = ["https://github.com/abseil/abseil-cpp/releases/download/20250512.0/abseil-cpp-20250512.0.tar.gz"],
|
||||||
)
|
)
|
||||||
|
|
||||||
if not native.existing_rule("fuchsia_sdk"):
|
if not native.existing_rule("fuchsia_sdk"):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user