Merge in build lp
[awesomized/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 test_true(hashkit_digest(hashk, "a", sizeof("a")));
351
352 return TEST_SUCCESS;
353 }
354
355 static test_return_t hashkit_set_function_test(hashkit_st *hashk)
356 {
357 for (int algo= int(HASHKIT_HASH_DEFAULT); algo < int(HASHKIT_HASH_MAX); algo++)
358 {
359 uint32_t x;
360 const char **ptr;
361 uint32_t *list;
362
363 hashkit_return_t rc= hashkit_set_function(hashk, static_cast<hashkit_hash_algorithm_t>(algo));
364
365 /* Hsieh is disabled most of the time for patent issues */
366 #ifndef HAVE_HSIEH_HASH
367 if (rc == HASHKIT_FAILURE && algo == HASHKIT_HASH_HSIEH)
368 continue;
369 #endif
370
371 #ifndef HAVE_MURMUR_HASH
372 if (rc == HASHKIT_FAILURE && algo == HASHKIT_HASH_MURMUR)
373 continue;
374 #endif
375
376 if (rc == HASHKIT_INVALID_ARGUMENT && algo == HASHKIT_HASH_CUSTOM)
377 continue;
378
379 test_true_got(rc == HASHKIT_SUCCESS, hashkit_strerror(NULL, rc));
380
381 switch (algo)
382 {
383 case HASHKIT_HASH_DEFAULT:
384 list= one_at_a_time_values;
385 break;
386 case HASHKIT_HASH_MD5:
387 list= md5_values;
388 break;
389 case HASHKIT_HASH_CRC:
390 list= crc_values;
391 break;
392 case HASHKIT_HASH_FNV1_64:
393 list= fnv1_64_values;
394 break;
395 case HASHKIT_HASH_FNV1A_64:
396 list= fnv1a_64_values;
397 break;
398 case HASHKIT_HASH_FNV1_32:
399 list= fnv1_32_values;
400 break;
401 case HASHKIT_HASH_FNV1A_32:
402 list= fnv1a_32_values;
403 break;
404 case HASHKIT_HASH_HSIEH:
405 list= hsieh_values;
406 break;
407 case HASHKIT_HASH_MURMUR:
408 list= murmur_values;
409 break;
410 case HASHKIT_HASH_JENKINS:
411 list= jenkins_values;
412 break;
413 case HASHKIT_HASH_CUSTOM:
414 case HASHKIT_HASH_MAX:
415 default:
416 list= NULL;
417 break;
418 }
419
420 // Now we make sure we did set the hash correctly.
421 if (list)
422 {
423 for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
424 {
425 uint32_t hash_val;
426
427 hash_val= hashkit_digest(hashk, *ptr, strlen(*ptr));
428 test_true(list[x] == hash_val);
429 }
430 }
431 else
432 {
433 return TEST_FAILURE;
434 }
435 }
436
437 return TEST_SUCCESS;
438 }
439
440 static uint32_t hash_test_function(const char *string, size_t string_length, void *context)
441 {
442 (void)context;
443 return libhashkit_md5(string, string_length);
444 }
445
446 static test_return_t hashkit_set_custom_function_test(hashkit_st *hashk)
447 {
448 hashkit_return_t rc;
449 uint32_t x;
450 const char **ptr;
451
452
453 rc= hashkit_set_custom_function(hashk, hash_test_function, NULL);
454 test_true(rc == HASHKIT_SUCCESS);
455
456 for (ptr= list_to_hash, x= 0; *ptr; ptr++, x++)
457 {
458 uint32_t hash_val;
459
460 hash_val= hashkit_digest(hashk, *ptr, strlen(*ptr));
461 test_true(md5_values[x] == hash_val);
462 }
463
464 return TEST_SUCCESS;
465 }
466
467 static test_return_t hashkit_set_distribution_function_test(hashkit_st *hashk)
468 {
469 for (int algo= int(HASHKIT_HASH_DEFAULT); algo < int(HASHKIT_HASH_MAX); algo++)
470 {
471 hashkit_return_t rc= hashkit_set_distribution_function(hashk, static_cast<hashkit_hash_algorithm_t>(algo));
472
473 /* Hsieh is disabled most of the time for patent issues */
474 if (rc == HASHKIT_FAILURE && algo == HASHKIT_HASH_HSIEH)
475 continue;
476
477 if (rc == HASHKIT_INVALID_ARGUMENT && algo == HASHKIT_HASH_CUSTOM)
478 continue;
479
480 test_true(rc == HASHKIT_SUCCESS);
481 }
482
483 return TEST_SUCCESS;
484 }
485
486 static test_return_t hashkit_set_custom_distribution_function_test(hashkit_st *hashk)
487 {
488 hashkit_return_t rc= hashkit_set_custom_distribution_function(hashk, hash_test_function, NULL);
489 test_true(rc == HASHKIT_SUCCESS);
490
491 return TEST_SUCCESS;
492 }
493
494
495 static test_return_t hashkit_get_function_test(hashkit_st *hashk)
496 {
497 for (int algo= int(HASHKIT_HASH_DEFAULT); algo < int(HASHKIT_HASH_MAX); algo++)
498 {
499
500 if (HASHKIT_HASH_CUSTOM or HASHKIT_HASH_HSIEH)
501 continue;
502
503 hashkit_return_t rc= hashkit_set_function(hashk, static_cast<hashkit_hash_algorithm_t>(algo));
504 test_true(rc == HASHKIT_SUCCESS);
505
506 test_true(hashkit_get_function(hashk) == algo);
507 }
508 return TEST_SUCCESS;
509 }
510
511 static test_return_t hashkit_compare_test(hashkit_st *hashk)
512 {
513 hashkit_st *clone= hashkit_clone(NULL, hashk);
514
515 test_true(hashkit_compare(clone, hashk));
516 hashkit_free(clone);
517
518 return TEST_SUCCESS;
519 }
520
521 test_st hashkit_st_functions[] ={
522 {"hashkit_digest", 0, (test_callback_fn*)hashkit_digest_test},
523 {"hashkit_set_function", 0, (test_callback_fn*)hashkit_set_function_test},
524 {"hashkit_set_custom_function", 0, (test_callback_fn*)hashkit_set_custom_function_test},
525 {"hashkit_get_function", 0, (test_callback_fn*)hashkit_get_function_test},
526 {"hashkit_set_distribution_function", 0, (test_callback_fn*)hashkit_set_distribution_function_test},
527 {"hashkit_set_custom_distribution_function", 0, (test_callback_fn*)hashkit_set_custom_distribution_function_test},
528 {"hashkit_compare", 0, (test_callback_fn*)hashkit_compare_test},
529 {0, 0, 0}
530 };
531
532 static test_return_t libhashkit_digest_test(hashkit_st *hashk)
533 {
534
535 (void)hashk;
536
537 uint32_t value= libhashkit_digest("a", sizeof("a"), HASHKIT_HASH_DEFAULT);
538 test_true(value);
539
540 return TEST_SUCCESS;
541 }
542
543 test_st library_functions[] ={
544 {"libhashkit_digest", 0, (test_callback_fn*)libhashkit_digest_test},
545 {0, 0, 0}
546 };
547
548 test_st hash_tests[] ={
549 {"one_at_a_time", 0, (test_callback_fn*)one_at_a_time_run },
550 {"md5", 0, (test_callback_fn*)md5_run },
551 {"crc", 0, (test_callback_fn*)crc_run },
552 {"fnv1_64", 0, (test_callback_fn*)fnv1_64_run },
553 {"fnv1a_64", 0, (test_callback_fn*)fnv1a_64_run },
554 {"fnv1_32", 0, (test_callback_fn*)fnv1_32_run },
555 {"fnv1a_32", 0, (test_callback_fn*)fnv1a_32_run },
556 {"hsieh", 0, (test_callback_fn*)hsieh_run },
557 {"murmur", 0, (test_callback_fn*)murmur_run },
558 {"jenkis", 0, (test_callback_fn*)jenkins_run },
559 {0, 0, (test_callback_fn*)0}
560 };
561
562 /*
563 * The following test suite is used to verify that we don't introduce
564 * regression bugs. If you want more information about the bug / test,
565 * you should look in the bug report at
566 * http://bugs.launchpad.net/libmemcached
567 */
568 test_st regression[]= {
569 {0, 0, 0}
570 };
571
572 collection_st collection[] ={
573 {"allocation", 0, 0, allocation},
574 {"hashkit_st_functions", 0, 0, hashkit_st_functions},
575 {"library_functions", 0, 0, library_functions},
576 {"hashing", 0, 0, hash_tests},
577 {"regression", 0, 0, regression},
578 {0, 0, 0, 0}
579 };
580
581 static void *world_create(libtest::server_startup_st&, test_return_t& error)
582 {
583 hashkit_st *hashk_ptr= hashkit_create(&global_hashk);
584
585 if (hashk_ptr != &global_hashk)
586 {
587 error= TEST_FAILURE;
588 return NULL;
589 }
590
591 if (hashkit_is_allocated(hashk_ptr) == true)
592 {
593 error= TEST_FAILURE;
594 return NULL;
595 }
596
597 return hashk_ptr;
598 }
599
600
601 static bool world_destroy(void *object)
602 {
603 hashkit_st *hashk= (hashkit_st *)object;
604 // Did we get back what we expected?
605 test_true(hashkit_is_allocated(hashk) == false);
606 hashkit_free(&global_hashk);
607
608 return TEST_SUCCESS;
609 }
610
611 void get_world(Framework *world)
612 {
613 world->collections= collection;
614 world->_create= world_create;
615 world->_destroy= world_destroy;
616 }