/builds/xfbs/passgen/src/tests/hashmap.c
Line | Count | Source |
1 | | #include "passgen/container/hashmap.h" |
2 | | #include "tests.h" |
3 | | #include <stdlib.h> |
4 | | #include <string.h> |
5 | | |
6 | 1 | test_result test_hashmap_init(void) { |
7 | 1 | passgen_hashmap map; |
8 | 1 | passgen_hashmap_init(&map, NULL); |
9 | 1 | passgen_hashmap_free(&map); |
10 | 1 | return test_ok; |
11 | 1 | } |
12 | | |
13 | 1 | test_result test_hashmap_context_utf8(void) { |
14 | 1 | passgen_hashmap map; |
15 | 1 | passgen_hashmap_init(&map, &passgen_hashmap_context_utf8); |
16 | 1 | |
17 | 1 | const char *key1 = "hello"; |
18 | 1 | const char *key2 = "hola"; |
19 | 1 | |
20 | 1 | assert(passgen_hashmap_context_utf8.equal(&map, key1, key1)); |
21 | 1 | assert(passgen_hashmap_context_utf8.equal(&map, key2, key2)); |
22 | 1 | assert(!passgen_hashmap_context_utf8.equal(&map, key1, key2)); |
23 | 1 | |
24 | 1 | assert_eq( |
25 | 1 | passgen_hashmap_context_utf8.hash(&map, key1, true), |
26 | 1 | 0xf6f0cd43722c7cfe); |
27 | 1 | assert_eq( |
28 | 1 | passgen_hashmap_context_utf8.hash(&map, key1, false), |
29 | 1 | 0x438bcb516e4d4abf); |
30 | 1 | |
31 | 1 | assert_eq( |
32 | 1 | passgen_hashmap_context_utf8.hash(&map, key2, true), |
33 | 1 | 0xcb99aa476d12f348); |
34 | 1 | assert_eq( |
35 | 1 | passgen_hashmap_context_utf8.hash(&map, key2, false), |
36 | 1 | 0xef7ec81d7aa533ea); |
37 | 1 | |
38 | 1 | passgen_hashmap_free(&map); |
39 | 1 | |
40 | 1 | return test_ok; |
41 | 1 | } |
42 | | |
43 | 1 | test_result test_hashmap_context_utf32(void) { |
44 | 1 | passgen_hashmap map; |
45 | 1 | passgen_hashmap_init(&map, &passgen_hashmap_context_utf32); |
46 | 1 | |
47 | 1 | uint32_t key1[] = {'h', 'e', 'l', 'l', 'o', 0}; |
48 | 1 | uint32_t key2[] = {'h', 'o', 'l', 'a', 0}; |
49 | 1 | |
50 | 1 | assert(passgen_hashmap_context_utf32.equal(&map, &key1[0], &key1[0])); |
51 | 1 | assert(passgen_hashmap_context_utf32.equal(&map, &key2[0], &key2[0])); |
52 | 1 | assert(!passgen_hashmap_context_utf32.equal(&map, &key1[0], &key2[0])); |
53 | 1 | |
54 | 1 | assert_eq( |
55 | 1 | passgen_hashmap_context_utf32.hash(&map, &key1[0], true), |
56 | 1 | 0x4b9a41e6925a46ad); |
57 | 1 | assert_eq( |
58 | 1 | passgen_hashmap_context_utf32.hash(&map, &key1[0], false), |
59 | 1 | 0x6ce43ac01a6144b8); |
60 | 1 | |
61 | 1 | assert_eq( |
62 | 1 | passgen_hashmap_context_utf32.hash(&map, &key2[0], true), |
63 | 1 | 0xdefab330a5dcde19); |
64 | 1 | assert_eq( |
65 | 1 | passgen_hashmap_context_utf32.hash(&map, &key2[0], false), |
66 | 1 | 0x45168f9b31b7e7bd); |
67 | 1 | |
68 | 1 | passgen_hashmap_free(&map); |
69 | 1 | |
70 | 1 | return test_ok; |
71 | 1 | } |
72 | | |
73 | 1 | test_result test_hashmap_insert_utf32(void) { |
74 | 1 | passgen_hashmap map; |
75 | 1 | passgen_hashmap_entry entry; |
76 | 1 | |
77 | 1 | passgen_hashmap_init(&map, &passgen_hashmap_context_utf32); |
78 | 1 | |
79 | 1 | uint32_t key1[] = {'h', 'e', 'l', 'l', 'o', 0}; |
80 | 1 | int value1; |
81 | 1 | entry = passgen_hashmap_insert(&map, &key1, &value1); |
82 | 1 | assert_eq(entry.key, NULL); |
83 | 1 | assert_eq(entry.value, NULL); |
84 | 1 | assert_eq(map.len, 1); |
85 | 1 | assert_eq(passgen_hashmap_lookup(&map, &key1)->value, &value1); |
86 | 1 | |
87 | 1 | uint32_t key2[] = {'h', 'o', 'l', 'a', 0}; |
88 | 1 | int value2; |
89 | 1 | entry = passgen_hashmap_insert(&map, &key2, &value2); |
90 | 1 | assert_eq(map.len, 2); |
91 | 1 | assert_eq(entry.key, NULL); |
92 | 1 | assert_eq(entry.value, NULL); |
93 | 1 | assert_eq(passgen_hashmap_lookup(&map, &key1)->value, &value1); |
94 | 1 | assert_eq(passgen_hashmap_lookup(&map, &key2)->value, &value2); |
95 | 1 | |
96 | 1 | passgen_hashmap_free(&map); |
97 | 1 | |
98 | 1 | return test_ok; |
99 | 1 | } |
100 | | |
101 | 1 | test_result test_hashmap_insert_utf8(void) { |
102 | 1 | passgen_hashmap map; |
103 | 1 | passgen_hashmap_init(&map, NULL); |
104 | 1 | |
105 | 1 | int value_a = 4, value_b = 7; |
106 | 1 | |
107 | 1 | passgen_hashmap_insert(&map, "hello", &value_a); |
108 | 1 | assert_eq(map.len, 1); |
109 | 1 | passgen_hashmap_insert(&map, "world", &value_b); |
110 | 1 | assert_eq(map.len, 2); |
111 | 1 | |
112 | 1 | passgen_hashmap_entry *entry; |
113 | 1 | entry = passgen_hashmap_lookup(&map, "hello"); |
114 | 1 | assert(entry); |
115 | 1 | assert_eq(entry->value, &value_a); |
116 | 1 | |
117 | 1 | entry = passgen_hashmap_lookup(&map, "world"); |
118 | 1 | assert(entry); |
119 | 1 | assert_eq(entry->value, &value_b); |
120 | 1 | |
121 | 1 | entry = passgen_hashmap_lookup(&map, "other"); |
122 | 1 | assert(!entry); |
123 | 1 | |
124 | 1 | passgen_hashmap_free(&map); |
125 | 1 | return test_ok; |
126 | 1 | } |
127 | | |
128 | 1 | test_result test_hashmap_insert_many(void) { |
129 | 1 | passgen_hashmap map; |
130 | 1 | passgen_hashmap_init(&map, NULL); |
131 | 1 | size_t insert_max = 10000; |
132 | 1 | |
133 | 1 | // insert large amount of items |
134 | 10.0k | for(size_t i = 0; i < insert_max; i++10.0k ) { |
135 | 10.0k | assert_eq(map.len, i); |
136 | 10.0k | char *key = malloc(32); |
137 | 10.0k | size_t *value = malloc(sizeof(size_t)); |
138 | 10.0k | *value = i; |
139 | 10.0k | snprintf(key, 32, "%zu", i); |
140 | 10.0k | passgen_hashmap_insert(&map, key, value); |
141 | 10.0k | |
142 | 10.0k | // fill factor is how many percent of slots are used. we want this |
143 | 10.0k | // to be high. |
144 | 10.0k | float fill = map.len * 100.0 / (double) map.capacity; |
145 | 10.0k | assert(fill > 3.0); |
146 | 10.0k | } |
147 | 1 | |
148 | 1 | // retrieve all items |
149 | 10.0k | for(size_t i = 0; 1 i < insert_max; i++10.0k ) { |
150 | 10.0k | char key[32]; |
151 | 10.0k | snprintf(key, 32, "%zu", i); |
152 | 10.0k | passgen_hashmap_entry *entry = passgen_hashmap_lookup(&map, key); |
153 | 10.0k | assert(entry); |
154 | 10.0k | size_t *value = entry->value; |
155 | 10.0k | assert_eq(*value, i); |
156 | 10.0k | } |
157 | 1 | |
158 | 1 | // release memory |
159 | 1 | passgen_hashmap_foreach(&map, NULL, passgen_hashmap_entry_free); |
160 | 1 | |
161 | 1 | passgen_hashmap_free(&map); |
162 | 1 | return test_ok; |
163 | 1 | } |
164 | | |
165 | 1 | test_result test_hashmap_remove(void) { |
166 | 1 | passgen_hashmap map; |
167 | 1 | passgen_hashmap_init(&map, NULL); |
168 | 1 | |
169 | 1 | int value_a = 4, value_b = 7; |
170 | 1 | |
171 | 1 | passgen_hashmap_insert(&map, "hello", &value_a); |
172 | 1 | passgen_hashmap_insert(&map, "world", &value_b); |
173 | 1 | assert_eq(map.len, 2); |
174 | 1 | |
175 | 1 | assert(passgen_hashmap_lookup(&map, "hello")); |
176 | 1 | assert(passgen_hashmap_lookup(&map, "world")); |
177 | 1 | assert(!passgen_hashmap_lookup(&map, "other")); |
178 | 1 | |
179 | 1 | passgen_hashmap_entry entry; |
180 | 1 | entry = passgen_hashmap_remove(&map, "hello"); |
181 | 1 | assert_eq(map.len, 1); |
182 | 1 | assert(entry.key); |
183 | 1 | assert_eq(entry.value, &value_a); |
184 | 1 | assert_streq(entry.key, "hello"); |
185 | 1 | |
186 | 1 | assert(!passgen_hashmap_lookup(&map, "hello")); |
187 | 1 | assert(passgen_hashmap_lookup(&map, "world")); |
188 | 1 | assert(!passgen_hashmap_lookup(&map, "other")); |
189 | 1 | |
190 | 1 | entry = passgen_hashmap_remove(&map, "world"); |
191 | 1 | assert_eq(map.len, 0); |
192 | 1 | assert(entry.key); |
193 | 1 | assert_eq(entry.value, &value_b); |
194 | 1 | assert_streq(entry.key, "world"); |
195 | 1 | |
196 | 1 | assert(!passgen_hashmap_lookup(&map, "hello")); |
197 | 1 | assert(!passgen_hashmap_lookup(&map, "world")); |
198 | 1 | assert(!passgen_hashmap_lookup(&map, "other")); |
199 | 1 | |
200 | 1 | passgen_hashmap_free(&map); |
201 | 1 | return test_ok; |
202 | 1 | } |
203 | | |
204 | 1 | test_result test_hashmap_lookup_empty(void) { |
205 | 1 | passgen_hashmap map; |
206 | 1 | passgen_hashmap_init(&map, NULL); |
207 | 1 | |
208 | 1 | passgen_hashmap_entry *entry = passgen_hashmap_lookup(&map, "test"); |
209 | 1 | assert(!entry); |
210 | 1 | |
211 | 1 | passgen_hashmap_free(&map); |
212 | 1 | return test_ok; |
213 | 1 | } |
214 | | |
215 | 1 | int function_fails(void *data, passgen_hashmap_entry *entry) { |
216 | 1 | (void) data; |
217 | 1 | (void) entry; |
218 | 1 | return 7; |
219 | 1 | } |
220 | | |
221 | 5 | int free_value(void *data, passgen_hashmap_entry *entry) { |
222 | 5 | (void) data; |
223 | 5 | free(entry->value); |
224 | 5 | return 0; |
225 | 5 | } |
226 | | |
227 | 1 | test_result test_hashmap_foreach(void) { |
228 | 1 | passgen_hashmap map; |
229 | 1 | passgen_hashmap_init(&map, NULL); |
230 | 1 | |
231 | 1 | passgen_hashmap_insert(&map, "alpha", malloc(255)); |
232 | 1 | passgen_hashmap_insert(&map, "beta", malloc(255)); |
233 | 1 | passgen_hashmap_insert(&map, "gamma", malloc(255)); |
234 | 1 | passgen_hashmap_insert(&map, "delta", malloc(255)); |
235 | 1 | passgen_hashmap_insert(&map, "epsilon", malloc(255)); |
236 | 1 | |
237 | 1 | assert_eq(passgen_hashmap_foreach(&map, NULL, function_fails), 7); |
238 | 1 | assert_eq(passgen_hashmap_foreach(&map, NULL, free_value), 0); |
239 | 1 | |
240 | 1 | passgen_hashmap_free(&map); |
241 | 1 | return test_ok; |
242 | 1 | } |