salted_seed_seq_test.cc (5240B)
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/salted_seed_seq.h" 16 17 #include <iterator> 18 #include <random> 19 #include <utility> 20 #include <vector> 21 22 #include "gmock/gmock.h" 23 #include "gtest/gtest.h" 24 25 using absl::random_internal::GetSaltMaterial; 26 using absl::random_internal::MakeSaltedSeedSeq; 27 using absl::random_internal::SaltedSeedSeq; 28 using testing::Eq; 29 using testing::Pointwise; 30 31 namespace { 32 33 template <typename Sseq> 34 void ConformsToInterface() { 35 // Check that the SeedSequence can be default-constructed. 36 { 37 Sseq default_constructed_seq; 38 } 39 // Check that the SeedSequence can be constructed with two iterators. 40 { 41 uint32_t init_array[] = {1, 3, 5, 7, 9}; 42 Sseq iterator_constructed_seq(std::begin(init_array), std::end(init_array)); 43 } 44 // Check that the SeedSequence can be std::initializer_list-constructed. 45 { 46 Sseq list_constructed_seq = {1, 3, 5, 7, 9, 11, 13}; 47 } 48 // Check that param() and size() return state provided to constructor. 49 { 50 uint32_t init_array[] = {1, 2, 3, 4, 5}; 51 Sseq seq(std::begin(init_array), std::end(init_array)); 52 EXPECT_EQ(seq.size(), ABSL_ARRAYSIZE(init_array)); 53 54 std::vector<uint32_t> state_vector; 55 seq.param(std::back_inserter(state_vector)); 56 57 EXPECT_EQ(state_vector.size(), ABSL_ARRAYSIZE(init_array)); 58 for (int i = 0; i < state_vector.size(); i++) { 59 EXPECT_EQ(state_vector[i], i + 1); 60 } 61 } 62 // Check for presence of generate() method. 63 { 64 Sseq seq; 65 uint32_t seeds[5]; 66 67 seq.generate(std::begin(seeds), std::end(seeds)); 68 } 69 } 70 71 TEST(SaltedSeedSeq, CheckInterfaces) { 72 // Control case 73 ConformsToInterface<std::seed_seq>(); 74 75 // Abseil classes 76 ConformsToInterface<SaltedSeedSeq<std::seed_seq>>(); 77 } 78 79 TEST(SaltedSeedSeq, CheckConstructingFromOtherSequence) { 80 std::vector<uint32_t> seed_values(10, 1); 81 std::seed_seq seq(seed_values.begin(), seed_values.end()); 82 auto salted_seq = MakeSaltedSeedSeq(std::move(seq)); 83 84 EXPECT_EQ(seq.size(), salted_seq.size()); 85 86 std::vector<uint32_t> param_result; 87 seq.param(std::back_inserter(param_result)); 88 89 EXPECT_EQ(seed_values, param_result); 90 } 91 92 TEST(SaltedSeedSeq, SaltedSaltedSeedSeqIsNotDoubleSalted) { 93 uint32_t init[] = {1, 3, 5, 7, 9}; 94 95 std::seed_seq seq(std::begin(init), std::end(init)); 96 97 // The first salting. 98 SaltedSeedSeq<std::seed_seq> salted_seq = MakeSaltedSeedSeq(std::move(seq)); 99 uint32_t a[16]; 100 salted_seq.generate(std::begin(a), std::end(a)); 101 102 // The second salting. 103 SaltedSeedSeq<std::seed_seq> salted_salted_seq = 104 MakeSaltedSeedSeq(std::move(salted_seq)); 105 uint32_t b[16]; 106 salted_salted_seq.generate(std::begin(b), std::end(b)); 107 108 // ... both should be equal. 109 EXPECT_THAT(b, Pointwise(Eq(), a)) << "a[0] " << a[0]; 110 } 111 112 TEST(SaltedSeedSeq, SeedMaterialIsSalted) { 113 const size_t kNumBlocks = 16; 114 115 uint32_t seed_material[kNumBlocks]; 116 std::random_device urandom{"/dev/urandom"}; 117 for (uint32_t& seed : seed_material) { 118 seed = urandom(); 119 } 120 121 std::seed_seq seq(std::begin(seed_material), std::end(seed_material)); 122 SaltedSeedSeq<std::seed_seq> salted_seq(std::begin(seed_material), 123 std::end(seed_material)); 124 125 bool salt_is_available = GetSaltMaterial().has_value(); 126 127 // If salt is available generated sequence should be different. 128 if (salt_is_available) { 129 uint32_t outputs[kNumBlocks]; 130 uint32_t salted_outputs[kNumBlocks]; 131 132 seq.generate(std::begin(outputs), std::end(outputs)); 133 salted_seq.generate(std::begin(salted_outputs), std::end(salted_outputs)); 134 135 EXPECT_THAT(outputs, Pointwise(testing::Ne(), salted_outputs)); 136 } 137 } 138 139 TEST(SaltedSeedSeq, GenerateAcceptsDifferentTypes) { 140 const size_t kNumBlocks = 4; 141 142 SaltedSeedSeq<std::seed_seq> seq({1, 2, 3}); 143 144 uint32_t expected[kNumBlocks]; 145 seq.generate(std::begin(expected), std::end(expected)); 146 147 // 32-bit outputs 148 { 149 unsigned long seed_material[kNumBlocks]; // NOLINT(runtime/int) 150 seq.generate(std::begin(seed_material), std::end(seed_material)); 151 EXPECT_THAT(seed_material, Pointwise(Eq(), expected)); 152 } 153 { 154 unsigned int seed_material[kNumBlocks]; // NOLINT(runtime/int) 155 seq.generate(std::begin(seed_material), std::end(seed_material)); 156 EXPECT_THAT(seed_material, Pointwise(Eq(), expected)); 157 } 158 159 // 64-bit outputs. 160 { 161 uint64_t seed_material[kNumBlocks]; 162 seq.generate(std::begin(seed_material), std::end(seed_material)); 163 EXPECT_THAT(seed_material, Pointwise(Eq(), expected)); 164 } 165 { 166 int64_t seed_material[kNumBlocks]; 167 seq.generate(std::begin(seed_material), std::end(seed_material)); 168 EXPECT_THAT(seed_material, Pointwise(Eq(), expected)); 169 } 170 } 171 172 } // namespace