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
This commit is contained in:
		
							parent
							
								
									8ba96a8244
								
							
						
					
					
						commit
						bcaae6009c
					
				
					 12 changed files with 1598 additions and 0 deletions
				
			
		
							
								
								
									
										194
									
								
								absl/random/mocking_bit_gen.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										194
									
								
								absl/random/mocking_bit_gen.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -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_
 | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue