tvl-depot/third_party/abseil_cpp/absl/random/mocking_bit_gen.h

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

229 lines
8.7 KiB
C
Raw Normal View History

// Copyright 2018 The Abseil Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// -----------------------------------------------------------------------------
// mocking_bit_gen.h
// -----------------------------------------------------------------------------
//
// This file includes an `absl::MockingBitGen` class to use as a mock within the
// Googletest testing framework. Such a mock is useful to provide deterministic
// values as return values within (otherwise random) Abseil distribution
// functions. Such determinism within a mock is useful within testing frameworks
// to test otherwise indeterminate APIs.
//
// More information about the Googletest testing framework is available at
// https://github.com/google/googletest
#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/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/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 {
Export of internal Abseil changes -- c99f979ad34f155fbeeea69b88bdc7458d89a21c by Derek Mauro <dmauro@google.com>: Remove a floating point division by zero test. This isn't testing behavior related to the library, and MSVC warns about it in opt mode. PiperOrigin-RevId: 285220804 -- 68b015491f0dbf1ab547994673281abd1f34cd4b by Gennadiy Rozental <rogeeff@google.com>: This CL introduces following changes to the class FlagImpl: * We eliminate the CommandLineFlagLocks struct. Instead callback guard and callback function are combined into a single CallbackData struct, while primary data lock is stored separately. * CallbackData member of class FlagImpl is initially set to be nullptr and is only allocated and initialized when a flag's callback is being set. For most flags we do not pay for the extra space and extra absl::Mutex now. * Primary data guard is stored in data_guard_ data member. This is a properly aligned character buffer of necessary size. During initialization of the flag we construct absl::Mutex in this space using placement new call. * We now avoid extra value copy after successful attempt to parse value out of string. Instead we swap flag's current value with tentative value we just produced. PiperOrigin-RevId: 285132636 -- ed45d118fb818969eb13094cf7827c885dfc562c by Tom Manshreck <shreck@google.com>: Change null-term* (and nul-term*) to NUL-term* in comments PiperOrigin-RevId: 285036610 -- 729619017944db895ce8d6d29c1995aa2e5628a5 by Derek Mauro <dmauro@google.com>: Use the Posix implementation of thread identity on MinGW. Some versions of MinGW suffer from thread_local bugs. PiperOrigin-RevId: 285022920 -- 39a25493503c76885bc3254c28f66a251c5b5bb0 by Greg Falcon <gfalcon@google.com>: Implementation detail change. Add further ABSL_NAMESPACE_BEGIN and _END annotation macros to files in Abseil. PiperOrigin-RevId: 285012012 GitOrigin-RevId: c99f979ad34f155fbeeea69b88bdc7458d89a21c Change-Id: I4c85d3704e45d11a9ac50d562f39640a6adbedc1
2019-12-12 19:36:03 +01:00
ABSL_NAMESPACE_BEGIN
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) / 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 {
public:
MockingBitGen() = default;
~MockingBitGen() {
Export of internal Abseil changes -- 990253454819ce26ff1dda9ab4bbc145b61d01e4 by Xiaoyi Zhang <zhangxy@google.com>: Import github PR https://github.com/abseil/abseil-cpp/pull/645 PiperOrigin-RevId: 303119797 -- 5ac845cb7929b7d1eaf59a309afd811db5001175 by Abseil Team <absl-team@google.com>: Fix internal exception spec compatibility error PiperOrigin-RevId: 303104081 -- 3290595dd866eecab3c7044e2e3ca0adb74f1bf5 by Gennadiy Rozental <rogeeff@google.com>: Use FlagValue<T> to represent the value of a flag. Place it directly after FlagImpl and use a computed offset refer to it. The offset is computed based on the assumption that the `value_` data member is placed directly after the impl_ data member in Flag<T>. This change will allow us to migrate to `T`-specific storage in the generic case. This change decreases the overhead for int flags by 32 bytes. PiperOrigin-RevId: 303038099 -- f2b37722cd7a6d3a60ef9713f0d2bbff56f3ddbf by Derek Mauro <dmauro@google.com>: Minor correctness fix for an ABSL_HAVE_BUILTIN conditional PiperOrigin-RevId: 302980666 -- 39c079a6141ae1c5728af8bf33a39c8aff9deb9f by Abseil Team <absl-team@google.com>: Use ABSL_HARDENING_ASSERT in b-tree and SwissTable iterators. PiperOrigin-RevId: 302970075 -- 9668a044e080c789df32bcaa1ffb5100831cd9fa by Benjamin Barenblat <bbaren@google.com>: Correct `add_subdirectory` line in CMake googletest support Commit bcefbdcdf6ad85046ccacee0aeffba5404d3e528 added support for building with CMake against a local googletest checkout, but I missed a line when constructing the diff. Change the `add_subdirectory` line to reference the correct directories. PiperOrigin-RevId: 302947488 -- 0a3c10fabf80a43ca69ab8b1570030e55f2be741 by Andy Soffer <asoffer@google.com>: Remove unused distribution format traits. PiperOrigin-RevId: 302896176 -- 0478f2f6270e5ed64c0e28ec09556ca90b2d46a9 by Samuel Benzaquen <sbenza@google.com>: Fix for CWG:2310. PiperOrigin-RevId: 302734089 -- 3cb978dda5cae5905affdc0914dcc2d27671ed11 by Samuel Benzaquen <sbenza@google.com>: Fix the Allocate/Deallocate functions to use the same underlying allocator type. PiperOrigin-RevId: 302721804 -- ae38d3984fb68b4e3ddc165fa8d5c24d5936be52 by Matthew Brown <matthewbr@google.com>: Internal Change PiperOrigin-RevId: 302717314 -- 7357cf7abd03cc60b6e82b5f28a8e34935c3b4dc by Andy Getzendanner <durandal@google.com>: Fix typo: s/ABSL_HARDENED_ASSERT/ABSL_HARDENING_ASSERT/ PiperOrigin-RevId: 302532164 GitOrigin-RevId: 990253454819ce26ff1dda9ab4bbc145b61d01e4 Change-Id: Ie595a221c16e1e7e1255ad42e029b646c5f3e11d
2020-03-26 16:48:01 +01:00
for (const auto& del : deleters_) del();
}
// URBG interface
using result_type = absl::BitGen::result_type;
static constexpr result_type(min)() { return (absl::BitGen::min)(); }
static constexpr result_type(max)() { return (absl::BitGen::max)(); }
result_type operator()() { return gen_(); }
private:
using match_impl_fn = void (*)(void* mock_fn, void* t_erased_arg_tuple,
void* t_erased_result);
struct MockData {
void* mock_fn = nullptr;
match_impl_fn match_impl = nullptr;
};
// GetMockFnType returns the testing::MockFunction for a result and tuple.
// This method only exists for type deduction and is otherwise unimplemented.
template <typename ResultT, typename... Args>
static auto GetMockFnType(ResultT, std::tuple<Args...>)
-> ::testing::MockFunction<ResultT(Args...)>;
// MockFnCaller is a helper method for use with absl::apply to
// apply an ArgTupleT to a compatible MockFunction.
// 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 ResultT, typename MockFnType, typename Tuple>
struct MockFnCaller;
// specialization for std::tuple.
template <typename ResultT, typename MockFnType, typename... Args>
struct MockFnCaller<ResultT, MockFnType, std::tuple<Args...>> {
MockFnType* fn;
inline ResultT operator()(Args... args) {
return fn->Call(std::move(args)...);
}
};
// MockingBitGen::RegisterMock
//
// RegisterMock<ResultT, ArgTupleT>(FastTypeIdType) is the main extension
// point for extending the MockingBitGen framework. It provides a mechanism to
// install a mock expectation for a function like ResultT(Args...) keyed by
// type_idex onto the MockingBitGen context. The key is that the type_index
// used to register must match the type index used to call the mock.
//
// The returned MockFunction<...> type can be used to setup additional
// distribution parameters of the expectation.
template <typename ResultT, typename ArgTupleT>
auto RegisterMock(base_internal::FastTypeIdType type)
-> decltype(GetMockFnType(std::declval<ResultT>(),
std::declval<ArgTupleT>()))& {
using MockFnType = decltype(
GetMockFnType(std::declval<ResultT>(), std::declval<ArgTupleT>()));
auto& mock = mocks_[type];
if (!mock.mock_fn) {
auto* mock_fn = new MockFnType;
mock.mock_fn = mock_fn;
mock.match_impl = &MatchImpl<ResultT, ArgTupleT>;
deleters_.emplace_back([mock_fn] { delete mock_fn; });
}
return *static_cast<MockFnType*>(mock.mock_fn);
}
// MockingBitGen::MatchImpl<> is a dispatch function which converts the
// generic type-erased parameters into a specific mock invocation call.
// 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.
template <typename ResultT, typename ArgTupleT>
static void MatchImpl(/*MockFnType<ResultT, Args...>*/ void* mock_fn,
/*ArgTupleT*/ void* args_tuple,
/*ResultT*/ void* result) {
using MockFnType = decltype(
GetMockFnType(std::declval<ResultT>(), std::declval<ArgTupleT>()));
*static_cast<ResultT*>(result) = absl::apply(
MockFnCaller<ResultT, MockFnType, ArgTupleT>{
static_cast<MockFnType*>(mock_fn)},
*static_cast<ArgTupleT*>(args_tuple));
}
// MockingBitGen::InvokeMock
//
// InvokeMock(FastTypeIdType, args, result) is the entrypoint for invoking
// mocks registered on MockingBitGen.
//
// When no mocks are registered on the provided FastTypeIdType, returns false.
// Otherwise attempts to invoke the mock function ResultT(Args...) that
// was previously registered via the type_index.
// 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.
inline bool InvokeMock(base_internal::FastTypeIdType type, void* args_tuple,
void* result) {
// Trigger a mock, if there exists one that matches `param`.
auto it = mocks_.find(type);
if (it == mocks_.end()) return false;
auto* mock_data = static_cast<MockData*>(&it->second);
mock_data->match_impl(mock_data->mock_fn, args_tuple, result);
return true;
}
absl::flat_hash_map<base_internal::FastTypeIdType, MockData> mocks_;
std::vector<std::function<void()>> deleters_;
absl::BitGen gen_;
template <typename>
friend struct ::absl::random_internal::DistributionCaller; // for InvokeMock
friend class ::absl::BitGenRef; // for InvokeMock
friend class ::absl::random_internal::MockHelpers; // for RegisterMock,
// InvokeMock
};
Export of internal Abseil changes -- c99f979ad34f155fbeeea69b88bdc7458d89a21c by Derek Mauro <dmauro@google.com>: Remove a floating point division by zero test. This isn't testing behavior related to the library, and MSVC warns about it in opt mode. PiperOrigin-RevId: 285220804 -- 68b015491f0dbf1ab547994673281abd1f34cd4b by Gennadiy Rozental <rogeeff@google.com>: This CL introduces following changes to the class FlagImpl: * We eliminate the CommandLineFlagLocks struct. Instead callback guard and callback function are combined into a single CallbackData struct, while primary data lock is stored separately. * CallbackData member of class FlagImpl is initially set to be nullptr and is only allocated and initialized when a flag's callback is being set. For most flags we do not pay for the extra space and extra absl::Mutex now. * Primary data guard is stored in data_guard_ data member. This is a properly aligned character buffer of necessary size. During initialization of the flag we construct absl::Mutex in this space using placement new call. * We now avoid extra value copy after successful attempt to parse value out of string. Instead we swap flag's current value with tentative value we just produced. PiperOrigin-RevId: 285132636 -- ed45d118fb818969eb13094cf7827c885dfc562c by Tom Manshreck <shreck@google.com>: Change null-term* (and nul-term*) to NUL-term* in comments PiperOrigin-RevId: 285036610 -- 729619017944db895ce8d6d29c1995aa2e5628a5 by Derek Mauro <dmauro@google.com>: Use the Posix implementation of thread identity on MinGW. Some versions of MinGW suffer from thread_local bugs. PiperOrigin-RevId: 285022920 -- 39a25493503c76885bc3254c28f66a251c5b5bb0 by Greg Falcon <gfalcon@google.com>: Implementation detail change. Add further ABSL_NAMESPACE_BEGIN and _END annotation macros to files in Abseil. PiperOrigin-RevId: 285012012 GitOrigin-RevId: c99f979ad34f155fbeeea69b88bdc7458d89a21c Change-Id: I4c85d3704e45d11a9ac50d562f39640a6adbedc1
2019-12-12 19:36:03 +01:00
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_MOCKING_BIT_GEN_H_