// Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary // source code may only be used and distributed under the Widevine License // Agreement. #include #include #include #include #include #include #include #include #include #include #include "cdm_random.h" namespace wvcdm { namespace { // Random data vector lengths. constexpr size_t kVectorLength = 1024; constexpr size_t kMaxRandomDataLength = CdmRandomGenerator::kMaxRandomDataLength; constexpr size_t kAboveMaxRandomDataLength = std::numeric_limits::max(); constexpr size_t kRandomTrialCount = 100; constexpr size_t kThreadCount = 16; constexpr unsigned int kSeeds[] = {0, 1337, 1565904109, 776964657}; class CdmRandomGeneratorTest : public testing::TestWithParam {}; } // namespace // Checks that the class CdmRandomGenerator meets the requirements of // UniformRandomBitGenerator. // ref: https://en.cppreference.com/w/cpp/named_req/UniformRandomBitGenerator TEST(CdmRandomGeneratorTest, UniformRandomBitGeneratorRequirements) { // Let G represent class CdmRandomGenerator, and g represent an instance // of CdmRandomGenerator. // 1) G::result_type is an unsigned integer (unspecified precision). EXPECT_TRUE(std::is_integral::value); EXPECT_TRUE(std::is_unsigned::value); // 2&3 a) G::min() and G::max() have the result type of G::result_type. EXPECT_TRUE((std::is_same::value)); EXPECT_TRUE((std::is_same::value)); // 2&3 b) G::min() is strictly less than G::max(). EXPECT_LT(CdmRandomGenerator::min(), CdmRandomGenerator::max()); // 4 a) g() have the result type of G::result_type. CdmRandomGenerator g; EXPECT_TRUE( (std::is_same::value)); // 4 b) g() is within [G::min() G::max()] std::vector values; for (size_t i = 0; i < kRandomTrialCount; ++i) { CdmRandomGenerator::result_type x = g(); EXPECT_LE(CdmRandomGenerator::min(), x); EXPECT_GE(CdmRandomGenerator::max(), x); values.push_back(x); } // Verify compilation. // std::shuffle(RandomIt first, RandomIt last, URBG&& g) requires the // class URBG to meet "UniformRandomBitGenerator" requirements. This // will fail to compile if the requirements are not met. std::shuffle(values.begin(), values.end(), CdmRandomGenerator()); } TEST_P(CdmRandomGeneratorTest, AllMethods) { const unsigned int seed = GetParam(); CdmRandomGenerator rng; rng.Seed(); rng.Seed(seed); rng.Rand(); rng(); rng.RandomInRange(1234, 1000000); rng.RandomInRange(1000000); rng.RandomData(kVectorLength); rng.RandomBool(); } TEST_P(CdmRandomGeneratorTest, RandomInRange) { const unsigned int seed = GetParam(); CdmRandomGenerator rng(seed); for (size_t i = 0; i < kRandomTrialCount; ++i) { const int rand_int = rng.Rand(); EXPECT_GE(rand_int, 0); EXPECT_LE(rand_int, RAND_MAX); } // Range size of 1. const uint64_t rand_u64_1 = rng.RandomInRange(100, 100); EXPECT_EQ(rand_u64_1, 100ul); // Range size of 2. const uint64_t rand_u64_2 = rng.RandomInRange(1234, 1235); EXPECT_GE(rand_u64_2, 1234ul); EXPECT_LE(rand_u64_2, 1235ul); // Small range. const uint64_t rand_u64_3 = rng.RandomInRange(10); EXPECT_LE(rand_u64_3, 10ul); // Max range, mainly checking that nothing crashes. rng.RandomInRange(0, std::numeric_limits::max()); // Invalid range representation. Should swap the bounds. const uint64_t rand_u64_4 = rng.RandomInRange(1235, 1234); EXPECT_GE(rand_u64_4, 1234ul); EXPECT_LE(rand_u64_4, 1235ul); } TEST_P(CdmRandomGeneratorTest, RandomDataLength) { const unsigned int seed = GetParam(); CdmRandomGenerator rng(seed); const std::string empty_data = rng.RandomData(0); EXPECT_EQ(empty_data.size(), 0ul); const std::string data = rng.RandomData(kVectorLength); EXPECT_EQ(data.size(), kVectorLength); const std::string max_data = rng.RandomData(kMaxRandomDataLength); EXPECT_EQ(max_data.size(), kMaxRandomDataLength); // Requesting data above the maximum length will result in an error, // returning an empty string. const std::string error_data = rng.RandomData(kAboveMaxRandomDataLength); EXPECT_EQ(error_data.size(), 0ul); } TEST_P(CdmRandomGeneratorTest, Reproducibility) { const unsigned int seed = GetParam(); CdmRandomGenerator rng(seed); const std::string random_data_1 = rng.RandomData(kVectorLength); // Reset generator. rng.Seed(seed); const std::string random_data_2 = rng.RandomData(kVectorLength); EXPECT_EQ(random_data_1, random_data_2); } TEST_P(CdmRandomGeneratorTest, ThreadSafety) { const unsigned int seed = GetParam(); CdmRandomGenerator rng(seed); bool barrier = true; auto thread_job = [&]() { while (barrier) { std::this_thread::sleep_for(std::chrono::microseconds(1)); } for (size_t i = 0; i < kRandomTrialCount; ++i) { rng.Rand(); } }; std::vector threads; for (size_t i = 0; i < kThreadCount; ++i) { threads.push_back(std::thread(thread_job)); } std::this_thread::sleep_for(std::chrono::microseconds(100)); barrier = false; for (auto& thread : threads) { thread.join(); } } INSTANTIATE_TEST_CASE_P(VariousSeeds, CdmRandomGeneratorTest, testing::ValuesIn(kSeeds)); TEST(CdmRandomTest, AllMethods) { CdmRandom::Rand(); CdmRandom::RandomInRange(1234, 1000000); CdmRandom::RandomInRange(1000000); CdmRandom::RandomData(kVectorLength); CdmRandom::RandomBool(); } } // namespace wvcdm