Merge in all of libtest updates.
[m6w6/libmemcached] / tests / hashkit_functions.cc
1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2 *
3 * libHashKit Functions Test
4 *
5 * Copyright (C) 2011 Data Differential, http://datadifferential.com/
6 * Copyright (C) 2006-2009 Brian Aker All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * * Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following disclaimer
17 * in the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * * The names of its contributors may not be used to endorse or
21 * promote products derived from this software without specific prior
22 * written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 *
36 */
37
38 #include <config.h>
39 #include <libtest/test.hpp>
40
41 using namespace libtest;
42
43 #include <cassert>
44 #include <cstdio>
45 #include <cstdlib>
46 #include <cstring>
47
48 #include <libhashkit/hashkit.h>
49
50 #include "hash_results.h"
51
52 static hashkit_st global_hashk;
53
54 /**
55 @brief hash_test_st is a structure we use in testing. It is currently empty.
56 */
57 typedef struct hash_test_st hash_test_st;
58
59 struct hash_test_st
60 {
61 bool _unused;
62 };
63
64 static test_return_t init_test(void *not_used)
65 {
66 hashkit_st hashk;
67 hashkit_st *hashk_ptr;
68 (void)not_used;
69
70 hashk_ptr= hashkit_create(&hashk);
71 test_true(hashk_ptr);
72 test_true(hashk_ptr == &hashk);
73 test_true(hashkit_is_allocated(hashk_ptr) == false);
74
75 hashkit_free(hashk_ptr);
76
77 return TEST_SUCCESS;
78 }
79
80 static test_return_t allocation_test(void *not_used)
81 {
82 hashkit_st *hashk_ptr;
83 (void)not_used;
84
85 hashk_ptr= hashkit_create(NULL);
86 test_true(hashk_ptr);
87 test_true(hashkit_is_allocated(hashk_ptr) == true);
88 hashkit_free(hashk_ptr);
89
90 return TEST_SUCCESS;
91 }
92
93 static test_return_t clone_test(hashkit_st *hashk)
94 {
95 // First we make sure that the testing system is giving us what we expect.
96 assert(&global_hashk == hashk);
97
98 // Second we test if hashk is even valid
99
100 /* All null? */
101 {
102 hashkit_st *hashk_ptr;
103 hashk_ptr= hashkit_clone(NULL, NULL);
104 test_true(hashk_ptr);
105 test_true(hashkit_is_allocated(hashk_ptr));
106 hashkit_free(hashk_ptr);
107 }
108
109 /* Can we init from null? */
110 {
111 hashkit_st *hashk_ptr;
112
113 hashk_ptr= hashkit_clone(NULL, hashk);
114
115 test_true(hashk_ptr);
116 test_true(hashkit_is_allocated(hashk_ptr));
117
118 hashkit_free(hashk_ptr);
119 }
120
121 /* Can we init from struct? */
122 {
123 hashkit_st declared_clone;
124 hashkit_st *hash_clone;
125
126 hash_clone= hashkit_clone(&declared_clone, NULL);
127 test_true(hash_clone);
128 test_true(hash_clone == &declared_clone);
129 test_false(hashkit_is_allocated(hash_clone));
130
131 hashkit_free(hash_clone);
132 }
133
134 /* Can we init from struct? */
135 {
136 hashkit_st declared_clone;
137 hashkit_st *hash_clone;
138
139 hash_clone= hashkit_clone(&declared_clone, hashk);
140 test_true(hash_clone);
141 test_true(hash_clone == &declared_clone);
142 test_false(hashkit_is_allocated(hash_clone));
143
144 hashkit_free(hash_clone);
145 }
146
147 return TEST_SUCCESS;
148 }
149
150 static test_return_t one_at_a_time_run (hashkit_st *hashk)
151 {
152 uint32_t x;
153 const char **ptr;
154 (void)hashk;
155
156 for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
157 {
158 uint32_t hash_val;
159
160 hash_val= libhashkit_one_at_a_time(*ptr, strlen(*ptr));
161 test_true(one_at_a_time_values[x] == hash_val);
162 }
163
164 return TEST_SUCCESS;
165 }
166
167 static test_return_t md5_run (hashkit_st *hashk)
168 {
169 uint32_t x;
170 const char **ptr;
171 (void)hashk;
172
173 for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
174 {
175 uint32_t hash_val;
176
177 hash_val= libhashkit_md5(*ptr, strlen(*ptr));
178 test_true(md5_values[x] == hash_val);
179 }
180
181 return TEST_SUCCESS;
182 }
183
184 static test_return_t crc_run (hashkit_st *hashk)
185 {
186 uint32_t x;
187 const char **ptr;
188 (void)hashk;
189
190 for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
191 {
192 uint32_t hash_val;
193
194 hash_val= libhashkit_crc32(*ptr, strlen(*ptr));
195 assert(crc_values[x] == hash_val);
196 }
197
198 return TEST_SUCCESS;
199 }
200
201 static test_return_t fnv1_64_run (hashkit_st *hashk)
202 {
203 uint32_t x;
204 const char **ptr;
205 (void)hashk;
206
207 for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
208 {
209 uint32_t hash_val;
210
211 hash_val= libhashkit_fnv1_64(*ptr, strlen(*ptr));
212 assert(fnv1_64_values[x] == hash_val);
213 }
214
215 return TEST_SUCCESS;
216 }
217
218 static test_return_t fnv1a_64_run (hashkit_st *hashk)
219 {
220 uint32_t x;
221 const char **ptr;
222 (void)hashk;
223
224 for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
225 {
226 uint32_t hash_val;
227
228 hash_val= libhashkit_fnv1a_64(*ptr, strlen(*ptr));
229 assert(fnv1a_64_values[x] == hash_val);
230 }
231
232 return TEST_SUCCESS;
233 }
234
235 static test_return_t fnv1_32_run (hashkit_st *hashk)
236 {
237 uint32_t x;
238 const char **ptr;
239 (void)hashk;
240
241 for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
242 {
243 uint32_t hash_val;
244
245 hash_val= libhashkit_fnv1_32(*ptr, strlen(*ptr));
246 assert(fnv1_32_values[x] == hash_val);
247 }
248
249 return TEST_SUCCESS;
250 }
251
252 static test_return_t fnv1a_32_run (hashkit_st *hashk)
253 {
254 uint32_t x;
255 const char **ptr;
256 (void)hashk;
257
258 for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
259 {
260 uint32_t hash_val;
261
262 hash_val= libhashkit_fnv1a_32(*ptr, strlen(*ptr));
263 assert(fnv1a_32_values[x] == hash_val);
264 }
265
266 return TEST_SUCCESS;
267 }
268
269 static test_return_t hsieh_run (hashkit_st *hashk)
270 {
271 uint32_t x;
272 const char **ptr;
273 (void)hashk;
274
275 for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
276 {
277 uint32_t hash_val;
278
279 #ifdef HAVE_HSIEH_HASH
280 hash_val= libhashkit_hsieh(*ptr, strlen(*ptr));
281 #else
282 hash_val= 1;
283 #endif
284 assert(hsieh_values[x] == hash_val);
285 }
286
287 return TEST_SUCCESS;
288 }
289
290 static test_return_t murmur_run (hashkit_st *hashk)
291 {
292 (void)hashk;
293
294 #ifdef WORDS_BIGENDIAN
295 (void)murmur_values;
296 return TEST_SKIPPED;
297 #else
298 uint32_t x;
299 const char **ptr;
300
301 for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
302 {
303 uint32_t hash_val;
304
305 #ifdef HAVE_MURMUR_HASH
306 hash_val= libhashkit_murmur(*ptr, strlen(*ptr));
307 #else
308 hash_val= 1;
309 #endif
310 assert(murmur_values[x] == hash_val);
311 }
312
313 return TEST_SUCCESS;
314 #endif
315 }
316
317 static test_return_t jenkins_run (hashkit_st *hashk)
318 {
319 uint32_t x;
320 const char **ptr;
321 (void)hashk;
322
323 for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
324 {
325 uint32_t hash_val;
326
327 hash_val= libhashkit_jenkins(*ptr, strlen(*ptr));
328 assert(jenkins_values[x] == hash_val);
329 }
330
331 return TEST_SUCCESS;
332 }
333
334
335
336
337 /**
338 @brief now we list out the tests.
339 */
340
341 test_st allocation[]= {
342 {"init", 0, (test_callback_fn*)init_test},
343 {"create and free", 0, (test_callback_fn*)allocation_test},
344 {"clone", 0, (test_callback_fn*)clone_test},
345 {0, 0, 0}
346 };
347
348 static test_return_t hashkit_digest_test(hashkit_st *hashk)
349 {
350 uint32_t value;
351 value= hashkit_digest(hashk, "a", sizeof("a"));
352
353 return TEST_SUCCESS;
354 }
355
356 static test_return_t hashkit_set_function_test(hashkit_st *hashk)
357 {
358 for (int algo= int(HASHKIT_HASH_DEFAULT); algo < int(HASHKIT_HASH_MAX); algo++)
359 {
360 uint32_t x;
361 const char **ptr;
362 uint32_t *list;
363
364 hashkit_return_t rc= hashkit_set_function(hashk, static_cast<hashkit_hash_algorithm_t>(algo));
365
366 /* Hsieh is disabled most of the time for patent issues */
367 #ifndef HAVE_HSIEH_HASH
368 if (rc == HASHKIT_FAILURE && algo == HASHKIT_HASH_HSIEH)
369 continue;
370 #endif
371
372 #ifndef HAVE_MURMUR_HASH
373 if (rc == HASHKIT_FAILURE && algo == HASHKIT_HASH_MURMUR)
374 continue;
375 #endif
376
377 if (rc == HASHKIT_INVALID_ARGUMENT && algo == HASHKIT_HASH_CUSTOM)
378 continue;
379
380 test_true_got(rc == HASHKIT_SUCCESS, hashkit_strerror(NULL, rc));
381
382 switch (algo)
383 {
384 case HASHKIT_HASH_DEFAULT:
385 list= one_at_a_time_values;
386 break;
387 case HASHKIT_HASH_MD5:
388 list= md5_values;
389 break;
390 case HASHKIT_HASH_CRC:
391 list= crc_values;
392 break;
393 case HASHKIT_HASH_FNV1_64:
394 list= fnv1_64_values;
395 break;
396 case HASHKIT_HASH_FNV1A_64:
397 list= fnv1a_64_values;
398 break;
399 case HASHKIT_HASH_FNV1_32:
400 list= fnv1_32_values;
401 break;
402 case HASHKIT_HASH_FNV1A_32:
403 list= fnv1a_32_values;
404 break;
405 case HASHKIT_HASH_HSIEH:
406 list= hsieh_values;
407 break;
408 case HASHKIT_HASH_MURMUR:
409 list= murmur_values;
410 break;
411 case HASHKIT_HASH_JENKINS:
412 list= jenkins_values;
413 break;
414 case HASHKIT_HASH_CUSTOM:
415 case HASHKIT_HASH_MAX:
416 default:
417 list= NULL;
418 break;
419 }
420
421 // Now we make sure we did set the hash correctly.
422 if (list)
423 {
424 for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
425 {
426 uint32_t hash_val;
427
428 hash_val= hashkit_digest(hashk, *ptr, strlen(*ptr));
429 test_true(list[x] == hash_val);
430 }
431 }
432 else
433 {
434 return TEST_FAILURE;
435 }
436 }
437
438 return TEST_SUCCESS;
439 }
440
441 static uint32_t hash_test_function(const char *string, size_t string_length, void *context)
442 {
443 (void)context;
444 return libhashkit_md5(string, string_length);
445 }
446
447 static test_return_t hashkit_set_custom_function_test(hashkit_st *hashk)
448 {
449 hashkit_return_t rc;
450 uint32_t x;
451 const char **ptr;
452
453
454 rc= hashkit_set_custom_function(hashk, hash_test_function, NULL);
455 test_true(rc == HASHKIT_SUCCESS);
456
457 for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
458 {
459 uint32_t hash_val;
460
461 hash_val= hashkit_digest(hashk, *ptr, strlen(*ptr));
462 test_true(md5_values[x] == hash_val);
463 }
464
465 return TEST_SUCCESS;
466 }
467
468 static test_return_t hashkit_set_distribution_function_test(hashkit_st *hashk)
469 {
470 for (int algo= int(HASHKIT_HASH_DEFAULT); algo < int(HASHKIT_HASH_MAX); algo++)
471 {
472 hashkit_return_t rc= hashkit_set_distribution_function(hashk, static_cast<hashkit_hash_algorithm_t>(algo));
473
474 /* Hsieh is disabled most of the time for patent issues */
475 if (rc == HASHKIT_FAILURE && algo == HASHKIT_HASH_HSIEH)
476 continue;
477
478 if (rc == HASHKIT_INVALID_ARGUMENT && algo == HASHKIT_HASH_CUSTOM)
479 continue;
480
481 test_true(rc == HASHKIT_SUCCESS);
482 }
483
484 return TEST_SUCCESS;
485 }
486
487 static test_return_t hashkit_set_custom_distribution_function_test(hashkit_st *hashk)
488 {
489 hashkit_return_t rc= hashkit_set_custom_distribution_function(hashk, hash_test_function, NULL);
490 test_true(rc == HASHKIT_SUCCESS);
491
492 return TEST_SUCCESS;
493 }
494
495
496 static test_return_t hashkit_get_function_test(hashkit_st *hashk)
497 {
498 for (int algo= int(HASHKIT_HASH_DEFAULT); algo < int(HASHKIT_HASH_MAX); algo++)
499 {
500
501 if (HASHKIT_HASH_CUSTOM or HASHKIT_HASH_HSIEH)
502 continue;
503
504 hashkit_return_t rc= hashkit_set_function(hashk, static_cast<hashkit_hash_algorithm_t>(algo));
505 test_true(rc == HASHKIT_SUCCESS);
506
507 test_true(hashkit_get_function(hashk) == algo);
508 }
509 return TEST_SUCCESS;
510 }
511
512 static test_return_t hashkit_compare_test(hashkit_st *hashk)
513 {
514 hashkit_st *clone= hashkit_clone(NULL, hashk);
515
516 test_true(hashkit_compare(clone, hashk));
517 hashkit_free(clone);
518
519 return TEST_SUCCESS;
520 }
521
522 test_st hashkit_st_functions[] ={
523 {"hashkit_digest", 0, (test_callback_fn*)hashkit_digest_test},
524 {"hashkit_set_function", 0, (test_callback_fn*)hashkit_set_function_test},
525 {"hashkit_set_custom_function", 0, (test_callback_fn*)hashkit_set_custom_function_test},
526 {"hashkit_get_function", 0, (test_callback_fn*)hashkit_get_function_test},
527 {"hashkit_set_distribution_function", 0, (test_callback_fn*)hashkit_set_distribution_function_test},
528 {"hashkit_set_custom_distribution_function", 0, (test_callback_fn*)hashkit_set_custom_distribution_function_test},
529 {"hashkit_compare", 0, (test_callback_fn*)hashkit_compare_test},
530 {0, 0, 0}
531 };
532
533 static test_return_t libhashkit_digest_test(hashkit_st *hashk)
534 {
535
536 (void)hashk;
537
538 uint32_t value= libhashkit_digest("a", sizeof("a"), HASHKIT_HASH_DEFAULT);
539 test_true(value);
540
541 return TEST_SUCCESS;
542 }
543
544 test_st library_functions[] ={
545 {"libhashkit_digest", 0, (test_callback_fn*)libhashkit_digest_test},
546 {0, 0, 0}
547 };
548
549 test_st hash_tests[] ={
550 {"one_at_a_time", 0, (test_callback_fn*)one_at_a_time_run },
551 {"md5", 0, (test_callback_fn*)md5_run },
552 {"crc", 0, (test_callback_fn*)crc_run },
553 {"fnv1_64", 0, (test_callback_fn*)fnv1_64_run },
554 {"fnv1a_64", 0, (test_callback_fn*)fnv1a_64_run },
555 {"fnv1_32", 0, (test_callback_fn*)fnv1_32_run },
556 {"fnv1a_32", 0, (test_callback_fn*)fnv1a_32_run },
557 {"hsieh", 0, (test_callback_fn*)hsieh_run },
558 {"murmur", 0, (test_callback_fn*)murmur_run },
559 {"jenkis", 0, (test_callback_fn*)jenkins_run },
560 {0, 0, (test_callback_fn*)0}
561 };
562
563 /*
564 * The following test suite is used to verify that we don't introduce
565 * regression bugs. If you want more information about the bug / test,
566 * you should look in the bug report at
567 * http://bugs.launchpad.net/libmemcached
568 */
569 test_st regression[]= {
570 {0, 0, 0}
571 };
572
573 collection_st collection[] ={
574 {"allocation", 0, 0, allocation},
575 {"hashkit_st_functions", 0, 0, hashkit_st_functions},
576 {"library_functions", 0, 0, library_functions},
577 {"hashing", 0, 0, hash_tests},
578 {"regression", 0, 0, regression},
579 {0, 0, 0, 0}
580 };
581
582 static void *world_create(libtest::server_startup_st&, test_return_t& error)
583 {
584 hashkit_st *hashk_ptr= hashkit_create(&global_hashk);
585
586 if (hashk_ptr != &global_hashk)
587 {
588 error= TEST_FAILURE;
589 return NULL;
590 }
591
592 if (hashkit_is_allocated(hashk_ptr) == true)
593 {
594 error= TEST_FAILURE;
595 return NULL;
596 }
597
598 return hashk_ptr;
599 }
600
601
602 static bool world_destroy(void *object)
603 {
604 hashkit_st *hashk= (hashkit_st *)object;
605 // Did we get back what we expected?
606 test_true(hashkit_is_allocated(hashk) == false);
607 hashkit_free(&global_hashk);
608
609 return TEST_SUCCESS;
610 }
611
612 void get_world(Framework *world)
613 {
614 world->collections= collection;
615 world->_create= world_create;
616 world->_destroy= world_destroy;
617 }