| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 | // 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_BEGINnamespace 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_internalABSL_NAMESPACE_END}  // namespace absl#endif  // ABSL_RANDOM_MOCKING_BIT_GEN_H_
 |