diff options
Diffstat (limited to 'src/test/test-hashmap-plain.c')
-rw-r--r-- | src/test/test-hashmap-plain.c | 170 |
1 files changed, 128 insertions, 42 deletions
diff --git a/src/test/test-hashmap-plain.c b/src/test/test-hashmap-plain.c index b695d4ee35..5376aa84c4 100644 --- a/src/test/test-hashmap-plain.c +++ b/src/test/test-hashmap-plain.c @@ -1,25 +1,21 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -/*** - Copyright © 2013 Daniel Buch -***/ #include "alloc-util.h" -#include "env-util.h" #include "hashmap.h" #include "log.h" +#include "stdio-util.h" #include "string-util.h" #include "strv.h" +#include "tests.h" #include "util.h" -static bool arg_slow = false; - void test_hashmap_funcs(void); static void test_hashmap_replace(void) { Hashmap *m; char *val1, *val2, *val3, *val4, *val5, *r; - log_info("%s", __func__); + log_info("/* %s */", __func__); m = hashmap_new(&string_hash_ops); @@ -59,7 +55,7 @@ static void test_hashmap_copy(void) { Hashmap *m, *copy; char *val1, *val2, *val3, *val4, *r; - log_info("%s", __func__); + log_info("/* %s */", __func__); val1 = strdup("val1"); assert_se(val1); @@ -97,7 +93,7 @@ static void test_hashmap_get_strv(void) { char **strv; char *val1, *val2, *val3, *val4; - log_info("%s", __func__); + log_info("/* %s */", __func__); val1 = strdup("val1"); assert_se(val1); @@ -135,7 +131,7 @@ static void test_hashmap_move_one(void) { Hashmap *m, *n; char *val1, *val2, *val3, *val4, *r; - log_info("%s", __func__); + log_info("/* %s */", __func__); val1 = strdup("val1"); assert_se(val1); @@ -176,7 +172,7 @@ static void test_hashmap_move(void) { Hashmap *m, *n; char *val1, *val2, *val3, *val4, *r; - log_info("%s", __func__); + log_info("/* %s */", __func__); val1 = strdup("val1"); assert_se(val1); @@ -220,7 +216,7 @@ static void test_hashmap_update(void) { Hashmap *m; char *val1, *val2, *r; - log_info("%s", __func__); + log_info("/* %s */", __func__); m = hashmap_new(&string_hash_ops); val1 = strdup("old_value"); @@ -252,7 +248,7 @@ static void test_hashmap_put(void) { void *val2 = (void*) "val 2"; _cleanup_free_ char* key1 = NULL; - log_info("%s", __func__); + log_info("/* %s */", __func__); assert_se(hashmap_ensure_allocated(&m, &string_hash_ops) >= 0); assert_se(m); @@ -272,7 +268,7 @@ static void test_hashmap_remove(void) { _cleanup_hashmap_free_ Hashmap *m = NULL; char *r; - log_info("%s", __func__); + log_info("/* %s */", __func__); r = hashmap_remove(NULL, "key 1"); assert_se(r == NULL); @@ -302,7 +298,7 @@ static void test_hashmap_remove2(void) { char val2[] = "val 2"; void *r, *r2; - log_info("%s", __func__); + log_info("/* %s */", __func__); r = hashmap_remove2(NULL, "key 1", &r2); assert_se(r == NULL); @@ -334,7 +330,7 @@ static void test_hashmap_remove_value(void) { char val1[] = "val 1"; char val2[] = "val 2"; - log_info("%s", __func__); + log_info("/* %s */", __func__); r = hashmap_remove_value(NULL, "key 1", val1); assert_se(r == NULL); @@ -368,7 +364,7 @@ static void test_hashmap_remove_and_put(void) { int valid; char *r; - log_info("%s", __func__); + log_info("/* %s */", __func__); m = hashmap_new(&string_hash_ops); assert_se(m); @@ -404,7 +400,7 @@ static void test_hashmap_remove_and_replace(void) { void *r; int i, j; - log_info("%s", __func__); + log_info("/* %s */", __func__); m = hashmap_new(&trivial_hash_ops); assert_se(m); @@ -457,7 +453,7 @@ static void test_hashmap_ensure_allocated(void) { Hashmap *m; int valid_hashmap; - log_info("%s", __func__); + log_info("/* %s */", __func__); m = hashmap_new(&string_hash_ops); @@ -480,7 +476,7 @@ static void test_hashmap_foreach_key(void) { "key 3\0" "key 4\0"; - log_info("%s", __func__); + log_info("/* %s */", __func__); m = hashmap_new(&string_hash_ops); @@ -512,7 +508,7 @@ static void test_hashmap_foreach(void) { char *val1, *val2, *val3, *val4, *s; unsigned count; - log_info("%s", __func__); + log_info("/* %s */", __func__); val1 = strdup("my val1"); assert_se(val1); @@ -564,7 +560,7 @@ static void test_hashmap_merge(void) { Hashmap *n; char *val1, *val2, *val3, *val4, *r; - log_info("%s", __func__); + log_info("/* %s */", __func__); val1 = strdup("my val1"); assert_se(val1); @@ -599,7 +595,7 @@ static void test_hashmap_contains(void) { Hashmap *m; char *val1; - log_info("%s", __func__); + log_info("/* %s */", __func__); val1 = strdup("my val"); assert_se(val1); @@ -621,7 +617,7 @@ static void test_hashmap_isempty(void) { Hashmap *m; char *val1; - log_info("%s", __func__); + log_info("/* %s */", __func__); val1 = strdup("my val"); assert_se(val1); @@ -640,7 +636,7 @@ static void test_hashmap_size(void) { Hashmap *m; char *val1, *val2, *val3, *val4; - log_info("%s", __func__); + log_info("/* %s */", __func__); val1 = strdup("my val"); assert_se(val1); @@ -672,7 +668,7 @@ static void test_hashmap_get(void) { char *r; char *val; - log_info("%s", __func__); + log_info("/* %s */", __func__); val = strdup("my val"); assert_se(val); @@ -701,7 +697,7 @@ static void test_hashmap_get2(void) { char key_orig[] = "Key 1"; void *key_copy; - log_info("%s", __func__); + log_info("/* %s */", __func__); val = strdup("my val"); assert_se(val); @@ -742,17 +738,22 @@ static void test_hashmap_many(void) { Hashmap *h; unsigned i, j; void *v, *k; + bool slow = slow_tests_enabled(); const struct { + const char *title; const struct hash_ops *ops; unsigned n_entries; } tests[] = { - { .ops = NULL, .n_entries = arg_slow ? 1 << 20 : 240 }, - { .ops = &crippled_hashmap_ops, .n_entries = arg_slow ? 1 << 14 : 140 }, + { "trivial_hashmap_ops", NULL, slow ? 1 << 20 : 240 }, + { "crippled_hashmap_ops", &crippled_hashmap_ops, slow ? 1 << 14 : 140 }, }; - log_info("%s (%s)", __func__, arg_slow ? "slow" : "fast"); + log_info("/* %s (%s) */", __func__, slow ? "slow" : "fast"); for (j = 0; j < ELEMENTSOF(tests); j++) { + usec_t ts = now(CLOCK_MONOTONIC), n; + char b[FORMAT_TIMESPAN_MAX]; + assert_se(h = hashmap_new(tests[j].ops)); for (i = 1; i < tests[j].n_entries*3; i+=3) { @@ -763,7 +764,8 @@ static void test_hashmap_many(void) { for (i = 1; i < tests[j].n_entries*3; i++) assert_se(hashmap_contains(h, UINT_TO_PTR(i)) == (i % 3 == 1)); - log_info("%u <= %u * 0.8 = %g", hashmap_size(h), hashmap_buckets(h), hashmap_buckets(h) * 0.8); + log_info("%s %u <= %u * 0.8 = %g", + tests[j].title, hashmap_size(h), hashmap_buckets(h), hashmap_buckets(h) * 0.8); assert_se(hashmap_size(h) <= hashmap_buckets(h) * 0.8); assert_se(hashmap_size(h) == tests[j].n_entries); @@ -775,13 +777,63 @@ static void test_hashmap_many(void) { } hashmap_free(h); + + n = now(CLOCK_MONOTONIC); + log_info("test took %s", format_timespan(b, sizeof b, n - ts, 0)); + } +} + +extern unsigned custom_counter; +extern const struct hash_ops boring_hash_ops, custom_hash_ops; + +static void test_hashmap_free(void) { + Hashmap *h; + bool slow = slow_tests_enabled(); + usec_t ts, n; + char b[FORMAT_TIMESPAN_MAX]; + unsigned n_entries = slow ? 1 << 20 : 240; + + const struct { + const char *title; + const struct hash_ops *ops; + unsigned expect_counter; + } tests[] = { + { "string_hash_ops", &boring_hash_ops, 2 * n_entries}, + { "custom_free_hash_ops", &custom_hash_ops, 0 }, + }; + + log_info("/* %s (%s, %u entries) */", __func__, slow ? "slow" : "fast", n_entries); + + for (unsigned j = 0; j < ELEMENTSOF(tests); j++) { + ts = now(CLOCK_MONOTONIC); + assert_se(h = hashmap_new(tests[j].ops)); + + custom_counter = 0; + for (unsigned i = 0; i < n_entries; i++) { + char s[DECIMAL_STR_MAX(unsigned)]; + char *k, *v; + + xsprintf(s, "%u", i); + assert_se(k = strdup(s)); + assert_se(v = strdup(s)); + custom_counter += 2; + + assert_se(hashmap_put(h, k, v) >= 0); + } + + hashmap_free(h); + + n = now(CLOCK_MONOTONIC); + log_info("%s test took %s", tests[j].title, format_timespan(b, sizeof b, n - ts, 0)); + + assert_se(custom_counter == tests[j].expect_counter); } } static void test_hashmap_first(void) { _cleanup_hashmap_free_ Hashmap *m = NULL; - log_info("%s", __func__); + log_info("/* %s */", __func__); m = hashmap_new(&string_hash_ops); assert_se(m); @@ -800,7 +852,7 @@ static void test_hashmap_first(void) { static void test_hashmap_first_key(void) { _cleanup_hashmap_free_ Hashmap *m = NULL; - log_info("%s", __func__); + log_info("/* %s */", __func__); m = hashmap_new(&string_hash_ops); assert_se(m); @@ -819,7 +871,7 @@ static void test_hashmap_first_key(void) { static void test_hashmap_steal_first_key(void) { _cleanup_hashmap_free_ Hashmap *m = NULL; - log_info("%s", __func__); + log_info("/* %s */", __func__); m = hashmap_new(&string_hash_ops); assert_se(m); @@ -836,7 +888,7 @@ static void test_hashmap_steal_first(void) { int seen[3] = {}; char *val; - log_info("%s", __func__); + log_info("/* %s */", __func__); m = hashmap_new(&string_hash_ops); assert_se(m); @@ -856,7 +908,7 @@ static void test_hashmap_steal_first(void) { static void test_hashmap_clear_free_free(void) { _cleanup_hashmap_free_ Hashmap *m = NULL; - log_info("%s", __func__); + log_info("/* %s */", __func__); m = hashmap_new(&string_hash_ops); assert_se(m); @@ -867,12 +919,49 @@ static void test_hashmap_clear_free_free(void) { hashmap_clear_free_free(m); assert_se(hashmap_isempty(m)); + + assert_se(hashmap_put(m, strdup("key 1"), strdup("value 1")) == 1); + assert_se(hashmap_put(m, strdup("key 2"), strdup("value 2")) == 1); + assert_se(hashmap_put(m, strdup("key 3"), strdup("value 3")) == 1); + + hashmap_clear_free_free(m); + assert_se(hashmap_isempty(m)); +} + +DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(test_hash_ops_key, char, string_hash_func, string_compare_func, free); +DEFINE_PRIVATE_HASH_OPS_FULL(test_hash_ops_full, char, string_hash_func, string_compare_func, free, char, free); + +static void test_hashmap_clear_free_with_destructor(void) { + _cleanup_hashmap_free_ Hashmap *m = NULL; + + log_info("/* %s */", __func__); + + m = hashmap_new(&test_hash_ops_key); + assert_se(m); + + assert_se(hashmap_put(m, strdup("key 1"), NULL) == 1); + assert_se(hashmap_put(m, strdup("key 2"), NULL) == 1); + assert_se(hashmap_put(m, strdup("key 3"), NULL) == 1); + + hashmap_clear_free(m); + assert_se(hashmap_isempty(m)); + m = hashmap_free(m); + + m = hashmap_new(&test_hash_ops_full); + assert_se(m); + + assert_se(hashmap_put(m, strdup("key 1"), strdup("value 1")) == 1); + assert_se(hashmap_put(m, strdup("key 2"), strdup("value 2")) == 1); + assert_se(hashmap_put(m, strdup("key 3"), strdup("value 3")) == 1); + + hashmap_clear_free(m); + assert_se(hashmap_isempty(m)); } static void test_hashmap_reserve(void) { _cleanup_hashmap_free_ Hashmap *m = NULL; - log_info("%s", __func__); + log_info("/* %s */", __func__); m = hashmap_new(&string_hash_ops); @@ -889,14 +978,9 @@ static void test_hashmap_reserve(void) { } void test_hashmap_funcs(void) { - int r; - log_parse_environment(); log_open(); - r = getenv_bool("SYSTEMD_SLOW_TESTS"); - arg_slow = r >= 0 ? r : SYSTEMD_SLOW_TESTS_DEFAULT; - test_hashmap_copy(); test_hashmap_get_strv(); test_hashmap_move_one(); @@ -919,10 +1003,12 @@ void test_hashmap_funcs(void) { test_hashmap_get2(); test_hashmap_size(); test_hashmap_many(); + test_hashmap_free(); test_hashmap_first(); test_hashmap_first_key(); test_hashmap_steal_first_key(); test_hashmap_steal_first(); test_hashmap_clear_free_free(); + test_hashmap_clear_free_with_destructor(); test_hashmap_reserve(); } |