LCOV - code coverage report
Current view: top level - test - hashtabletest.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 151 151 100.0 %
Date: 2015-05-24 18:28:16 Functions: 10 10 100.0 %

          Line data    Source code
       1             : /***************************************************************************//**
       2             : 
       3             :   @file         hashtabletest.c
       4             : 
       5             :   @author       Stephen Brennan
       6             : 
       7             :   @date         Created Tuesday,  5 December 2013
       8             : 
       9             :   @brief        A test of the hash table.
      10             : 
      11             :   @copyright    Copyright (c) 2013-2015, Stephen Brennan.  Released under the
      12             :                 Revised BSD License.  See the LICENSE.txt file for details.
      13             : 
      14             : *******************************************************************************/
      15             : 
      16             : #include <stdio.h>
      17             : 
      18             : #include "tests.h"
      19             : #include "libstephen/ut.h"
      20             : #include "libstephen/ht.h"
      21             : 
      22             : #define TEST_PAIRS 5
      23             : 
      24             : char *test_keys[] = {
      25             :   "first key",
      26             :   "second key",
      27             :   "third key",
      28             :   "fourth key",
      29             :   "fifth key"
      30             : };
      31             : 
      32             : char *test_values[] = {
      33             :   "first value",
      34             :   "second value",
      35             :   "third value",
      36             :   "fourth value",
      37             :   "fifth value"
      38             : };
      39             : 
      40             : int ht_test_deletions = 0;
      41             : 
      42         211 : void ht_test_deleter(DATA dValue)
      43             : {
      44         211 :   ht_test_deletions++;
      45         211 : }
      46             : 
      47          40 : unsigned int ht_test_constant_hash(DATA dKey)
      48             : {
      49             :   // return random_die_roll();
      50          40 :   return 4;
      51             : }
      52             : 
      53         542 : unsigned int ht_test_linear_hash(DATA dKey)
      54             : {
      55         542 :   return (unsigned int) dKey.data_llint;
      56             : }
      57             : 
      58             : /**
      59             :    This doesn't really just test insert.  It also tests create and get.  But I
      60             :    can't really isolate *just* insert.
      61             :  */
      62           1 : int ht_test_insert()
      63             : {
      64           1 :   smb_status status = SMB_SUCCESS;
      65             :   DATA key, value;
      66             :   int i;
      67           1 :   smb_ht *table = ht_create(&ht_string_hash, &data_compare_string);
      68             : 
      69           6 :   for (i = 0; i < TEST_PAIRS; i++) {
      70           5 :     key.data_ptr = test_keys[i];
      71           5 :     value.data_ptr = test_values[i];
      72           5 :     ht_insert(table, key, value);
      73             :   }
      74             : 
      75           6 :   for (i = 0; i < TEST_PAIRS; i++) {
      76           5 :     key.data_ptr = test_keys[i];
      77           5 :     TEST_ASSERT(test_values[i] == ht_get(table, key, &status).data_ptr);
      78           5 :     TEST_ASSERT(status == SMB_SUCCESS);
      79             :   }
      80             : 
      81           1 :   ht_delete(table);
      82           1 :   return 0;
      83             : }
      84             : 
      85           1 : int ht_test_remove()
      86             : {
      87           1 :   smb_status status= SMB_SUCCESS;
      88             :   DATA key, value;
      89             :   int i;
      90           1 :   smb_ht *table = ht_create(&ht_string_hash, &data_compare_string);
      91           1 :   ht_test_deletions = 0;
      92             : 
      93           6 :   for (i = 0; i < TEST_PAIRS; i++) {
      94           5 :     key.data_ptr = test_keys[i];
      95           5 :     value.data_ptr = test_values[i];
      96           5 :     ht_insert(table, key, value);
      97             :   }
      98             : 
      99           1 :   TEST_ASSERT(table->length == TEST_PAIRS);
     100             : 
     101           6 :   for (i = 0; i < TEST_PAIRS; i++) {
     102           5 :     key.data_ptr = test_keys[i];
     103           5 :     value = ht_get(table, key, &status);
     104           5 :     TEST_ASSERT(status == SMB_SUCCESS);
     105           5 :     TEST_ASSERT(test_values[i] == value.data_ptr);
     106           5 :     ht_remove_act(table, key, ht_test_deleter, &status);
     107           5 :     TEST_ASSERT(status == SMB_SUCCESS);
     108           5 :     TEST_ASSERT(table->length == TEST_PAIRS - i - 1);
     109             :   }
     110             : 
     111           1 :   ht_delete_act(table, ht_test_deleter);
     112           1 :   TEST_ASSERT(ht_test_deletions == TEST_PAIRS);
     113           1 :   return 0;
     114             : }
     115             : 
     116             : /*
     117             :   This test expecs a NOT_FOUND_ERROR
     118             :  */
     119           1 : int ht_test_remove_invalid()
     120             : {
     121           1 :   smb_status status = SMB_SUCCESS;
     122             :   DATA key;
     123           1 :   smb_ht *table = ht_create(&ht_string_hash, &data_compare_string);
     124             : 
     125           1 :   key.data_ptr = "invalid key";
     126           1 :   ht_get(table, key, &status);
     127           1 :   TEST_ASSERT(status == SMB_NOT_FOUND_ERROR);
     128             : 
     129           1 :   ht_delete(table);
     130           1 :   return 0;
     131             : }
     132             : 
     133             : /**
     134             :    This test intentionally uses a very bad hash function that returns a
     135             :    constant.  This way, I can test whether the insertion and removal for large
     136             :    buckets is working.
     137             :  */
     138           1 : int ht_test_buckets()
     139             : {
     140           1 :   smb_status status = SMB_SUCCESS;
     141             :   DATA key, value;
     142             :   int i;
     143           1 :   smb_ht *table = ht_create(&ht_test_constant_hash, &data_compare_int);
     144           1 :   ht_test_deletions = 0;
     145             : 
     146          21 :   for (i = 0; i < 20; i++) {
     147          20 :     key.data_llint = i;
     148          20 :     value.data_llint = -i;
     149          20 :     ht_insert(table, key, value);
     150          20 :     TEST_ASSERT(status == SMB_SUCCESS);
     151          20 :     TEST_ASSERT(table->length == i+1);
     152             :   }
     153             : 
     154             :   // Remove one from the middle of the bucket list.
     155           1 :   key.data_llint = 10;
     156           1 :   ht_remove_act(table, key, ht_test_deleter, &status);
     157           1 :   TEST_ASSERT(status == SMB_SUCCESS);
     158           1 :   TEST_ASSERT(table->length == 19);
     159             : 
     160             :   // Remove one from the beginning of the bucket list.
     161           1 :   key.data_llint = 0;
     162           1 :   ht_remove_act(table, key, ht_test_deleter, &status);
     163           1 :   TEST_ASSERT(status == SMB_SUCCESS);
     164           1 :   TEST_ASSERT(table->length == 18);
     165             : 
     166             :   //ht_print(table, 0);
     167             : 
     168             :   // Remove from the end of the list.
     169           1 :   key.data_llint = 19;
     170           1 :   ht_remove_act(table, key, ht_test_deleter, &status);
     171           1 :   TEST_ASSERT(status == SMB_SUCCESS);
     172           1 :   TEST_ASSERT(table->length == 17);
     173             : 
     174             :   //ht_print(table, 0);
     175             : 
     176             :   // Verify that the other items are still there.
     177          10 :   for (i = 1; i < 10; i++) {
     178           9 :     key.data_llint = i;
     179           9 :     value = ht_get(table, key, &status);
     180           9 :     TEST_ASSERT(status == SMB_SUCCESS);
     181           9 :     TEST_ASSERT(value.data_llint == -i);
     182             :   }
     183             : 
     184           9 :   for (i = 11; i < 19; i++) {
     185           8 :     key.data_llint = i;
     186           8 :     value = ht_get(table, key, &status);
     187           8 :     TEST_ASSERT(status == SMB_SUCCESS);
     188           8 :     TEST_ASSERT(value.data_llint == -i);
     189             :   }
     190             : 
     191           1 :   ht_delete_act(table, ht_test_deleter);
     192           1 :   TEST_ASSERT(ht_test_deletions == 20);
     193           1 :   return 0;
     194             : }
     195             : 
     196             : /**
     197             :    This test adds to the hash table until it is forced to reallocate.  Then it
     198             :    checks that every value is still accessible.
     199             :  */
     200           1 : int ht_test_resize()
     201             : {
     202           1 :   smb_status status = SMB_SUCCESS;
     203             :   DATA key, value;
     204             :   int i;
     205             :   // Truncating addition will trim this to the number just before expanding.
     206           1 :   int last_stable = 1 + (int) (HASH_TABLE_INITIAL_SIZE * HASH_TABLE_MAX_LOAD_FACTOR);
     207           1 :   smb_ht *table = ht_create(ht_test_linear_hash, &data_compare_int);
     208           1 :   ht_test_deletions = 0;
     209             : 
     210         181 :   for (i = 0; i < last_stable; i++) {
     211         180 :     key.data_llint = i;
     212         180 :     value.data_llint = -i;
     213         180 :     ht_insert(table, key, value);
     214         180 :     TEST_ASSERT(table->allocated == HASH_TABLE_INITIAL_SIZE);
     215         180 :     TEST_ASSERT(table->length == i + 1);
     216             :   }
     217             : 
     218           1 :   key.data_llint = last_stable;
     219           1 :   value.data_llint = -last_stable;
     220           1 :   ht_insert(table, key, value);
     221           1 :   TEST_ASSERT(table->allocated > HASH_TABLE_INITIAL_SIZE);
     222           1 :   TEST_ASSERT(table->length == last_stable + 1);
     223             : 
     224         182 :   for (i = 0; i <= last_stable; i++) {
     225         181 :     key.data_llint = i;
     226         181 :     value = ht_get(table, key, &status);
     227         181 :     TEST_ASSERT(status == SMB_SUCCESS);
     228         181 :     TEST_ASSERT(value.data_llint == -i);
     229             :   }
     230             : 
     231           1 :   ht_delete_act(table, ht_test_deleter);
     232           1 :   TEST_ASSERT(ht_test_deletions == last_stable + 1);
     233           1 :   return 0;
     234             : }
     235             : 
     236           1 : int ht_test_duplicate()
     237             : {
     238           1 :   smb_status status = SMB_SUCCESS;
     239             :   DATA key, value;
     240             :   int i;
     241           1 :   char *newKey = "not the first value";
     242           1 :   smb_ht *table = ht_create(ht_string_hash, &data_compare_string);
     243           1 :   ht_test_deletions = 0;
     244             : 
     245           6 :   for (i = 0; i < TEST_PAIRS; i++) {
     246           5 :     key.data_ptr = test_keys[i];
     247           5 :     value.data_ptr = test_values[i];
     248           5 :     ht_insert(table, key, value);
     249             :   }
     250             : 
     251           4 :   for (i = 0; i < TEST_PAIRS; i += 2) {
     252           3 :     TEST_ASSERT(table->length == TEST_PAIRS);
     253             : 
     254           3 :     key.data_ptr = test_keys[i];
     255           3 :     value.data_ptr = newKey;
     256           3 :     ht_insert(table, key, value);
     257           3 :     value = ht_get(table, key, &status);
     258           3 :     TEST_ASSERT(status == SMB_SUCCESS);
     259           3 :     TEST_ASSERT(value.data_ptr == newKey);
     260             :   }
     261             : 
     262           6 :   for (i = 0; i < TEST_PAIRS; i++) {
     263           5 :     key.data_ptr = test_keys[i];
     264           5 :     value = ht_get(table, key, &status);
     265           5 :     TEST_ASSERT(status == SMB_SUCCESS);
     266           5 :     if (i % 2 == 1) {
     267           2 :       TEST_ASSERT(value.data_ptr == test_values[i]);
     268             :     } else {
     269           3 :       TEST_ASSERT(value.data_ptr == newKey);
     270             :     }
     271             :   }
     272             : 
     273           1 :   ht_delete_act(table, ht_test_deleter);
     274           1 :   TEST_ASSERT(ht_test_deletions == TEST_PAIRS);
     275           1 :   return 0;
     276             : }
     277             : 
     278           1 : void hash_table_test()
     279             : {
     280           1 :   smb_ut_group *group = su_create_test_group("hash table");
     281             : 
     282           1 :   smb_ut_test *insert = su_create_test("insert", ht_test_insert);
     283           1 :   su_add_test(group, insert);
     284             : 
     285           1 :   smb_ut_test *remove = su_create_test("remove", ht_test_remove);
     286           1 :   su_add_test(group, remove);
     287             : 
     288           1 :   smb_ut_test *remove_invalid = su_create_test("remove_invalid", ht_test_remove_invalid);
     289           1 :   su_add_test(group, remove_invalid);
     290             : 
     291           1 :   smb_ut_test *buckets = su_create_test("buckets", ht_test_buckets);
     292           1 :   su_add_test(group, buckets);
     293             : 
     294           1 :   smb_ut_test *resize = su_create_test("resize", ht_test_resize);
     295           1 :   su_add_test(group, resize);
     296             : 
     297           1 :   smb_ut_test *duplicate = su_create_test("duplicate", ht_test_duplicate);
     298           1 :   su_add_test(group, duplicate);
     299             : 
     300           1 :   su_run_group(group);
     301           1 :   su_delete_group(group);
     302           1 : }

Generated by: LCOV version 1.11