tvl-depot/absl/random/mocking_bit_gen.h
Abseil Team 79e0dc1151 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 bcefbdcdf6 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 11:51:59 -04:00

198 lines
6.8 KiB
C++

// 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 <typeindex>
#include <typeinfo>
#include <utility>
#include "gmock/gmock.h"
#include "gtest/gtest.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/mocking_bit_gen_base.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
namespace random_internal {
template <typename, typename>
struct MockSingleOverload;
} // 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) / 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.
//
class MockingBitGen : public absl::random_internal::MockingBitGenBase {
public:
MockingBitGen() {}
~MockingBitGen() override {
for (const auto& del : deleters_) del();
}
private:
template <typename DistrT, typename... Args>
using MockFnType =
::testing::MockFunction<typename DistrT::result_type(Args...)>;
// MockingBitGen::Register
//
// Register<DistrT, FormatT, ArgTupleT> is the main extension point for
// extending the MockingBitGen framework. It provides a mechanism to install a
// mock expectation for the distribution `distr_t` onto the MockingBitGen
// context.
//
// The returned MockFunction<...> type can be used to setup additional
// distribution parameters of the expectation.
template <typename DistrT, typename... Args, typename... Ms>
decltype(std::declval<MockFnType<DistrT, Args...>>().gmock_Call(
std::declval<Ms>()...))
Register(Ms&&... matchers) {
auto& mock =
mocks_[std::type_index(GetTypeId<DistrT, std::tuple<Args...>>())];
if (!mock.mock_fn) {
auto* mock_fn = new MockFnType<DistrT, Args...>;
mock.mock_fn = mock_fn;
mock.match_impl = &MatchImpl<DistrT, Args...>;
deleters_.emplace_back([mock_fn] { delete mock_fn; });
}
return static_cast<MockFnType<DistrT, Args...>*>(mock.mock_fn)
->gmock_Call(std::forward<Ms>(matchers)...);
}
mutable std::vector<std::function<void()>> deleters_;
using match_impl_fn = void (*)(void* mock_fn, void* t_erased_dist_args,
void* t_erased_result);
struct MockData {
void* mock_fn = nullptr;
match_impl_fn match_impl = nullptr;
};
mutable absl::flat_hash_map<std::type_index, MockData> mocks_;
template <typename DistrT, typename... Args>
static void MatchImpl(void* mock_fn, void* dist_args, void* result) {
using result_type = typename DistrT::result_type;
*static_cast<result_type*>(result) = absl::apply(
[mock_fn](Args... args) -> result_type {
return (*static_cast<MockFnType<DistrT, Args...>*>(mock_fn))
.Call(std::move(args)...);
},
*static_cast<std::tuple<Args...>*>(dist_args));
}
// Looks for an appropriate mock - Returns the mocked result if one is found.
// Otherwise, returns a random value generated by the underlying URBG.
bool CallImpl(const std::type_info& key_type, void* dist_args,
void* result) override {
// Trigger a mock, if there exists one that matches `param`.
auto it = mocks_.find(std::type_index(key_type));
if (it == mocks_.end()) return false;
auto* mock_data = static_cast<MockData*>(&it->second);
mock_data->match_impl(mock_data->mock_fn, dist_args, result);
return true;
}
template <typename, typename>
friend struct ::absl::random_internal::MockSingleOverload;
friend struct ::absl::random_internal::DistributionCaller<
absl::MockingBitGen>;
};
// -----------------------------------------------------------------------------
// Implementation Details Only Below
// -----------------------------------------------------------------------------
namespace random_internal {
template <>
struct DistributionCaller<absl::MockingBitGen> {
template <typename DistrT, typename... Args>
static typename DistrT::result_type Call(absl::MockingBitGen* gen,
Args&&... args) {
return gen->template Call<DistrT>(std::forward<Args>(args)...);
}
};
} // namespace random_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_RANDOM_MOCKING_BIT_GEN_H_