explicit_seed_seq_test.cc 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. // Copyright 2017 The Abseil Authors.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // https://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "absl/random/internal/explicit_seed_seq.h"
  15. #include <iterator>
  16. #include <random>
  17. #include <utility>
  18. #include "gmock/gmock.h"
  19. #include "gtest/gtest.h"
  20. #include "absl/random/seed_sequences.h"
  21. namespace {
  22. using ::absl::random_internal::ExplicitSeedSeq;
  23. template <typename Sseq>
  24. bool ConformsToInterface() {
  25. // Check that the SeedSequence can be default-constructed.
  26. { Sseq default_constructed_seq; }
  27. // Check that the SeedSequence can be constructed with two iterators.
  28. {
  29. uint32_t init_array[] = {1, 3, 5, 7, 9};
  30. Sseq iterator_constructed_seq(init_array, &init_array[5]);
  31. }
  32. // Check that the SeedSequence can be std::initializer_list-constructed.
  33. { Sseq list_constructed_seq = {1, 3, 5, 7, 9, 11, 13}; }
  34. // Check that param() and size() return state provided to constructor.
  35. {
  36. uint32_t init_array[] = {1, 2, 3, 4, 5};
  37. Sseq seq(init_array, &init_array[ABSL_ARRAYSIZE(init_array)]);
  38. EXPECT_EQ(seq.size(), ABSL_ARRAYSIZE(init_array));
  39. uint32_t state_array[ABSL_ARRAYSIZE(init_array)];
  40. seq.param(state_array);
  41. for (int i = 0; i < ABSL_ARRAYSIZE(state_array); i++) {
  42. EXPECT_EQ(state_array[i], i + 1);
  43. }
  44. }
  45. // Check for presence of generate() method.
  46. {
  47. Sseq seq;
  48. uint32_t seeds[5];
  49. seq.generate(seeds, &seeds[ABSL_ARRAYSIZE(seeds)]);
  50. }
  51. return true;
  52. }
  53. } // namespace
  54. TEST(SeedSequences, CheckInterfaces) {
  55. // Control case
  56. EXPECT_TRUE(ConformsToInterface<std::seed_seq>());
  57. // Abseil classes
  58. EXPECT_TRUE(ConformsToInterface<ExplicitSeedSeq>());
  59. }
  60. TEST(ExplicitSeedSeq, DefaultConstructorGeneratesZeros) {
  61. const size_t kNumBlocks = 128;
  62. uint32_t outputs[kNumBlocks];
  63. ExplicitSeedSeq seq;
  64. seq.generate(outputs, &outputs[kNumBlocks]);
  65. for (uint32_t& seed : outputs) {
  66. EXPECT_EQ(seed, 0);
  67. }
  68. }
  69. TEST(ExplicitSeeqSeq, SeedMaterialIsForwardedIdentically) {
  70. const size_t kNumBlocks = 128;
  71. uint32_t seed_material[kNumBlocks];
  72. std::random_device urandom{"/dev/urandom"};
  73. for (uint32_t& seed : seed_material) {
  74. seed = urandom();
  75. }
  76. ExplicitSeedSeq seq(seed_material, &seed_material[kNumBlocks]);
  77. // Check that output is same as seed-material provided to constructor.
  78. {
  79. const size_t kNumGenerated = kNumBlocks / 2;
  80. uint32_t outputs[kNumGenerated];
  81. seq.generate(outputs, &outputs[kNumGenerated]);
  82. for (size_t i = 0; i < kNumGenerated; i++) {
  83. EXPECT_EQ(outputs[i], seed_material[i]);
  84. }
  85. }
  86. // Check that SeedSequence is stateless between invocations: Despite the last
  87. // invocation of generate() only consuming half of the input-entropy, the same
  88. // entropy will be recycled for the next invocation.
  89. {
  90. const size_t kNumGenerated = kNumBlocks;
  91. uint32_t outputs[kNumGenerated];
  92. seq.generate(outputs, &outputs[kNumGenerated]);
  93. for (size_t i = 0; i < kNumGenerated; i++) {
  94. EXPECT_EQ(outputs[i], seed_material[i]);
  95. }
  96. }
  97. // Check that when more seed-material is asked for than is provided, nonzero
  98. // values are still written.
  99. {
  100. const size_t kNumGenerated = kNumBlocks * 2;
  101. uint32_t outputs[kNumGenerated];
  102. seq.generate(outputs, &outputs[kNumGenerated]);
  103. for (size_t i = 0; i < kNumGenerated; i++) {
  104. EXPECT_EQ(outputs[i], seed_material[i % kNumBlocks]);
  105. }
  106. }
  107. }
  108. TEST(ExplicitSeedSeq, CopyAndMoveConstructors) {
  109. using testing::Each;
  110. using testing::Eq;
  111. using testing::Not;
  112. using testing::Pointwise;
  113. uint32_t entropy[4];
  114. std::random_device urandom("/dev/urandom");
  115. for (uint32_t& entry : entropy) {
  116. entry = urandom();
  117. }
  118. ExplicitSeedSeq seq_from_entropy(std::begin(entropy), std::end(entropy));
  119. // Copy constructor.
  120. {
  121. ExplicitSeedSeq seq_copy(seq_from_entropy);
  122. EXPECT_EQ(seq_copy.size(), seq_from_entropy.size());
  123. std::vector<uint32_t> seeds_1;
  124. seeds_1.resize(1000, 0);
  125. std::vector<uint32_t> seeds_2;
  126. seeds_2.resize(1000, 1);
  127. seq_from_entropy.generate(seeds_1.begin(), seeds_1.end());
  128. seq_copy.generate(seeds_2.begin(), seeds_2.end());
  129. EXPECT_THAT(seeds_1, Pointwise(Eq(), seeds_2));
  130. }
  131. // Assignment operator.
  132. {
  133. for (uint32_t& entry : entropy) {
  134. entry = urandom();
  135. }
  136. ExplicitSeedSeq another_seq(std::begin(entropy), std::end(entropy));
  137. std::vector<uint32_t> seeds_1;
  138. seeds_1.resize(1000, 0);
  139. std::vector<uint32_t> seeds_2;
  140. seeds_2.resize(1000, 0);
  141. seq_from_entropy.generate(seeds_1.begin(), seeds_1.end());
  142. another_seq.generate(seeds_2.begin(), seeds_2.end());
  143. // Assert precondition: Sequences generated by seed-sequences are not equal.
  144. EXPECT_THAT(seeds_1, Not(Pointwise(Eq(), seeds_2)));
  145. // Apply the assignment-operator.
  146. another_seq = seq_from_entropy;
  147. // Re-generate seeds.
  148. seq_from_entropy.generate(seeds_1.begin(), seeds_1.end());
  149. another_seq.generate(seeds_2.begin(), seeds_2.end());
  150. // Seeds generated by seed-sequences should now be equal.
  151. EXPECT_THAT(seeds_1, Pointwise(Eq(), seeds_2));
  152. }
  153. // Move constructor.
  154. {
  155. // Get seeds from seed-sequence constructed from entropy.
  156. std::vector<uint32_t> seeds_1;
  157. seeds_1.resize(1000, 0);
  158. seq_from_entropy.generate(seeds_1.begin(), seeds_1.end());
  159. // Apply move-constructor move the sequence to another instance.
  160. absl::random_internal::ExplicitSeedSeq moved_seq(
  161. std::move(seq_from_entropy));
  162. std::vector<uint32_t> seeds_2;
  163. seeds_2.resize(1000, 1);
  164. moved_seq.generate(seeds_2.begin(), seeds_2.end());
  165. // Verify that seeds produced by moved-instance are the same as original.
  166. EXPECT_THAT(seeds_1, Pointwise(Eq(), seeds_2));
  167. // Verify that the moved-from instance now behaves like a
  168. // default-constructed instance.
  169. EXPECT_EQ(seq_from_entropy.size(), 0);
  170. seq_from_entropy.generate(seeds_1.begin(), seeds_1.end());
  171. EXPECT_THAT(seeds_1, Each(Eq(0)));
  172. }
  173. }
  174. TEST(ExplicitSeedSeq, StdURBGGoldenTests) {
  175. // Verify that for std::- URBG instances the results are stable across
  176. // platforms (these should have deterministic output).
  177. {
  178. ExplicitSeedSeq seed_sequence{12, 34, 56};
  179. std::minstd_rand rng(seed_sequence);
  180. std::minstd_rand::result_type values[4] = {rng(), rng(), rng(), rng()};
  181. EXPECT_THAT(values,
  182. testing::ElementsAre(579252, 43785881, 464353103, 1501811174));
  183. }
  184. {
  185. ExplicitSeedSeq seed_sequence{12, 34, 56};
  186. std::mt19937 rng(seed_sequence);
  187. std::mt19937::result_type values[4] = {rng(), rng(), rng(), rng()};
  188. EXPECT_THAT(values, testing::ElementsAre(138416803, 151130212, 33817739,
  189. 138416803));
  190. }
  191. {
  192. ExplicitSeedSeq seed_sequence{12, 34, 56};
  193. std::mt19937_64 rng(seed_sequence);
  194. std::mt19937_64::result_type values[4] = {rng(), rng(), rng(), rng()};
  195. EXPECT_THAT(values,
  196. testing::ElementsAre(19738651785169348, 1464811352364190456,
  197. 18054685302720800, 19738651785169348));
  198. }
  199. }