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