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