Add time functions, simplify API
[libcontrac.git] / tests / test_contrac.c
1 /** \ingroup contrac
2 * @file
3 * @author David Llewellyn-Jones
4 * @version $(VERSION)
5 *
6 * @section LICENSE
7 *
8 *
9 *
10 * @brief
11 * @section DESCRIPTION
12 *
13 *
14 *
15 */
16
17 // Includes
18
19 #include <check.h>
20 #include <malloc.h>
21
22 #include "contrac/contrac.h"
23 #include "contrac/contrac_private.h"
24 #include "contrac/utils.h"
25 #include "contrac/dtk.h"
26 #include "contrac/rpi.h"
27 #include "contrac/dtk_list.h"
28 #include "contrac/rpi_list.h"
29 #include "contrac/match.h"
30
31 // Defines
32
33 // Structures
34
35 // Function prototypes
36
37 // Override time function
38 static time_t fake_time = 0;
39 time_t time(time_t *__timer) {
40 return fake_time;
41 }
42
43 // Function definitions
44
45 START_TEST (check_base64) {
46 //bool result;
47 //int pos;
48 char *string[4] = {
49 "This is a string", // 16
50 "Maybe upon a time", // 17
51 "And then there was", // 18
52 "In the end there is", // 19
53 };
54 char *base64[4] = {
55 "VGhpcyBpcyBhIHN0cmluZw==", // 24
56 "TWF5YmUgdXBvbiBhIHRpbWU=", // 24
57 "QW5kIHRoZW4gdGhlcmUgd2Fz", // 24
58 "SW4gdGhlIGVuZCB0aGVyZSBpcw==", // 24
59 };
60 size_t size;
61 char * output;
62 int pos;
63
64 for (pos = 0; pos < 4; ++pos) {
65 // Encode
66 size = base64_encode_size(strlen(string[pos]));
67
68 ck_assert(size == (strlen(base64[pos]) + 1));
69 output = calloc(sizeof(char), size);
70
71 base64_encode_binary_to_base64((unsigned char *)string[pos], strlen(string[pos]), (unsigned char *)output, &size);
72
73 ck_assert(size == (strlen(base64[pos]) + 1));
74 ck_assert_str_eq(output, base64[pos]);
75
76 // Decode
77 size = base64_decode_size(strlen(base64[pos]));
78
79 ck_assert(size >= (strlen(string[pos]) + 1));
80 ck_assert(size < (strlen(string[pos]) + 4));
81 output = calloc(sizeof(char), size + 1);
82
83 base64_decode_base64_to_binary((unsigned char *)base64[pos], strlen(base64[pos]), (unsigned char *)output, &size);
84
85 ck_assert(size >= (strlen(string[pos]) + 1));
86 ck_assert(size < (strlen(string[pos]) + 4));
87 ck_assert_str_eq(output, string[pos]);
88 }
89 }
90 END_TEST
91
92 START_TEST (check_contrac) {
93 bool result;
94 unsigned char const *tk;
95 int pos;
96
97 // Generate some keys, check the results
98 Contrac * contrac;
99
100 contrac = contrac_new();
101 ck_assert(contrac != NULL);
102
103 result = contrac_get_initialised(contrac);
104 ck_assert(result == false);
105
106 tk = contrac_get_tracing_key(contrac);
107 // The tracing key will initialise to zero by default
108 for (pos = 0; pos < TK_SIZE; ++pos) {
109 ck_assert(tk[pos] == 0);
110 }
111
112 result = contrac_generate_tracing_key(contrac);
113 ck_assert(result == true);
114
115 result = contrac_get_initialised(contrac);
116 ck_assert(result == false);
117
118 // The random generator could generate all zeros, but we'll take the risk
119 tk = contrac_get_tracing_key(contrac);
120 result = false;
121 for (pos = 0; pos < TK_SIZE; ++pos) {
122 if (tk[pos] != 0) {
123 result = true;
124 }
125 }
126 ck_assert(result == true);
127
128 result = contrac_get_initialised(contrac);
129 ck_assert(result == false);
130
131 result = contrac_set_day_number(contrac, 23);
132 ck_assert(result == true);
133
134 result = contrac_get_initialised(contrac);
135 ck_assert(result == false);
136
137 result = contrac_set_time_interval_number(contrac, 76);
138 ck_assert(result == true);
139
140 result = contrac_get_initialised(contrac);
141 ck_assert(result == true);
142
143 // Clean up
144 contrac_delete(contrac);
145 }
146 END_TEST
147
148 START_TEST (check_dtk) {
149 bool result;
150 char const *tracing_key_base64 = "3UmKrtcQ2tfLE8UPSXHb4PtgRfE0E2xdSs+PGVIS8cc=";
151 char tk_base64[TK_SIZE_BASE64 + 1];
152 char dtk_base64[DTK_SIZE_BASE64 + 1];
153
154 // Generate some keys, check the results
155 Contrac * contrac;
156
157 contrac = contrac_new();
158 ck_assert(contrac != NULL);
159
160 contrac_set_tracing_key_base64(contrac, tracing_key_base64);
161
162 contrac_get_tracing_key_base64(contrac, tk_base64);
163 ck_assert_int_eq(strlen(tk_base64), TK_SIZE_BASE64);
164 ck_assert_str_eq(tracing_key_base64, tk_base64);
165
166 // Check the Daily Tracing Keys are generated correctly
167 // Should use the standard test vectors when they're available
168
169 result = contrac_set_day_number(contrac, 12);
170 ck_assert(result);
171 contrac_get_daily_key_base64(contrac, dtk_base64);
172 ck_assert_int_eq(strlen(dtk_base64), DTK_SIZE_BASE64);
173 ck_assert_str_eq(dtk_base64, "AzZ389DsGecAjZqby1sLNQ==");
174
175
176 result = contrac_set_day_number(contrac, 0);
177 ck_assert(result);
178 contrac_get_daily_key_base64(contrac, dtk_base64);
179 ck_assert_int_eq(strlen(dtk_base64), DTK_SIZE_BASE64);
180 ck_assert_str_eq(dtk_base64, "p7LrsTReTw3k721eIWDjRw==");
181
182 result = contrac_set_day_number(contrac, 143);
183 ck_assert(result);
184 contrac_get_daily_key_base64(contrac, dtk_base64);
185 ck_assert_int_eq(strlen(dtk_base64), DTK_SIZE_BASE64);
186 ck_assert_str_eq(dtk_base64, "f6RZL/2wGCzxSBzZc9xVNQ==");
187
188 // Clean up
189 contrac_delete(contrac);
190 }
191 END_TEST
192
193 START_TEST (check_rpi) {
194 bool result;
195 char const *tracing_key_base64[2] = {
196 "3UmKrtcQ2tfLE8UPSXHb4PtgRfE0E2xdSs+PGVIS8cc=",
197 "U3CgpSjF0qFW8DNSTHVWF99few5FOW7RV7kA9j6LFTc=",
198 };
199 char rpi_base64[RPI_SIZE_BASE64 + 1];
200
201 // Generate some keys, check the results
202 Contrac * contrac;
203
204 contrac = contrac_new();
205 ck_assert(contrac != NULL);
206
207 contrac_set_tracing_key_base64(contrac, tracing_key_base64[0]);
208
209 result = contrac_set_day_number(contrac, 9);
210 ck_assert(result);
211
212 // Check the Rolling Proximity Identifiers are generated correctly
213 // Should use the standard test vectors when they're available
214
215 result = contrac_set_time_interval_number(contrac, 0);
216 ck_assert(result);
217 contrac_get_proximity_id_base64(contrac, rpi_base64);
218 ck_assert_int_eq(strlen(rpi_base64), RPI_SIZE_BASE64);
219 ck_assert_str_eq(rpi_base64, "yStiu899O+6xvdLiUdrpsA==");
220
221 result = contrac_set_time_interval_number(contrac, 82);
222 ck_assert(result);
223 contrac_get_proximity_id_base64(contrac, rpi_base64);
224 ck_assert_int_eq(strlen(rpi_base64), RPI_SIZE_BASE64);
225 ck_assert_str_eq(rpi_base64, "aFTYIeEUGYKELi8TUUql+Q==");
226
227 result = contrac_set_time_interval_number(contrac, 143);
228 ck_assert(result);
229 contrac_get_proximity_id_base64(contrac, rpi_base64);
230 ck_assert_int_eq(strlen(rpi_base64), RPI_SIZE_BASE64);
231 ck_assert_str_eq(rpi_base64, "MK9mDdgTsgsh6Vxp0XhasA==");
232
233 contrac_set_tracing_key_base64(contrac, tracing_key_base64[1]);
234
235 result = contrac_set_day_number(contrac, 500);
236 ck_assert(result);
237
238 result = contrac_set_time_interval_number(contrac, 1);
239 ck_assert(result);
240 contrac_get_proximity_id_base64(contrac, rpi_base64);
241 ck_assert_int_eq(strlen(rpi_base64), RPI_SIZE_BASE64);
242 ck_assert_str_eq(rpi_base64, "layNswS/rQxovfYnBhjXJg==");
243
244 result = contrac_set_time_interval_number(contrac, 27);
245 ck_assert(result);
246 contrac_get_proximity_id_base64(contrac, rpi_base64);
247 ck_assert_int_eq(strlen(rpi_base64), RPI_SIZE_BASE64);
248 ck_assert_str_eq(rpi_base64, "BJyzAC3hyVfcWOhQ9paEFA==");
249
250 result = contrac_set_time_interval_number(contrac, 143);
251 ck_assert(result);
252 contrac_get_proximity_id_base64(contrac, rpi_base64);
253 ck_assert_int_eq(strlen(rpi_base64), RPI_SIZE_BASE64);
254 ck_assert_str_eq(rpi_base64, "ItETUQc372fOzJKHvF8z6w==");
255
256 // Clean up
257 contrac_delete(contrac);
258 }
259 END_TEST
260
261 START_TEST (check_match) {
262 bool result;
263 char const *tracing_key_base64 = "3UmKrtcQ2tfLE8UPSXHb4PtgRfE0E2xdSs+PGVIS8cc=";
264 RpiList * beacon_list;
265 DtkList * diagnosis_list;
266 // There are four matches in amongst this lot
267 // (day, time) = (12, 15), (1175, 142), (1175, 67), (12, 93)
268 uint32_t beacon_days[8] = {55, 12, 0, 8787, 1175, 1175, 187, 12};
269 uint8_t beacon_times[8] = {1, 15, 5, 101, 142, 67, 51, 93};
270 uint32_t diagnosis_days[2] = {1175, 12};
271 // Summarise the four matches
272 uint32_t match_days[4] = {12, 1175, 1175, 12};
273 uint8_t match_times[4] = {15, 142, 67, 93};
274 int pos;
275 const unsigned char * rpi_bytes;
276 const unsigned char * dtk_bytes;
277 MatchList * matches;
278 MatchListItem const * match;
279
280 // Generate some keys, check the results
281 Contrac * contrac;
282
283 contrac = contrac_new();
284 ck_assert(contrac != NULL);
285
286 contrac_set_tracing_key_base64(contrac, tracing_key_base64);
287
288 // Generate some beacons (as if collected over BlueTooth)
289
290 beacon_list = rpi_list_new();
291
292 for (pos = 0; pos < 8; ++pos) {
293 result = contrac_set_day_number(contrac, beacon_days[pos]);
294 ck_assert(result);
295
296 result = contrac_set_time_interval_number(contrac, beacon_times[pos]);
297 ck_assert(result);
298
299 rpi_bytes = contrac_get_proximity_id(contrac);
300 rpi_list_add_beacon(beacon_list, rpi_bytes, beacon_times[pos]);
301 }
302
303 // Generate some diagnosis data (as if provided by a diagnosis server)
304
305 diagnosis_list = dtk_list_new();
306 for (pos = 0; pos < 2; ++pos) {
307 result = contrac_set_day_number(contrac, diagnosis_days[pos]);
308 ck_assert(result);
309
310 dtk_bytes = contrac_get_daily_key(contrac);
311 dtk_list_add_diagnosis(diagnosis_list, dtk_bytes, diagnosis_days[pos]);
312 }
313
314 // Check that the matching algorithm identifies the beacons that match
315
316 matches = match_list_new();
317 match_list_find_matches(matches, beacon_list, diagnosis_list);
318
319 match = match_list_first(matches);
320
321 while (match) {
322 result = false;
323 for (pos = 0; pos < 4; ++pos) {
324 if ((match_list_get_day_number(match) == match_days[pos]) && (match_list_get_time_interval_number(match) == match_times[pos])) {
325 result = true;
326 }
327 }
328
329 ck_assert(result);
330
331 match = match_list_next(match);
332 }
333 ck_assert_int_eq(match_list_count(matches), 4);
334
335 // Clean up
336 match_list_delete(matches);
337 rpi_list_delete(beacon_list);
338 dtk_list_delete(diagnosis_list);
339 contrac_delete(contrac);
340 }
341 END_TEST
342
343 START_TEST (check_time) {
344 bool result;
345 char const *tracing_key_base64 = "3UmKrtcQ2tfLE8UPSXHb4PtgRfE0E2xdSs+PGVIS8cc=";
346 uint32_t dn;
347 uint8_t tn;
348 time_t base = 1587415596;
349 time_t check;
350 Contrac * contrac;
351 char dtk_base64[DTK_SIZE_BASE64 + 1];
352 char rpi_base64[RPI_SIZE_BASE64 + 1];
353
354 check = base;
355 dn = epoch_to_day_number(check);
356 ck_assert_int_eq(dn, 18372);
357 tn = epoch_to_time_interval_number(check);
358 ck_assert_int_eq(tn, 124);
359
360 check = base + (24 * 60 * 60);
361 dn = epoch_to_day_number(check);
362 ck_assert_int_eq(dn, 18372 + 1);
363 tn = epoch_to_time_interval_number(check);
364 ck_assert_int_eq(tn, 124);
365
366 check = base - 675 * (24 * 60 * 60);
367 dn = epoch_to_day_number(check);
368 ck_assert_int_eq(dn, 18372 - 675);
369 tn = epoch_to_time_interval_number(check);
370 ck_assert_int_eq(tn, 124);
371
372 check = base + 15 * (10 * 60);
373 dn = epoch_to_day_number(check);
374 ck_assert_int_eq(dn, 18372);
375 tn = epoch_to_time_interval_number(check);
376 ck_assert_int_eq(tn, 124 + 15);
377
378 fake_time = 1587415596;
379
380 contrac = contrac_new();
381 contrac_set_tracing_key_base64(contrac, tracing_key_base64);
382
383 contrac_update_current_time(contrac);
384 result = contrac_get_initialised(contrac);
385 ck_assert(result);
386
387 contrac_get_daily_key_base64(contrac, dtk_base64);
388 ck_assert_str_eq(dtk_base64, "6GMXmeDAR5XU0AEtZQJ+tA==");
389
390 contrac_get_proximity_id_base64(contrac, rpi_base64);
391 ck_assert_str_eq(rpi_base64, "ysbjVuF7xf9eDH2y2T8VpQ==");
392
393 contrac_delete(contrac);
394 }
395 END_TEST
396
397 int main(void) {
398 int failed;
399 Suite * s;
400 SRunner *sr;
401 TCase * tc;
402
403 s = suite_create("libcontrac");
404
405 tc = tcase_create("Contrac");
406 tcase_add_test(tc, check_base64);
407 tcase_add_test(tc, check_contrac);
408 tcase_add_test(tc, check_dtk);
409 tcase_add_test(tc, check_rpi);
410 tcase_add_test(tc, check_match);
411 tcase_add_test(tc, check_time);
412 suite_add_tcase(s, tc);
413 sr = srunner_create(s);
414
415 srunner_run_all(sr, CK_NORMAL);
416 failed = srunner_ntests_failed(sr);
417 srunner_free(sr);
418
419 return (failed == 0) ? 0 : -1;
420 }
421