Commit bcaae600 by Abseil Team Committed by Andy Soffer

Export of internal Abseil changes

--
4503a1945d61540d3f7dd9ee2399297fbd423b82 by Andy Soffer <asoffer@google.com>:

Releasing absl::MockingBitGen and absl::BitGenRef

PiperOrigin-RevId: 281594380

--
2cb926fd9e39b5fa24c9541bfafcf18916cf7df2 by Abseil Team <absl-team@google.com>:

Explicitly export files needed by other packages

PiperOrigin-RevId: 281482304
GitOrigin-RevId: 4503a1945d61540d3f7dd9ee2399297fbd423b82
Change-Id: Id9f694eaaa23f42de817c8e8a28e6f86444f5637
parent 8ba96a82
......@@ -110,6 +110,58 @@ cc_library(
],
)
cc_library(
name = "bit_gen_ref",
hdrs = ["bit_gen_ref.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
"//absl/base:core_headers",
"//absl/meta:type_traits",
"//absl/random/internal:distribution_caller",
"//absl/random/internal:fast_uniform_bits",
"//absl/random/internal:mocking_bit_gen_base",
],
)
cc_library(
name = "mock_distributions",
testonly = 1,
hdrs = ["mock_distributions.h"],
deps = [
":distributions",
":mocking_bit_gen",
"//absl/meta:type_traits",
"//absl/random/internal:mock_overload_set",
"@com_google_googletest//:gtest",
],
)
cc_library(
name = "mocking_bit_gen",
testonly = 1,
srcs = [
"mocking_bit_gen.cc",
],
hdrs = [
"mocking_bit_gen.h",
],
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":distributions",
"//absl/base:raw_logging_internal",
"//absl/container:flat_hash_map",
"//absl/meta:type_traits",
"//absl/random/internal:distribution_caller",
"//absl/random/internal:mocking_bit_gen_base",
"//absl/strings",
"//absl/types:span",
"//absl/types:variant",
"//absl/utility",
"@com_google_googletest//:gtest",
],
)
cc_test(
name = "bernoulli_distribution_test",
size = "small",
......@@ -346,6 +398,46 @@ cc_test(
)
cc_test(
name = "bit_gen_ref_test",
size = "small",
srcs = ["bit_gen_ref_test.cc"],
copts = ABSL_TEST_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":bit_gen_ref",
":random",
"//absl/random/internal:sequence_urbg",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "mocking_bit_gen_test",
size = "small",
srcs = ["mocking_bit_gen_test.cc"],
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":bit_gen_ref",
":mock_distributions",
":mocking_bit_gen",
":random",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "mock_distributions_test",
size = "small",
srcs = ["mock_distributions_test.cc"],
deps = [
":mock_distributions",
":mocking_bit_gen",
":random",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "examples_test",
size = "small",
srcs = ["examples_test.cc"],
......
......@@ -34,6 +34,132 @@ absl_cc_library(
absl_cc_library(
NAME
random_bit_gen_ref
HDRS
"bit_gen_ref.h"
COPTS
${ABSL_DEFAULT_COPTS}
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
absl::core_headers
absl::random_internal_distribution_caller
absl::random_internal_fast_uniform_bits
absl::random_internal_mocking_bit_gen_base
absl::type_traits
)
absl_cc_test(
NAME
random_bit_gen_ref_test
SRCS
"bit_gen_ref_test.cc"
COPTS
${ABSL_TEST_COPTS}
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
absl::random_bit_gen_ref
absl::random_random
absl::random_internal_sequence_urbg
gmock
gtest_main
)
# Internal-only target, do not depend on directly.
absl_cc_library(
NAME
random_internal_mocking_bit_gen_base
HDRS
"internal/mocking_bit_gen_base.h"
COPTS
${ABSL_DEFAULT_COPTS}
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
absl::random_random
absl::strings
)
# Internal-only target, do not depend on directly.
absl_cc_library(
NAME
random_internal_mock_overload_set
HDRS
"internal/mock_overload_set.h"
COPTS
${ABSL_DEFAULT_COPTS}
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
absl::random_mocking_bit_gen
TESTONLY
)
absl_cc_library(
NAME
random_mocking_bit_gen
HDRS
"mock_distributions.h"
"mocking_bit_gen.h"
SRCS
"mocking_bit_gen.cc"
COPTS
${ABSL_DEFAULT_COPTS}
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
absl::flat_hash_map
absl::raw_logging_internal
absl::random_distributions
absl::random_internal_distribution_caller
absl::random_internal_mocking_bit_gen_base
absl::random_internal_mock_overload_set
absl::strings
absl::span
absl::type_traits
absl::utility
absl::variant
gmock
gtest
TESTONLY
)
absl_cc_test(
NAME
random_mock_distributions_test
SRCS
"mock_distributions_test.cc"
COPTS
${ABSL_TEST_COPTS}
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
absl::random_mocking_bit_gen
absl::random_random
gmock
gtest_main
)
absl_cc_test(
NAME
random_mocking_bit_gen_test
SRCS
"mocking_bit_gen_test.cc"
COPTS
${ABSL_TEST_COPTS}
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
DEPS
absl::random_bit_gen_ref
absl::random_mocking_bit_gen
absl::random_random
gmock
gtest_main
)
absl_cc_library(
NAME
random_distributions
SRCS
"discrete_distribution.cc"
......
//
// 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.
//
// -----------------------------------------------------------------------------
// File: bit_gen_ref.h
// -----------------------------------------------------------------------------
//
// This header defines a bit generator "reference" class, for use in interfaces
// that take both Abseil (e.g. `absl::BitGen`) and standard library (e.g.
// `std::mt19937`) bit generators.
#ifndef ABSL_RANDOM_BIT_GEN_REF_H_
#define ABSL_RANDOM_BIT_GEN_REF_H_
#include "absl/base/macros.h"
#include "absl/meta/type_traits.h"
#include "absl/random/internal/distribution_caller.h"
#include "absl/random/internal/fast_uniform_bits.h"
#include "absl/random/internal/mocking_bit_gen_base.h"
namespace absl {
namespace random_internal {
template <typename URBG, typename = void, typename = void, typename = void>
struct is_urbg : std::false_type {};
template <typename URBG>
struct is_urbg<
URBG,
absl::enable_if_t<std::is_same<
typename URBG::result_type,
typename std::decay<decltype((URBG::min)())>::type>::value>,
absl::enable_if_t<std::is_same<
typename URBG::result_type,
typename std::decay<decltype((URBG::max)())>::type>::value>,
absl::enable_if_t<std::is_same<
typename URBG::result_type,
typename std::decay<decltype(std::declval<URBG>()())>::type>::value>>
: std::true_type {};
} // namespace random_internal
// -----------------------------------------------------------------------------
// absl::BitGenRef
// -----------------------------------------------------------------------------
//
// `absl::BitGenRef` is a type-erasing class that provides a generator-agnostic
// non-owning "reference" interface for use in place of any specific uniform
// random bit generator (URBG). This class may be used for both Abseil
// (e.g. `absl::BitGen`, `absl::InsecureBitGen`) and Standard library (e.g
// `std::mt19937`, `std::minstd_rand`) bit generators.
//
// Like other reference classes, `absl::BitGenRef` does not own the
// underlying bit generator, and the underlying instance must outlive the
// `absl::BitGenRef`.
//
// `absl::BitGenRef` is particularly useful when used with an
// `absl::MockingBitGen` to test specific paths in functions which use random
// values.
//
// Example:
// void TakesBitGenRef(absl::BitGenRef gen) {
// int x = absl::Uniform<int>(gen, 0, 1000);
// }
//
class BitGenRef {
public:
using result_type = uint64_t;
BitGenRef(const absl::BitGenRef&) = default;
BitGenRef(absl::BitGenRef&&) = default;
BitGenRef& operator=(const absl::BitGenRef&) = default;
BitGenRef& operator=(absl::BitGenRef&&) = default;
template <typename URBG,
typename absl::enable_if_t<
(!std::is_same<URBG, BitGenRef>::value &&
random_internal::is_urbg<URBG>::value)>* = nullptr>
BitGenRef(URBG& gen) // NOLINT
: mocked_gen_ptr_(MakeMockPointer(&gen)),
t_erased_gen_ptr_(reinterpret_cast<uintptr_t>(&gen)),
generate_impl_fn_(ImplFn<URBG>) {
}
static constexpr result_type(min)() {
return (std::numeric_limits<result_type>::min)();
}
static constexpr result_type(max)() {
return (std::numeric_limits<result_type>::max)();
}
result_type operator()() { return generate_impl_fn_(t_erased_gen_ptr_); }
private:
friend struct absl::random_internal::DistributionCaller<absl::BitGenRef>;
using impl_fn = result_type (*)(uintptr_t);
using mocker_base_t = absl::random_internal::MockingBitGenBase;
// Convert an arbitrary URBG pointer into either a valid mocker_base_t
// pointer or a nullptr.
static inline mocker_base_t* MakeMockPointer(mocker_base_t* t) { return t; }
static inline mocker_base_t* MakeMockPointer(void*) { return nullptr; }
template <typename URBG>
static result_type ImplFn(uintptr_t ptr) {
// Ensure that the return values from operator() fill the entire
// range promised by result_type, min() and max().
absl::random_internal::FastUniformBits<result_type> fast_uniform_bits;
return fast_uniform_bits(*reinterpret_cast<URBG*>(ptr));
}
mocker_base_t* mocked_gen_ptr_;
uintptr_t t_erased_gen_ptr_;
impl_fn generate_impl_fn_;
};
namespace random_internal {
template <>
struct DistributionCaller<absl::BitGenRef> {
template <typename DistrT, typename FormatT, typename... Args>
static typename DistrT::result_type Call(absl::BitGenRef* gen_ref,
Args&&... args) {
auto* mock_ptr = gen_ref->mocked_gen_ptr_;
if (mock_ptr == nullptr) {
DistrT dist(std::forward<Args>(args)...);
return dist(*gen_ref);
} else {
return mock_ptr->template Call<DistrT, FormatT>(
std::forward<Args>(args)...);
}
}
};
} // namespace random_internal
} // namespace absl
#endif // ABSL_RANDOM_BIT_GEN_REF_H_
//
// 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.
//
#include "absl/random/bit_gen_ref.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/random/internal/sequence_urbg.h"
#include "absl/random/random.h"
namespace absl {
class ConstBitGen : public absl::random_internal::MockingBitGenBase {
bool CallImpl(const std::type_info&, void*, void* result) override {
*static_cast<int*>(result) = 42;
return true;
}
};
namespace random_internal {
template <>
struct DistributionCaller<ConstBitGen> {
template <typename DistrT, typename FormatT, typename... Args>
static typename DistrT::result_type Call(ConstBitGen* gen, Args&&... args) {
return gen->template Call<DistrT, FormatT>(std::forward<Args>(args)...);
}
};
} // namespace random_internal
namespace {
int FnTest(absl::BitGenRef gen_ref) { return absl::Uniform(gen_ref, 1, 7); }
template <typename T>
class BitGenRefTest : public testing::Test {};
using BitGenTypes =
::testing::Types<absl::BitGen, absl::InsecureBitGen, std::mt19937,
std::mt19937_64, std::minstd_rand>;
TYPED_TEST_SUITE(BitGenRefTest, BitGenTypes);
TYPED_TEST(BitGenRefTest, BasicTest) {
TypeParam gen;
auto x = FnTest(gen);
EXPECT_NEAR(x, 4, 3);
}
TYPED_TEST(BitGenRefTest, Copyable) {
TypeParam gen;
absl::BitGenRef gen_ref(gen);
FnTest(gen_ref); // Copy
}
TEST(BitGenRefTest, PassThroughEquivalence) {
// sequence_urbg returns 64-bit results.
absl::random_internal::sequence_urbg urbg(
{0x0003eb76f6f7f755ull, 0xFFCEA50FDB2F953Bull, 0xC332DDEFBE6C5AA5ull,
0x6558218568AB9702ull, 0x2AEF7DAD5B6E2F84ull, 0x1521B62829076170ull,
0xECDD4775619F1510ull, 0x13CCA830EB61BD96ull, 0x0334FE1EAA0363CFull,
0xB5735C904C70A239ull, 0xD59E9E0BCBAADE14ull, 0xEECC86BC60622CA7ull});
std::vector<uint64_t> output(12);
{
absl::BitGenRef view(urbg);
for (auto& v : output) {
v = view();
}
}
std::vector<uint64_t> expected(
{0x0003eb76f6f7f755ull, 0xFFCEA50FDB2F953Bull, 0xC332DDEFBE6C5AA5ull,
0x6558218568AB9702ull, 0x2AEF7DAD5B6E2F84ull, 0x1521B62829076170ull,
0xECDD4775619F1510ull, 0x13CCA830EB61BD96ull, 0x0334FE1EAA0363CFull,
0xB5735C904C70A239ull, 0xD59E9E0BCBAADE14ull, 0xEECC86BC60622CA7ull});
EXPECT_THAT(output, testing::Eq(expected));
}
TEST(BitGenRefTest, MockingBitGenBaseOverrides) {
ConstBitGen const_gen;
EXPECT_EQ(FnTest(const_gen), 42);
absl::BitGenRef gen_ref(const_gen);
EXPECT_EQ(FnTest(gen_ref), 42); // Copy
}
} // namespace
} // namespace absl
......@@ -493,6 +493,29 @@ cc_test(
],
)
cc_library(
name = "mocking_bit_gen_base",
hdrs = ["mocking_bit_gen_base.h"],
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
"//absl/random",
"//absl/strings",
],
)
cc_library(
name = "mock_overload_set",
testonly = 1,
hdrs = ["mock_overload_set.h"],
visibility = [
"//absl/random:__pkg__",
],
deps = [
"//absl/random:mocking_bit_gen",
"@com_google_googletest//:gtest",
],
)
cc_test(
name = "nonsecure_base_test",
size = "small",
......
//
// Copyright 2019 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.
#ifndef ABSL_RANDOM_INTERNAL_MOCK_OVERLOAD_SET_H_
#define ABSL_RANDOM_INTERNAL_MOCK_OVERLOAD_SET_H_
#include <type_traits>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/random/mocking_bit_gen.h"
namespace absl {
namespace random_internal {
template <typename DistrT, typename Fn>
struct MockSingleOverload;
// MockSingleOverload
//
// MockSingleOverload hooks in to gMock's `ON_CALL` and `EXPECT_CALL` macros.
// EXPECT_CALL(mock_single_overload, Call(...))` will expand to a call to
// `mock_single_overload.gmock_Call(...)`. Because expectations are stored on
// the MockingBitGen (an argument passed inside `Call(...)`), this forwards to
// arguments to Mocking::Register.
template <typename DistrT, typename Ret, typename... Args>
struct MockSingleOverload<DistrT, Ret(MockingBitGen&, Args...)> {
static_assert(std::is_same<typename DistrT::result_type, Ret>::value,
"Overload signature must have return type matching the "
"distributions result type.");
auto gmock_Call(
absl::MockingBitGen& gen, // NOLINT(google-runtime-references)
const ::testing::Matcher<Args>&... args)
-> decltype(gen.Register<DistrT, Args...>(args...)) {
return gen.Register<DistrT, Args...>(args...);
}
};
template <typename DistrT, typename Ret, typename Arg, typename... Args>
struct MockSingleOverload<DistrT, Ret(Arg, MockingBitGen&, Args...)> {
static_assert(std::is_same<typename DistrT::result_type, Ret>::value,
"Overload signature must have return type matching the "
"distributions result type.");
auto gmock_Call(
const ::testing::Matcher<Arg>& arg,
absl::MockingBitGen& gen, // NOLINT(google-runtime-references)
const ::testing::Matcher<Args>&... args)
-> decltype(gen.Register<DistrT, Arg, Args...>(arg, args...)) {
return gen.Register<DistrT, Arg, Args...>(arg, args...);
}
};
// MockOverloadSet
//
// MockOverloadSet takes a distribution and a collection of signatures and
// performs overload resolution amongst all the overloads. This makes
// `EXPECT_CALL(mock_overload_set, Call(...))` expand and do overload resolution
// correctly.
template <typename DistrT, typename... Signatures>
struct MockOverloadSet;
template <typename DistrT, typename Sig>
struct MockOverloadSet<DistrT, Sig> : public MockSingleOverload<DistrT, Sig> {
using MockSingleOverload<DistrT, Sig>::gmock_Call;
};
template <typename DistrT, typename FirstSig, typename... Rest>
struct MockOverloadSet<DistrT, FirstSig, Rest...>
: public MockSingleOverload<DistrT, FirstSig>,
public MockOverloadSet<DistrT, Rest...> {
using MockSingleOverload<DistrT, FirstSig>::gmock_Call;
using MockOverloadSet<DistrT, Rest...>::gmock_Call;
};
} // namespace random_internal
} // namespace absl
#endif // ABSL_RANDOM_INTERNAL_MOCK_OVERLOAD_SET_H_
//
// 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.
//
#ifndef ABSL_RANDOM_INTERNAL_MOCKING_BIT_GEN_BASE_H_
#define ABSL_RANDOM_INTERNAL_MOCKING_BIT_GEN_BASE_H_
#include <atomic>
#include <deque>
#include <string>
#include <typeinfo>
#include "absl/random/random.h"
#include "absl/strings/str_cat.h"
namespace absl {
namespace random_internal {
// MockingBitGenExpectationFormatter is invoked to format unsatisfied mocks
// and remaining results into a description string.
template <typename DistrT, typename FormatT>
struct MockingBitGenExpectationFormatter {
std::string operator()(absl::string_view args) {
return absl::StrCat(FormatT::FunctionName(), "(", args, ")");
}
};
// MockingBitGenCallFormatter is invoked to format each distribution call
// into a description string for the mock log.
template <typename DistrT, typename FormatT>
struct MockingBitGenCallFormatter {
std::string operator()(const DistrT& dist,
const typename DistrT::result_type& result) {
return absl::StrCat(
FormatT::FunctionName(), "(", FormatT::FormatArgs(dist), ") => {",
FormatT::FormatResults(absl::MakeSpan(&result, 1)), "}");
}
};
class MockingBitGenBase {
template <typename>
friend struct DistributionCaller;
using generator_type = absl::BitGen;
public:
// URBG interface
using result_type = generator_type::result_type;
static constexpr result_type(min)() { return (generator_type::min)(); }
static constexpr result_type(max)() { return (generator_type::max)(); }
result_type operator()() { return gen_(); }
MockingBitGenBase() : gen_(), observed_call_log_() {}
virtual ~MockingBitGenBase() = default;
protected:
const std::deque<std::string>& observed_call_log() {
return observed_call_log_;
}
// CallImpl is the type-erased virtual dispatch.
// The type of dist is always distribution<T>,
// The type of result is always distribution<T>::result_type.
virtual bool CallImpl(const std::type_info& distr_type, void* dist_args,
void* result) = 0;
template <typename DistrT, typename ArgTupleT>
static const std::type_info& GetTypeId() {
return typeid(std::pair<absl::decay_t<DistrT>, absl::decay_t<ArgTupleT>>);
}
// Call the generating distribution function.
// Invoked by DistributionCaller<>::Call<DistT, FormatT>.
// DistT is the distribution type.
// FormatT is the distribution formatter traits type.
template <typename DistrT, typename FormatT, typename... Args>
typename DistrT::result_type Call(Args&&... args) {
using distr_result_type = typename DistrT::result_type;
using ArgTupleT = std::tuple<absl::decay_t<Args>...>;
ArgTupleT arg_tuple(std::forward<Args>(args)...);
auto dist = absl::make_from_tuple<DistrT>(arg_tuple);
distr_result_type result{};
bool found_match =
CallImpl(GetTypeId<DistrT, ArgTupleT>(), &arg_tuple, &result);
if (!found_match) {
result = dist(gen_);
}
// TODO(asoffer): Forwarding the args through means we no longer need to
// extract them from the from the distribution in formatter traits. We can
// just StrJoin them.
observed_call_log_.push_back(
MockingBitGenCallFormatter<DistrT, FormatT>{}(dist, result));
return result;
}
private:
generator_type gen_;
std::deque<std::string> observed_call_log_;
}; // namespace random_internal
} // namespace random_internal
} // namespace absl
#endif // ABSL_RANDOM_INTERNAL_MOCKING_BIT_GEN_BASE_H_
// 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.
#include "absl/random/mock_distributions.h"
#include "gtest/gtest.h"
#include "absl/random/mocking_bit_gen.h"
#include "absl/random/random.h"
namespace {
using ::testing::Return;
TEST(MockDistributions, Examples) {
absl::MockingBitGen gen;
EXPECT_NE(absl::Uniform<int>(gen, 1, 1000000), 20);
EXPECT_CALL(absl::MockUniform<int>(), Call(gen, 1, 1000000))
.WillOnce(Return(20));
EXPECT_EQ(absl::Uniform<int>(gen, 1, 1000000), 20);
EXPECT_NE(absl::Uniform<double>(gen, 0.0, 100.0), 5.0);
EXPECT_CALL(absl::MockUniform<double>(), Call(gen, 0.0, 100.0))
.WillOnce(Return(5.0));
EXPECT_EQ(absl::Uniform<double>(gen, 0.0, 100.0), 5.0);
EXPECT_NE(absl::Exponential<double>(gen, 1.0), 42);
EXPECT_CALL(absl::MockExponential<double>(), Call(gen, 1.0))
.WillOnce(Return(42));
EXPECT_EQ(absl::Exponential<double>(gen, 1.0), 42);
EXPECT_NE(absl::Poisson<int>(gen, 1.0), 500);
EXPECT_CALL(absl::MockPoisson<int>(), Call(gen, 1.0)).WillOnce(Return(500));
EXPECT_EQ(absl::Poisson<int>(gen, 1.0), 500);
EXPECT_NE(absl::Bernoulli(gen, 0.000001), true);
EXPECT_CALL(absl::MockBernoulli(), Call(gen, 0.000001))
.WillOnce(Return(true));
EXPECT_EQ(absl::Bernoulli(gen, 0.000001), true);
EXPECT_NE(absl::Beta<double>(gen, 3.0, 2.0), 0.567);
EXPECT_CALL(absl::MockBeta<double>(), Call(gen, 3.0, 2.0))
.WillOnce(Return(0.567));
EXPECT_EQ(absl::Beta<double>(gen, 3.0, 2.0), 0.567);
EXPECT_NE(absl::Zipf<int>(gen, 1000000, 2.0, 1.0), 1221);
EXPECT_CALL(absl::MockZipf<int>(), Call(gen, 1000000, 2.0, 1.0))
.WillOnce(Return(1221));
EXPECT_EQ(absl::Zipf<int>(gen, 1000000, 2.0, 1.0), 1221);
EXPECT_NE(absl::Gaussian<double>(gen, 0.0, 1.0), 0.001);
EXPECT_CALL(absl::MockGaussian<double>(), Call(gen, 0.0, 1.0))
.WillOnce(Return(0.001));
EXPECT_EQ(absl::Gaussian<double>(gen, 0.0, 1.0), 0.001);
EXPECT_NE(absl::LogUniform<int>(gen, 0, 1000000, 2), 2040);
EXPECT_CALL(absl::MockLogUniform<int>(), Call(gen, 0, 1000000, 2))
.WillOnce(Return(2040));
EXPECT_EQ(absl::LogUniform<int>(gen, 0, 1000000, 2), 2040);
}
} // namespace
//
// 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.
//
#include "absl/random/mocking_bit_gen.h"
#include <string>
namespace absl {
MockingBitGen::~MockingBitGen() {
for (const auto& del : deleters_) {
del();
}
}
} // namespace absl
// 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 {
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;
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 FormatT, typename... Args>
static typename DistrT::result_type Call(absl::MockingBitGen* gen,
Args&&... args) {
return gen->template Call<DistrT, FormatT>(std::forward<Args>(args)...);
}
};
} // namespace random_internal
} // namespace absl
#endif // ABSL_RANDOM_MOCKING_BIT_GEN_H_
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment