]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/test/test-hashmap-plain.c
ci: re-enable uefi secure boot
[thirdparty/systemd.git] / src / test / test-hashmap-plain.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
32a4456c 2
4f18ff2e
YW
3#include <unistd.h>
4
b5efdb8a 5#include "alloc-util.h"
07630cea 6#include "hashmap.h"
3d14a300 7#include "log.h"
d8b4d14d 8#include "nulstr-util.h"
8872c3a3 9#include "stdio-util.h"
32a4456c 10#include "strv.h"
0cf29baa 11#include "tests.h"
965040d8 12#include "time-util.h"
32a4456c 13
fc4a9c9c
YW
14/* PROJECT_FILE, which is used by ASSERT_XYZ(), cannot be used in generated files, as the build directory
15 * may be outside of the source directory. */
16#ifdef ORDERED
17# undef PROJECT_FILE
18# define PROJECT_FILE __FILE__
19#endif
20
c462e63e 21TEST(hashmap_replace) {
5d2a48da 22 _cleanup_hashmap_free_ Hashmap *m = NULL;
5b87bccc
DT
23 _cleanup_free_ char *val1 = NULL, *val2 = NULL, *val3 = NULL, *val4 = NULL, *val5 = NULL;
24 char *r;
32a4456c
MS
25
26 m = hashmap_new(&string_hash_ops);
27
28 val1 = strdup("val1");
29 assert_se(val1);
30 val2 = strdup("val2");
31 assert_se(val2);
32 val3 = strdup("val3");
33 assert_se(val3);
34 val4 = strdup("val4");
35 assert_se(val4);
36 val5 = strdup("val5");
37 assert_se(val5);
38
39 hashmap_put(m, "key 1", val1);
40 hashmap_put(m, "key 2", val2);
41 hashmap_put(m, "key 3", val3);
42 hashmap_put(m, "key 4", val4);
43
44 hashmap_replace(m, "key 3", val1);
45 r = hashmap_get(m, "key 3");
c79e88b3 46 ASSERT_STREQ(r, "val1");
32a4456c
MS
47
48 hashmap_replace(m, "key 5", val5);
49 r = hashmap_get(m, "key 5");
c79e88b3 50 ASSERT_STREQ(r, "val5");
32a4456c
MS
51}
52
afb1fe36
MC
53TEST(hashmap_ensure_replace) {
54 _cleanup_hashmap_free_ Hashmap *m = NULL;
55 _cleanup_free_ char *val1 = NULL, *val2 = NULL;
56
57 val1 = strdup("val1");
58 ASSERT_NOT_NULL(val1);
59 val2 = strdup("val2");
60 ASSERT_NOT_NULL(val2);
61
62 ASSERT_OK(hashmap_ensure_replace(&m, &string_hash_ops, val1, val2));
63
64 ASSERT_OK(hashmap_ensure_replace(&m, &string_hash_ops, "key 1", val1));
65 ASSERT_STREQ(hashmap_get(m, "key 1"), "val1");
66
67 ASSERT_OK(hashmap_ensure_replace(&m, &string_hash_ops, "key 2", val2));
68 ASSERT_STREQ(hashmap_get(m, "key 2"), "val2");
69
70 ASSERT_OK(hashmap_ensure_replace(&m, &string_hash_ops, "key 3", val1));
71 ASSERT_STREQ(hashmap_get(m, "key 3"), "val1");
72
73 ASSERT_OK(hashmap_ensure_replace(&m, &string_hash_ops, "key 3", val2));
74 ASSERT_STREQ(hashmap_get(m, "key 3"), "val2");
75}
76
c462e63e 77TEST(hashmap_copy) {
58f0cd14 78 _cleanup_hashmap_free_ Hashmap *m = NULL, *copy = NULL;
32a4456c 79
278e3adf 80 ASSERT_NOT_NULL((m = hashmap_new(&string_hash_ops)));
32a4456c 81
58f0cd14
YW
82 ASSERT_OK_POSITIVE(hashmap_put(m, "key 1", (void*) "val1"));
83 ASSERT_OK_POSITIVE(hashmap_put(m, "key 2", (void*) "val2"));
84 ASSERT_OK_POSITIVE(hashmap_put(m, "key 3", (void*) "val3"));
85 ASSERT_OK_POSITIVE(hashmap_put(m, "key 4", (void*) "val4"));
32a4456c 86
278e3adf 87 ASSERT_NOT_NULL((copy = hashmap_copy(m)));
32a4456c 88
58f0cd14
YW
89 ASSERT_STREQ(hashmap_get(copy, "key 1"), "val1");
90 ASSERT_STREQ(hashmap_get(copy, "key 2"), "val2");
91 ASSERT_STREQ(hashmap_get(copy, "key 3"), "val3");
92 ASSERT_STREQ(hashmap_get(copy, "key 4"), "val4");
32a4456c
MS
93}
94
c462e63e 95TEST(hashmap_get_strv) {
5d2a48da
YW
96 _cleanup_hashmap_free_ Hashmap *m = NULL;
97 _cleanup_strv_free_ char **strv = NULL;
32a4456c
MS
98 char *val1, *val2, *val3, *val4;
99
100 val1 = strdup("val1");
101 assert_se(val1);
102 val2 = strdup("val2");
103 assert_se(val2);
104 val3 = strdup("val3");
105 assert_se(val3);
106 val4 = strdup("val4");
107 assert_se(val4);
108
109 m = hashmap_new(&string_hash_ops);
110
111 hashmap_put(m, "key 1", val1);
112 hashmap_put(m, "key 2", val2);
113 hashmap_put(m, "key 3", val3);
114 hashmap_put(m, "key 4", val4);
115
116 strv = hashmap_get_strv(m);
117
118#ifndef ORDERED
119 strv = strv_sort(strv);
120#endif
121
c79e88b3
IK
122 ASSERT_STREQ(strv[0], "val1");
123 ASSERT_STREQ(strv[1], "val2");
124 ASSERT_STREQ(strv[2], "val3");
125 ASSERT_STREQ(strv[3], "val4");
32a4456c
MS
126}
127
c462e63e 128TEST(hashmap_move_one) {
58f0cd14 129 _cleanup_hashmap_free_ Hashmap *m = NULL, *n = NULL;
32a4456c
MS
130 char *val1, *val2, *val3, *val4, *r;
131
132 val1 = strdup("val1");
133 assert_se(val1);
134 val2 = strdup("val2");
135 assert_se(val2);
136 val3 = strdup("val3");
137 assert_se(val3);
138 val4 = strdup("val4");
139 assert_se(val4);
140
58f0cd14
YW
141 m = hashmap_new(&string_hash_ops_value_free);
142 n = hashmap_new(&string_hash_ops_value_free);
32a4456c
MS
143
144 hashmap_put(m, "key 1", val1);
145 hashmap_put(m, "key 2", val2);
146 hashmap_put(m, "key 3", val3);
147 hashmap_put(m, "key 4", val4);
148
9ba81d5a
MS
149 assert_se(hashmap_move_one(n, NULL, "key 3") == -ENOENT);
150 assert_se(hashmap_move_one(n, m, "key 5") == -ENOENT);
151 assert_se(hashmap_move_one(n, m, "key 3") == 0);
152 assert_se(hashmap_move_one(n, m, "key 4") == 0);
32a4456c
MS
153
154 r = hashmap_get(n, "key 3");
155 assert_se(r && streq(r, "val3"));
156 r = hashmap_get(n, "key 4");
157 assert_se(r && streq(r, "val4"));
158 r = hashmap_get(m, "key 3");
159 assert_se(!r);
160
9ba81d5a 161 assert_se(hashmap_move_one(n, m, "key 3") == -EEXIST);
9ba81d5a
MS
162}
163
c462e63e 164TEST(hashmap_move) {
58f0cd14 165 _cleanup_hashmap_free_ Hashmap *m = NULL, *n = NULL;
9ba81d5a
MS
166 char *val1, *val2, *val3, *val4, *r;
167
168 val1 = strdup("val1");
169 assert_se(val1);
170 val2 = strdup("val2");
171 assert_se(val2);
172 val3 = strdup("val3");
173 assert_se(val3);
174 val4 = strdup("val4");
175 assert_se(val4);
176
58f0cd14
YW
177 m = hashmap_new(&string_hash_ops_value_free);
178 n = hashmap_new(&string_hash_ops_value_free);
9ba81d5a
MS
179
180 hashmap_put(n, "key 1", strdup(val1));
181 hashmap_put(m, "key 1", val1);
182 hashmap_put(m, "key 2", val2);
183 hashmap_put(m, "key 3", val3);
184 hashmap_put(m, "key 4", val4);
185
e80afdb3
MS
186 assert_se(hashmap_move(n, NULL) == 0);
187 assert_se(hashmap_move(n, m) == 0);
9ba81d5a
MS
188
189 assert_se(hashmap_size(m) == 1);
190 r = hashmap_get(m, "key 1");
191 assert_se(r && streq(r, "val1"));
192
193 r = hashmap_get(n, "key 1");
194 assert_se(r && streq(r, "val1"));
195 r = hashmap_get(n, "key 2");
196 assert_se(r && streq(r, "val2"));
197 r = hashmap_get(n, "key 3");
198 assert_se(r && streq(r, "val3"));
199 r = hashmap_get(n, "key 4");
200 assert_se(r && streq(r, "val4"));
32a4456c
MS
201}
202
c462e63e 203TEST(hashmap_update) {
5d2a48da 204 _cleanup_hashmap_free_ Hashmap *m = NULL;
5b87bccc
DT
205 _cleanup_free_ char *val1 = NULL, *val2 = NULL;
206 char *r;
32a4456c
MS
207
208 m = hashmap_new(&string_hash_ops);
209 val1 = strdup("old_value");
210 assert_se(val1);
211 val2 = strdup("new_value");
212 assert_se(val2);
213
214 hashmap_put(m, "key 1", val1);
215 r = hashmap_get(m, "key 1");
c79e88b3 216 ASSERT_STREQ(r, "old_value");
32a4456c 217
9ba81d5a
MS
218 assert_se(hashmap_update(m, "key 2", val2) == -ENOENT);
219 r = hashmap_get(m, "key 1");
c79e88b3 220 ASSERT_STREQ(r, "old_value");
9ba81d5a
MS
221
222 assert_se(hashmap_update(m, "key 1", val2) == 0);
32a4456c 223 r = hashmap_get(m, "key 1");
c79e88b3 224 ASSERT_STREQ(r, "new_value");
32a4456c
MS
225}
226
c462e63e 227TEST(hashmap_put) {
5d2a48da 228 _cleanup_hashmap_free_ Hashmap *m = NULL;
32a4456c 229 int valid_hashmap_put;
9ba81d5a 230 void *val1 = (void*) "val 1";
435fc317
MP
231 void *val2 = (void*) "val 2";
232 _cleanup_free_ char* key1 = NULL;
32a4456c 233
9ff7c5b0 234 assert_se(hashmap_ensure_allocated(&m, &string_hash_ops) == 1);
9ba81d5a 235 assert_se(m);
32a4456c 236
9ba81d5a 237 valid_hashmap_put = hashmap_put(m, "key 1", val1);
32a4456c 238 assert_se(valid_hashmap_put == 1);
9ba81d5a 239 assert_se(hashmap_put(m, "key 1", val1) == 0);
435fc317
MP
240 assert_se(hashmap_put(m, "key 1", val2) == -EEXIST);
241 key1 = strdup("key 1");
242 assert_se(hashmap_put(m, key1, val1) == 0);
243 assert_se(hashmap_put(m, key1, val2) == -EEXIST);
32a4456c
MS
244}
245
c462e63e 246TEST(hashmap_remove1) {
9ba81d5a
MS
247 _cleanup_hashmap_free_ Hashmap *m = NULL;
248 char *r;
249
250 r = hashmap_remove(NULL, "key 1");
5152b845 251 ASSERT_NULL(r);
9ba81d5a
MS
252
253 m = hashmap_new(&string_hash_ops);
254 assert_se(m);
255
256 r = hashmap_remove(m, "no such key");
5152b845 257 ASSERT_NULL(r);
9ba81d5a
MS
258
259 hashmap_put(m, "key 1", (void*) "val 1");
260 hashmap_put(m, "key 2", (void*) "val 2");
261
262 r = hashmap_remove(m, "key 1");
c79e88b3 263 ASSERT_STREQ(r, "val 1");
9ba81d5a
MS
264
265 r = hashmap_get(m, "key 2");
c79e88b3 266 ASSERT_STREQ(r, "val 2");
9ba81d5a
MS
267 assert_se(!hashmap_get(m, "key 1"));
268}
269
c462e63e 270TEST(hashmap_remove2) {
58f0cd14 271 _cleanup_hashmap_free_ Hashmap *m = NULL;
9ba81d5a
MS
272 char key1[] = "key 1";
273 char key2[] = "key 2";
274 char val1[] = "val 1";
275 char val2[] = "val 2";
276 void *r, *r2;
277
278 r = hashmap_remove2(NULL, "key 1", &r2);
5152b845 279 ASSERT_NULL(r);
9ba81d5a 280
58f0cd14 281 m = hashmap_new(&string_hash_ops_free_free);
9ba81d5a
MS
282 assert_se(m);
283
284 r = hashmap_remove2(m, "no such key", &r2);
5152b845 285 ASSERT_NULL(r);
9ba81d5a
MS
286
287 hashmap_put(m, strdup(key1), strdup(val1));
288 hashmap_put(m, strdup(key2), strdup(val2));
289
290 r = hashmap_remove2(m, key1, &r2);
c79e88b3
IK
291 ASSERT_STREQ(r, val1);
292 ASSERT_STREQ(r2, key1);
9ba81d5a
MS
293 free(r);
294 free(r2);
295
296 r = hashmap_get(m, key2);
c79e88b3 297 ASSERT_STREQ(r, val2);
9ba81d5a
MS
298 assert_se(!hashmap_get(m, key1));
299}
300
c462e63e 301TEST(hashmap_remove_value) {
9ba81d5a
MS
302 _cleanup_hashmap_free_ Hashmap *m = NULL;
303 char *r;
304
d09139e1
ZJS
305 char val1[] = "val 1";
306 char val2[] = "val 2";
307
308 r = hashmap_remove_value(NULL, "key 1", val1);
5152b845 309 ASSERT_NULL(r);
9ba81d5a
MS
310
311 m = hashmap_new(&string_hash_ops);
312 assert_se(m);
313
d09139e1 314 r = hashmap_remove_value(m, "key 1", val1);
5152b845 315 ASSERT_NULL(r);
9ba81d5a 316
d09139e1
ZJS
317 hashmap_put(m, "key 1", val1);
318 hashmap_put(m, "key 2", val2);
9ba81d5a 319
d09139e1 320 r = hashmap_remove_value(m, "key 1", val1);
c79e88b3 321 ASSERT_STREQ(r, "val 1");
9ba81d5a
MS
322
323 r = hashmap_get(m, "key 2");
c79e88b3 324 ASSERT_STREQ(r, "val 2");
9ba81d5a
MS
325 assert_se(!hashmap_get(m, "key 1"));
326
d09139e1 327 r = hashmap_remove_value(m, "key 2", val1);
5152b845 328 ASSERT_NULL(r);
9ba81d5a
MS
329
330 r = hashmap_get(m, "key 2");
c79e88b3 331 ASSERT_STREQ(r, "val 2");
9ba81d5a
MS
332 assert_se(!hashmap_get(m, "key 1"));
333}
334
c462e63e 335TEST(hashmap_remove_and_put) {
32a4456c
MS
336 _cleanup_hashmap_free_ Hashmap *m = NULL;
337 int valid;
338 char *r;
339
340 m = hashmap_new(&string_hash_ops);
341 assert_se(m);
342
9ba81d5a
MS
343 valid = hashmap_remove_and_put(m, "invalid key", "new key", NULL);
344 assert_se(valid == -ENOENT);
32a4456c
MS
345
346 valid = hashmap_put(m, "key 1", (void*) (const char *) "val 1");
347 assert_se(valid == 1);
9ba81d5a
MS
348
349 valid = hashmap_remove_and_put(NULL, "key 1", "key 2", (void*) (const char *) "val 2");
350 assert_se(valid == -ENOENT);
351
32a4456c
MS
352 valid = hashmap_remove_and_put(m, "key 1", "key 2", (void*) (const char *) "val 2");
353 assert_se(valid == 0);
354
355 r = hashmap_get(m, "key 2");
c79e88b3 356 ASSERT_STREQ(r, "val 2");
32a4456c
MS
357 assert_se(!hashmap_get(m, "key 1"));
358
359 valid = hashmap_put(m, "key 3", (void*) (const char *) "val 3");
360 assert_se(valid == 1);
361 valid = hashmap_remove_and_put(m, "key 3", "key 2", (void*) (const char *) "val 2");
9ba81d5a
MS
362 assert_se(valid == -EEXIST);
363}
364
c462e63e 365TEST(hashmap_remove_and_replace) {
9ba81d5a
MS
366 _cleanup_hashmap_free_ Hashmap *m = NULL;
367 int valid;
368 void *key1 = UINT_TO_PTR(1);
369 void *key2 = UINT_TO_PTR(2);
370 void *key3 = UINT_TO_PTR(3);
371 void *r;
e1323fbf 372 int i, j;
9ba81d5a
MS
373
374 m = hashmap_new(&trivial_hash_ops);
375 assert_se(m);
376
377 valid = hashmap_remove_and_replace(m, key1, key2, NULL);
378 assert_se(valid == -ENOENT);
379
380 valid = hashmap_put(m, key1, key1);
381 assert_se(valid == 1);
382
383 valid = hashmap_remove_and_replace(NULL, key1, key2, key2);
384 assert_se(valid == -ENOENT);
385
386 valid = hashmap_remove_and_replace(m, key1, key2, key2);
387 assert_se(valid == 0);
388
389 r = hashmap_get(m, key2);
390 assert_se(r == key2);
391 assert_se(!hashmap_get(m, key1));
392
393 valid = hashmap_put(m, key3, key3);
394 assert_se(valid == 1);
395 valid = hashmap_remove_and_replace(m, key3, key2, key2);
396 assert_se(valid == 0);
397 r = hashmap_get(m, key2);
398 assert_se(r == key2);
399 assert_se(!hashmap_get(m, key3));
e1323fbf
MS
400
401 /* Repeat this test several times to increase the chance of hitting
402 * the less likely case in hashmap_remove_and_replace where it
403 * compensates for the backward shift. */
404 for (i = 0; i < 20; i++) {
405 hashmap_clear(m);
406
407 for (j = 1; j < 7; j++)
408 hashmap_put(m, UINT_TO_PTR(10*i + j), UINT_TO_PTR(10*i + j));
409 valid = hashmap_remove_and_replace(m, UINT_TO_PTR(10*i + 1),
410 UINT_TO_PTR(10*i + 2),
411 UINT_TO_PTR(10*i + 2));
412 assert_se(valid == 0);
413 assert_se(!hashmap_get(m, UINT_TO_PTR(10*i + 1)));
414 for (j = 2; j < 7; j++) {
415 r = hashmap_get(m, UINT_TO_PTR(10*i + j));
416 assert_se(r == UINT_TO_PTR(10*i + j));
417 }
418 }
32a4456c
MS
419}
420
c462e63e 421TEST(hashmap_ensure_allocated) {
9ff7c5b0 422 _cleanup_hashmap_free_ Hashmap *m = NULL;
32a4456c 423
bc169c4f
YW
424 ASSERT_OK_POSITIVE(hashmap_ensure_allocated(&m, &string_hash_ops));
425 ASSERT_OK_ZERO(hashmap_ensure_allocated(&m, &string_hash_ops));
426 ASSERT_SIGNAL(hashmap_ensure_allocated(&m, &trivial_hash_ops), SIGABRT);
32a4456c
MS
427}
428
c462e63e 429TEST(hashmap_foreach_key) {
5d2a48da 430 _cleanup_hashmap_free_ Hashmap *m = NULL;
32a4456c
MS
431 bool key_found[] = { false, false, false, false };
432 const char *s;
433 const char *key;
434 static const char key_table[] =
435 "key 1\0"
436 "key 2\0"
437 "key 3\0"
438 "key 4\0";
439
440 m = hashmap_new(&string_hash_ops);
441
12e2b70f
DDM
442 NULSTR_FOREACH(k, key_table)
443 hashmap_put(m, k, (void*) (const char*) "my dummy val");
32a4456c 444
90e74a66 445 HASHMAP_FOREACH_KEY(s, key, m) {
f21b863e 446 assert_se(s);
32a4456c
MS
447 if (!key_found[0] && streq(key, "key 1"))
448 key_found[0] = true;
449 else if (!key_found[1] && streq(key, "key 2"))
450 key_found[1] = true;
451 else if (!key_found[2] && streq(key, "key 3"))
452 key_found[2] = true;
453 else if (!key_found[3] && streq(key, "fail"))
454 key_found[3] = true;
455 }
456
457 assert_se(m);
458 assert_se(key_found[0] && key_found[1] && key_found[2] && !key_found[3]);
32a4456c
MS
459}
460
c462e63e 461TEST(hashmap_foreach) {
58f0cd14 462 _cleanup_hashmap_free_ Hashmap *m = NULL;
32a4456c
MS
463 bool value_found[] = { false, false, false, false };
464 char *val1, *val2, *val3, *val4, *s;
9ba81d5a 465 unsigned count;
32a4456c
MS
466
467 val1 = strdup("my val1");
468 assert_se(val1);
469 val2 = strdup("my val2");
470 assert_se(val2);
471 val3 = strdup("my val3");
472 assert_se(val3);
473 val4 = strdup("my val4");
474 assert_se(val4);
475
9ba81d5a 476 count = 0;
90e74a66 477 HASHMAP_FOREACH(s, m)
9ba81d5a
MS
478 count++;
479 assert_se(count == 0);
480
58f0cd14 481 m = hashmap_new(&string_hash_ops_value_free);
32a4456c 482
9ba81d5a 483 count = 0;
90e74a66 484 HASHMAP_FOREACH(s, m)
9ba81d5a
MS
485 count++;
486 assert_se(count == 0);
487
32a4456c
MS
488 hashmap_put(m, "Key 1", val1);
489 hashmap_put(m, "Key 2", val2);
490 hashmap_put(m, "Key 3", val3);
491 hashmap_put(m, "Key 4", val4);
492
90e74a66 493 HASHMAP_FOREACH(s, m) {
32a4456c
MS
494 if (!value_found[0] && streq(s, val1))
495 value_found[0] = true;
496 else if (!value_found[1] && streq(s, val2))
497 value_found[1] = true;
498 else if (!value_found[2] && streq(s, val3))
499 value_found[2] = true;
500 else if (!value_found[3] && streq(s, val4))
501 value_found[3] = true;
502 }
503
504 assert_se(m);
505 assert_se(value_found[0] && value_found[1] && value_found[2] && value_found[3]);
32a4456c
MS
506}
507
c462e63e 508TEST(hashmap_merge) {
58f0cd14 509 _cleanup_hashmap_free_ Hashmap *m = NULL, *n = NULL;
32a4456c
MS
510 char *val1, *val2, *val3, *val4, *r;
511
512 val1 = strdup("my val1");
513 assert_se(val1);
514 val2 = strdup("my val2");
515 assert_se(val2);
516 val3 = strdup("my val3");
517 assert_se(val3);
518 val4 = strdup("my val4");
519 assert_se(val4);
520
58f0cd14 521 m = hashmap_new(&string_hash_ops_value_free);
9ff7c5b0 522 n = hashmap_new(&string_hash_ops);
32a4456c
MS
523
524 hashmap_put(m, "Key 1", val1);
525 hashmap_put(m, "Key 2", val2);
526 hashmap_put(n, "Key 3", val3);
527 hashmap_put(n, "Key 4", val4);
528
529 assert_se(hashmap_merge(m, n) == 0);
530 r = hashmap_get(m, "Key 3");
531 assert_se(r && streq(r, "my val3"));
532 r = hashmap_get(m, "Key 4");
533 assert_se(r && streq(r, "my val4"));
534
32a4456c 535 assert_se(m);
9ff7c5b0 536 assert_se(n);
32a4456c
MS
537}
538
c462e63e 539TEST(hashmap_contains) {
58f0cd14 540 _cleanup_hashmap_free_ Hashmap *m = NULL;
32a4456c
MS
541 char *val1;
542
543 val1 = strdup("my val");
544 assert_se(val1);
545
58f0cd14 546 m = hashmap_new(&string_hash_ops_value_free);
32a4456c
MS
547
548 assert_se(!hashmap_contains(m, "Key 1"));
549 hashmap_put(m, "Key 1", val1);
550 assert_se(hashmap_contains(m, "Key 1"));
9ba81d5a
MS
551 assert_se(!hashmap_contains(m, "Key 2"));
552
553 assert_se(!hashmap_contains(NULL, "Key 1"));
32a4456c
MS
554
555 assert_se(m);
32a4456c
MS
556}
557
c462e63e 558TEST(hashmap_isempty) {
58f0cd14 559 _cleanup_hashmap_free_ Hashmap *m = NULL;
32a4456c
MS
560 char *val1;
561
562 val1 = strdup("my val");
563 assert_se(val1);
564
58f0cd14 565 m = hashmap_new(&string_hash_ops_value_free);
32a4456c
MS
566
567 assert_se(hashmap_isempty(m));
568 hashmap_put(m, "Key 1", val1);
569 assert_se(!hashmap_isempty(m));
570
571 assert_se(m);
32a4456c
MS
572}
573
c462e63e 574TEST(hashmap_size) {
58f0cd14 575 _cleanup_hashmap_free_ Hashmap *m = NULL;
32a4456c
MS
576 char *val1, *val2, *val3, *val4;
577
578 val1 = strdup("my val");
579 assert_se(val1);
580 val2 = strdup("my val");
581 assert_se(val2);
582 val3 = strdup("my val");
583 assert_se(val3);
584 val4 = strdup("my val");
585 assert_se(val4);
586
9ba81d5a
MS
587 assert_se(hashmap_size(NULL) == 0);
588 assert_se(hashmap_buckets(NULL) == 0);
589
58f0cd14 590 m = hashmap_new(&string_hash_ops_value_free);
32a4456c
MS
591
592 hashmap_put(m, "Key 1", val1);
593 hashmap_put(m, "Key 2", val2);
594 hashmap_put(m, "Key 3", val3);
595 hashmap_put(m, "Key 4", val4);
596
597 assert_se(m);
598 assert_se(hashmap_size(m) == 4);
9ba81d5a 599 assert_se(hashmap_buckets(m) >= 4);
32a4456c
MS
600}
601
c462e63e 602TEST(hashmap_get) {
58f0cd14 603 _cleanup_hashmap_free_ Hashmap *m = NULL;
32a4456c
MS
604 char *r;
605 char *val;
606
607 val = strdup("my val");
608 assert_se(val);
609
9ba81d5a 610 r = hashmap_get(NULL, "Key 1");
5152b845 611 ASSERT_NULL(r);
9ba81d5a 612
58f0cd14 613 m = hashmap_new(&string_hash_ops_value_free);
32a4456c
MS
614
615 hashmap_put(m, "Key 1", val);
616
617 r = hashmap_get(m, "Key 1");
c79e88b3 618 ASSERT_STREQ(r, val);
32a4456c 619
9ba81d5a 620 r = hashmap_get(m, "no such key");
5152b845 621 ASSERT_NULL(r);
9ba81d5a 622
32a4456c 623 assert_se(m);
32a4456c
MS
624}
625
c462e63e 626TEST(hashmap_get2) {
58f0cd14 627 _cleanup_hashmap_free_ Hashmap *m = NULL;
9ba81d5a
MS
628 char *r;
629 char *val;
630 char key_orig[] = "Key 1";
631 void *key_copy;
632
633 val = strdup("my val");
634 assert_se(val);
635
636 key_copy = strdup(key_orig);
637 assert_se(key_copy);
638
639 r = hashmap_get2(NULL, key_orig, &key_copy);
5152b845 640 ASSERT_NULL(r);
9ba81d5a 641
58f0cd14 642 m = hashmap_new(&string_hash_ops_free_free);
9ba81d5a
MS
643
644 hashmap_put(m, key_copy, val);
645 key_copy = NULL;
646
647 r = hashmap_get2(m, key_orig, &key_copy);
c79e88b3 648 ASSERT_STREQ(r, val);
9ba81d5a 649 assert_se(key_orig != key_copy);
c79e88b3 650 ASSERT_STREQ(key_orig, key_copy);
9ba81d5a
MS
651
652 r = hashmap_get2(m, "no such key", NULL);
5152b845 653 ASSERT_NULL(r);
9ba81d5a
MS
654
655 assert_se(m);
9ba81d5a
MS
656}
657
b826ab58
TG
658static void crippled_hashmap_func(const void *p, struct siphash *state) {
659 return trivial_hash_func(INT_TO_PTR(PTR_TO_INT(p) & 0xff), state);
9ba81d5a
MS
660}
661
662static const struct hash_ops crippled_hashmap_ops = {
663 .hash = crippled_hashmap_func,
664 .compare = trivial_compare_func,
665};
666
c462e63e 667TEST(hashmap_many) {
32a4456c 668 Hashmap *h;
ddb8a639 669 unsigned i;
9ba81d5a 670 void *v, *k;
0cf29baa 671 bool slow = slow_tests_enabled();
3d14a300 672 const struct {
32ca2911 673 const char *title;
9ba81d5a
MS
674 const struct hash_ops *ops;
675 unsigned n_entries;
676 } tests[] = {
32ca2911
ZJS
677 { "trivial_hashmap_ops", NULL, slow ? 1 << 20 : 240 },
678 { "crippled_hashmap_ops", &crippled_hashmap_ops, slow ? 1 << 14 : 140 },
9ba81d5a 679 };
32a4456c 680
32ca2911 681 log_info("/* %s (%s) */", __func__, slow ? "slow" : "fast");
32a4456c 682
ddb8a639 683 FOREACH_ELEMENT(test, tests) {
32ca2911 684 usec_t ts = now(CLOCK_MONOTONIC), n;
32ca2911 685
ddb8a639 686 assert_se(h = hashmap_new(test->ops));
32a4456c 687
ddb8a639 688 for (i = 1; i < test->n_entries*3; i+=3) {
9ba81d5a
MS
689 assert_se(hashmap_put(h, UINT_TO_PTR(i), UINT_TO_PTR(i)) >= 0);
690 assert_se(PTR_TO_UINT(hashmap_get(h, UINT_TO_PTR(i))) == i);
691 }
692
ddb8a639 693 for (i = 1; i < test->n_entries*3; i++)
9ba81d5a 694 assert_se(hashmap_contains(h, UINT_TO_PTR(i)) == (i % 3 == 1));
32a4456c 695
32ca2911 696 log_info("%s %u <= %u * 0.8 = %g",
ddb8a639 697 test->title, hashmap_size(h), hashmap_buckets(h), hashmap_buckets(h) * 0.8);
32a4456c 698
ce79279b 699 assert_se(hashmap_size(h) <= hashmap_buckets(h) * 0.8);
ddb8a639 700 assert_se(hashmap_size(h) == test->n_entries);
32a4456c 701
9ba81d5a
MS
702 while (!hashmap_isempty(h)) {
703 k = hashmap_first_key(h);
704 v = hashmap_remove(h, k);
705 assert_se(v == k);
706 }
32a4456c 707
9ba81d5a 708 hashmap_free(h);
32ca2911
ZJS
709
710 n = now(CLOCK_MONOTONIC);
5291f26d 711 log_info("test took %s", FORMAT_TIMESPAN(n - ts, 0));
9ba81d5a
MS
712 }
713}
714
8872c3a3
ZJS
715extern unsigned custom_counter;
716extern const struct hash_ops boring_hash_ops, custom_hash_ops;
717
c462e63e 718TEST(hashmap_free) {
8872c3a3
ZJS
719 Hashmap *h;
720 bool slow = slow_tests_enabled();
721 usec_t ts, n;
8872c3a3
ZJS
722 unsigned n_entries = slow ? 1 << 20 : 240;
723
724 const struct {
725 const char *title;
726 const struct hash_ops *ops;
727 unsigned expect_counter;
728 } tests[] = {
729 { "string_hash_ops", &boring_hash_ops, 2 * n_entries},
730 { "custom_free_hash_ops", &custom_hash_ops, 0 },
731 };
732
733 log_info("/* %s (%s, %u entries) */", __func__, slow ? "slow" : "fast", n_entries);
734
ddb8a639 735 FOREACH_ELEMENT(test, tests) {
8872c3a3 736 ts = now(CLOCK_MONOTONIC);
ddb8a639 737 assert_se(h = hashmap_new(test->ops));
8872c3a3
ZJS
738
739 custom_counter = 0;
740 for (unsigned i = 0; i < n_entries; i++) {
741 char s[DECIMAL_STR_MAX(unsigned)];
742 char *k, *v;
743
744 xsprintf(s, "%u", i);
745 assert_se(k = strdup(s));
746 assert_se(v = strdup(s));
747 custom_counter += 2;
748
749 assert_se(hashmap_put(h, k, v) >= 0);
750 }
751
752 hashmap_free(h);
753
754 n = now(CLOCK_MONOTONIC);
ddb8a639 755 log_info("%s test took %s", test->title, FORMAT_TIMESPAN(n - ts, 0));
8872c3a3 756
ddb8a639 757 assert_se(custom_counter == test->expect_counter);
8872c3a3
ZJS
758 }
759}
760
c462e63e 761TEST(hashmap_first) {
9ba81d5a
MS
762 _cleanup_hashmap_free_ Hashmap *m = NULL;
763
764 m = hashmap_new(&string_hash_ops);
765 assert_se(m);
766
767 assert_se(!hashmap_first(m));
768 assert_se(hashmap_put(m, "key 1", (void*) "val 1") == 1);
c79e88b3 769 ASSERT_STREQ(hashmap_first(m), "val 1");
9ba81d5a
MS
770 assert_se(hashmap_put(m, "key 2", (void*) "val 2") == 1);
771#ifdef ORDERED
c79e88b3 772 ASSERT_STREQ(hashmap_first(m), "val 1");
9ba81d5a 773 assert_se(hashmap_remove(m, "key 1"));
c79e88b3 774 ASSERT_STREQ(hashmap_first(m), "val 2");
9ba81d5a 775#endif
32a4456c
MS
776}
777
c462e63e 778TEST(hashmap_first_key) {
32a4456c
MS
779 _cleanup_hashmap_free_ Hashmap *m = NULL;
780
781 m = hashmap_new(&string_hash_ops);
782 assert_se(m);
783
784 assert_se(!hashmap_first_key(m));
785 assert_se(hashmap_put(m, "key 1", NULL) == 1);
c79e88b3 786 ASSERT_STREQ(hashmap_first_key(m), "key 1");
32a4456c
MS
787 assert_se(hashmap_put(m, "key 2", NULL) == 1);
788#ifdef ORDERED
c79e88b3 789 ASSERT_STREQ(hashmap_first_key(m), "key 1");
5152b845 790 ASSERT_NULL(hashmap_remove(m, "key 1"));
c79e88b3 791 ASSERT_STREQ(hashmap_first_key(m), "key 2");
32a4456c
MS
792#endif
793}
794
c462e63e 795TEST(hashmap_steal_first_key) {
32a4456c
MS
796 _cleanup_hashmap_free_ Hashmap *m = NULL;
797
798 m = hashmap_new(&string_hash_ops);
799 assert_se(m);
800
801 assert_se(!hashmap_steal_first_key(m));
802 assert_se(hashmap_put(m, "key 1", NULL) == 1);
c79e88b3 803 ASSERT_STREQ(hashmap_steal_first_key(m), "key 1");
32a4456c
MS
804
805 assert_se(hashmap_isempty(m));
806}
807
c462e63e 808TEST(hashmap_steal_first) {
32a4456c
MS
809 _cleanup_hashmap_free_ Hashmap *m = NULL;
810 int seen[3] = {};
811 char *val;
812
813 m = hashmap_new(&string_hash_ops);
814 assert_se(m);
815
816 assert_se(hashmap_put(m, "key 1", (void*) "1") == 1);
817 assert_se(hashmap_put(m, "key 2", (void*) "22") == 1);
818 assert_se(hashmap_put(m, "key 3", (void*) "333") == 1);
819
820 while ((val = hashmap_steal_first(m)))
821 seen[strlen(val) - 1]++;
822
823 assert_se(seen[0] == 1 && seen[1] == 1 && seen[2] == 1);
824
825 assert_se(hashmap_isempty(m));
826}
827
58f0cd14
YW
828DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(test_hash_ops_key, char, string_hash_func, string_compare_func, free);
829DEFINE_PRIVATE_HASH_OPS_FULL(test_hash_ops_full, char, string_hash_func, string_compare_func, free, char, free);
830
831TEST(hashmap_clear) {
32a4456c
MS
832 _cleanup_hashmap_free_ Hashmap *m = NULL;
833
58f0cd14 834 m = hashmap_new(&string_hash_ops_free_free);
32a4456c
MS
835 assert_se(m);
836
837 assert_se(hashmap_put(m, strdup("key 1"), NULL) == 1);
838 assert_se(hashmap_put(m, strdup("key 2"), NULL) == 1);
839 assert_se(hashmap_put(m, strdup("key 3"), NULL) == 1);
840
58f0cd14 841 hashmap_clear(m);
32a4456c 842 assert_se(hashmap_isempty(m));
98233ee5
YW
843
844 assert_se(hashmap_put(m, strdup("key 1"), strdup("value 1")) == 1);
845 assert_se(hashmap_put(m, strdup("key 2"), strdup("value 2")) == 1);
846 assert_se(hashmap_put(m, strdup("key 3"), strdup("value 3")) == 1);
847
58f0cd14 848 hashmap_clear(m);
98233ee5 849 assert_se(hashmap_isempty(m));
58f0cd14 850 m = hashmap_free(m);
98233ee5 851
98233ee5
YW
852 m = hashmap_new(&test_hash_ops_key);
853 assert_se(m);
854
855 assert_se(hashmap_put(m, strdup("key 1"), NULL) == 1);
856 assert_se(hashmap_put(m, strdup("key 2"), NULL) == 1);
857 assert_se(hashmap_put(m, strdup("key 3"), NULL) == 1);
858
58f0cd14 859 hashmap_clear(m);
98233ee5
YW
860 assert_se(hashmap_isempty(m));
861 m = hashmap_free(m);
862
863 m = hashmap_new(&test_hash_ops_full);
864 assert_se(m);
865
866 assert_se(hashmap_put(m, strdup("key 1"), strdup("value 1")) == 1);
867 assert_se(hashmap_put(m, strdup("key 2"), strdup("value 2")) == 1);
868 assert_se(hashmap_put(m, strdup("key 3"), strdup("value 3")) == 1);
869
58f0cd14 870 hashmap_clear(m);
98233ee5 871 assert_se(hashmap_isempty(m));
32a4456c
MS
872}
873
c462e63e 874TEST(hashmap_reserve) {
8f88aed7
MS
875 _cleanup_hashmap_free_ Hashmap *m = NULL;
876
877 m = hashmap_new(&string_hash_ops);
878
879 assert_se(hashmap_reserve(m, 1) == 0);
880 assert_se(hashmap_buckets(m) < 1000);
881 assert_se(hashmap_reserve(m, 1000) == 0);
882 assert_se(hashmap_buckets(m) >= 1000);
883 assert_se(hashmap_isempty(m));
884
885 assert_se(hashmap_put(m, "key 1", (void*) "val 1") == 1);
886
887 assert_se(hashmap_reserve(m, UINT_MAX) == -ENOMEM);
888 assert_se(hashmap_reserve(m, UINT_MAX - 1) == -ENOMEM);
889}
890
c462e63e 891TEST(path_hashmap) {
d578f909
ZJS
892 _cleanup_hashmap_free_ Hashmap *h = NULL;
893
d578f909
ZJS
894 assert_se(h = hashmap_new(&path_hash_ops));
895
896 assert_se(hashmap_put(h, "foo", INT_TO_PTR(1)) >= 0);
897 assert_se(hashmap_put(h, "/foo", INT_TO_PTR(2)) >= 0);
898 assert_se(hashmap_put(h, "//foo", INT_TO_PTR(3)) == -EEXIST);
899 assert_se(hashmap_put(h, "//foox/", INT_TO_PTR(4)) >= 0);
900 assert_se(hashmap_put(h, "/foox////", INT_TO_PTR(5)) == -EEXIST);
353df443 901 assert_se(hashmap_put(h, "//././/foox//.//.", INT_TO_PTR(5)) == -EEXIST);
d578f909
ZJS
902 assert_se(hashmap_put(h, "foo//////bar/quux//", INT_TO_PTR(6)) >= 0);
903 assert_se(hashmap_put(h, "foo/bar//quux/", INT_TO_PTR(8)) == -EEXIST);
353df443
YW
904 assert_se(hashmap_put(h, "foo./ba.r//.quux/", INT_TO_PTR(9)) >= 0);
905 assert_se(hashmap_put(h, "foo./ba.r//.//.quux///./", INT_TO_PTR(10)) == -EEXIST);
d578f909
ZJS
906
907 assert_se(hashmap_get(h, "foo") == INT_TO_PTR(1));
908 assert_se(hashmap_get(h, "foo/") == INT_TO_PTR(1));
909 assert_se(hashmap_get(h, "foo////") == INT_TO_PTR(1));
910 assert_se(hashmap_get(h, "/foo") == INT_TO_PTR(2));
911 assert_se(hashmap_get(h, "//foo") == INT_TO_PTR(2));
912 assert_se(hashmap_get(h, "/////foo////") == INT_TO_PTR(2));
913 assert_se(hashmap_get(h, "/////foox////") == INT_TO_PTR(4));
353df443 914 assert_se(hashmap_get(h, "/.///./foox//.//") == INT_TO_PTR(4));
d578f909
ZJS
915 assert_se(hashmap_get(h, "/foox/") == INT_TO_PTR(4));
916 assert_se(hashmap_get(h, "/foox") == INT_TO_PTR(4));
917 assert_se(!hashmap_get(h, "foox"));
918 assert_se(hashmap_get(h, "foo/bar/quux") == INT_TO_PTR(6));
919 assert_se(hashmap_get(h, "foo////bar////quux/////") == INT_TO_PTR(6));
920 assert_se(!hashmap_get(h, "/foo////bar////quux/////"));
353df443 921 assert_se(hashmap_get(h, "foo././//ba.r////.quux///.//.") == INT_TO_PTR(9));
d578f909
ZJS
922}
923
c462e63e 924TEST(string_strv_hashmap) {
87da8784
ZJS
925 _cleanup_hashmap_free_ Hashmap *m = NULL;
926 char **s;
927
87da8784
ZJS
928 assert_se(string_strv_hashmap_put(&m, "foo", "bar") == 1);
929 assert_se(string_strv_hashmap_put(&m, "foo", "bar") == 0);
930 assert_se(string_strv_hashmap_put(&m, "foo", "BAR") == 1);
931 assert_se(string_strv_hashmap_put(&m, "foo", "BAR") == 0);
932 assert_se(string_strv_hashmap_put(&m, "foo", "bar") == 0);
933 assert_se(hashmap_contains(m, "foo"));
934
935 s = hashmap_get(m, "foo");
936 assert_se(strv_equal(s, STRV_MAKE("bar", "BAR")));
937
938 assert_se(string_strv_hashmap_put(&m, "xxx", "bar") == 1);
939 assert_se(string_strv_hashmap_put(&m, "xxx", "bar") == 0);
940 assert_se(string_strv_hashmap_put(&m, "xxx", "BAR") == 1);
941 assert_se(string_strv_hashmap_put(&m, "xxx", "BAR") == 0);
942 assert_se(string_strv_hashmap_put(&m, "xxx", "bar") == 0);
943 assert_se(hashmap_contains(m, "xxx"));
944
945 s = hashmap_get(m, "xxx");
946 assert_se(strv_equal(s, STRV_MAKE("bar", "BAR")));
c540875c
YW
947
948 string_strv_hashmap_remove(m, "foo", "bar");
278e3adf 949 ASSERT_NOT_NULL((s = hashmap_get(m, "foo")));
c540875c
YW
950 ASSERT_TRUE(strv_equal(s, STRV_MAKE("BAR")));
951
952 string_strv_hashmap_remove(m, "foo", "BAR");
953 ASSERT_NULL(hashmap_get(m, "foo"));
954
955 string_strv_hashmap_remove(m, "xxx", "BAR");
278e3adf 956 ASSERT_NOT_NULL((s = hashmap_get(m, "xxx")));
c540875c
YW
957 ASSERT_TRUE(strv_equal(s, STRV_MAKE("bar")));
958
959 string_strv_hashmap_remove(m, "xxx", "bar");
960 ASSERT_NULL(hashmap_get(m, "xxx"));
961
962 ASSERT_TRUE(hashmap_isempty(m));
87da8784
ZJS
963}
964
c619033f
YW
965TEST(hashmap_dump_sorted) {
966 static void * const expected[] = { UINT_TO_PTR(123U), UINT_TO_PTR(12U), UINT_TO_PTR(345U), };
c425c885
AV
967 static const char *expected_keys[] = { "key 0", "key 1", "key 2", };
968 static void * const expected_keys2[] = { UINT_TO_PTR(111U), UINT_TO_PTR(222U), UINT_TO_PTR(333U), };
c619033f
YW
969 _cleanup_hashmap_free_ Hashmap *m = NULL;
970 _cleanup_free_ void **vals = NULL;
971 size_t n;
972
973 assert_se(m = hashmap_new(&string_hash_ops));
974
975 assert_se(hashmap_dump_sorted(m, &vals, &n) >= 0);
976 assert_se(n == 0);
977 assert_se(!vals);
978
979 assert_se(hashmap_put(m, "key 0", expected[0]) == 1);
980 assert_se(hashmap_put(m, "key 1", expected[1]) == 1);
981 assert_se(hashmap_put(m, "key 2", expected[2]) == 1);
982
983 assert_se(hashmap_dump_sorted(m, &vals, &n) >= 0);
984 assert_se(n == ELEMENTSOF(expected));
985 assert_se(memcmp(vals, expected, n * sizeof(void*)) == 0);
986
c425c885
AV
987 vals = mfree(vals);
988
989 assert_se(hashmap_dump_keys_sorted(m, &vals, &n) >= 0);
990 assert_se(n == ELEMENTSOF(expected_keys));
991 for (size_t i = 0; i < n; i++)
c79e88b3 992 ASSERT_STREQ(vals[i], expected_keys[i]);
c425c885 993
c619033f
YW
994 vals = mfree(vals);
995 m = hashmap_free(m);
996
997 assert_se(m = hashmap_new(NULL));
998
999 assert_se(hashmap_dump_sorted(m, &vals, &n) >= 0);
1000 assert_se(n == 0);
1001 assert_se(!vals);
1002
1003 assert_se(hashmap_put(m, UINT_TO_PTR(333U), expected[2]) == 1);
1004 assert_se(hashmap_put(m, UINT_TO_PTR(222U), expected[1]) == 1);
1005 assert_se(hashmap_put(m, UINT_TO_PTR(111U), expected[0]) == 1);
1006
1007 assert_se(hashmap_dump_sorted(m, &vals, &n) >= 0);
1008 assert_se(n == ELEMENTSOF(expected));
1009 assert_se(memcmp(vals, expected, n * sizeof(void*)) == 0);
c425c885
AV
1010
1011 vals = mfree(vals);
1012
1013 assert_se(hashmap_dump_keys_sorted(m, &vals, &n) >= 0);
1014 assert_se(n == ELEMENTSOF(expected_keys2));
1015 assert_se(memcmp(vals, expected_keys2, n * sizeof(void*)) == 0);
c619033f
YW
1016}
1017
c462e63e
JJ
1018/* Signal to test-hashmap.c that tests from this compilation unit were run. */
1019extern int n_extern_tests_run;
1020TEST(ensure_extern_hashmap_tests) {
1021 n_extern_tests_run++;
32a4456c 1022}