#include #include #include "encoder.h" #include "openssl_hash_impl.h" #include "unix_kernel_rand_impl.h" // We need the same "random" inputs to the IRR // each time to have reproducible tests. FILE* mock_urandom(void) { int i; FILE *fp; fp = tmpfile(); for (i = 0; i < 1024; i++) { fputc((i * 17) % 256, fp); } fflush(fp); fp = freopen(NULL, "r", fp); return fp; } class EncoderTest : public ::testing::Test { protected: EncoderTest() { encoder_id = std::string("metric-name").c_str(); fp = mock_urandom(); irr_rand = new rappor::UnixKernelRand(fp); } virtual ~EncoderTest() { fclose(fp); delete irr_rand; delete deps; delete params; delete encoder; } FILE* fp; const char* encoder_id; rappor::UnixKernelRand *irr_rand; rappor::Deps *deps; rappor::Params *params; rappor::Encoder *encoder; rappor::Bits bits_out; std::vector bits_vector; }; // Uses HmacSha256 and 32-bit outputs. class EncoderUint32Test : public EncoderTest { protected: EncoderUint32Test() { deps = new rappor::Deps(rappor::Md5, "client-secret", rappor::HmacSha256, *irr_rand); params = new rappor::Params(32, // num_bits (k) 2, // num_hashes (h) 128, // num_cohorts (m) 0.25, // probability f for PRR 0.75, // probability p for IRR 0.5); // probability q for IRR encoder = new rappor::Encoder(encoder_id, *params, *deps); } }; // Uses HmacDrbg and variable-size vector outputs. class EncoderUnlimTest : public EncoderTest { protected: EncoderUnlimTest() { deps = new rappor::Deps(rappor::Md5, "client-secret", rappor::HmacDrbg, *irr_rand); params = new rappor::Params(64, // num_bits (k) 2, // num_hashes (h) 128, // num_cohorts (m) 0.25, // probability f for PRR 0.75, // probability p for IRR 0.5); // probability q for IRR encoder = new rappor::Encoder(encoder_id, *params, *deps); } }; ///// EncoderUint32Test TEST_F(EncoderUint32Test, EncodeStringUint32) { ASSERT_TRUE(encoder->EncodeString("foo", &bits_out)); ASSERT_EQ(2281639167, bits_out); ASSERT_EQ(3, encoder->cohort()); } TEST_F(EncoderUint32Test, EncodeStringUint32Cohort) { encoder->set_cohort(4); // Set pre-selected cohort. ASSERT_TRUE(encoder->EncodeString("foo", &bits_out)); ASSERT_EQ(2281637247, bits_out); ASSERT_EQ(4, encoder->cohort()); } TEST_F(EncoderUint32Test, EncodeBitsUint32) { ASSERT_TRUE(encoder->EncodeBits(0x123, &bits_out)); ASSERT_EQ(2784956095, bits_out); ASSERT_EQ(3, encoder->cohort()); } // Negative tests // num_bits is negative. TEST_F(EncoderUint32Test, NumBitsMustBePositiveDeathTest) { ::testing::FLAGS_gtest_death_test_style = "threadsafe"; delete params; params = new rappor::Params(-1, // num_bits (k) [BAD] 2, // num_hashes (h) 128, // num_cohorts (m) 0.25, // probability f for PRR 0.75, // probability p for IRR 0.5); // probability q for IRR EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps), "Assertion.*failed"); } // num_hashes is negative. TEST_F(EncoderUint32Test, NumHashesMustBePositiveDeathTest) { ::testing::FLAGS_gtest_death_test_style = "threadsafe"; delete params; params = new rappor::Params(32, // num_bits (k) -1, // num_hashes (h) [BAD] 128, // num_cohorts (m) 0.25, // probability f for PRR 0.75, // probability p for IRR 0.5); // probability q for IRR EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps), "Assertion.*failed"); } // num_cohorts is negative. TEST_F(EncoderUint32Test, NumCohortsMustBePositiveDeathTest) { ::testing::FLAGS_gtest_death_test_style = "threadsafe"; delete params; params = new rappor::Params(32, // num_bits (k) 2, // num_hashes (h) -1, // num_cohorts (m) [BAD] 0.25, // probability f for PRR 0.75, // probability p for IRR 0.5); // probability q for IRR EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps), "Encoder.*Assertion.*failed"); } // Invalid probabilities. TEST_F(EncoderUint32Test, InvalidProbabilitiesDeathTest) { ::testing::FLAGS_gtest_death_test_style = "threadsafe"; // prob_f negative. delete params; params = new rappor::Params(32, // num_bits (k) 2, // num_hashes (h) 1, // num_cohorts (m) -0.1, // probability f for PRR [BAD] 0.75, // probability p for IRR 0.5); // probability q for IRR EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps), "Assertion.*failed"); // prob_f > 1. delete params; params = new rappor::Params(32, // num_bits (k) 2, // num_hashes (h) 1, // num_cohorts (m) 1.1, // probability f for PRR [BAD] 0.75, // probability p for IRR 0.5); // probability q for IRR EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps), "Assertion.*failed"); // prob_p < 0. delete params; params = new rappor::Params(32, // num_bits (k) 2, // num_hashes (h) 1, // num_cohorts (m) 0.25, // probability f for PRR -0.1, // probability p for IRR [BAD] 0.5); // probability q for IRR EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps), "Assertion.*failed"); // prob_p > 1. delete params; params = new rappor::Params(32, // num_bits (k) 2, // num_hashes (h) 1, // num_cohorts (m) 0.25, // probability f for PRR 1.1, // probability p for IRR [BAD] 0.5); // probability q for IRR EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps), "Assertion.*failed"); // prob_q < 0. delete params; params = new rappor::Params(32, // num_bits (k) 2, // num_hashes (h) 1, // num_cohorts (m) 0.25, // probability f for PRR 0.75, // probability p for IRR -0.1); // probability q for IRR [BAD] EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps), "Assertion.*failed"); // prob_q > 1. delete params; params = new rappor::Params(32, // num_bits (k) 2, // num_hashes (h) 1, // num_cohorts (m) 0.25, // probability f for PRR 0.75, // probability p for IRR 1.1); // probability q for IRR [BAD] EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps), "Assertion.*failed"); } // num_bits 64 when only 32 bits are possible. TEST_F(EncoderUint32Test, Sha256NoMoreThan32BitsDeathTest) { ::testing::FLAGS_gtest_death_test_style = "threadsafe"; delete params; params = new rappor::Params(64, // num_bits (k) 2, // num_hashes (h) 128, // num_cohorts (m) 0.25, // probability f for PRR 0.75, // probability p for IRR 0.5); // probability q for IRR EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps), "Assertion.*failed"); } // num_hashes too high. TEST_F(EncoderUint32Test, NumHashesNoMoreThan16DeathTest) { ::testing::FLAGS_gtest_death_test_style = "threadsafe"; delete params; params = new rappor::Params(32, // num_bits (k) 17, // num_hashes (h) 128, // num_cohorts (m) 0.25, // probability f for PRR 0.75, // probability p for IRR 0.5); // probability q for IRR EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps), "Assertion.*failed"); } // EncoderString with 4-byte vector and HMACSHA256 and // EncoderString with Uint32 and HMACSHA256 should match. TEST_F(EncoderUint32Test, StringUint32AndStringVectorMatch) { ASSERT_TRUE(encoder->EncodeString("foo", &bits_out)); ASSERT_EQ(2281639167, bits_out); std::vector expected_out(4); expected_out[0] = (bits_out & 0xFF000000) >> 24; expected_out[1] = (bits_out & 0x00FF0000) >> 16; expected_out[2] = (bits_out & 0x0000FF00) >> 8; expected_out[3] = bits_out & 0x000000FF; // Reset the mock randomizer. delete irr_rand; delete deps; delete encoder; fclose(fp); fp = mock_urandom(); irr_rand = new rappor::UnixKernelRand(fp); deps = new rappor::Deps(rappor::Md5, "client-secret", rappor::HmacSha256, *irr_rand); encoder = new rappor::Encoder(encoder_id, *params, *deps); ASSERT_TRUE(encoder->EncodeString("foo", &bits_vector)); ASSERT_EQ(expected_out, bits_vector); } ///// EncoderUnlimTest TEST_F(EncoderUnlimTest, EncodeStringUint64) { static const uint8_t ex[] = { 134, 255, 11, 255, 252, 119, 240, 223 }; std::vector expected_vector(ex, ex + sizeof(ex)); ASSERT_TRUE(encoder->EncodeString("foo", &bits_vector)); ASSERT_EQ(expected_vector, bits_vector); ASSERT_EQ(93, encoder->cohort()); } // Negative tests. TEST_F(EncoderUnlimTest, NumBitsNotMultipleOf8DeathTest) { ::testing::FLAGS_gtest_death_test_style = "threadsafe"; delete params; params = new rappor::Params(63, // num_bits (k) [BAD] 17, // num_hashes (h) 128, // num_cohorts (m) 0.25, // probability f for PRR 0.75, // probability p for IRR 0.5); // probability q for IRR EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps), "Assertion.*failed"); } int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }