aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Abseil Team <absl-team@google.com>2019-11-20 13:55:25 -0800
committerGravatar Andy Soffer <asoffer@google.com>2019-11-20 17:01:15 -0500
commitbcaae6009c0833b73c6fa7bdd972921d8081a724 (patch)
tree129b38c7e160276c10af9efa482536b05dd514fc
parent8ba96a8244bbe334d09542e92d566673a65c1f78 (diff)
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
-rw-r--r--absl/random/BUILD.bazel92
-rw-r--r--absl/random/CMakeLists.txt126
-rw-r--r--absl/random/bit_gen_ref.h151
-rw-r--r--absl/random/bit_gen_ref_test.cc99
-rw-r--r--absl/random/internal/BUILD.bazel23
-rw-r--r--absl/random/internal/mock_overload_set.h89
-rw-r--r--absl/random/internal/mocking_bit_gen_base.h118
-rw-r--r--absl/random/mock_distributions.h259
-rw-r--r--absl/random/mock_distributions_test.cc72
-rw-r--r--absl/random/mocking_bit_gen.cc28
-rw-r--r--absl/random/mocking_bit_gen.h194
-rw-r--r--absl/random/mocking_bit_gen_test.cc347
12 files changed, 1598 insertions, 0 deletions
diff --git a/absl/random/BUILD.bazel b/absl/random/BUILD.bazel
index c3520df..2585b39 100644
--- a/absl/random/BUILD.bazel
+++ b/absl/random/BUILD.bazel
@@ -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"],
diff --git a/absl/random/CMakeLists.txt b/absl/random/CMakeLists.txt
index 264a6f3..13e9635 100644
--- a/absl/random/CMakeLists.txt
+++ b/absl/random/CMakeLists.txt
@@ -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"
diff --git a/absl/random/bit_gen_ref.h b/absl/random/bit_gen_ref.h
new file mode 100644
index 0000000..00e904f
--- /dev/null
+++ b/absl/random/bit_gen_ref.h
@@ -0,0 +1,151 @@
+//
+// 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_
diff --git a/absl/random/bit_gen_ref_test.cc b/absl/random/bit_gen_ref_test.cc
new file mode 100644
index 0000000..bc02ca5
--- /dev/null
+++ b/absl/random/bit_gen_ref_test.cc
@@ -0,0 +1,99 @@
+//
+// 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
diff --git a/absl/random/internal/BUILD.bazel b/absl/random/internal/BUILD.bazel
index cc9bc01..5026e2b 100644
--- a/absl/random/internal/BUILD.bazel
+++ b/absl/random/internal/BUILD.bazel
@@ -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",
diff --git a/absl/random/internal/mock_overload_set.h b/absl/random/internal/mock_overload_set.h
new file mode 100644
index 0000000..539313d
--- /dev/null
+++ b/absl/random/internal/mock_overload_set.h
@@ -0,0 +1,89 @@
+//
+// 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_
diff --git a/absl/random/internal/mocking_bit_gen_base.h b/absl/random/internal/mocking_bit_gen_base.h
new file mode 100644
index 0000000..aff2ba6
--- /dev/null
+++ b/absl/random/internal/mocking_bit_gen_base.h
@@ -0,0 +1,118 @@
+//
+// 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_
diff --git a/absl/random/mock_distributions.h b/absl/random/mock_distributions.h
new file mode 100644
index 0000000..1af98a2
--- /dev/null
+++ b/absl/random/mock_distributions.h
@@ -0,0 +1,259 @@
+// 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: mock_distributions.h
+// -----------------------------------------------------------------------------
+//
+// This file contains mock distribution functions for use alongside an
+// `absl::MockingBitGen` object within the Googletest testing framework. Such
+// mocks are useful to provide deterministic values as return values within
+// (otherwise random) Abseil distribution functions.
+//
+// The return type of each function is a mock expectation object which
+// is used to set the match result.
+//
+// More information about the Googletest testing framework is available at
+// https://github.com/google/googletest
+//
+// Example:
+//
+// absl::MockingBitGen mock;
+// EXPECT_CALL(absl::MockUniform<int>(), Call(mock, 1, 1000))
+// .WillRepeatedly(testing::ReturnRoundRobin({20, 40}));
+//
+// EXPECT_EQ(absl::Uniform<int>(gen, 1, 1000), 20);
+// EXPECT_EQ(absl::Uniform<int>(gen, 1, 1000), 40);
+// EXPECT_EQ(absl::Uniform<int>(gen, 1, 1000), 20);
+// EXPECT_EQ(absl::Uniform<int>(gen, 1, 1000), 40);
+
+#ifndef ABSL_RANDOM_MOCK_DISTRIBUTIONS_H_
+#define ABSL_RANDOM_MOCK_DISTRIBUTIONS_H_
+
+#include <limits>
+#include <type_traits>
+#include <utility>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/meta/type_traits.h"
+#include "absl/random/distributions.h"
+#include "absl/random/internal/mock_overload_set.h"
+#include "absl/random/mocking_bit_gen.h"
+
+namespace absl {
+
+// -----------------------------------------------------------------------------
+// absl::MockUniform
+// -----------------------------------------------------------------------------
+//
+// Matches calls to absl::Uniform.
+//
+// `absl::MockUniform` is a class template used in conjunction with Googletest's
+// `ON_CALL()` and `EXPECT_CALL()` macros. To use it, default-construct an
+// instance of it inside `ON_CALL()` or `EXPECT_CALL()`, and use `Call(...)` the
+// same way one would define mocks on a Googletest `MockFunction()`.
+//
+// Example:
+//
+// absl::MockingBitGen mock;
+// EXPECT_CALL(absl::MockUniform<uint32_t>(), Call(mock))
+// .WillOnce(Return(123456));
+// auto x = absl::Uniform<uint32_t>(mock);
+// assert(x == 123456)
+//
+template <typename R>
+using MockUniform = random_internal::MockOverloadSet<
+ random_internal::UniformDistributionWrapper<R>,
+ R(IntervalClosedOpenTag, MockingBitGen&, R, R),
+ R(IntervalClosedClosedTag, MockingBitGen&, R, R),
+ R(IntervalOpenOpenTag, MockingBitGen&, R, R),
+ R(IntervalOpenClosedTag, MockingBitGen&, R, R), R(MockingBitGen&, R, R),
+ R(MockingBitGen&)>;
+
+// -----------------------------------------------------------------------------
+// absl::MockBernoulli
+// -----------------------------------------------------------------------------
+//
+// Matches calls to absl::Bernoulli.
+//
+// `absl::MockBernoulli` is a class used in conjunction with Googletest's
+// `ON_CALL()` and `EXPECT_CALL()` macros. To use it, default-construct an
+// instance of it inside `ON_CALL()` or `EXPECT_CALL()`, and use `Call(...)` the
+// same way one would define mocks on a Googletest `MockFunction()`.
+//
+// Example:
+//
+// absl::MockingBitGen mock;
+// EXPECT_CALL(absl::MockBernoulli(), Call(mock, testing::_))
+// .WillOnce(Return(false));
+// assert(absl::Bernoulli(mock, 0.5) == false);
+//
+using MockBernoulli =
+ random_internal::MockOverloadSet<absl::bernoulli_distribution,
+ bool(MockingBitGen&, double)>;
+
+// -----------------------------------------------------------------------------
+// absl::MockBeta
+// -----------------------------------------------------------------------------
+//
+// Matches calls to absl::Beta.
+//
+// `absl::MockBeta` is a class used in conjunction with Googletest's `ON_CALL()`
+// and `EXPECT_CALL()` macros. To use it, default-construct an instance of it
+// inside `ON_CALL()` or `EXPECT_CALL()`, and use `Call(...)` the same way one
+// would define mocks on a Googletest `MockFunction()`.
+//
+// Example:
+//
+// absl::MockingBitGen mock;
+// EXPECT_CALL(absl::MockBeta(), Call(mock, 3.0, 2.0))
+// .WillOnce(Return(0.567));
+// auto x = absl::Beta<double>(mock, 3.0, 2.0);
+// assert(x == 0.567);
+//
+template <typename RealType>
+using MockBeta =
+ random_internal::MockOverloadSet<absl::beta_distribution<RealType>,
+ RealType(MockingBitGen&, RealType,
+ RealType)>;
+
+// -----------------------------------------------------------------------------
+// absl::MockExponential
+// -----------------------------------------------------------------------------
+//
+// Matches calls to absl::Exponential.
+//
+// `absl::MockExponential` is a class template used in conjunction with
+// Googletest's `ON_CALL()` and `EXPECT_CALL()` macros. To use it,
+// default-construct an instance of it inside `ON_CALL()` or `EXPECT_CALL()`,
+// and use `Call(...)` the same way one would define mocks on a
+// Googletest `MockFunction()`.
+//
+// Example:
+//
+// absl::MockingBitGen mock;
+// EXPECT_CALL(absl::MockExponential<double>(), Call(mock, 0.5))
+// .WillOnce(Return(12.3456789));
+// auto x = absl::Exponential<double>(mock, 0.5);
+// assert(x == 12.3456789)
+//
+template <typename RealType>
+using MockExponential =
+ random_internal::MockOverloadSet<absl::exponential_distribution<RealType>,
+ RealType(MockingBitGen&, RealType)>;
+
+// -----------------------------------------------------------------------------
+// absl::MockGaussian
+// -----------------------------------------------------------------------------
+//
+// Matches calls to absl::Gaussian.
+//
+// `absl::MockGaussian` is a class template used in conjunction with
+// Googletest's `ON_CALL()` and `EXPECT_CALL()` macros. To use it,
+// default-construct an instance of it inside `ON_CALL()` or `EXPECT_CALL()`,
+// and use `Call(...)` the same way one would define mocks on a
+// Googletest `MockFunction()`.
+//
+// Example:
+//
+// absl::MockingBitGen mock;
+// EXPECT_CALL(absl::MockGaussian<double>(), Call(mock, 16.3, 3.3))
+// .WillOnce(Return(12.3456789));
+// auto x = absl::Gaussian<double>(mock, 16.3, 3.3);
+// assert(x == 12.3456789)
+//
+template <typename RealType>
+using MockGaussian =
+ random_internal::MockOverloadSet<absl::gaussian_distribution<RealType>,
+ RealType(MockingBitGen&, RealType,
+ RealType)>;
+
+// -----------------------------------------------------------------------------
+// absl::MockLogUniform
+// -----------------------------------------------------------------------------
+//
+// Matches calls to absl::LogUniform.
+//
+// `absl::MockLogUniform` is a class template used in conjunction with
+// Googletest's `ON_CALL()` and `EXPECT_CALL()` macros. To use it,
+// default-construct an instance of it inside `ON_CALL()` or `EXPECT_CALL()`,
+// and use `Call(...)` the same way one would define mocks on a
+// Googletest `MockFunction()`.
+//
+// Example:
+//
+// absl::MockingBitGen mock;
+// EXPECT_CALL(absl::MockLogUniform<int>(), Call(mock, 10, 10000, 10))
+// .WillOnce(Return(1221));
+// auto x = absl::LogUniform<int>(mock, 10, 10000, 10);
+// assert(x == 1221)
+//
+template <typename IntType>
+using MockLogUniform = random_internal::MockOverloadSet<
+ absl::log_uniform_int_distribution<IntType>,
+ IntType(MockingBitGen&, IntType, IntType, IntType)>;
+
+// -----------------------------------------------------------------------------
+// absl::MockPoisson
+// -----------------------------------------------------------------------------
+//
+// Matches calls to absl::Poisson.
+//
+// `absl::MockPoisson` is a class template used in conjunction with Googletest's
+// `ON_CALL()` and `EXPECT_CALL()` macros. To use it, default-construct an
+// instance of it inside `ON_CALL()` or `EXPECT_CALL()`, and use `Call(...)` the
+// same way one would define mocks on a Googletest `MockFunction()`.
+//
+// Example:
+//
+// absl::MockingBitGen mock;
+// EXPECT_CALL(absl::MockPoisson<int>(), Call(mock, 2.0))
+// .WillOnce(Return(1221));
+// auto x = absl::Poisson<int>(mock, 2.0);
+// assert(x == 1221)
+//
+template <typename IntType>
+using MockPoisson =
+ random_internal::MockOverloadSet<absl::poisson_distribution<IntType>,
+ IntType(MockingBitGen&, double)>;
+
+// -----------------------------------------------------------------------------
+// absl::MockZipf
+// -----------------------------------------------------------------------------
+//
+// Matches calls to absl::Zipf.
+//
+// `absl::MockZipf` is a class template used in conjunction with Googletest's
+// `ON_CALL()` and `EXPECT_CALL()` macros. To use it, default-construct an
+// instance of it inside `ON_CALL()` or `EXPECT_CALL()`, and use `Call(...)` the
+// same way one would define mocks on a Googletest `MockFunction()`.
+//
+// Example:
+//
+// absl::MockingBitGen mock;
+// EXPECT_CALL(absl::MockZipf<int>(), Call(mock, 1000000, 2.0, 1.0))
+// .WillOnce(Return(1221));
+// auto x = absl::Zipf<int>(mock, 1000000, 2.0, 1.0);
+// assert(x == 1221)
+//
+template <typename IntType>
+using MockZipf =
+ random_internal::MockOverloadSet<absl::zipf_distribution<IntType>,
+ IntType(MockingBitGen&, IntType, double,
+ double)>;
+
+} // namespace absl
+
+#endif // ABSL_RANDOM_MOCK_DISTRIBUTIONS_H_
diff --git a/absl/random/mock_distributions_test.cc b/absl/random/mock_distributions_test.cc
new file mode 100644
index 0000000..de23baf
--- /dev/null
+++ b/absl/random/mock_distributions_test.cc
@@ -0,0 +1,72 @@
+// 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
diff --git a/absl/random/mocking_bit_gen.cc b/absl/random/mocking_bit_gen.cc
new file mode 100644
index 0000000..7314452
--- /dev/null
+++ b/absl/random/mocking_bit_gen.cc
@@ -0,0 +1,28 @@
+//
+// 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
diff --git a/absl/random/mocking_bit_gen.h b/absl/random/mocking_bit_gen.h
new file mode 100644
index 0000000..d1b524a
--- /dev/null
+++ b/absl/random/mocking_bit_gen.h
@@ -0,0 +1,194 @@
+// 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_
diff --git a/absl/random/mocking_bit_gen_test.cc b/absl/random/mocking_bit_gen_test.cc
new file mode 100644
index 0000000..dcf74fd
--- /dev/null
+++ b/absl/random/mocking_bit_gen_test.cc
@@ -0,0 +1,347 @@
+//
+// 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 <numeric>
+#include <random>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest-spi.h"
+#include "gtest/gtest.h"
+#include "absl/random/bit_gen_ref.h"
+#include "absl/random/mock_distributions.h"
+#include "absl/random/random.h"
+
+namespace {
+using ::testing::Ne;
+using ::testing::Return;
+
+TEST(BasicMocking, AllDistributionsAreOverridable) {
+ 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::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);
+}
+
+TEST(BasicMocking, OnDistribution) {
+ absl::MockingBitGen gen;
+
+ EXPECT_NE(absl::Uniform<int>(gen, 1, 1000000), 20);
+ ON_CALL(absl::MockUniform<int>(), Call(gen, 1, 1000000))
+ .WillByDefault(Return(20));
+ EXPECT_EQ(absl::Uniform<int>(gen, 1, 1000000), 20);
+
+ EXPECT_NE(absl::Uniform<double>(gen, 0.0, 100.0), 5.0);
+ ON_CALL(absl::MockUniform<double>(), Call(gen, 0.0, 100.0))
+ .WillByDefault(Return(5.0));
+ EXPECT_EQ(absl::Uniform<double>(gen, 0.0, 100.0), 5.0);
+
+ EXPECT_NE(absl::Exponential<double>(gen, 1.0), 42);
+ ON_CALL(absl::MockExponential<double>(), Call(gen, 1.0))
+ .WillByDefault(Return(42));
+ EXPECT_EQ(absl::Exponential<double>(gen, 1.0), 42);
+
+ EXPECT_NE(absl::Poisson<int>(gen, 1.0), 500);
+ ON_CALL(absl::MockPoisson<int>(), Call(gen, 1.0)).WillByDefault(Return(500));
+ EXPECT_EQ(absl::Poisson<int>(gen, 1.0), 500);
+
+ EXPECT_NE(absl::Bernoulli(gen, 0.000001), true);
+ ON_CALL(absl::MockBernoulli(), Call(gen, 0.000001))
+ .WillByDefault(Return(true));
+ EXPECT_EQ(absl::Bernoulli(gen, 0.000001), true);
+
+ EXPECT_NE(absl::Zipf<int>(gen, 1000000, 2.0, 1.0), 1221);
+ ON_CALL(absl::MockZipf<int>(), Call(gen, 1000000, 2.0, 1.0))
+ .WillByDefault(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);
+ ON_CALL(absl::MockGaussian<double>(), Call(gen, 0.0, 1.0))
+ .WillByDefault(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);
+ ON_CALL(absl::MockLogUniform<int>(), Call(gen, 0, 1000000, 2))
+ .WillByDefault(Return(2040));
+ EXPECT_EQ(absl::LogUniform<int>(gen, 0, 1000000, 2), 2040);
+}
+
+TEST(BasicMocking, GMockMatchers) {
+ absl::MockingBitGen gen;
+
+ EXPECT_NE(absl::Zipf<int>(gen, 1000000, 2.0, 1.0), 1221);
+ ON_CALL(absl::MockZipf<int>(), Call(gen, 1000000, 2.0, 1.0))
+ .WillByDefault(Return(1221));
+ EXPECT_EQ(absl::Zipf<int>(gen, 1000000, 2.0, 1.0), 1221);
+}
+
+TEST(BasicMocking, OverridesWithMultipleGMockExpectations) {
+ absl::MockingBitGen gen;
+
+ EXPECT_CALL(absl::MockUniform<int>(), Call(gen, 1, 10000))
+ .WillOnce(Return(20))
+ .WillOnce(Return(40))
+ .WillOnce(Return(60));
+ EXPECT_EQ(absl::Uniform(gen, 1, 10000), 20);
+ EXPECT_EQ(absl::Uniform(gen, 1, 10000), 40);
+ EXPECT_EQ(absl::Uniform(gen, 1, 10000), 60);
+}
+
+TEST(BasicMocking, DefaultArgument) {
+ absl::MockingBitGen gen;
+
+ ON_CALL(absl::MockExponential<double>(), Call(gen, 1.0))
+ .WillByDefault(Return(200));
+
+ EXPECT_EQ(absl::Exponential<double>(gen), 200);
+ EXPECT_EQ(absl::Exponential<double>(gen, 1.0), 200);
+}
+
+TEST(BasicMocking, MultipleGenerators) {
+ auto get_value = [](absl::BitGenRef gen_ref) {
+ return absl::Uniform(gen_ref, 1, 1000000);
+ };
+ absl::MockingBitGen unmocked_generator;
+ absl::MockingBitGen mocked_with_3;
+ absl::MockingBitGen mocked_with_11;
+
+ EXPECT_CALL(absl::MockUniform<int>(), Call(mocked_with_3, 1, 1000000))
+ .WillOnce(Return(3))
+ .WillRepeatedly(Return(17));
+ EXPECT_CALL(absl::MockUniform<int>(), Call(mocked_with_11, 1, 1000000))
+ .WillOnce(Return(11))
+ .WillRepeatedly(Return(17));
+
+ // Ensure that unmocked generator generates neither value.
+ int unmocked_value = get_value(unmocked_generator);
+ EXPECT_NE(unmocked_value, 3);
+ EXPECT_NE(unmocked_value, 11);
+ // Mocked generators should generate their mocked values.
+ EXPECT_EQ(get_value(mocked_with_3), 3);
+ EXPECT_EQ(get_value(mocked_with_11), 11);
+ // Ensure that the mocks have expired.
+ EXPECT_NE(get_value(mocked_with_3), 3);
+ EXPECT_NE(get_value(mocked_with_11), 11);
+}
+
+TEST(BasicMocking, MocksNotTrigeredForIncorrectTypes) {
+ absl::MockingBitGen gen;
+ EXPECT_CALL(absl::MockUniform<uint32_t>(), Call(gen)).WillOnce(Return(42));
+
+ EXPECT_NE(absl::Uniform<uint16_t>(gen), 42); // Not mocked
+ EXPECT_EQ(absl::Uniform<uint32_t>(gen), 42); // Mock triggered
+}
+
+TEST(BasicMocking, FailsOnUnsatisfiedMocks) {
+ EXPECT_NONFATAL_FAILURE(
+ []() {
+ absl::MockingBitGen gen;
+ EXPECT_CALL(absl::MockExponential<double>(), Call(gen, 1.0))
+ .WillOnce(Return(3.0));
+ // Does not call absl::Exponential().
+ }(),
+ "unsatisfied and active");
+}
+
+TEST(OnUniform, RespectsUniformIntervalSemantics) {
+ absl::MockingBitGen gen;
+
+ EXPECT_CALL(absl::MockUniform<int>(),
+ Call(absl::IntervalClosed, gen, 1, 1000000))
+ .WillOnce(Return(301));
+ EXPECT_NE(absl::Uniform(gen, 1, 1000000), 301); // Not mocked
+ EXPECT_EQ(absl::Uniform(absl::IntervalClosed, gen, 1, 1000000), 301);
+}
+
+TEST(OnUniform, RespectsNoArgUnsignedShorthand) {
+ absl::MockingBitGen gen;
+ EXPECT_CALL(absl::MockUniform<uint32_t>(), Call(gen)).WillOnce(Return(42));
+ EXPECT_EQ(absl::Uniform<uint32_t>(gen), 42);
+}
+
+TEST(RepeatedlyModifier, ForceSnakeEyesForManyDice) {
+ auto roll_some_dice = [](absl::BitGenRef gen_ref) {
+ std::vector<int> results(16);
+ for (auto& r : results) {
+ r = absl::Uniform(absl::IntervalClosed, gen_ref, 1, 6);
+ }
+ return results;
+ };
+ std::vector<int> results;
+ absl::MockingBitGen gen;
+
+ // Without any mocked calls, not all dice roll a "6".
+ results = roll_some_dice(gen);
+ EXPECT_LT(std::accumulate(std::begin(results), std::end(results), 0),
+ results.size() * 6);
+
+ // Verify that we can force all "6"-rolls, with mocking.
+ ON_CALL(absl::MockUniform<int>(), Call(absl::IntervalClosed, gen, 1, 6))
+ .WillByDefault(Return(6));
+ results = roll_some_dice(gen);
+ EXPECT_EQ(std::accumulate(std::begin(results), std::end(results), 0),
+ results.size() * 6);
+}
+
+TEST(WillOnce, DistinctCounters) {
+ absl::MockingBitGen gen;
+ EXPECT_CALL(absl::MockUniform<int>(), Call(gen, 1, 1000000))
+ .Times(3)
+ .WillRepeatedly(Return(0));
+ EXPECT_CALL(absl::MockUniform<int>(), Call(gen, 1000001, 2000000))
+ .Times(3)
+ .WillRepeatedly(Return(1));
+ EXPECT_EQ(absl::Uniform(gen, 1000001, 2000000), 1);
+ EXPECT_EQ(absl::Uniform(gen, 1, 1000000), 0);
+ EXPECT_EQ(absl::Uniform(gen, 1000001, 2000000), 1);
+ EXPECT_EQ(absl::Uniform(gen, 1, 1000000), 0);
+ EXPECT_EQ(absl::Uniform(gen, 1000001, 2000000), 1);
+ EXPECT_EQ(absl::Uniform(gen, 1, 1000000), 0);
+}
+
+TEST(TimesModifier, ModifierSaturatesAndExpires) {
+ EXPECT_NONFATAL_FAILURE(
+ []() {
+ absl::MockingBitGen gen;
+ EXPECT_CALL(absl::MockUniform<int>(), Call(gen, 1, 1000000))
+ .Times(3)
+ .WillRepeatedly(Return(15))
+ .RetiresOnSaturation();
+
+ EXPECT_EQ(absl::Uniform(gen, 1, 1000000), 15);
+ EXPECT_EQ(absl::Uniform(gen, 1, 1000000), 15);
+ EXPECT_EQ(absl::Uniform(gen, 1, 1000000), 15);
+ // Times(3) has expired - Should get a different value now.
+
+ EXPECT_NE(absl::Uniform(gen, 1, 1000000), 15);
+ }(),
+ "");
+}
+
+TEST(TimesModifier, Times0) {
+ absl::MockingBitGen gen;
+ EXPECT_CALL(absl::MockBernoulli(), Call(gen, 0.0)).Times(0);
+ EXPECT_CALL(absl::MockPoisson<int>(), Call(gen, 1.0)).Times(0);
+}
+
+TEST(AnythingMatcher, MatchesAnyArgument) {
+ using testing::_;
+
+ {
+ absl::MockingBitGen gen;
+ ON_CALL(absl::MockUniform<int>(), Call(absl::IntervalClosed, gen, _, 1000))
+ .WillByDefault(Return(11));
+ ON_CALL(absl::MockUniform<int>(),
+ Call(absl::IntervalClosed, gen, _, Ne(1000)))
+ .WillByDefault(Return(99));
+
+ EXPECT_EQ(absl::Uniform(absl::IntervalClosed, gen, 10, 1000000), 99);
+ EXPECT_EQ(absl::Uniform(absl::IntervalClosed, gen, 10, 1000), 11);
+ }
+
+ {
+ absl::MockingBitGen gen;
+ ON_CALL(absl::MockUniform<int>(), Call(gen, 1, _))
+ .WillByDefault(Return(25));
+ ON_CALL(absl::MockUniform<int>(), Call(gen, Ne(1), _))
+ .WillByDefault(Return(99));
+ EXPECT_EQ(absl::Uniform(gen, 3, 1000000), 99);
+ EXPECT_EQ(absl::Uniform(gen, 1, 1000000), 25);
+ }
+
+ {
+ absl::MockingBitGen gen;
+ ON_CALL(absl::MockUniform<int>(), Call(gen, _, _))
+ .WillByDefault(Return(145));
+ EXPECT_EQ(absl::Uniform(gen, 1, 1000), 145);
+ EXPECT_EQ(absl::Uniform(gen, 10, 1000), 145);
+ EXPECT_EQ(absl::Uniform(gen, 100, 1000), 145);
+ }
+}
+
+TEST(AnythingMatcher, WithWillByDefault) {
+ using testing::_;
+ absl::MockingBitGen gen;
+ std::vector<int> values = {11, 22, 33, 44, 55, 66, 77, 88, 99, 1010};
+
+ ON_CALL(absl::MockUniform<size_t>(), Call(gen, 0, _))
+ .WillByDefault(Return(0));
+ for (int i = 0; i < 100; i++) {
+ auto& elem = values[absl::Uniform(gen, 0u, values.size())];
+ EXPECT_EQ(elem, 11);
+ }
+}
+
+TEST(BasicMocking, WillByDefaultWithArgs) {
+ using testing::_;
+
+ absl::MockingBitGen gen;
+ ON_CALL(absl::MockPoisson<int>(), Call(gen, _))
+ .WillByDefault(
+ [](double lambda) { return static_cast<int>(lambda * 10); });
+ EXPECT_EQ(absl::Poisson<int>(gen, 1.7), 17);
+ EXPECT_EQ(absl::Poisson<int>(gen, 0.03), 0);
+}
+
+TEST(MockingBitGen, InSequenceSucceedsInOrder) {
+ absl::MockingBitGen gen;
+
+ testing::InSequence seq;
+
+ EXPECT_CALL(absl::MockPoisson<int>(), Call(gen, 1.0)).WillOnce(Return(3));
+ EXPECT_CALL(absl::MockPoisson<int>(), Call(gen, 2.0)).WillOnce(Return(4));
+
+ EXPECT_EQ(absl::Poisson<int>(gen, 1.0), 3);
+ EXPECT_EQ(absl::Poisson<int>(gen, 2.0), 4);
+}
+
+} // namespace