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