mirror of
https://github.com/google/googletest.git
synced 2026-06-15 08:26:11 +08:00
Compare commits
4 Commits
0fd0f052ec
...
a02d683d41
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a02d683d41 | ||
|
|
7140cd416c | ||
|
|
a721f1b20c | ||
|
|
0b65649543 |
@ -3386,30 +3386,6 @@ With this definition, the above assertion will give a better message:
|
||||
Actual: 27 (the remainder is 6)
|
||||
```
|
||||
|
||||
#### Using EXPECT_ Statements in Matchers
|
||||
|
||||
You can also use `EXPECT_...` statements inside custom matcher definitions. In
|
||||
many cases, this allows you to write your matcher more concisely while still
|
||||
providing an informative error message. For example:
|
||||
|
||||
```cpp
|
||||
MATCHER(IsDivisibleBy7, "") {
|
||||
const auto remainder = arg % 7;
|
||||
EXPECT_EQ(remainder, 0);
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
If you write a test that includes the line `EXPECT_THAT(27, IsDivisibleBy7());`,
|
||||
you will get an error something like the following:
|
||||
|
||||
```shell
|
||||
Expected equality of these values:
|
||||
remainder
|
||||
Which is: 6
|
||||
0
|
||||
```
|
||||
|
||||
#### `MatchAndExplain`
|
||||
|
||||
You should let `MatchAndExplain()` print *any additional information* that can
|
||||
@ -3429,6 +3405,66 @@ the value of `(arg % 7) == 0` can be implicitly converted to a `bool`. In the
|
||||
`arg_type` will be `int`; if it takes an `unsigned long`, `arg_type` will be
|
||||
`unsigned long`; and so on.
|
||||
|
||||
#### Anti-pattern: Using EXPECT_ Statements in Matchers
|
||||
|
||||
Using `EXPECT_...` statements inside custom matcher definitions is an
|
||||
**anti-pattern** and should be avoided.
|
||||
|
||||
While it might appear to write matchers more concisely and generate informative
|
||||
messages, this pattern has critical issues:
|
||||
|
||||
1. **Negation Breakage (`Not`):** If wrapped in `Not(IsDivisibleBy7())`,
|
||||
evaluating it still triggers the internal `EXPECT_EQ`, registering a test
|
||||
failure on the runner even when the overall assertion is expected to
|
||||
succeed.
|
||||
2. **Composition / Container Breakage (`AnyOf`, `AllOf`, `Contains`):** When
|
||||
composed or used inside container matchers, elements that are expected
|
||||
mismatches will trigger the internal `EXPECT_` and register spurious
|
||||
failures.
|
||||
3. **ASSERT_* compilation errors:** `ASSERT_*` macros use `return;` to abort
|
||||
from a void function. Since matchers return `bool`, using `ASSERT_` inside
|
||||
them triggers a compilation error.
|
||||
4. **Purity Violations:** Matchers must be functionally pure (side-effect
|
||||
free), whereas registering global failures is a major side effect.
|
||||
5. **Line Number Confusion:** Failure reports point to the matcher's definition
|
||||
line rather than the calling `EXPECT_THAT`
|
||||
line.
|
||||
|
||||
##### The Anti-Pattern
|
||||
|
||||
```cpp
|
||||
// Anti-pattern: Do not do this!
|
||||
MATCHER(IsDivisibleBy7, "") {
|
||||
const auto remainder = arg % 7;
|
||||
EXPECT_EQ(remainder, 0); // Spurious failures if negated/composed!
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
##### The Correct Solution
|
||||
|
||||
To write concise matchers that delegate to other matchers and safely propagate
|
||||
the mismatch explanation, use **`::testing::ExplainMatchResult`** instead,
|
||||
passing it the sub-matcher, the value to check, and the `result_listener`:
|
||||
|
||||
```cpp
|
||||
MATCHER(IsDivisibleBy7, "") {
|
||||
const auto remainder = arg % 7;
|
||||
return ::testing::ExplainMatchResult(::testing::Eq(0), remainder,
|
||||
result_listener);
|
||||
}
|
||||
```
|
||||
|
||||
If you write a test that includes the line:
|
||||
|
||||
```cpp
|
||||
EXPECT_THAT(28, Not(IsDivisibleBy7()));
|
||||
```
|
||||
|
||||
it will correctly report the mismatch, properly point to the `EXPECT_THAT` line
|
||||
number, and support negation (`Not`) and composition (`AllOf`, `AnyOf`, etc.)
|
||||
without registering spurious failures.
|
||||
|
||||
### Writing New Parameterized Matchers Quickly
|
||||
|
||||
Sometimes you'll want to define a matcher that has parameters. For that you can
|
||||
|
||||
@ -28,15 +28,6 @@ macro(fix_default_compiler_settings_)
|
||||
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
|
||||
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
|
||||
if (NOT BUILD_SHARED_LIBS AND NOT gtest_force_shared_crt)
|
||||
# When Google Test is built as a shared library, it should also use
|
||||
# shared runtime libraries. Otherwise, it may end up with multiple
|
||||
# copies of runtime library data in different modules, resulting in
|
||||
# hard-to-find crashes. When it is built as a static library, it is
|
||||
# preferable to use CRT as static libraries, as we don't have to rely
|
||||
# on CRT DLLs being available. CMake always defaults to using shared
|
||||
# CRT libraries, so we override that default here.
|
||||
string(REPLACE "/MD" "-MT" ${flag_var} "${${flag_var}}")
|
||||
|
||||
# When using Ninja with Clang, static builds pass -D_DLL on Windows.
|
||||
# This is incorrect and should not happen, so we fix that here.
|
||||
string(REPLACE "-D_DLL" "" ${flag_var} "${${flag_var}}")
|
||||
@ -70,7 +61,19 @@ macro(config_compiler_and_linker)
|
||||
endif()
|
||||
|
||||
fix_default_compiler_settings_()
|
||||
|
||||
if (MSVC)
|
||||
# When Google Test is built as a shared library, it should also use
|
||||
# shared runtime libraries. Otherwise, it may end up with multiple
|
||||
# copies of runtime library data in different modules, resulting in
|
||||
# hard-to-find crashes. When it is built as a static library, it is
|
||||
# preferable to use CRT as static libraries, as we don't have to rely
|
||||
# on CRT DLLs being available. CMake defaults to using shared
|
||||
# CRT libraries, so we change that here.
|
||||
if (NOT BUILD_SHARED_LIBS AND NOT gtest_force_shared_crt AND NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY)
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
endif()
|
||||
|
||||
# Newlines inside flags variables break CMake's NMake generator.
|
||||
# TODO(vladl@google.com): Add -RTCs and -RTCu to debug builds.
|
||||
set(cxx_base_flags "-GS -W4 -WX -wd4251 -wd4275 -nologo -J")
|
||||
|
||||
@ -129,7 +129,7 @@ class GTEST_API_ Message {
|
||||
int>::type = 0
|
||||
#endif // GTEST_HAS_ABSL
|
||||
>
|
||||
inline Message& operator<<(const T& val) {
|
||||
Message& operator<<(const T& val) {
|
||||
// Some libraries overload << for STL containers. These
|
||||
// overloads are defined in the global namespace instead of ::std.
|
||||
//
|
||||
@ -155,7 +155,7 @@ class GTEST_API_ Message {
|
||||
template <typename T,
|
||||
typename std::enable_if<absl::HasAbslStringify<T>::value, // NOLINT
|
||||
int>::type = 0>
|
||||
inline Message& operator<<(const T& val) {
|
||||
Message& operator<<(const T& val) {
|
||||
// ::operator<< is needed here for a similar reason as with the non-Abseil
|
||||
// version above
|
||||
using ::operator<<;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user