2022-01-22 14:57:10 +00:00
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
#include "test.h"
|
|
|
|
|
#include "hashmap.h"
|
|
|
|
|
|
|
|
|
|
static struct apfl_hashmap
|
|
|
|
|
init_int2int(testctx t)
|
|
|
|
|
{
|
|
|
|
|
struct apfl_hashmap map;
|
|
|
|
|
if (!apfl_hashmap_init(
|
|
|
|
|
&map,
|
2022-02-08 21:53:13 +00:00
|
|
|
test_allocator(t),
|
2022-01-22 14:57:10 +00:00
|
|
|
(struct apfl_hashmap_callbacks) { .opaque = NULL },
|
|
|
|
|
sizeof(int),
|
|
|
|
|
sizeof(int)
|
|
|
|
|
)) {
|
|
|
|
|
test_fatalf(t, "Failed initializing int2int map!");
|
|
|
|
|
}
|
|
|
|
|
return map;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
assert_len(testctx t, struct apfl_hashmap map, size_t want, const char *label)
|
|
|
|
|
{
|
|
|
|
|
size_t have = apfl_hashmap_count(map);
|
|
|
|
|
if (have != want) {
|
|
|
|
|
test_failf(t, "%s: expected count to be %d, got %d instead", label, want, have);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
check_get_int2int(testctx t, struct apfl_hashmap *map, int k, int v)
|
|
|
|
|
{
|
|
|
|
|
int have;
|
|
|
|
|
if (apfl_hashmap_get(map, &k, &have)) {
|
|
|
|
|
if (have != v) {
|
|
|
|
|
test_failf(t, "Got %d instead of %d for key %d", have, v, k);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
test_failf(t, "Failed getting %d (expected %d)", k, v);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
check_set_int2int(testctx t, struct apfl_hashmap *map, int k, int v)
|
|
|
|
|
{
|
|
|
|
|
if (!apfl_hashmap_set(map, &k, &v)) {
|
|
|
|
|
test_fatalf(t, "Failed setting %d -> %d", k, v);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
check_get_int2int(t, map, k, v);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
check_not_exists_int2int(testctx t, struct apfl_hashmap *map, int k)
|
|
|
|
|
{
|
|
|
|
|
int v;
|
|
|
|
|
if (apfl_hashmap_get(map, &k, &v)) {
|
|
|
|
|
test_failf(t, "Expected key %d to not be set, but got value %d", k, v);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
check_get_str2str(testctx t, struct apfl_hashmap *map, const char *k, const char *v)
|
|
|
|
|
{
|
|
|
|
|
char *have;
|
|
|
|
|
if (apfl_hashmap_get(map, &k, &have)) {
|
|
|
|
|
if (strcmp(v, have) != 0) {
|
|
|
|
|
test_failf(t, "Got %s instead of %s for key %s", have, v, k);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
test_failf(t, "Failed getting %s (expected %s)", k, v);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free(have);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
check_set_str2str(testctx t, struct apfl_hashmap *map, const char *k, const char *v)
|
|
|
|
|
{
|
|
|
|
|
if (!apfl_hashmap_set(map, &k, &v)) {
|
|
|
|
|
test_fatalf(t, "Failed setting %s -> %s", k, v);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
check_get_str2str(t, map, k, v);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
check_not_exists_str2str(testctx t, struct apfl_hashmap *map, const char *k)
|
|
|
|
|
{
|
|
|
|
|
char *v;
|
|
|
|
|
if (apfl_hashmap_get(map, &k, &v)) {
|
|
|
|
|
test_failf(t, "Expected key %s to not be set, but got value %s", k, v);
|
|
|
|
|
free(v);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
str2str_keys_eq(void *_opaque, const void *_a, const void *_b)
|
|
|
|
|
{
|
|
|
|
|
testctx t = _opaque;
|
|
|
|
|
const char * const *a = _a;
|
|
|
|
|
const char * const *b = _b;
|
|
|
|
|
|
|
|
|
|
if (a == b) {
|
|
|
|
|
test_fatalf(t, "keys_eq callback: a == b, this should not happen!");
|
|
|
|
|
}
|
|
|
|
|
if (*a == *b) {
|
|
|
|
|
test_fatalf(t, "keys_eq callback: *a == *b, this should not happen!");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return strcmp(*a, *b) == 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static apfl_hash
|
|
|
|
|
str2str_calc_hash(void *opaque, const void *_key)
|
|
|
|
|
{
|
|
|
|
|
(void)opaque;
|
|
|
|
|
const char * const *key = _key;
|
|
|
|
|
|
|
|
|
|
return apfl_hash_fnv1a(*key, strlen(*key));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
destroy_str_kv(char **strptr)
|
|
|
|
|
{
|
|
|
|
|
free(*strptr);
|
|
|
|
|
*strptr = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
str2str_destroy_key(void *opaque, void *_key)
|
|
|
|
|
{
|
|
|
|
|
(void)opaque;
|
|
|
|
|
destroy_str_kv(_key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
str2str_destroy_value(void *opaque, void *_value)
|
|
|
|
|
{
|
|
|
|
|
(void)opaque;
|
|
|
|
|
destroy_str_kv(_value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
copy_str_kv(testctx t, char **dest, char **src)
|
|
|
|
|
{
|
|
|
|
|
size_t len = strlen(*src);
|
|
|
|
|
*dest = must_alloc(t, len + 1);
|
|
|
|
|
memcpy(*dest, *src, len + 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
str2str_copy_key(void *_opaque, void *_dest, void *_src)
|
|
|
|
|
{
|
|
|
|
|
testctx t = _opaque;
|
|
|
|
|
copy_str_kv(t, _dest, _src);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
str2str_copy_value(void *_opaque, void *_dest, void *_src)
|
|
|
|
|
{
|
|
|
|
|
testctx t = _opaque;
|
|
|
|
|
copy_str_kv(t, _dest, _src);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct apfl_hashmap
|
|
|
|
|
init_str2str(testctx t)
|
|
|
|
|
{
|
|
|
|
|
struct apfl_hashmap map;
|
|
|
|
|
if (!apfl_hashmap_init(
|
|
|
|
|
&map,
|
2022-02-08 21:53:13 +00:00
|
|
|
test_allocator(t),
|
2022-01-22 14:57:10 +00:00
|
|
|
(struct apfl_hashmap_callbacks) {
|
|
|
|
|
.opaque = t,
|
|
|
|
|
.keys_eq = str2str_keys_eq,
|
|
|
|
|
.calc_hash = str2str_calc_hash,
|
|
|
|
|
.destroy_key = str2str_destroy_key,
|
|
|
|
|
.destroy_value = str2str_destroy_value,
|
|
|
|
|
.copy_key = str2str_copy_key,
|
|
|
|
|
.copy_value = str2str_copy_value,
|
|
|
|
|
},
|
|
|
|
|
sizeof(char *),
|
|
|
|
|
sizeof(char *)
|
|
|
|
|
)) {
|
|
|
|
|
test_fatalf(t, "Failed initializing str2str map!");
|
|
|
|
|
}
|
|
|
|
|
return map;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(int2int_set_get_delete, t) {
|
|
|
|
|
struct apfl_hashmap map = init_int2int(t);
|
|
|
|
|
assert_len(t, map, 0, "after init");
|
|
|
|
|
|
|
|
|
|
int k = 1337;
|
|
|
|
|
check_set_int2int(t, &map, k, 666);
|
|
|
|
|
assert_len(t, map, 1, "after setting");
|
|
|
|
|
|
|
|
|
|
apfl_hashmap_delete(&map, &k);
|
|
|
|
|
|
|
|
|
|
check_not_exists_int2int(t, &map, k);
|
|
|
|
|
|
|
|
|
|
assert_len(t, map, 0, "after deleting");
|
|
|
|
|
|
|
|
|
|
apfl_hashmap_deinit(&map);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(int2int_set_overwrite, t) {
|
|
|
|
|
struct apfl_hashmap map = init_int2int(t);
|
|
|
|
|
assert_len(t, map, 0, "after init");
|
|
|
|
|
|
|
|
|
|
check_set_int2int(t, &map, 42, 1337);
|
|
|
|
|
assert_len(t, map, 1, "after setting");
|
|
|
|
|
|
|
|
|
|
check_set_int2int(t, &map, 42, 666);
|
|
|
|
|
assert_len(t, map, 1, "after setting again");
|
|
|
|
|
|
|
|
|
|
apfl_hashmap_deinit(&map);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(int2int_set_many, t) {
|
|
|
|
|
struct apfl_hashmap map = init_int2int(t);
|
|
|
|
|
assert_len(t, map, 0, "after init");
|
|
|
|
|
|
|
|
|
|
check_set_int2int(t, &map, 42, 1337);
|
|
|
|
|
assert_len(t, map, 1, "after setting 42");
|
|
|
|
|
|
|
|
|
|
check_set_int2int(t, &map, 123, 456);
|
|
|
|
|
assert_len(t, map, 2, "after setting 123");
|
|
|
|
|
|
|
|
|
|
check_set_int2int(t, &map, 42, 666);
|
|
|
|
|
assert_len(t, map, 2, "after setting 42 again");
|
|
|
|
|
|
|
|
|
|
check_set_int2int(t, &map, 1, 2);
|
|
|
|
|
assert_len(t, map, 3, "after setting 1");
|
|
|
|
|
|
|
|
|
|
check_set_int2int(t, &map, 0, 0);
|
|
|
|
|
assert_len(t, map, 4, "after setting 0");
|
|
|
|
|
|
|
|
|
|
// Let's check, if they are still in the map
|
|
|
|
|
check_get_int2int(t, &map, 42, 666);
|
|
|
|
|
check_get_int2int(t, &map, 123, 456);
|
|
|
|
|
check_get_int2int(t, &map, 1, 2);
|
|
|
|
|
check_get_int2int(t, &map, 0, 0);
|
|
|
|
|
|
|
|
|
|
apfl_hashmap_deinit(&map);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define ITERATING_SWITCH_CASE(t, key, seen, value_want, value_have) \
|
|
|
|
|
case key: \
|
|
|
|
|
if (seen) { \
|
|
|
|
|
test_failf( \
|
|
|
|
|
t, \
|
|
|
|
|
"already seen key %d, got it again (with value=%d)", \
|
|
|
|
|
key, \
|
|
|
|
|
value_have \
|
|
|
|
|
); \
|
|
|
|
|
} else { \
|
|
|
|
|
seen = true; \
|
|
|
|
|
if (value_have != value_want) { \
|
|
|
|
|
test_failf( \
|
|
|
|
|
t, \
|
|
|
|
|
"got key %d but with wrong value: want=%d, have=%d", \
|
|
|
|
|
key, \
|
|
|
|
|
value_want, \
|
|
|
|
|
value_have \
|
|
|
|
|
); \
|
|
|
|
|
} \
|
|
|
|
|
} \
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
TEST(int2int_iterating, t) {
|
|
|
|
|
struct apfl_hashmap map = init_int2int(t);
|
|
|
|
|
|
|
|
|
|
check_set_int2int(t, &map, 123, 456);
|
|
|
|
|
check_set_int2int(t, &map, 42, 666);
|
|
|
|
|
check_set_int2int(t, &map, 1, 2);
|
|
|
|
|
check_set_int2int(t, &map, 0, 0);
|
|
|
|
|
|
|
|
|
|
bool seen_123 = false;
|
|
|
|
|
bool seen_42 = false;
|
|
|
|
|
bool seen_1 = false;
|
|
|
|
|
bool seen_0 = false;
|
|
|
|
|
|
|
|
|
|
for (
|
|
|
|
|
struct apfl_hashmap_cursor it = apfl_hashmap_get_cursor(&map);
|
|
|
|
|
!apfl_hashmap_cursor_is_end(it);
|
|
|
|
|
apfl_hashmap_cursor_next(&it)
|
|
|
|
|
) {
|
|
|
|
|
int k, v;
|
|
|
|
|
|
|
|
|
|
apfl_hashmap_cursor_get_key(it, &k);
|
|
|
|
|
apfl_hashmap_cursor_get_value(it, &v);
|
|
|
|
|
|
|
|
|
|
switch (k) {
|
|
|
|
|
ITERATING_SWITCH_CASE(t, 123, seen_123, 456, v)
|
|
|
|
|
ITERATING_SWITCH_CASE(t, 42, seen_42, 666, v)
|
|
|
|
|
ITERATING_SWITCH_CASE(t, 1, seen_1, 2, v)
|
|
|
|
|
ITERATING_SWITCH_CASE(t, 0, seen_0, 0, v)
|
|
|
|
|
default:
|
|
|
|
|
test_failf(t, "Seen unexpected key %d with value %d", k, v);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!seen_123) {
|
|
|
|
|
test_failf(t, "Did not see key 123");
|
|
|
|
|
}
|
|
|
|
|
if (!seen_42) {
|
|
|
|
|
test_failf(t, "Did not see key 42");
|
|
|
|
|
}
|
|
|
|
|
if (!seen_1) {
|
|
|
|
|
test_failf(t, "Did not see key 1");
|
|
|
|
|
}
|
|
|
|
|
if (!seen_0) {
|
|
|
|
|
test_failf(t, "Did not see key 0");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
apfl_hashmap_deinit(&map);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(int2int_moving, t) {
|
|
|
|
|
struct apfl_hashmap orig = init_int2int(t);
|
|
|
|
|
|
|
|
|
|
check_set_int2int(t, &orig, 011, 899);
|
|
|
|
|
check_set_int2int(t, &orig, 988, 199);
|
|
|
|
|
check_set_int2int(t, &orig, 911, 972);
|
|
|
|
|
check_set_int2int(t, &orig, 5, 3);
|
|
|
|
|
|
|
|
|
|
struct apfl_hashmap new = apfl_hashmap_move(&orig);
|
|
|
|
|
|
|
|
|
|
assert_len(t, new, 4, "after moving");
|
|
|
|
|
check_get_int2int(t, &new, 011, 899);
|
|
|
|
|
check_get_int2int(t, &new, 988, 199);
|
|
|
|
|
check_get_int2int(t, &new, 911, 972);
|
|
|
|
|
check_get_int2int(t, &new, 5, 3);
|
|
|
|
|
|
|
|
|
|
apfl_hashmap_deinit(&new);
|
|
|
|
|
apfl_hashmap_deinit(&orig); // not neccessary, but should still work without crashing
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(int2int_copying, t) {
|
|
|
|
|
struct apfl_hashmap orig = init_int2int(t);
|
|
|
|
|
|
|
|
|
|
check_set_int2int(t, &orig, 1, 111);
|
|
|
|
|
check_set_int2int(t, &orig, 2, 222);
|
|
|
|
|
check_set_int2int(t, &orig, 3, 333);
|
|
|
|
|
check_set_int2int(t, &orig, 4, 444);
|
|
|
|
|
|
|
|
|
|
struct apfl_hashmap copy;
|
|
|
|
|
if (!apfl_hashmap_copy(©, orig)) {
|
|
|
|
|
test_fatalf(t, "Copying failed");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert_len(t, orig, 4, "orig after moving");
|
|
|
|
|
check_get_int2int(t, &orig, 1, 111);
|
|
|
|
|
check_get_int2int(t, &orig, 2, 222);
|
|
|
|
|
check_get_int2int(t, &orig, 3, 333);
|
|
|
|
|
check_get_int2int(t, &orig, 4, 444);
|
|
|
|
|
|
|
|
|
|
assert_len(t, copy, 4, "copy after moving");
|
|
|
|
|
check_get_int2int(t, ©, 1, 111);
|
|
|
|
|
check_get_int2int(t, ©, 2, 222);
|
|
|
|
|
check_get_int2int(t, ©, 3, 333);
|
|
|
|
|
check_get_int2int(t, ©, 4, 444);
|
|
|
|
|
|
|
|
|
|
// Setting something in orig should not influence the copy
|
|
|
|
|
check_set_int2int(t, &orig, 5, 555);
|
|
|
|
|
check_not_exists_int2int(t, ©, 5);
|
|
|
|
|
|
|
|
|
|
// And the other way around too
|
|
|
|
|
check_set_int2int(t, ©, 6, 666);
|
|
|
|
|
check_not_exists_int2int(t, &orig, 6);
|
|
|
|
|
|
|
|
|
|
// Overwriting something in orig should not influence the copy
|
|
|
|
|
check_set_int2int(t, &orig, 1, 1337);
|
|
|
|
|
check_get_int2int(t, ©, 1, 111);
|
|
|
|
|
|
|
|
|
|
// And the other way around too
|
|
|
|
|
check_set_int2int(t, ©, 2, 1337);
|
|
|
|
|
check_get_int2int(t, &orig, 2, 222);
|
|
|
|
|
|
|
|
|
|
int k;
|
|
|
|
|
// Deleting something in orig should not influence the copy
|
|
|
|
|
k = 3;
|
|
|
|
|
apfl_hashmap_delete(&orig, &k);
|
|
|
|
|
check_get_int2int(t, ©, 3, 333);
|
|
|
|
|
|
|
|
|
|
// And the other way around too
|
|
|
|
|
k = 4;
|
|
|
|
|
apfl_hashmap_delete(©, &k);
|
|
|
|
|
check_get_int2int(t, &orig, 4, 444);
|
|
|
|
|
|
|
|
|
|
apfl_hashmap_deinit(©);
|
|
|
|
|
apfl_hashmap_deinit(&orig);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(str2str_set_get_delete, t) {
|
|
|
|
|
struct apfl_hashmap map = init_str2str(t);
|
|
|
|
|
assert_len(t, map, 0, "after init");
|
|
|
|
|
|
|
|
|
|
const char *k = "foo";
|
|
|
|
|
check_set_str2str(t, &map, k, "bar");
|
|
|
|
|
assert_len(t, map, 1, "after setting");
|
|
|
|
|
|
|
|
|
|
apfl_hashmap_delete(&map, &k);
|
|
|
|
|
|
|
|
|
|
check_not_exists_str2str(t, &map, k);
|
|
|
|
|
|
|
|
|
|
assert_len(t, map, 0, "after deleting");
|
|
|
|
|
|
|
|
|
|
apfl_hashmap_deinit(&map);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(str2str_set_overwrite, t) {
|
|
|
|
|
struct apfl_hashmap map = init_str2str(t);
|
|
|
|
|
assert_len(t, map, 0, "after init");
|
|
|
|
|
|
|
|
|
|
check_set_str2str(t, &map, "foo", "bar");
|
|
|
|
|
assert_len(t, map, 1, "after setting");
|
|
|
|
|
|
|
|
|
|
check_set_str2str(t, &map, "foo", "baz");
|
|
|
|
|
assert_len(t, map, 1, "after setting again");
|
|
|
|
|
|
|
|
|
|
apfl_hashmap_deinit(&map);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(str2str_set_many, t) {
|
|
|
|
|
struct apfl_hashmap map = init_str2str(t);
|
|
|
|
|
assert_len(t, map, 0, "after init");
|
|
|
|
|
|
|
|
|
|
check_set_str2str(t, &map, "foo", "abc");
|
|
|
|
|
assert_len(t, map, 1, "after setting foo");
|
|
|
|
|
|
|
|
|
|
check_set_str2str(t, &map, "bar", "def");
|
|
|
|
|
assert_len(t, map, 2, "after setting bar");
|
|
|
|
|
|
|
|
|
|
check_set_str2str(t, &map, "foo", "ghi");
|
|
|
|
|
assert_len(t, map, 2, "after setting foo again");
|
|
|
|
|
|
|
|
|
|
check_set_str2str(t, &map, "baz", "jkl");
|
|
|
|
|
assert_len(t, map, 3, "after setting 1");
|
|
|
|
|
|
|
|
|
|
check_set_str2str(t, &map, "", "");
|
|
|
|
|
assert_len(t, map, 4, "after setting \"\"");
|
|
|
|
|
|
|
|
|
|
// Let's check, if they are still in the map
|
|
|
|
|
check_get_str2str(t, &map, "foo", "ghi");
|
|
|
|
|
check_get_str2str(t, &map, "bar", "def");
|
|
|
|
|
check_get_str2str(t, &map, "baz", "jkl");
|
|
|
|
|
check_get_str2str(t, &map, "", "");
|
|
|
|
|
|
|
|
|
|
apfl_hashmap_deinit(&map);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define ITERATING_SEEN_CHECK(t, key, seen, value_want, value_have) \
|
|
|
|
|
if (seen) { \
|
|
|
|
|
test_failf( \
|
|
|
|
|
t, \
|
|
|
|
|
"already seen key %s, got it again (with value=%s)", \
|
|
|
|
|
key, \
|
|
|
|
|
value_have \
|
|
|
|
|
); \
|
|
|
|
|
} else { \
|
|
|
|
|
seen = true; \
|
|
|
|
|
if (strcmp(value_have, value_want) != 0) { \
|
|
|
|
|
test_failf( \
|
|
|
|
|
t, \
|
|
|
|
|
"got key %s but with wrong value: want=%s, have=%s", \
|
|
|
|
|
key, \
|
|
|
|
|
value_want, \
|
|
|
|
|
value_have \
|
|
|
|
|
); \
|
|
|
|
|
} \
|
|
|
|
|
} \
|
|
|
|
|
|
|
|
|
|
TEST(str2str_iterating, t) {
|
|
|
|
|
struct apfl_hashmap map = init_str2str(t);
|
|
|
|
|
|
|
|
|
|
check_set_str2str(t, &map, "foo", "abc");
|
|
|
|
|
check_set_str2str(t, &map, "bar", "def");
|
|
|
|
|
check_set_str2str(t, &map, "baz", "ghi");
|
|
|
|
|
check_set_str2str(t, &map, "", "");
|
|
|
|
|
|
|
|
|
|
bool seen_foo = false;
|
|
|
|
|
bool seen_bar = false;
|
|
|
|
|
bool seen_baz = false;
|
|
|
|
|
bool seen_blank = false;
|
|
|
|
|
|
|
|
|
|
for (
|
|
|
|
|
struct apfl_hashmap_cursor it = apfl_hashmap_get_cursor(&map);
|
|
|
|
|
!apfl_hashmap_cursor_is_end(it);
|
|
|
|
|
apfl_hashmap_cursor_next(&it)
|
|
|
|
|
) {
|
|
|
|
|
char *k;
|
|
|
|
|
char *v;
|
|
|
|
|
|
|
|
|
|
apfl_hashmap_cursor_get_key(it, &k);
|
|
|
|
|
apfl_hashmap_cursor_get_value(it, &v);
|
|
|
|
|
|
|
|
|
|
if (strcmp(k, "foo") == 0) {
|
|
|
|
|
ITERATING_SEEN_CHECK(t, "foo", seen_foo, "abc", v)
|
|
|
|
|
} else if (strcmp(k, "bar") == 0) {
|
|
|
|
|
ITERATING_SEEN_CHECK(t, "bar", seen_bar, "def", v)
|
|
|
|
|
} else if (strcmp(k, "baz") == 0) {
|
|
|
|
|
ITERATING_SEEN_CHECK(t, "baz", seen_baz, "ghi", v)
|
|
|
|
|
} else if (strcmp(k, "") == 0) {
|
|
|
|
|
ITERATING_SEEN_CHECK(t, "", seen_blank, "", v)
|
|
|
|
|
} else {
|
|
|
|
|
test_failf(t, "Seen unexpected key %s with value %s", k, v);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free(k);
|
|
|
|
|
free(v);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!seen_foo) {
|
|
|
|
|
test_failf(t, "Did not see key foo");
|
|
|
|
|
}
|
|
|
|
|
if (!seen_bar) {
|
|
|
|
|
test_failf(t, "Did not see key bar");
|
|
|
|
|
}
|
|
|
|
|
if (!seen_baz) {
|
|
|
|
|
test_failf(t, "Did not see key baz");
|
|
|
|
|
}
|
|
|
|
|
if (!seen_blank) {
|
|
|
|
|
test_failf(t, "Did not see key \"\"");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
apfl_hashmap_deinit(&map);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(str2str_moving, t) {
|
|
|
|
|
struct apfl_hashmap orig = init_str2str(t);
|
|
|
|
|
|
|
|
|
|
check_set_str2str(t, &orig, "foo", "abc");
|
|
|
|
|
check_set_str2str(t, &orig, "bar", "def");
|
|
|
|
|
check_set_str2str(t, &orig, "baz", "ghi");
|
|
|
|
|
check_set_str2str(t, &orig, "quux", "jkl");
|
|
|
|
|
|
|
|
|
|
struct apfl_hashmap new = apfl_hashmap_move(&orig);
|
|
|
|
|
|
|
|
|
|
assert_len(t, new, 4, "after moving");
|
|
|
|
|
check_get_str2str(t, &new, "foo", "abc");
|
|
|
|
|
check_get_str2str(t, &new, "bar", "def");
|
|
|
|
|
check_get_str2str(t, &new, "baz", "ghi");
|
|
|
|
|
check_get_str2str(t, &new, "quux", "jkl");
|
|
|
|
|
|
|
|
|
|
apfl_hashmap_deinit(&new);
|
|
|
|
|
apfl_hashmap_deinit(&orig); // not neccessary, but should still work without crashing
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(str2str_copying, t) {
|
|
|
|
|
struct apfl_hashmap orig = init_str2str(t);
|
|
|
|
|
|
|
|
|
|
check_set_str2str(t, &orig, "foo", "abc");
|
|
|
|
|
check_set_str2str(t, &orig, "bar", "def");
|
|
|
|
|
check_set_str2str(t, &orig, "baz", "ghi");
|
|
|
|
|
check_set_str2str(t, &orig, "quux", "jkl");
|
|
|
|
|
|
|
|
|
|
struct apfl_hashmap copy;
|
|
|
|
|
if (!apfl_hashmap_copy(©, orig)) {
|
|
|
|
|
test_fatalf(t, "Copying failed");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert_len(t, orig, 4, "orig after moving");
|
|
|
|
|
check_get_str2str(t, &orig, "foo", "abc");
|
|
|
|
|
check_get_str2str(t, &orig, "bar", "def");
|
|
|
|
|
check_get_str2str(t, &orig, "baz", "ghi");
|
|
|
|
|
check_get_str2str(t, &orig, "quux", "jkl");
|
|
|
|
|
|
|
|
|
|
assert_len(t, copy, 4, "copy after moving");
|
|
|
|
|
check_get_str2str(t, ©, "foo", "abc");
|
|
|
|
|
check_get_str2str(t, ©, "bar", "def");
|
|
|
|
|
check_get_str2str(t, ©, "baz", "ghi");
|
|
|
|
|
check_get_str2str(t, ©, "quux", "jkl");
|
|
|
|
|
|
|
|
|
|
// Setting something in orig should not influence the copy
|
|
|
|
|
check_set_str2str(t, &orig, "X", "xxx");
|
|
|
|
|
check_not_exists_str2str(t, ©, "X");
|
|
|
|
|
|
|
|
|
|
// And the other way around too
|
|
|
|
|
check_set_str2str(t, ©, "Y", "yyy");
|
|
|
|
|
check_not_exists_str2str(t, &orig, "Y");
|
|
|
|
|
|
|
|
|
|
// Overwriting something in orig should not influence the copy
|
|
|
|
|
check_set_str2str(t, &orig, "foo", "newfoo");
|
|
|
|
|
check_get_str2str(t, ©, "foo", "abc");
|
|
|
|
|
|
|
|
|
|
// And the other way around too
|
|
|
|
|
check_set_str2str(t, ©, "bar", "newbar");
|
|
|
|
|
check_get_str2str(t, &orig, "bar", "def");
|
|
|
|
|
|
|
|
|
|
const char *k;
|
|
|
|
|
// Deleting something in orig should not influence the copy
|
|
|
|
|
k = "baz";
|
|
|
|
|
apfl_hashmap_delete(&orig, &k);
|
|
|
|
|
check_get_str2str(t, ©, k, "ghi");
|
|
|
|
|
|
|
|
|
|
// And the other way around too
|
|
|
|
|
k = "quux";
|
|
|
|
|
apfl_hashmap_delete(©, &k);
|
|
|
|
|
check_get_str2str(t, &orig, k, "jkl");
|
|
|
|
|
|
|
|
|
|
apfl_hashmap_deinit(©);
|
|
|
|
|
apfl_hashmap_deinit(&orig);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TESTS_BEGIN
|
|
|
|
|
ADDTEST(int2int_set_get_delete),
|
|
|
|
|
ADDTEST(int2int_set_overwrite),
|
|
|
|
|
ADDTEST(int2int_set_many),
|
|
|
|
|
ADDTEST(int2int_iterating),
|
|
|
|
|
ADDTEST(int2int_moving),
|
|
|
|
|
ADDTEST(int2int_copying),
|
|
|
|
|
|
|
|
|
|
ADDTEST(str2str_set_get_delete),
|
|
|
|
|
ADDTEST(str2str_set_overwrite),
|
|
|
|
|
ADDTEST(str2str_set_many),
|
|
|
|
|
ADDTEST(str2str_iterating),
|
|
|
|
|
ADDTEST(str2str_moving),
|
|
|
|
|
ADDTEST(str2str_copying),
|
|
|
|
|
TESTS_END
|