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