]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
basic/hashmap: allow NULL values in strdup hashmaps and add test
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Wed, 29 Apr 2020 07:55:28 +0000 (09:55 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Wed, 6 May 2020 14:56:42 +0000 (16:56 +0200)
src/basic/hashmap.c
src/test/test-hashmap.c

index 7abe62fa93768793bf79cae6e244850cb8997032..efbe95bb9e33f90e087fdad9e45b95da5e87a315 100644 (file)
@@ -1775,22 +1775,30 @@ int hashmap_put_strdup(Hashmap **h, const char *k, const char *v) {
                 return r;
 
         _cleanup_free_ char *kdup = NULL, *vdup = NULL;
+
         kdup = strdup(k);
-        vdup = strdup(v);
-        if (!kdup || !vdup)
+        if (!kdup)
                 return -ENOMEM;
 
+        if (v) {
+                vdup = strdup(v);
+                if (!vdup)
+                        return -ENOMEM;
+        }
+
         r = hashmap_put(*h, kdup, vdup);
         if (r < 0) {
-                if (r == -EEXIST && streq(v, hashmap_get(*h, kdup)))
+                if (r == -EEXIST && streq_ptr(v, hashmap_get(*h, kdup)))
                         return 0;
                 return r;
         }
 
-        assert(r > 0); /* 0 would mean vdup is already in the hashmap, which cannot be */
-        kdup = vdup = NULL;
+        /* 0 with non-null vdup would mean vdup is already in the hashmap, which cannot be */
+        assert(vdup == NULL || r > 0);
+        if (r > 0)
+                kdup = vdup = NULL;
 
-        return 0;
+        return r;
 }
 
 int set_put_strdup(Set **s, const char *p) {
index 1a6e8ffa58e98c2246c44333537e4cf191e17a4e..94dbbf157692f03329fb1aedcae1c36fb30e67ff 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include "hashmap.h"
+#include "string-util.h"
 #include "util.h"
 
 unsigned custom_counter = 0;
@@ -109,6 +110,58 @@ static void test_iterated_cache(void) {
         assert_se(iterated_cache_free(c) == NULL);
 }
 
+static void test_hashmap_put_strdup(void) {
+        _cleanup_hashmap_free_ Hashmap *m = NULL;
+        char *s;
+
+        /* We don't have ordered_hashmap_put_strdup() yet. If it is added,
+         * these tests should be moved to test-hashmap-plain.c. */
+
+        log_info("/* %s */", __func__);
+
+        assert_se(hashmap_put_strdup(&m, "foo", "bar") == 1);
+        assert_se(hashmap_put_strdup(&m, "foo", "bar") == 0);
+        assert_se(hashmap_put_strdup(&m, "foo", "BAR") == -EEXIST);
+        assert_se(hashmap_put_strdup(&m, "foo", "bar") == 0);
+        assert_se(hashmap_contains(m, "foo"));
+
+        s = hashmap_get(m, "foo");
+        assert_se(streq(s, "bar"));
+
+        assert_se(hashmap_put_strdup(&m, "xxx", "bar") == 1);
+        assert_se(hashmap_put_strdup(&m, "xxx", "bar") == 0);
+        assert_se(hashmap_put_strdup(&m, "xxx", "BAR") == -EEXIST);
+        assert_se(hashmap_put_strdup(&m, "xxx", "bar") == 0);
+        assert_se(hashmap_contains(m, "xxx"));
+
+        s = hashmap_get(m, "xxx");
+        assert_se(streq(s, "bar"));
+}
+
+static void test_hashmap_put_strdup_null(void) {
+        _cleanup_hashmap_free_ Hashmap *m = NULL;
+        char *s;
+
+        log_info("/* %s */", __func__);
+
+        assert_se(hashmap_put_strdup(&m, "foo", "bar") == 1);
+        assert_se(hashmap_put_strdup(&m, "foo", "bar") == 0);
+        assert_se(hashmap_put_strdup(&m, "foo", NULL) == -EEXIST);
+        assert_se(hashmap_put_strdup(&m, "foo", "bar") == 0);
+        assert_se(hashmap_contains(m, "foo"));
+
+        s = hashmap_get(m, "foo");
+        assert_se(streq(s, "bar"));
+
+        assert_se(hashmap_put_strdup(&m, "xxx", NULL) == 1);
+        assert_se(hashmap_put_strdup(&m, "xxx", "bar") == -EEXIST);
+        assert_se(hashmap_put_strdup(&m, "xxx", NULL) == 0);
+        assert_se(hashmap_contains(m, "xxx"));
+
+        s = hashmap_get(m, "xxx");
+        assert_se(s == NULL);
+}
+
 int main(int argc, const char *argv[]) {
         /* This file tests in test-hashmap-plain.c, and tests in test-hashmap-ordered.c, which is generated
          * from test-hashmap-plain.c. Hashmap tests should be added to test-hashmap-plain.c, and here only if
@@ -127,6 +180,8 @@ int main(int argc, const char *argv[]) {
         test_trivial_compare_func();
         test_string_compare_func();
         test_iterated_cache();
+        test_hashmap_put_strdup();
+        test_hashmap_put_strdup_null();
 
         return 0;
 }