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
15 #include "absl/random/internal/nonsecure_base.h"
16
17 #include <algorithm>
18 #include <cstdint>
19 #include <iostream>
20 #include <memory>
21 #include <random>
22 #include <sstream>
23
24 #include "gtest/gtest.h"
25 #include "absl/random/distributions.h"
26 #include "absl/random/random.h"
27 #include "absl/strings/str_cat.h"
28
29 namespace {
30
31 using ExampleNonsecureURBG =
32 absl::random_internal::NonsecureURBGBase<std::mt19937>;
33
34 template <typename T>
Use(const T &)35 void Use(const T&) {}
36
37 } // namespace
38
TEST(NonsecureURBGBase,DefaultConstructorIsValid)39 TEST(NonsecureURBGBase, DefaultConstructorIsValid) {
40 ExampleNonsecureURBG urbg;
41 }
42
43 // Ensure that the recommended template-instantiations are valid.
TEST(RecommendedTemplates,CanBeConstructed)44 TEST(RecommendedTemplates, CanBeConstructed) {
45 absl::BitGen default_generator;
46 absl::InsecureBitGen insecure_generator;
47 }
48
TEST(RecommendedTemplates,CanDiscardValues)49 TEST(RecommendedTemplates, CanDiscardValues) {
50 absl::BitGen default_generator;
51 absl::InsecureBitGen insecure_generator;
52
53 default_generator.discard(5);
54 insecure_generator.discard(5);
55 }
56
TEST(NonsecureURBGBase,StandardInterface)57 TEST(NonsecureURBGBase, StandardInterface) {
58 // Names after definition of [rand.req.urbg] in C++ standard.
59 // e us a value of E
60 // v is a lvalue of E
61 // x, y are possibly const values of E
62 // s is a value of T
63 // q is a value satisfying requirements of seed_sequence
64 // z is a value of type unsigned long long
65 // os is a some specialization of basic_ostream
66 // is is a some specialization of basic_istream
67
68 using E = absl::random_internal::NonsecureURBGBase<std::minstd_rand>;
69
70 using T = typename E::result_type;
71
72 static_assert(!std::is_copy_constructible<E>::value,
73 "NonsecureURBGBase should not be copy constructible");
74
75 static_assert(!absl::is_copy_assignable<E>::value,
76 "NonsecureURBGBase should not be copy assignable");
77
78 static_assert(std::is_move_constructible<E>::value,
79 "NonsecureURBGBase should be move constructible");
80
81 static_assert(absl::is_move_assignable<E>::value,
82 "NonsecureURBGBase should be move assignable");
83
84 static_assert(std::is_same<decltype(std::declval<E>()()), T>::value,
85 "return type of operator() must be result_type");
86
87 {
88 const E x, y;
89 Use(x);
90 Use(y);
91
92 static_assert(std::is_same<decltype(x == y), bool>::value,
93 "return type of operator== must be bool");
94
95 static_assert(std::is_same<decltype(x != y), bool>::value,
96 "return type of operator== must be bool");
97 }
98
99 E e;
100 std::seed_seq q{1, 2, 3};
101
102 E{};
103 E{q};
104
105 // Copy constructor not supported.
106 // E{x};
107
108 // result_type seed constructor not supported.
109 // E{T{1}};
110
111 // Move constructors are supported.
112 {
113 E tmp(q);
114 E m = std::move(tmp);
115 E n(std::move(m));
116 EXPECT_TRUE(e != n);
117 }
118
119 // Comparisons work.
120 {
121 // MSVC emits error 2718 when using EXPECT_EQ(e, x)
122 // * actual parameter with __declspec(align('#')) won't be aligned
123 E a(q);
124 E b(q);
125
126 EXPECT_TRUE(a != e);
127 EXPECT_TRUE(a == b);
128
129 a();
130 EXPECT_TRUE(a != b);
131 }
132
133 // e.seed(s) not supported.
134
135 // [rand.req.eng] specifies the parameter as 'unsigned long long'
136 // e.discard(unsigned long long) is supported.
137 unsigned long long z = 1; // NOLINT(runtime/int)
138 e.discard(z);
139 }
140
TEST(NonsecureURBGBase,SeedSeqConstructorIsValid)141 TEST(NonsecureURBGBase, SeedSeqConstructorIsValid) {
142 std::seed_seq seq;
143 ExampleNonsecureURBG rbg(seq);
144 }
145
TEST(NonsecureURBGBase,CompatibleWithDistributionUtils)146 TEST(NonsecureURBGBase, CompatibleWithDistributionUtils) {
147 ExampleNonsecureURBG rbg;
148
149 absl::Uniform(rbg, 0, 100);
150 absl::Uniform(rbg, 0.5, 0.7);
151 absl::Poisson<uint32_t>(rbg);
152 absl::Exponential<float>(rbg);
153 }
154
TEST(NonsecureURBGBase,CompatibleWithStdDistributions)155 TEST(NonsecureURBGBase, CompatibleWithStdDistributions) {
156 ExampleNonsecureURBG rbg;
157
158 // Cast to void to suppress [[nodiscard]] warnings
159 static_cast<void>(std::uniform_int_distribution<uint32_t>(0, 100)(rbg));
160 static_cast<void>(std::uniform_real_distribution<float>()(rbg));
161 static_cast<void>(std::bernoulli_distribution(0.2)(rbg));
162 }
163
TEST(NonsecureURBGBase,ConsecutiveDefaultInstancesYieldUniqueVariates)164 TEST(NonsecureURBGBase, ConsecutiveDefaultInstancesYieldUniqueVariates) {
165 const size_t kNumSamples = 128;
166
167 ExampleNonsecureURBG rbg1;
168 ExampleNonsecureURBG rbg2;
169
170 for (size_t i = 0; i < kNumSamples; i++) {
171 EXPECT_NE(rbg1(), rbg2());
172 }
173 }
174
TEST(NonsecureURBGBase,EqualSeedSequencesYieldEqualVariates)175 TEST(NonsecureURBGBase, EqualSeedSequencesYieldEqualVariates) {
176 std::seed_seq seq;
177
178 ExampleNonsecureURBG rbg1(seq);
179 ExampleNonsecureURBG rbg2(seq);
180
181 // ExampleNonsecureURBG rbg3({1, 2, 3}); // Should not compile.
182
183 for (uint32_t i = 0; i < 1000; i++) {
184 EXPECT_EQ(rbg1(), rbg2());
185 }
186
187 rbg1.discard(100);
188 rbg2.discard(100);
189
190 // The sequences should continue after discarding
191 for (uint32_t i = 0; i < 1000; i++) {
192 EXPECT_EQ(rbg1(), rbg2());
193 }
194 }
195
TEST(RandenPoolSeedSeqTest,SeederWorksForU32)196 TEST(RandenPoolSeedSeqTest, SeederWorksForU32) {
197 absl::random_internal::RandenPoolSeedSeq seeder;
198
199 uint32_t state[2] = {0, 0};
200 seeder.generate(std::begin(state), std::end(state));
201 EXPECT_FALSE(state[0] == 0 && state[1] == 0);
202 }
203
TEST(RandenPoolSeedSeqTest,SeederWorksForU64)204 TEST(RandenPoolSeedSeqTest, SeederWorksForU64) {
205 absl::random_internal::RandenPoolSeedSeq seeder;
206
207 uint64_t state[2] = {0, 0};
208 seeder.generate(std::begin(state), std::end(state));
209 EXPECT_FALSE(state[0] == 0 && state[1] == 0);
210 EXPECT_FALSE((state[0] >> 32) == 0 && (state[1] >> 32) == 0);
211 }
212
TEST(RandenPoolSeedSeqTest,SeederWorksForS32)213 TEST(RandenPoolSeedSeqTest, SeederWorksForS32) {
214 absl::random_internal::RandenPoolSeedSeq seeder;
215
216 int32_t state[2] = {0, 0};
217 seeder.generate(std::begin(state), std::end(state));
218 EXPECT_FALSE(state[0] == 0 && state[1] == 0);
219 }
220
TEST(RandenPoolSeedSeqTest,SeederWorksForVector)221 TEST(RandenPoolSeedSeqTest, SeederWorksForVector) {
222 absl::random_internal::RandenPoolSeedSeq seeder;
223
224 std::vector<uint32_t> state(2);
225 seeder.generate(std::begin(state), std::end(state));
226 EXPECT_FALSE(state[0] == 0 && state[1] == 0);
227 }
228