aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMosder <xmosder12@gmail.com>2026-08-31 16:20:32 +0200
committerMosder <xmosder12@gmail.com>2026-08-31 16:20:32 +0200
commit87807516500ea3a963308135c8561f3a5832348c (patch)
tree4dc9ca8eded59891998c68cf3b9d30ab73151f04
parent0992d8a901d4197c9220f50f08a0ba906cb7d8e4 (diff)
feat: added tests for hashmap
-rw-r--r--include/moslib/ds/hashmap.h18
-rw-r--r--src/ds/hashmap.c9
-rw-r--r--tests/ds/hashmap_tests.c125
3 files changed, 146 insertions, 6 deletions
diff --git a/include/moslib/ds/hashmap.h b/include/moslib/ds/hashmap.h
index 0e040c3..a05fa67 100644
--- a/include/moslib/ds/hashmap.h
+++ b/include/moslib/ds/hashmap.h
@@ -10,6 +10,8 @@
// <type> key;
// <type> val;
// };
+// can use:
+// HM_DEF(name, tk, tv) -> expands to: typedef struct {tk key; tv val;} name
//
// Struct needs to have these two values. Ig it could have more and it would work if you just use
// the entry functions, but would have uninitialized values for hm_put as that one will only
@@ -45,6 +47,7 @@
#ifndef MOS_FORCE_PREFIXES
+#define HM_DEF MOS_HM_DEF
#define hm_new mos_hm_new
#define hm_put mos_hm_put
#define hm_put_e mos_hm_put_e
@@ -62,6 +65,11 @@ typedef struct {
int (*eq)(void *key1, void *key2);
} MosHmInitArgs;
+// clang-format off
+// Macro to define Entry struct easier
+#define MOS_HM_DEF(name, key_t, val_t) typedef struct {key_t key; val_t val;} name
+// clang-format on
+
// Create a new hashmap
//
// Optional arguments:
@@ -80,7 +88,7 @@ typedef struct {
//
// Returns:
// pointer to the new hashmap
-#define mos_hm_new(...) mos_hm_new_fn((MosHmInitArgs){.key = DEFAULT, __VA_ARGS__})
+#define mos_hm_new(...) mos_hm_new_fn((MosHmInitArgs){__VA_ARGS__})
// Put given value with given key in the hashmap
// If entry of the same key exists - overwrites it
@@ -120,7 +128,7 @@ typedef struct {
//
// Returns:
// value of the entry with given key or 0 if no such entry exist
-#define mos_hm_get(hm, key)
+#define mos_hm_get(hm, key) 0
// Get a pointer to an entry with specific key in hashmap
//
@@ -133,7 +141,7 @@ typedef struct {
//
// Returns:
// pointer to the entry or NULL if no entry with such key exists
-#define mos_hm_get_e(hm, key)
+#define mos_hm_get_e(hm, key) NULL
// Get a pointer to the first entry in the hashmap
//
@@ -143,7 +151,7 @@ typedef struct {
//
// Returns:
// pointer to the first entry or NULL if hashmap is empty
-#define mos_hm_first(hm)
+#define mos_hm_first(hm) NULL
// Get the pointer to the next entry in the hashmap from the pointer to the current one
// If pointer is NULL - gets the first entry from the hashmap
@@ -157,7 +165,7 @@ typedef struct {
//
// Returns:
// pointer to the next entry or NULL if there's no more entries
-#define mos_hm_next(hm, curr)
+#define mos_hm_next(hm, curr) NULL
// Free the hashmap
//
diff --git a/src/ds/hashmap.c b/src/ds/hashmap.c
index 2c5784a..b0e13ac 100644
--- a/src/ds/hashmap.c
+++ b/src/ds/hashmap.c
@@ -1,2 +1,11 @@
#define MOS_FORCE_PREFIXES
#include "moslib/ds/hashmap.h"
+
+void *mos_hm_new_fn(MosHmInitArgs args) {
+ (void)args;
+ return NULL;
+}
+
+void mos_hm_free(void *hm) {
+ (void)hm;
+}
diff --git a/tests/ds/hashmap_tests.c b/tests/ds/hashmap_tests.c
index 83efe03..49e4261 100644
--- a/tests/ds/hashmap_tests.c
+++ b/tests/ds/hashmap_tests.c
@@ -1,7 +1,130 @@
#include "hashmap_tests.h"
#include "moslib/ds/hashmap.h"
+#include <stdlib.h>
+#include <string.h>
+
+#include "moslib/ds/array.h"
+#include "moslib/string.h"
+
+Test put_get() {
+ HM_DEF(E, float, int);
+ E *hm = NULL;
+
+ hm_put(hm, 0.0f, 69);
+ hm_put(hm, 1.0f, 420);
+ test_assert(hm_get(hm, 0.0f) == 69, "hm_get got value not from hm_put");
+ test_assert(hm_get(hm, 1.0f) == 420, "hm_get got value not from hm_put");
+
+ hm_put(hm, 0.0f, 2137);
+ test_assert(hm_get(hm, 0.0f) == 2137, "hm_put didn't update value properly");
+
+ // a lot of puts and gets to test expansion of hashmap
+ for (int i = 2; i < 100; i++) {
+ hm_put(hm, (float)i, i);
+ }
+ int flag = 1;
+ for (int i = 2; i < 100; i++) {
+ if (hm_get(hm, (float)i) != i)
+ flag = 0;
+ }
+ test_assert(flag, "hm_put / hm_get failed when expansion was needed");
+
+ hm_free(hm);
+}
+
+Test put_e_get_e() {
+ HM_DEF(E, float, int);
+ E *hm = NULL;
+
+ hm_put_e(hm, (E){0.0f, 69});
+ hm_put_e(hm, (E){1.0f, 420});
+ E e = {0.0f, 69};
+ test_assert(memcmp(&e, hm_get_e(hm, 0.0f), sizeof(E)) == 0, "hm_get_e got entry not from hm_put_e");
+ e = (E){1.0f, 420};
+ test_assert(memcmp(&e, hm_get_e(hm, 1.0f), sizeof(E)) == 0, "hm_get_e got entry not from hm_put_e");
+
+ e = (E){1.0f, 2137};
+ hm_put_e(hm, e);
+ test_assert(memcmp(&e, hm_get_e(hm, 1.0f), sizeof(E)) == 0, "hm_put_e didn't update entry properly");
+
+ hm_free(hm);
+}
+
+Test str_key() {
+ HM_DEF(E, char *, int);
+ E *hm = hm_new(.key = STR);
+
+ char *str = "key";
+ char *str2 = strdup(str);
+ hm_put(hm, str, 69);
+ hm_put(hm, "hey", 420);
+ test_assert(hm_get(hm, str2) == 69, "hm_get got value not from hm_put");
+ test_assert(hm_get(hm, "hey") == 420, "hm_get got value not from hm_put");
+
+ hm_put(hm, str2, 2137);
+ test_assert(hm_get(hm, str) == 2137, "hm_put didn't update value properly");
+
+ free(str2);
+ hm_free(hm);
+}
+
+Test ss_key() {
+ HM_DEF(E, StringSlice, int);
+ E *hm = hm_new(.key = SS);
+
+ char *str = "key";
+ char *str2 = strdup(str);
+ StringSlice ss = ss_from_str(str);
+ StringSlice ss2 = ss_from_str(str2);
+ hm_put(hm, ss, 69);
+ hm_put(hm, SS_LIT("hey"), 420);
+ test_assert(hm_get(hm, ss2) == 69, "hm_get got value not from hm_put");
+ test_assert(hm_get(hm, SS_LIT("hey")) == 420, "hm_get got value not from hm_put");
+
+ hm_put(hm, ss2, 2137);
+ test_assert(hm_get(hm, ss) == 2137, "hm_put didn't update value properly");
+
+ free(str2);
+ hm_free(hm);
+}
+
+Test looping() {
+ HM_DEF(E, int, int);
+ E *hm = NULL;
+
+ hm_put(hm, 1, 10);
+ hm_put(hm, 2, 20);
+ hm_put(hm, 3, 30);
+
+ E *allowed = NULL;
+ E items[] = {{1, 10}, {2, 20}, {3, 30}};
+ arr_append_n(allowed, items, 3);
+
+ test_assert(memcmp(hm_first(hm), hm_next(hm, NULL), sizeof(E)), "hm_next(hm, NULL) != hm_first(hm)");
+ E *e = NULL;
+ while ((e = hm_next(hm, e))) {
+ int flag = 0;
+ for (size_t i = 0; i < arr_len(allowed); i++) {
+ if (memcmp(e, allowed + i, sizeof(E)) == 0) {
+ flag = 1;
+ arr_del(allowed, i);
+ break;
+ }
+ }
+ test_assert(flag, "hm_next produced an entry that wasn't put in the hashmap");
+ }
+ test_assert(arr_len(allowed) == 0, "hm_next didn't produce every entry from hashmap when it looped over it");
+
+ arr_free(allowed);
+ hm_free(hm);
+}
+
void ds_hashmap_tests(Tester *tester) {
TestGroup *group = add_test_group(tester, "moslib/ds/hashmap.h");
- (void)group;
+ add_test(group, put_get);
+ add_test(group, put_e_get_e);
+ add_test(group, str_key);
+ add_test(group, ss_key);
+ add_test(group, looping);
}