Compare commits

...

10 Commits

Author SHA1 Message Date
stoorx
94f19b4a03 Explicitly include <array> header due to build fail on MSVC 2025-11-22 22:48:57 +03:00
stoorx
18172295df Fix CombineAsTest/CopyConstructible test 2025-11-22 22:48:57 +03:00
stoorx
cb67f16d48 Add the documentation for CombineAs<R>() param generator 2025-11-22 22:48:57 +03:00
stoorx
7049d96dd7 Add CombineAs<R>() generator function
`CombineAs<R>()` allows to construct the required type directly from combined arguments. As it would be a composition of `ConvertGenerator()` and `Combine()`, but without `std::tuple` in between.
2025-11-22 22:48:56 +03:00
stoorx
d3414c2c46 Refactor Combine() generator function 2025-11-22 22:48:56 +03:00
stoorx
ceeca5fcea Refactor Values() generator function to resolve more complicated type transformations 2025-11-22 22:48:56 +03:00
Derek Mauro
1b96fa13f5 Switch to referenceful lock holder for Abseil compatibility
PiperOrigin-RevId: 831156684
Change-Id: I8a8b017ec2fc318a65f57e04428c030c707ee682
2025-11-11 18:56:52 -08:00
Abseil Team
085af2cc08 Automated rollback of commit 37678c92fb183b148163dd173430b4ab88586a26.
PiperOrigin-RevId: 829765029
Change-Id: Ia5534b109e0abfd17a74d89ce58d6588a6255f94
2025-11-08 02:53:26 -08:00
Abseil Team
37678c92fb gtest_fail_if_no_test_selected: Rephrase error message.
Sharded tests interact awkwardly with --gtest_fail_if_no_test_selected, but we
can't speak clearly enough to the use cases to complicate the mental model, so
instead we attempt to clarify the simplest approach to debugging a single test
when sharding and --gtest_fail_if_no_test_selected are both in use: unset the
flag.

PiperOrigin-RevId: 829686145
Change-Id: I9ebbddc6e7537feefe2a3707fd323fc9132b99d1
2025-11-07 20:50:29 -08:00
David Pizzuto
dedab73a68 gtest_fail_if_no_test_selected: Rephrase error message.
Sharded tests interact awkwardly with --gtest_fail_if_no_test_selected, but we
can't speak clearly enough to the use cases to complicate the mental model, so
instead we attempt to clarify the simplest approach to debugging a single test
when sharding and --gtest_fail_if_no_test_selected are both in use: unset the
flag.

PiperOrigin-RevId: 829609266
Change-Id: I090d5bfac979171532249e9312feef8d9aad5f16
2025-11-07 16:02:48 -08:00
14 changed files with 277 additions and 128 deletions

View File

@ -103,14 +103,15 @@ namespace:
<span id="param-generators"></span>
| Parameter Generator | Behavior |
| ------------------- | ---------------------------------------------------- |
| `Range(begin, end [, step])` | Yields values `{begin, begin+step, begin+step+step, ...}`. The values do not include `end`. `step` defaults to 1. |
| `Values(v1, v2, ..., vN)` | Yields values `{v1, v2, ..., vN}`. |
| `ValuesIn(container)` or `ValuesIn(begin,end)` | Yields values from a C-style array, an STL-style container, or an iterator range `[begin, end)`. |
| `Bool()` | Yields sequence `{false, true}`. |
| `Combine(g1, g2, ..., gN)` | Yields as `std::tuple` *n*-tuples all combinations (Cartesian product) of the values generated by the given *n* generators `g1`, `g2`, ..., `gN`. |
| `ConvertGenerator<T>(g)` 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. |
| Parameter Generator | Behavior |
|---------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `Range(begin, end [, step])` | Yields values `{begin, begin+step, begin+step+step, ...}`. The values do not include `end`. `step` defaults to 1. |
| `Values(v1, v2, ..., vN)` | Yields values `{v1, v2, ..., vN}`. |
| `ValuesIn(container)` or `ValuesIn(begin,end)` | Yields values from a C-style array, an STL-style container, or an iterator range `[begin, end)`. |
| `Bool()` | Yields sequence `{false, true}`. |
| `Combine(g1, g2, ..., gN)` | Yields as `std::tuple` *n*-tuples all combinations (Cartesian product) of the values generated by the given *n* generators `g1`, `g2`, ..., `gN`. |
| `CombineAs<R>(g1, g2, ..., gN)` | Yields as `R` *n*-instances all combinations (Cartesian product) of the values generated by the given *n* generators `g1`, `g2`, ..., `gN`. |
| `ConvertGenerator<T>(g)` or `ConvertGenerator(g, func)` | Yields values generated by generator `g`, `static_cast` from `T`. (Note: `T` might not be what you expect. See [*Using ConvertGenerator*](#using-convertgenerator) below.) The second overload uses `func` to perform the conversion. |
The optional last argument *`name_generator`* is a function or functor that
generates custom test name suffixes based on the test parameters. The function
@ -234,6 +235,24 @@ To overcome this problem you can specify the generated type explicitly:
dangling reference because the type deduction strips off the reference and the
`const`).
###### Using `CombineAs`
If you think the code above is too complicated, and you do not want to deal
with tuples, you may want to use `CombineAs<R>()` which works like a combination
of `Combine()` + `ConvertGenerator()` + tuple unpacking function.
```cpp
// The fixture's parameter type.
class MyParam {
public:
MyParam(int, bool);
...
};
INSTANTIATE_TEST_SUITE_P(MyInstantiation, MyTestSuite,
CombineAs<MyParam>(Values(1, 1.2), Bool()));
```
### TYPED_TEST_SUITE {#TYPED_TEST_SUITE}
`TYPED_TEST_SUITE(`*`TestFixtureName`*`,`*`Types`*`)`

View File

@ -15,7 +15,7 @@ variety of googletest features.
derived fixtures.
* Sample #6 demonstrates type-parameterized tests.
* Sample #7 teaches the basics of value-parameterized tests.
* Sample #8 shows using `Combine()` in value-parameterized tests.
* Sample #8 shows using `Combine()` and `CombineAs<R>()` in value-parameterized tests.
* Sample #9 shows use of the listener API to modify Google Test's console
output and the use of its reflection API to inspect test results.
* Sample #10 shows use of the listener API to implement a primitive memory

View File

@ -1467,7 +1467,7 @@ class FunctionMocker<R(Args...)> final : public UntypedFunctionMockerBase {
// function have been satisfied. If not, it will report Google Test
// non-fatal failures for the violations.
~FunctionMocker() override GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
MutexLock l(&g_gmock_mutex);
MutexLock l(g_gmock_mutex);
VerifyAndClearExpectationsLocked();
Mock::UnregisterLocked(this);
ClearDefaultActionsLocked();
@ -1646,7 +1646,7 @@ class FunctionMocker<R(Args...)> final : public UntypedFunctionMockerBase {
GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
const ArgumentTuple& args =
*static_cast<const ArgumentTuple*>(untyped_args);
MutexLock l(&g_gmock_mutex);
MutexLock l(g_gmock_mutex);
TypedExpectation<F>* exp = this->FindMatchingExpectationLocked(args);
if (exp == nullptr) { // A match wasn't found.
this->FormatUnexpectedCallMessageLocked(args, what, why);

View File

@ -156,7 +156,7 @@ GTEST_API_ void Log(LogSeverity severity, const std::string& message,
if (!LogIsVisible(severity)) return;
// Ensures that logs from different threads don't interleave.
MutexLock l(&g_log_mutex);
MutexLock l(g_log_mutex);
if (severity == kWarning) {
// Prints a GMOCK WARNING marker to make the warnings easily searchable.

View File

@ -212,7 +212,7 @@ void ExpectationBase::CheckActionCountIfNotDone() const
GTEST_LOCK_EXCLUDED_(mutex_) {
bool should_check = false;
{
MutexLock l(&mutex_);
MutexLock l(mutex_);
if (!action_count_checked_) {
action_count_checked_ = true;
should_check = true;
@ -318,7 +318,7 @@ UntypedFunctionMockerBase::~UntypedFunctionMockerBase() = default;
void UntypedFunctionMockerBase::RegisterOwner(const void* mock_obj)
GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
{
MutexLock l(&g_gmock_mutex);
MutexLock l(g_gmock_mutex);
mock_obj_ = mock_obj;
}
Mock::Register(mock_obj, this);
@ -332,7 +332,7 @@ void UntypedFunctionMockerBase::SetOwnerAndName(const void* mock_obj,
GTEST_LOCK_EXCLUDED_(g_gmock_mutex) {
// We protect name_ under g_gmock_mutex in case this mock function
// is called from two threads concurrently.
MutexLock l(&g_gmock_mutex);
MutexLock l(g_gmock_mutex);
mock_obj_ = mock_obj;
name_ = name;
}
@ -345,7 +345,7 @@ const void* UntypedFunctionMockerBase::MockObject() const
{
// We protect mock_obj_ under g_gmock_mutex in case this mock
// function is called from two threads concurrently.
MutexLock l(&g_gmock_mutex);
MutexLock l(g_gmock_mutex);
Assert(mock_obj_ != nullptr, __FILE__, __LINE__,
"MockObject() must not be called before RegisterOwner() or "
"SetOwnerAndName() has been called.");
@ -362,7 +362,7 @@ const char* UntypedFunctionMockerBase::Name() const
{
// We protect name_ under g_gmock_mutex in case this mock
// function is called from two threads concurrently.
MutexLock l(&g_gmock_mutex);
MutexLock l(g_gmock_mutex);
Assert(name_ != nullptr, __FILE__, __LINE__,
"Name() must not be called before SetOwnerAndName() has "
"been called.");
@ -490,7 +490,7 @@ class MockObjectRegistry {
// failure, unless the user explicitly asked us to ignore it.
~MockObjectRegistry() {
if (!GMOCK_FLAG_GET(catch_leaked_mocks)) return;
internal::MutexLock l(&internal::g_gmock_mutex);
internal::MutexLock l(internal::g_gmock_mutex);
int leaked_count = 0;
for (StateMap::const_iterator it = states_.begin(); it != states_.end();
@ -559,7 +559,7 @@ UninterestingCallReactionMap() {
void SetReactionOnUninterestingCalls(uintptr_t mock_obj,
internal::CallReaction reaction)
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
internal::MutexLock l(&internal::g_gmock_mutex);
internal::MutexLock l(internal::g_gmock_mutex);
UninterestingCallReactionMap()[mock_obj] = reaction;
}
@ -590,7 +590,7 @@ void Mock::FailUninterestingCalls(uintptr_t mock_obj)
// entry in the call-reaction table should be removed.
void Mock::UnregisterCallReaction(uintptr_t mock_obj)
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
internal::MutexLock l(&internal::g_gmock_mutex);
internal::MutexLock l(internal::g_gmock_mutex);
UninterestingCallReactionMap().erase(static_cast<uintptr_t>(mock_obj));
}
@ -598,7 +598,7 @@ void Mock::UnregisterCallReaction(uintptr_t mock_obj)
// made on the given mock object.
internal::CallReaction Mock::GetReactionOnUninterestingCalls(
const void* mock_obj) GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
internal::MutexLock l(&internal::g_gmock_mutex);
internal::MutexLock l(internal::g_gmock_mutex);
return (UninterestingCallReactionMap().count(
reinterpret_cast<uintptr_t>(mock_obj)) == 0)
? internal::intToCallReaction(
@ -611,7 +611,7 @@ internal::CallReaction Mock::GetReactionOnUninterestingCalls(
// objects.
void Mock::AllowLeak(const void* mock_obj)
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
internal::MutexLock l(&internal::g_gmock_mutex);
internal::MutexLock l(internal::g_gmock_mutex);
g_mock_object_registry.states()[mock_obj].leakable = true;
}
@ -620,7 +620,7 @@ void Mock::AllowLeak(const void* mock_obj)
// Test non-fatal failures and returns false.
bool Mock::VerifyAndClearExpectations(void* mock_obj)
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
internal::MutexLock l(&internal::g_gmock_mutex);
internal::MutexLock l(internal::g_gmock_mutex);
return VerifyAndClearExpectationsLocked(mock_obj);
}
@ -629,7 +629,7 @@ bool Mock::VerifyAndClearExpectations(void* mock_obj)
// verification was successful.
bool Mock::VerifyAndClear(void* mock_obj)
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
internal::MutexLock l(&internal::g_gmock_mutex);
internal::MutexLock l(internal::g_gmock_mutex);
ClearDefaultActionsLocked(mock_obj);
return VerifyAndClearExpectationsLocked(mock_obj);
}
@ -679,7 +679,7 @@ bool Mock::IsStrict(void* mock_obj)
void Mock::Register(const void* mock_obj,
internal::UntypedFunctionMockerBase* mocker)
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
internal::MutexLock l(&internal::g_gmock_mutex);
internal::MutexLock l(internal::g_gmock_mutex);
g_mock_object_registry.states()[mock_obj].function_mockers.insert(mocker);
}
@ -689,7 +689,7 @@ void Mock::Register(const void* mock_obj,
void Mock::RegisterUseByOnCallOrExpectCall(const void* mock_obj,
const char* file, int line)
GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
internal::MutexLock l(&internal::g_gmock_mutex);
internal::MutexLock l(internal::g_gmock_mutex);
MockObjectState& state = g_mock_object_registry.states()[mock_obj];
if (state.first_used_file == nullptr) {
state.first_used_file = file;

View File

@ -174,6 +174,7 @@ TEST_P(DerivedTest, DoesBlah) {
#endif // 0
#include <array>
#include <functional>
#include <iterator>
#include <utility>
@ -332,9 +333,10 @@ internal::ParamGenerator<typename Container::value_type> ValuesIn(
// INSTANTIATE_TEST_SUITE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5));
//
//
template <typename... T>
internal::ValueArray<T...> Values(T... v) {
return internal::ValueArray<T...>(std::move(v)...);
template <typename... Ts>
internal::ParamGenerator<std::common_type_t<Ts...>> Values(Ts... vs) {
return ValuesIn(
std::array<std::common_type_t<Ts...>, sizeof...(Ts)>{std::move(vs)...});
}
// Bool() allows generating tests with parameters in a set of (false, true).
@ -359,6 +361,47 @@ internal::ValueArray<T...> Values(T... v) {
//
inline internal::ParamGenerator<bool> Bool() { return Values(false, true); }
// CombineAs() allows the user to combine two or more sequences to produce
// values of a Cartesian product of those sequences' elements converted to
// the required type.
//
// Synopsis:
// CombineAs<MyClass>(gen1, gen2, ..., genN)
// - returns a generator producing sequences with elements coming from
// the Cartesian product of elements from the sequences generated by
// gen1, gen2, ..., genN. The sequence elements will have a type of
// Myclass where elements from sequences produced by gen1, gen2, ..., genN
// was provided to the MyClass constructor parameters.
//
// Example:
//
// This will instantiate tests in test suite AnimalTest each one with
// the parameter values Animal("cat", BLACK), Animal("cat", WHITE),
// Animal("dog", BLACK), and Animal("dog", WHITE):
// enum Color { BLACK, GRAY, WHITE };
//
// struct Animal {
// std::string name;
// Color color;
// };
//
// class AnimalTest
// : public testing::TestWithParam<Animal> {...};
//
// TEST_P(AnimalTest, AnimalLooksNice) {...}
//
// INSTANTIATE_TEST_SUITE_P(AnimalVariations, AnimalTest,
// CombineAs<Animal>(Values("cat", "dog"),
// Values(BLACK, WHITE)));
//
template <typename R, typename... T>
internal::ParamGenerator<R> CombineAs(
internal::ParamGenerator<T>&&... generators) {
return internal::ParamGenerator<R>(
new internal::CartesianProductGenerator<R, T...>(
std::forward<decltype(generators)>(generators)...));
}
// Combine() allows the user to combine two or more sequences to produce
// values of a Cartesian product of those sequences' elements.
//
@ -403,9 +446,11 @@ inline internal::ParamGenerator<bool> Bool() { return Values(false, true); }
// INSTANTIATE_TEST_SUITE_P(TwoBoolSequence, FlagDependentTest,
// Combine(Bool(), Bool()));
//
template <typename... Generator>
internal::CartesianProductHolder<Generator...> Combine(const Generator&... g) {
return internal::CartesianProductHolder<Generator...>(g...);
template <typename... T>
internal::ParamGenerator<std::tuple<T...>> Combine(
internal::ParamGenerator<T>&&... generators) {
return CombineAs<std::tuple<T...>, T...>(
std::forward<decltype(generators)>(generators)...);
}
// ConvertGenerator() wraps a parameter generator in order to cast each produced

View File

@ -61,15 +61,15 @@
#include <vector>
#include "gtest/gtest-assertion-result.h" // IWYU pragma: export
#include "gtest/gtest-death-test.h" // IWYU pragma: export
#include "gtest/gtest-matchers.h" // IWYU pragma: export
#include "gtest/gtest-message.h" // IWYU pragma: export
#include "gtest/gtest-param-test.h" // IWYU pragma: export
#include "gtest/gtest-printers.h" // IWYU pragma: export
#include "gtest/gtest-test-part.h" // IWYU pragma: export
#include "gtest/gtest-typed-test.h" // IWYU pragma: export
#include "gtest/gtest_pred_impl.h" // IWYU pragma: export
#include "gtest/gtest_prod.h" // IWYU pragma: export
#include "gtest/gtest-death-test.h" // IWYU pragma: export
#include "gtest/gtest-matchers.h" // IWYU pragma: export
#include "gtest/gtest-message.h" // IWYU pragma: export
#include "gtest/gtest-param-test.h" // IWYU pragma: export
#include "gtest/gtest-printers.h" // IWYU pragma: export
#include "gtest/gtest-test-part.h" // IWYU pragma: export
#include "gtest/gtest-typed-test.h" // IWYU pragma: export
#include "gtest/gtest_pred_impl.h" // IWYU pragma: export
#include "gtest/gtest_prod.h" // IWYU pragma: export
#include "gtest/internal/gtest-internal.h"
#include "gtest/internal/gtest-string.h"
@ -1664,7 +1664,8 @@ class GTEST_API_ AssertHelper {
// the GetParam() method.
//
// Use it with one of the parameter generator defining functions, like Range(),
// Values(), ValuesIn(), Bool(), Combine(), and ConvertGenerator<T>().
// Values(), ValuesIn(), Bool(), Combine(), CombineAs<R>(), and
// ConvertGenerator<T>().
//
// class FooTest : public ::testing::TestWithParam<int> {
// protected:

View File

@ -180,6 +180,11 @@ class ParamGeneratorInterface {
virtual ParamIteratorInterface<T>* End() const = 0;
};
template <class GeneratedT,
typename StdFunction =
std::function<const GeneratedT&(const GeneratedT&)>>
class ParamConverterGenerator;
// Wraps ParamGeneratorInterface<T> and provides general generator syntax
// compatible with the STL Container concept.
// This class implements copy initialization semantics and the contained
@ -201,6 +206,11 @@ class ParamGenerator {
iterator begin() const { return iterator(impl_->Begin()); }
iterator end() const { return iterator(impl_->End()); }
template <typename R>
operator ParamGenerator<R>() {
return ParamConverterGenerator<T>(*this);
}
private:
std::shared_ptr<const ParamGeneratorInterface<T>> impl_;
};
@ -796,39 +806,15 @@ internal::ParamGenerator<typename Container::value_type> ValuesIn(
const Container& container);
namespace internal {
// Used in the Values() function to provide polymorphic capabilities.
GTEST_DISABLE_MSC_WARNINGS_PUSH_(4100)
template <typename... Ts>
class ValueArray {
template <typename R, typename... T>
class CartesianProductGenerator : public ParamGeneratorInterface<R> {
public:
explicit ValueArray(Ts... v) : v_(FlatTupleConstructTag{}, std::move(v)...) {}
using ParamType = R;
template <typename T>
operator ParamGenerator<T>() const { // NOLINT
return ValuesIn(MakeVector<T>(std::make_index_sequence<sizeof...(Ts)>()));
}
explicit CartesianProductGenerator(ParamGenerator<T>&&... g)
: generators_(std::forward<decltype(g)>(g)...) {}
private:
template <typename T, size_t... I>
std::vector<T> MakeVector(std::index_sequence<I...>) const {
return std::vector<T>{static_cast<T>(v_.template Get<I>())...};
}
FlatTuple<Ts...> v_;
};
GTEST_DISABLE_MSC_WARNINGS_POP_() // 4100
template <typename... T>
class CartesianProductGenerator
: public ParamGeneratorInterface<::std::tuple<T...>> {
public:
typedef ::std::tuple<T...> ParamType;
CartesianProductGenerator(const std::tuple<ParamGenerator<T>...>& g)
: generators_(g) {}
~CartesianProductGenerator() override = default;
ParamIteratorInterface<ParamType>* Begin() const override {
@ -916,7 +902,8 @@ class CartesianProductGenerator
void ComputeCurrentValue() {
if (!AtEnd())
current_value_ = std::make_shared<ParamType>(*std::get<I>(current_)...);
current_value_ =
std::make_shared<ParamType>(ParamType{*std::get<I>(current_)...});
}
bool AtEnd() const {
bool at_end = false;
@ -938,20 +925,6 @@ class CartesianProductGenerator
std::tuple<ParamGenerator<T>...> generators_;
};
template <class... Gen>
class CartesianProductHolder {
public:
CartesianProductHolder(const Gen&... g) : generators_(g...) {}
template <typename... T>
operator ParamGenerator<::std::tuple<T...>>() const {
return ParamGenerator<::std::tuple<T...>>(
new CartesianProductGenerator<T...>(generators_));
}
private:
std::tuple<Gen...> generators_;
};
template <typename From, typename To, typename Func>
class ParamGeneratorConverter : public ParamGeneratorInterface<To> {
public:
@ -1020,9 +993,7 @@ class ParamGeneratorConverter : public ParamGeneratorInterface<To> {
Func converter_;
}; // class ParamGeneratorConverter
template <class GeneratedT,
typename StdFunction =
std::function<const GeneratedT&(const GeneratedT&)>>
template <class GeneratedT, typename StdFunction>
class ParamConverterGenerator {
public:
ParamConverterGenerator(ParamGenerator<GeneratedT> g) // NOLINT

View File

@ -1424,12 +1424,11 @@ class GTEST_API_ Mutex {
// "MutexLock l(&mu)". Hence the typedef trick below.
class GTestMutexLock {
public:
explicit GTestMutexLock(Mutex* mutex) : mutex_(mutex) { mutex_->lock(); }
~GTestMutexLock() { mutex_->unlock(); }
explicit GTestMutexLock(Mutex& mutex) : mutex_(mutex) { mutex_.lock(); }
~GTestMutexLock() { mutex_.unlock(); }
private:
Mutex* const mutex_;
Mutex& mutex_;
GTestMutexLock(const GTestMutexLock&) = delete;
GTestMutexLock& operator=(const GTestMutexLock&) = delete;
@ -1716,12 +1715,11 @@ class Mutex : public MutexBase {
// "MutexLock l(&mu)". Hence the typedef trick below.
class GTestMutexLock {
public:
explicit GTestMutexLock(MutexBase* mutex) : mutex_(mutex) { mutex_->lock(); }
~GTestMutexLock() { mutex_->unlock(); }
explicit GTestMutexLock(MutexBase& mutex) : mutex_(mutex) { mutex_.lock(); }
~GTestMutexLock() { mutex_.unlock(); }
private:
MutexBase* const mutex_;
MutexBase& mutex_;
GTestMutexLock(const GTestMutexLock&) = delete;
GTestMutexLock& operator=(const GTestMutexLock&) = delete;
@ -1881,7 +1879,7 @@ class Mutex {
// "MutexLock l(&mu)". Hence the typedef trick below.
class GTestMutexLock {
public:
explicit GTestMutexLock(Mutex*) {} // NOLINT
explicit GTestMutexLock(Mutex&) {} // NOLINT
};
typedef GTestMutexLock MutexLock;

View File

@ -81,6 +81,7 @@ class HybridPrimeTable : public PrimeTable {
using ::testing::Bool;
using ::testing::Combine;
using ::testing::CombineAs;
using ::testing::TestWithParam;
using ::testing::Values;
@ -151,4 +152,45 @@ TEST_P(PrimeTableTest, CanGetNextPrime) {
INSTANTIATE_TEST_SUITE_P(MeaningfulTestParameters, PrimeTableTest,
Combine(Bool(), Values(1, 10)));
// But now you look at the PrimeTableTest and you think dealing with std::tuple
// requires some boilerplate to unwrap it. You can use combined parameters of
// custom types easily with help of CombineAs<R>().
struct WellTypedPrimeTableTestParams {
bool force_on_the_fly;
int max_precalculated;
};
class WellTypedPrimeTableTest
: public TestWithParam<WellTypedPrimeTableTestParams> {
protected:
void SetUp() override {
// It is possible to avoid destructuring of the std::tuple if we use struct
// as the test parameter type.
table_ = new HybridPrimeTable(GetParam().force_on_the_fly,
GetParam().max_precalculated);
}
void TearDown() override {
delete table_;
table_ = nullptr;
}
HybridPrimeTable* table_ = nullptr;
};
// The tests are made the same way as above
TEST_P(WellTypedPrimeTableTest, CanGetNextPrime) {
EXPECT_EQ(2, table_->GetNextPrime(0));
EXPECT_EQ(3, table_->GetNextPrime(2));
EXPECT_EQ(5, table_->GetNextPrime(3));
EXPECT_EQ(7, table_->GetNextPrime(5));
EXPECT_EQ(11, table_->GetNextPrime(7));
EXPECT_EQ(131, table_->GetNextPrime(128));
}
// Here we instantiate our tests with combined parameters and straightforward
// typing. CombineAs<R>() allows you to generate all possible combinations of
// values the same way as Combine() does, but also converts them to the desired
// type.
INSTANTIATE_TEST_SUITE_P(MeaningfulTestParameters, WellTypedPrimeTableTest,
CombineAs<WellTypedPrimeTableTestParams>(Bool(), Values(1, 10)));
} // namespace

View File

@ -499,7 +499,7 @@ class ThreadLocalRegistryImpl {
MemoryIsNotDeallocated memory_is_not_deallocated;
#endif // _MSC_VER
DWORD current_thread = ::GetCurrentThreadId();
MutexLock lock(&mutex_);
MutexLock lock(mutex_);
ThreadIdToThreadLocals* const thread_to_thread_locals =
GetThreadLocalsMapLocked();
ThreadIdToThreadLocals::iterator thread_local_pos =
@ -532,7 +532,7 @@ class ThreadLocalRegistryImpl {
// Clean up the ThreadLocalValues data structure while holding the lock, but
// defer the destruction of the ThreadLocalValueHolderBases.
{
MutexLock lock(&mutex_);
MutexLock lock(mutex_);
ThreadIdToThreadLocals* const thread_to_thread_locals =
GetThreadLocalsMapLocked();
for (ThreadIdToThreadLocals::iterator it =
@ -559,7 +559,7 @@ class ThreadLocalRegistryImpl {
// Clean up the ThreadIdToThreadLocals data structure while holding the
// lock, but defer the destruction of the ThreadLocalValueHolderBases.
{
MutexLock lock(&mutex_);
MutexLock lock(mutex_);
ThreadIdToThreadLocals* const thread_to_thread_locals =
GetThreadLocalsMapLocked();
ThreadIdToThreadLocals::iterator thread_local_pos =

View File

@ -1086,14 +1086,14 @@ void DefaultPerThreadTestPartResultReporter::ReportTestPartResult(
// Returns the global test part result reporter.
TestPartResultReporterInterface*
UnitTestImpl::GetGlobalTestPartResultReporter() {
internal::MutexLock lock(&global_test_part_result_reporter_mutex_);
internal::MutexLock lock(global_test_part_result_reporter_mutex_);
return global_test_part_result_reporter_;
}
// Sets the global test part result reporter.
void UnitTestImpl::SetGlobalTestPartResultReporter(
TestPartResultReporterInterface* reporter) {
internal::MutexLock lock(&global_test_part_result_reporter_mutex_);
internal::MutexLock lock(global_test_part_result_reporter_mutex_);
global_test_part_result_reporter_ = reporter;
}
@ -2347,7 +2347,7 @@ void TestResult::RecordProperty(const std::string& xml_element,
if (!ValidateTestProperty(xml_element, test_property)) {
return;
}
internal::MutexLock lock(&test_properties_mutex_);
internal::MutexLock lock(test_properties_mutex_);
const std::vector<TestProperty>::iterator property_with_matching_key =
std::find_if(test_properties_.begin(), test_properties_.end(),
internal::TestPropertyKeyIs(test_property.key()));
@ -5088,7 +5088,7 @@ std::string OsStackTraceGetter::CurrentStackTrace(int max_depth, int skip_count)
void* caller_frame = nullptr;
{
MutexLock lock(&mutex_);
MutexLock lock(mutex_);
caller_frame = caller_frame_;
}
@ -5127,7 +5127,7 @@ void OsStackTraceGetter::UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_) {
caller_frame = nullptr;
}
MutexLock lock(&mutex_);
MutexLock lock(mutex_);
caller_frame_ = caller_frame;
#endif // GTEST_HAS_ABSL
}
@ -5390,13 +5390,13 @@ void UnitTest::UponLeavingGTest() {
// Sets the TestSuite object for the test that's currently running.
void UnitTest::set_current_test_suite(TestSuite* a_current_test_suite) {
internal::MutexLock lock(&mutex_);
internal::MutexLock lock(mutex_);
impl_->set_current_test_suite(a_current_test_suite);
}
// Sets the TestInfo object for the test that's currently running.
void UnitTest::set_current_test_info(TestInfo* a_current_test_info) {
internal::MutexLock lock(&mutex_);
internal::MutexLock lock(mutex_);
impl_->set_current_test_info(a_current_test_info);
}
@ -5435,7 +5435,7 @@ void UnitTest::AddTestPartResult(TestPartResult::Type result_type,
Message msg;
msg << message;
internal::MutexLock lock(&mutex_);
internal::MutexLock lock(mutex_);
if (!impl_->gtest_trace_stack().empty()) {
msg << "\n" << GTEST_NAME_ << " trace:";
@ -5618,7 +5618,7 @@ const char* UnitTest::original_working_dir() const {
// or NULL if no test is running.
const TestSuite* UnitTest::current_test_suite() const
GTEST_LOCK_EXCLUDED_(mutex_) {
internal::MutexLock lock(&mutex_);
internal::MutexLock lock(mutex_);
return impl_->current_test_suite();
}
@ -5626,7 +5626,7 @@ const TestSuite* UnitTest::current_test_suite() const
#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
const TestCase* UnitTest::current_test_case() const
GTEST_LOCK_EXCLUDED_(mutex_) {
internal::MutexLock lock(&mutex_);
internal::MutexLock lock(mutex_);
return impl_->current_test_suite();
}
#endif
@ -5635,7 +5635,7 @@ const TestCase* UnitTest::current_test_case() const
// or NULL if no test is running.
const TestInfo* UnitTest::current_test_info() const
GTEST_LOCK_EXCLUDED_(mutex_) {
internal::MutexLock lock(&mutex_);
internal::MutexLock lock(mutex_);
return impl_->current_test_info();
}
@ -5659,13 +5659,13 @@ UnitTest::~UnitTest() { delete impl_; }
// Google Test trace stack.
void UnitTest::PushGTestTrace(const internal::TraceInfo& trace)
GTEST_LOCK_EXCLUDED_(mutex_) {
internal::MutexLock lock(&mutex_);
internal::MutexLock lock(mutex_);
impl_->gtest_trace_stack().push_back(trace);
}
// Pops a trace from the per-thread Google Test trace stack.
void UnitTest::PopGTestTrace() GTEST_LOCK_EXCLUDED_(mutex_) {
internal::MutexLock lock(&mutex_);
internal::MutexLock lock(mutex_);
impl_->gtest_trace_stack().pop_back();
}
@ -6088,15 +6088,17 @@ bool UnitTestImpl::RunAllTests() {
repeater->OnEnvironmentsTearDownEnd(*parent_);
}
} else if (GTEST_FLAG_GET(fail_if_no_test_selected)) {
// If there were no tests to run, bail if we were requested to be strict.
// If there were no tests to run, bail if we were requested to be
// strict.
constexpr char kNoTestsSelectedMessage[] =
"No tests were selected to run. Please make sure at least one test "
"exists and is not disabled! If the test is sharded, you may have "
"defined more shards than test cases, which is wasteful. If you also "
"defined --gtest_filter, that filter is taken into account, so "
"shards with no matching test cases will hit this error. Either "
"disable sharding, set --gtest_fail_if_no_test_selected=false, or "
"remove the filter to resolve this error.";
"No tests ran. Check that tests exist and are not disabled or "
"filtered out.\n\n"
"For sharded runs, this error indicates an empty shard. This can "
"happen if you have more shards than tests, or if --gtest_filter "
"leaves a shard with no tests.\n\n"
"To permit empty shards (e.g., when debugging with a filter), "
"specify \n"
"--gtest_fail_if_no_test_selected=false.";
ColoredPrintf(GTestColor::kRed, "%s\n", kNoTestsSelectedMessage);
return false;
}

View File

@ -588,6 +588,75 @@ TEST(ConvertTest, NonDefaultConstructAssign) {
EXPECT_TRUE(it == gen.end());
}
TEST(CombineAsTest, DefaultConstructible) {
struct DefaultConstructible {
int x;
std::string s;
bool operator==(const DefaultConstructible& other) const {
return x == other.x && s == other.s;
}
};
static_assert(std::is_default_constructible_v<DefaultConstructible>);
ParamGenerator<DefaultConstructible> gen =
testing::CombineAs<DefaultConstructible>(Values(0, 1), Values("A", "B"));
DefaultConstructible expected_values[] = {
{0, "A"}, {0, "B"}, {1, "A"}, {1, "B"}};
VerifyGenerator(gen, expected_values);
}
TEST(CombineAsTest, NonDefaultConstructible) {
class NonDefaultConstructible {
public:
NonDefaultConstructible(const int i_arg, std::string s_arg)
: i_(i_arg), s_(std::move(s_arg)) {}
bool operator==(const NonDefaultConstructible& other) const {
return i_ == other.i_ && s_ == other.s_;
}
private:
int i_;
std::string s_;
};
static_assert(!std::is_default_constructible_v<NonDefaultConstructible>);
ParamGenerator<NonDefaultConstructible> gen =
testing::CombineAs<NonDefaultConstructible>(Values(0, 1),
Values("A", "B"));
NonDefaultConstructible expected_values[] = {
{0, "A"}, {0, "B"}, {1, "A"}, {1, "B"}};
VerifyGenerator(gen, expected_values);
}
TEST(CombineAsTest, CopyConstructible) {
class CopyConstructible {
public:
CopyConstructible(const CopyConstructible& other) = default;
CopyConstructible(const int i_arg, std::string s_arg)
: i_(i_arg), s_(std::move(s_arg)) {}
bool operator==(const CopyConstructible& other) const {
return i_ == other.i_ && s_ == other.s_;
}
private:
int i_;
std::string s_;
};
static_assert(std::is_copy_constructible_v<CopyConstructible>);
ParamGenerator<CopyConstructible> gen = testing::CombineAs<CopyConstructible>(
Values(CopyConstructible(0, "A"), CopyConstructible(1, "B")));
CopyConstructible expected_values[] = {CopyConstructible(0, "A"),
CopyConstructible(1, "B")};
VerifyGenerator(gen, expected_values);
}
TEST(ConvertTest, WithConverterLambdaAndDeducedType) {
const ParamGenerator<ConstructFromT<int8_t>> gen =
ConvertGenerator(Values("0", std::string("1")), [](const std::string& s) {

View File

@ -308,7 +308,7 @@ TEST(GetThreadCountTest, ReturnsCorrectValue) {
internal::Mutex mutex;
{
internal::MutexLock lock(&mutex);
internal::MutexLock lock(mutex);
pthread_attr_t attr;
ASSERT_EQ(0, pthread_attr_init(&attr));
ASSERT_EQ(0, pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE));
@ -1028,7 +1028,9 @@ TEST(MutexDeathTest, AssertHeldShouldAssertWhenNotLocked) {
EXPECT_DEATH_IF_SUPPORTED(
{
Mutex m;
{ MutexLock lock(&m); }
{
MutexLock lock(m);
}
m.AssertHeld();
},
"thread .*hold");
@ -1036,13 +1038,13 @@ TEST(MutexDeathTest, AssertHeldShouldAssertWhenNotLocked) {
TEST(MutexTest, AssertHeldShouldNotAssertWhenLocked) {
Mutex m;
MutexLock lock(&m);
MutexLock lock(m);
m.AssertHeld();
}
class AtomicCounterWithMutex {
public:
explicit AtomicCounterWithMutex(Mutex* mutex)
explicit AtomicCounterWithMutex(Mutex& mutex)
: value_(0), mutex_(mutex), random_(42) {}
void Increment() {
@ -1083,7 +1085,7 @@ class AtomicCounterWithMutex {
private:
volatile int value_;
Mutex* const mutex_; // Protects value_.
Mutex& mutex_; // Protects value_.
Random random_;
};
@ -1094,7 +1096,7 @@ void CountingThreadFunc(pair<AtomicCounterWithMutex*, int> param) {
// Tests that the mutex only lets one thread at a time to lock it.
TEST(MutexTest, OnlyOneThreadCanLockAtATime) {
Mutex mutex;
AtomicCounterWithMutex locked_counter(&mutex);
AtomicCounterWithMutex locked_counter(mutex);
typedef ThreadWithParam<pair<AtomicCounterWithMutex*, int> > ThreadType;
const int kCycleCount = 20;