diff options
Diffstat (limited to 'absl/random/mocking_bit_gen.h')
-rw-r--r-- | absl/random/mocking_bit_gen.h | 158 |
1 files changed, 86 insertions, 72 deletions
diff --git a/absl/random/mocking_bit_gen.h b/absl/random/mocking_bit_gen.h index 89fa5a47..041989de 100644 --- a/absl/random/mocking_bit_gen.h +++ b/absl/random/mocking_bit_gen.h @@ -28,83 +28,37 @@ #ifndef ABSL_RANDOM_MOCKING_BIT_GEN_H_ #define ABSL_RANDOM_MOCKING_BIT_GEN_H_ -#include <iterator> -#include <limits> #include <memory> #include <tuple> #include <type_traits> #include <utility> #include "gmock/gmock.h" -#include "gtest/gtest.h" +#include "absl/base/attributes.h" +#include "absl/base/config.h" #include "absl/base/internal/fast_type_id.h" #include "absl/container/flat_hash_map.h" #include "absl/meta/type_traits.h" -#include "absl/random/distributions.h" -#include "absl/random/internal/distribution_caller.h" +#include "absl/random/internal/mock_helpers.h" #include "absl/random/random.h" -#include "absl/strings/str_cat.h" -#include "absl/strings/str_join.h" -#include "absl/types/span.h" -#include "absl/types/variant.h" #include "absl/utility/utility.h" namespace absl { ABSL_NAMESPACE_BEGIN +class BitGenRef; + namespace random_internal { template <typename> struct DistributionCaller; class MockHelpers; -} // namespace random_internal -class BitGenRef; - -// MockingBitGen -// -// `absl::MockingBitGen` is a mock Uniform Random Bit Generator (URBG) class -// which can act in place of an `absl::BitGen` URBG within tests using the -// Googletest testing framework. -// -// Usage: -// -// Use an `absl::MockingBitGen` along with a mock distribution object (within -// mock_distributions.h) inside Googletest constructs such as ON_CALL(), -// EXPECT_TRUE(), etc. to produce deterministic results conforming to the -// distribution's API contract. -// -// Example: -// -// // Mock a call to an `absl::Bernoulli` distribution using Googletest -// absl::MockingBitGen bitgen; -// -// ON_CALL(absl::MockBernoulli(), Call(bitgen, 0.5)) -// .WillByDefault(testing::Return(true)); -// EXPECT_TRUE(absl::Bernoulli(bitgen, 0.5)); -// -// // Mock a call to an `absl::Uniform` distribution within Googletest -// absl::MockingBitGen bitgen; -// -// ON_CALL(absl::MockUniform<int>(), Call(bitgen, testing::_, testing::_)) -// .WillByDefault([] (int low, int high) { -// return low + (high - low) / 2; -// }); -// -// EXPECT_EQ(absl::Uniform<int>(gen, 0, 10), 5); -// EXPECT_EQ(absl::Uniform<int>(gen, 30, 40), 35); -// -// At this time, only mock distributions supplied within the Abseil random -// library are officially supported. -// -// EXPECT_CALL and ON_CALL need to be made within the same DLL component as -// the call to absl::Uniform and related methods, otherwise mocking will fail -// since the underlying implementation creates a type-specific pointer which -// will be distinct across different DLL boundaries. -// -class MockingBitGen { +// Implements MockingBitGen with an option to turn on extra validation. +template <bool EnableValidation> +class MockingBitGenImpl { public: - MockingBitGen() = default; - ~MockingBitGen() = default; + MockingBitGenImpl() = default; + ~MockingBitGenImpl() = default; // URBG interface using result_type = absl::BitGen::result_type; @@ -125,15 +79,19 @@ class MockingBitGen { // NOTE: MockFnCaller is essentially equivalent to the lambda: // [fn](auto... args) { return fn->Call(std::move(args)...)} // however that fails to build on some supported platforms. - template <typename MockFnType, typename ResultT, typename Tuple> + template <typename MockFnType, typename ValidatorT, typename ResultT, + typename Tuple> struct MockFnCaller; // specialization for std::tuple. - template <typename MockFnType, typename ResultT, typename... Args> - struct MockFnCaller<MockFnType, ResultT, std::tuple<Args...>> { + template <typename MockFnType, typename ValidatorT, typename ResultT, + typename... Args> + struct MockFnCaller<MockFnType, ValidatorT, ResultT, std::tuple<Args...>> { MockFnType* fn; inline ResultT operator()(Args... args) { - return fn->Call(std::move(args)...); + ResultT result = fn->Call(args...); + ValidatorT::Validate(result, args...); + return result; } }; @@ -150,16 +108,17 @@ class MockingBitGen { /*ResultT*/ void* result) = 0; }; - template <typename MockFnType, typename ResultT, typename ArgTupleT> + template <typename MockFnType, typename ValidatorT, typename ResultT, + typename ArgTupleT> class FunctionHolderImpl final : public FunctionHolder { public: - void Apply(void* args_tuple, void* result) override { + void Apply(void* args_tuple, void* result) final { // Requires tuple_args to point to a ArgTupleT, which is a // std::tuple<Args...> used to invoke the mock function. Requires result // to point to a ResultT, which is the result of the call. - *static_cast<ResultT*>(result) = - absl::apply(MockFnCaller<MockFnType, ResultT, ArgTupleT>{&mock_fn_}, - *static_cast<ArgTupleT*>(args_tuple)); + *static_cast<ResultT*>(result) = absl::apply( + MockFnCaller<MockFnType, ValidatorT, ResultT, ArgTupleT>{&mock_fn_}, + *static_cast<ArgTupleT*>(args_tuple)); } MockFnType mock_fn_; @@ -175,26 +134,29 @@ class MockingBitGen { // // The returned MockFunction<...> type can be used to setup additional // distribution parameters of the expectation. - template <typename ResultT, typename ArgTupleT, typename SelfT> - auto RegisterMock(SelfT&, base_internal::FastTypeIdType type) + template <typename ResultT, typename ArgTupleT, typename SelfT, + typename ValidatorT> + auto RegisterMock(SelfT&, base_internal::FastTypeIdType type, ValidatorT) -> decltype(GetMockFnType(std::declval<ResultT>(), std::declval<ArgTupleT>()))& { + using ActualValidatorT = + std::conditional_t<EnableValidation, ValidatorT, NoOpValidator>; using MockFnType = decltype(GetMockFnType(std::declval<ResultT>(), std::declval<ArgTupleT>())); using WrappedFnType = absl::conditional_t< - std::is_same<SelfT, ::testing::NiceMock<absl::MockingBitGen>>::value, + std::is_same<SelfT, ::testing::NiceMock<MockingBitGenImpl>>::value, ::testing::NiceMock<MockFnType>, absl::conditional_t< - std::is_same<SelfT, - ::testing::NaggyMock<absl::MockingBitGen>>::value, + std::is_same<SelfT, ::testing::NaggyMock<MockingBitGenImpl>>::value, ::testing::NaggyMock<MockFnType>, absl::conditional_t< std::is_same<SelfT, - ::testing::StrictMock<absl::MockingBitGen>>::value, + ::testing::StrictMock<MockingBitGenImpl>>::value, ::testing::StrictMock<MockFnType>, MockFnType>>>; - using ImplT = FunctionHolderImpl<WrappedFnType, ResultT, ArgTupleT>; + using ImplT = + FunctionHolderImpl<WrappedFnType, ActualValidatorT, ResultT, ArgTupleT>; auto& mock = mocks_[type]; if (!mock) { mock = absl::make_unique<ImplT>(); @@ -234,6 +196,58 @@ class MockingBitGen { // InvokeMock }; +} // namespace random_internal + +// MockingBitGen +// +// `absl::MockingBitGen` is a mock Uniform Random Bit Generator (URBG) class +// which can act in place of an `absl::BitGen` URBG within tests using the +// Googletest testing framework. +// +// Usage: +// +// Use an `absl::MockingBitGen` along with a mock distribution object (within +// mock_distributions.h) inside Googletest constructs such as ON_CALL(), +// EXPECT_TRUE(), etc. to produce deterministic results conforming to the +// distribution's API contract. +// +// Example: +// +// // Mock a call to an `absl::Bernoulli` distribution using Googletest +// absl::MockingBitGen bitgen; +// +// ON_CALL(absl::MockBernoulli(), Call(bitgen, 0.5)) +// .WillByDefault(testing::Return(true)); +// EXPECT_TRUE(absl::Bernoulli(bitgen, 0.5)); +// +// // Mock a call to an `absl::Uniform` distribution within Googletest +// absl::MockingBitGen bitgen; +// +// ON_CALL(absl::MockUniform<int>(), Call(bitgen, testing::_, testing::_)) +// .WillByDefault([] (int low, int high) { +// return low + (high - low) / 2; +// }); +// +// EXPECT_EQ(absl::Uniform<int>(gen, 0, 10), 5); +// EXPECT_EQ(absl::Uniform<int>(gen, 30, 40), 35); +// +// At this time, only mock distributions supplied within the Abseil random +// library are officially supported. +// +// EXPECT_CALL and ON_CALL need to be made within the same DLL component as +// the call to absl::Uniform and related methods, otherwise mocking will fail +// since the underlying implementation creates a type-specific pointer which +// will be distinct across different DLL boundaries. +// +using MockingBitGen = random_internal::MockingBitGenImpl<true>; + +// UnvalidatedMockingBitGen +// +// UnvalidatedMockingBitGen is a variant of MockingBitGen which does no extra +// validation. +using UnvalidatedMockingBitGen ABSL_DEPRECATED("Use MockingBitGen instead") = + random_internal::MockingBitGenImpl<false>; + ABSL_NAMESPACE_END } // namespace absl |