1*2abb3134SXin Li #include <gtest/gtest.h>
2*2abb3134SXin Li #include <stdexcept>
3*2abb3134SXin Li
4*2abb3134SXin Li #include "encoder.h"
5*2abb3134SXin Li #include "openssl_hash_impl.h"
6*2abb3134SXin Li #include "unix_kernel_rand_impl.h"
7*2abb3134SXin Li
8*2abb3134SXin Li // We need the same "random" inputs to the IRR
9*2abb3134SXin Li // each time to have reproducible tests.
mock_urandom(void)10*2abb3134SXin Li FILE* mock_urandom(void) {
11*2abb3134SXin Li int i;
12*2abb3134SXin Li FILE *fp;
13*2abb3134SXin Li fp = tmpfile();
14*2abb3134SXin Li for (i = 0; i < 1024; i++) {
15*2abb3134SXin Li fputc((i * 17) % 256, fp);
16*2abb3134SXin Li }
17*2abb3134SXin Li fflush(fp);
18*2abb3134SXin Li fp = freopen(NULL, "r", fp);
19*2abb3134SXin Li return fp;
20*2abb3134SXin Li }
21*2abb3134SXin Li
22*2abb3134SXin Li class EncoderTest : public ::testing::Test {
23*2abb3134SXin Li protected:
EncoderTest()24*2abb3134SXin Li EncoderTest() {
25*2abb3134SXin Li encoder_id = std::string("metric-name").c_str();
26*2abb3134SXin Li fp = mock_urandom();
27*2abb3134SXin Li irr_rand = new rappor::UnixKernelRand(fp);
28*2abb3134SXin Li }
29*2abb3134SXin Li
~EncoderTest()30*2abb3134SXin Li virtual ~EncoderTest() {
31*2abb3134SXin Li fclose(fp);
32*2abb3134SXin Li delete irr_rand;
33*2abb3134SXin Li delete deps;
34*2abb3134SXin Li delete params;
35*2abb3134SXin Li delete encoder;
36*2abb3134SXin Li }
37*2abb3134SXin Li
38*2abb3134SXin Li FILE* fp; const char* encoder_id;
39*2abb3134SXin Li rappor::UnixKernelRand *irr_rand;
40*2abb3134SXin Li rappor::Deps *deps;
41*2abb3134SXin Li rappor::Params *params;
42*2abb3134SXin Li rappor::Encoder *encoder;
43*2abb3134SXin Li rappor::Bits bits_out;
44*2abb3134SXin Li std::vector<uint8_t> bits_vector;
45*2abb3134SXin Li };
46*2abb3134SXin Li
47*2abb3134SXin Li // Uses HmacSha256 and 32-bit outputs.
48*2abb3134SXin Li class EncoderUint32Test : public EncoderTest {
49*2abb3134SXin Li protected:
EncoderUint32Test()50*2abb3134SXin Li EncoderUint32Test() {
51*2abb3134SXin Li deps = new rappor::Deps(rappor::Md5, "client-secret", rappor::HmacSha256,
52*2abb3134SXin Li *irr_rand);
53*2abb3134SXin Li params = new rappor::Params(32, // num_bits (k)
54*2abb3134SXin Li 2, // num_hashes (h)
55*2abb3134SXin Li 128, // num_cohorts (m)
56*2abb3134SXin Li 0.25, // probability f for PRR
57*2abb3134SXin Li 0.75, // probability p for IRR
58*2abb3134SXin Li 0.5); // probability q for IRR
59*2abb3134SXin Li encoder = new rappor::Encoder(encoder_id, *params, *deps);
60*2abb3134SXin Li }
61*2abb3134SXin Li };
62*2abb3134SXin Li
63*2abb3134SXin Li // Uses HmacDrbg and variable-size vector outputs.
64*2abb3134SXin Li class EncoderUnlimTest : public EncoderTest {
65*2abb3134SXin Li protected:
EncoderUnlimTest()66*2abb3134SXin Li EncoderUnlimTest() {
67*2abb3134SXin Li deps = new rappor::Deps(rappor::Md5, "client-secret", rappor::HmacDrbg,
68*2abb3134SXin Li *irr_rand);
69*2abb3134SXin Li params = new rappor::Params(64, // num_bits (k)
70*2abb3134SXin Li 2, // num_hashes (h)
71*2abb3134SXin Li 128, // num_cohorts (m)
72*2abb3134SXin Li 0.25, // probability f for PRR
73*2abb3134SXin Li 0.75, // probability p for IRR
74*2abb3134SXin Li 0.5); // probability q for IRR
75*2abb3134SXin Li encoder = new rappor::Encoder(encoder_id, *params, *deps);
76*2abb3134SXin Li }
77*2abb3134SXin Li };
78*2abb3134SXin Li
79*2abb3134SXin Li
80*2abb3134SXin Li ///// EncoderUint32Test
TEST_F(EncoderUint32Test,EncodeStringUint32)81*2abb3134SXin Li TEST_F(EncoderUint32Test, EncodeStringUint32) {
82*2abb3134SXin Li ASSERT_TRUE(encoder->EncodeString("foo", &bits_out));
83*2abb3134SXin Li ASSERT_EQ(2281639167, bits_out);
84*2abb3134SXin Li ASSERT_EQ(3, encoder->cohort());
85*2abb3134SXin Li }
86*2abb3134SXin Li
TEST_F(EncoderUint32Test,EncodeStringUint32Cohort)87*2abb3134SXin Li TEST_F(EncoderUint32Test, EncodeStringUint32Cohort) {
88*2abb3134SXin Li encoder->set_cohort(4); // Set pre-selected cohort.
89*2abb3134SXin Li ASSERT_TRUE(encoder->EncodeString("foo", &bits_out));
90*2abb3134SXin Li ASSERT_EQ(2281637247, bits_out);
91*2abb3134SXin Li ASSERT_EQ(4, encoder->cohort());
92*2abb3134SXin Li }
93*2abb3134SXin Li
TEST_F(EncoderUint32Test,EncodeBitsUint32)94*2abb3134SXin Li TEST_F(EncoderUint32Test, EncodeBitsUint32) {
95*2abb3134SXin Li ASSERT_TRUE(encoder->EncodeBits(0x123, &bits_out));
96*2abb3134SXin Li ASSERT_EQ(2784956095, bits_out);
97*2abb3134SXin Li ASSERT_EQ(3, encoder->cohort());
98*2abb3134SXin Li }
99*2abb3134SXin Li
100*2abb3134SXin Li // Negative tests
101*2abb3134SXin Li // num_bits is negative.
TEST_F(EncoderUint32Test,NumBitsMustBePositiveDeathTest)102*2abb3134SXin Li TEST_F(EncoderUint32Test, NumBitsMustBePositiveDeathTest) {
103*2abb3134SXin Li ::testing::FLAGS_gtest_death_test_style = "threadsafe";
104*2abb3134SXin Li delete params;
105*2abb3134SXin Li params = new rappor::Params(-1, // num_bits (k) [BAD]
106*2abb3134SXin Li 2, // num_hashes (h)
107*2abb3134SXin Li 128, // num_cohorts (m)
108*2abb3134SXin Li 0.25, // probability f for PRR
109*2abb3134SXin Li 0.75, // probability p for IRR
110*2abb3134SXin Li 0.5); // probability q for IRR
111*2abb3134SXin Li EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps),
112*2abb3134SXin Li "Assertion.*failed");
113*2abb3134SXin Li }
114*2abb3134SXin Li
115*2abb3134SXin Li // num_hashes is negative.
TEST_F(EncoderUint32Test,NumHashesMustBePositiveDeathTest)116*2abb3134SXin Li TEST_F(EncoderUint32Test, NumHashesMustBePositiveDeathTest) {
117*2abb3134SXin Li ::testing::FLAGS_gtest_death_test_style = "threadsafe";
118*2abb3134SXin Li delete params;
119*2abb3134SXin Li params = new rappor::Params(32, // num_bits (k)
120*2abb3134SXin Li -1, // num_hashes (h) [BAD]
121*2abb3134SXin Li 128, // num_cohorts (m)
122*2abb3134SXin Li 0.25, // probability f for PRR
123*2abb3134SXin Li 0.75, // probability p for IRR
124*2abb3134SXin Li 0.5); // probability q for IRR
125*2abb3134SXin Li EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps),
126*2abb3134SXin Li "Assertion.*failed");
127*2abb3134SXin Li }
128*2abb3134SXin Li
129*2abb3134SXin Li // num_cohorts is negative.
TEST_F(EncoderUint32Test,NumCohortsMustBePositiveDeathTest)130*2abb3134SXin Li TEST_F(EncoderUint32Test, NumCohortsMustBePositiveDeathTest) {
131*2abb3134SXin Li ::testing::FLAGS_gtest_death_test_style = "threadsafe";
132*2abb3134SXin Li delete params;
133*2abb3134SXin Li params = new rappor::Params(32, // num_bits (k)
134*2abb3134SXin Li 2, // num_hashes (h)
135*2abb3134SXin Li -1, // num_cohorts (m) [BAD]
136*2abb3134SXin Li 0.25, // probability f for PRR
137*2abb3134SXin Li 0.75, // probability p for IRR
138*2abb3134SXin Li 0.5); // probability q for IRR
139*2abb3134SXin Li EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps),
140*2abb3134SXin Li "Encoder.*Assertion.*failed");
141*2abb3134SXin Li }
142*2abb3134SXin Li
143*2abb3134SXin Li // Invalid probabilities.
TEST_F(EncoderUint32Test,InvalidProbabilitiesDeathTest)144*2abb3134SXin Li TEST_F(EncoderUint32Test, InvalidProbabilitiesDeathTest) {
145*2abb3134SXin Li ::testing::FLAGS_gtest_death_test_style = "threadsafe";
146*2abb3134SXin Li // prob_f negative.
147*2abb3134SXin Li delete params;
148*2abb3134SXin Li params = new rappor::Params(32, // num_bits (k)
149*2abb3134SXin Li 2, // num_hashes (h)
150*2abb3134SXin Li 1, // num_cohorts (m)
151*2abb3134SXin Li -0.1, // probability f for PRR [BAD]
152*2abb3134SXin Li 0.75, // probability p for IRR
153*2abb3134SXin Li 0.5); // probability q for IRR
154*2abb3134SXin Li EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps),
155*2abb3134SXin Li "Assertion.*failed");
156*2abb3134SXin Li // prob_f > 1.
157*2abb3134SXin Li delete params;
158*2abb3134SXin Li params = new rappor::Params(32, // num_bits (k)
159*2abb3134SXin Li 2, // num_hashes (h)
160*2abb3134SXin Li 1, // num_cohorts (m)
161*2abb3134SXin Li 1.1, // probability f for PRR [BAD]
162*2abb3134SXin Li 0.75, // probability p for IRR
163*2abb3134SXin Li 0.5); // probability q for IRR
164*2abb3134SXin Li EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps),
165*2abb3134SXin Li "Assertion.*failed");
166*2abb3134SXin Li // prob_p < 0.
167*2abb3134SXin Li delete params;
168*2abb3134SXin Li params = new rappor::Params(32, // num_bits (k)
169*2abb3134SXin Li 2, // num_hashes (h)
170*2abb3134SXin Li 1, // num_cohorts (m)
171*2abb3134SXin Li 0.25, // probability f for PRR
172*2abb3134SXin Li -0.1, // probability p for IRR [BAD]
173*2abb3134SXin Li 0.5); // probability q for IRR
174*2abb3134SXin Li EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps),
175*2abb3134SXin Li "Assertion.*failed");
176*2abb3134SXin Li // prob_p > 1.
177*2abb3134SXin Li delete params;
178*2abb3134SXin Li params = new rappor::Params(32, // num_bits (k)
179*2abb3134SXin Li 2, // num_hashes (h)
180*2abb3134SXin Li 1, // num_cohorts (m)
181*2abb3134SXin Li 0.25, // probability f for PRR
182*2abb3134SXin Li 1.1, // probability p for IRR [BAD]
183*2abb3134SXin Li 0.5); // probability q for IRR
184*2abb3134SXin Li EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps),
185*2abb3134SXin Li "Assertion.*failed");
186*2abb3134SXin Li // prob_q < 0.
187*2abb3134SXin Li delete params;
188*2abb3134SXin Li params = new rappor::Params(32, // num_bits (k)
189*2abb3134SXin Li 2, // num_hashes (h)
190*2abb3134SXin Li 1, // num_cohorts (m)
191*2abb3134SXin Li 0.25, // probability f for PRR
192*2abb3134SXin Li 0.75, // probability p for IRR
193*2abb3134SXin Li -0.1); // probability q for IRR [BAD]
194*2abb3134SXin Li EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps),
195*2abb3134SXin Li "Assertion.*failed");
196*2abb3134SXin Li // prob_q > 1.
197*2abb3134SXin Li delete params;
198*2abb3134SXin Li params = new rappor::Params(32, // num_bits (k)
199*2abb3134SXin Li 2, // num_hashes (h)
200*2abb3134SXin Li 1, // num_cohorts (m)
201*2abb3134SXin Li 0.25, // probability f for PRR
202*2abb3134SXin Li 0.75, // probability p for IRR
203*2abb3134SXin Li 1.1); // probability q for IRR [BAD]
204*2abb3134SXin Li EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps),
205*2abb3134SXin Li "Assertion.*failed");
206*2abb3134SXin Li }
207*2abb3134SXin Li
208*2abb3134SXin Li // num_bits 64 when only 32 bits are possible.
TEST_F(EncoderUint32Test,Sha256NoMoreThan32BitsDeathTest)209*2abb3134SXin Li TEST_F(EncoderUint32Test, Sha256NoMoreThan32BitsDeathTest) {
210*2abb3134SXin Li ::testing::FLAGS_gtest_death_test_style = "threadsafe";
211*2abb3134SXin Li delete params;
212*2abb3134SXin Li params = new rappor::Params(64, // num_bits (k)
213*2abb3134SXin Li 2, // num_hashes (h)
214*2abb3134SXin Li 128, // num_cohorts (m)
215*2abb3134SXin Li 0.25, // probability f for PRR
216*2abb3134SXin Li 0.75, // probability p for IRR
217*2abb3134SXin Li 0.5); // probability q for IRR
218*2abb3134SXin Li EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps),
219*2abb3134SXin Li "Assertion.*failed");
220*2abb3134SXin Li }
221*2abb3134SXin Li
222*2abb3134SXin Li // num_hashes too high.
TEST_F(EncoderUint32Test,NumHashesNoMoreThan16DeathTest)223*2abb3134SXin Li TEST_F(EncoderUint32Test, NumHashesNoMoreThan16DeathTest) {
224*2abb3134SXin Li ::testing::FLAGS_gtest_death_test_style = "threadsafe";
225*2abb3134SXin Li delete params;
226*2abb3134SXin Li params = new rappor::Params(32, // num_bits (k)
227*2abb3134SXin Li 17, // num_hashes (h)
228*2abb3134SXin Li 128, // num_cohorts (m)
229*2abb3134SXin Li 0.25, // probability f for PRR
230*2abb3134SXin Li 0.75, // probability p for IRR
231*2abb3134SXin Li 0.5); // probability q for IRR
232*2abb3134SXin Li EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps),
233*2abb3134SXin Li "Assertion.*failed");
234*2abb3134SXin Li }
235*2abb3134SXin Li
236*2abb3134SXin Li // EncoderString with 4-byte vector and HMACSHA256 and
237*2abb3134SXin Li // EncoderString with Uint32 and HMACSHA256 should match.
TEST_F(EncoderUint32Test,StringUint32AndStringVectorMatch)238*2abb3134SXin Li TEST_F(EncoderUint32Test, StringUint32AndStringVectorMatch) {
239*2abb3134SXin Li ASSERT_TRUE(encoder->EncodeString("foo", &bits_out));
240*2abb3134SXin Li ASSERT_EQ(2281639167, bits_out);
241*2abb3134SXin Li std::vector<uint8_t> expected_out(4);
242*2abb3134SXin Li expected_out[0] = (bits_out & 0xFF000000) >> 24;
243*2abb3134SXin Li expected_out[1] = (bits_out & 0x00FF0000) >> 16;
244*2abb3134SXin Li expected_out[2] = (bits_out & 0x0000FF00) >> 8;
245*2abb3134SXin Li expected_out[3] = bits_out & 0x000000FF;
246*2abb3134SXin Li
247*2abb3134SXin Li // Reset the mock randomizer.
248*2abb3134SXin Li delete irr_rand;
249*2abb3134SXin Li delete deps;
250*2abb3134SXin Li delete encoder;
251*2abb3134SXin Li fclose(fp);
252*2abb3134SXin Li fp = mock_urandom();
253*2abb3134SXin Li irr_rand = new rappor::UnixKernelRand(fp);
254*2abb3134SXin Li deps = new rappor::Deps(rappor::Md5, "client-secret", rappor::HmacSha256,
255*2abb3134SXin Li *irr_rand);
256*2abb3134SXin Li encoder = new rappor::Encoder(encoder_id, *params, *deps);
257*2abb3134SXin Li ASSERT_TRUE(encoder->EncodeString("foo", &bits_vector));
258*2abb3134SXin Li ASSERT_EQ(expected_out, bits_vector);
259*2abb3134SXin Li }
260*2abb3134SXin Li
261*2abb3134SXin Li ///// EncoderUnlimTest
262*2abb3134SXin Li
TEST_F(EncoderUnlimTest,EncodeStringUint64)263*2abb3134SXin Li TEST_F(EncoderUnlimTest, EncodeStringUint64) {
264*2abb3134SXin Li static const uint8_t ex[] = { 134, 255, 11, 255, 252, 119, 240, 223 };
265*2abb3134SXin Li std::vector<uint8_t> expected_vector(ex, ex + sizeof(ex));
266*2abb3134SXin Li
267*2abb3134SXin Li ASSERT_TRUE(encoder->EncodeString("foo", &bits_vector));
268*2abb3134SXin Li ASSERT_EQ(expected_vector, bits_vector);
269*2abb3134SXin Li ASSERT_EQ(93, encoder->cohort());
270*2abb3134SXin Li }
271*2abb3134SXin Li
272*2abb3134SXin Li // Negative tests.
TEST_F(EncoderUnlimTest,NumBitsNotMultipleOf8DeathTest)273*2abb3134SXin Li TEST_F(EncoderUnlimTest, NumBitsNotMultipleOf8DeathTest) {
274*2abb3134SXin Li ::testing::FLAGS_gtest_death_test_style = "threadsafe";
275*2abb3134SXin Li delete params;
276*2abb3134SXin Li params = new rappor::Params(63, // num_bits (k) [BAD]
277*2abb3134SXin Li 17, // num_hashes (h)
278*2abb3134SXin Li 128, // num_cohorts (m)
279*2abb3134SXin Li 0.25, // probability f for PRR
280*2abb3134SXin Li 0.75, // probability p for IRR
281*2abb3134SXin Li 0.5); // probability q for IRR
282*2abb3134SXin Li EXPECT_DEATH(rappor::Encoder(encoder_id, *params, *deps),
283*2abb3134SXin Li "Assertion.*failed");
284*2abb3134SXin Li }
285*2abb3134SXin Li
main(int argc,char ** argv)286*2abb3134SXin Li int main(int argc, char **argv) {
287*2abb3134SXin Li ::testing::InitGoogleTest(&argc, argv);
288*2abb3134SXin Li return RUN_ALL_TESTS();
289*2abb3134SXin Li }
290