Skip to content

Commit

Permalink
utils: add map iteration iterator
Browse files Browse the repository at this point in the history
  • Loading branch information
jmayclin committed Jan 25, 2024
1 parent 8ee7a3c commit 968e43d
Show file tree
Hide file tree
Showing 4 changed files with 325 additions and 106 deletions.
328 changes: 223 additions & 105 deletions tests/unit/s2n_map_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,159 +19,277 @@

#include "api/s2n.h"
#include "s2n_test.h"
#include "utils/s2n_map_internal.h"

DEFINE_POINTER_CLEANUP_FUNC(struct s2n_map_iterator *, s2n_map_iterator_free);

int main(int argc, char **argv)
{
char keystr[sizeof("ffff")];
char valstr[sizeof("16384")];
struct s2n_map *empty, *map;
struct s2n_blob key = { 0 };
struct s2n_blob val = { 0 };
bool key_found;
/* s2n_map test */
{
char keystr[sizeof("ffff")];
char valstr[sizeof("16384")];
uint32_t size;
struct s2n_map *empty, *map;
struct s2n_blob key = { 0 };
struct s2n_blob val = { 0 };
bool key_found;

BEGIN_TEST();
EXPECT_SUCCESS(s2n_disable_tls13_in_test());

EXPECT_NOT_NULL(empty = s2n_map_new());
EXPECT_OK(s2n_map_size(empty, &size));
EXPECT_EQUAL(size, 0);

/* Try a lookup on an empty map. Expect an error because the map is still mutable. */
EXPECT_SUCCESS(snprintf(keystr, sizeof(keystr), "%04x", 1234));
key.data = (void *) keystr;
key.size = strlen(keystr) + 1;
EXPECT_ERROR(s2n_map_lookup(empty, &key, &val, &key_found));

BEGIN_TEST();
EXPECT_SUCCESS(s2n_disable_tls13_in_test());
EXPECT_SUCCESS(snprintf(valstr, sizeof(valstr), "%05d", 1234));
val.data = (void *) valstr;
val.size = strlen(valstr) + 1;

EXPECT_NOT_NULL(empty = s2n_map_new());
/* Try to add/put key with zero-size data. Expect failures */
key.size = 0;
EXPECT_ERROR(s2n_map_add(empty, &key, &val));
EXPECT_ERROR(s2n_map_put(empty, &key, &val));
key.size = strlen(keystr) + 1;

/* Try a lookup on an empty map. Expect an error because the map is still mutable. */
EXPECT_SUCCESS(snprintf(keystr, sizeof(keystr), "%04x", 1234));
key.data = (void *) keystr;
key.size = strlen(keystr) + 1;
EXPECT_ERROR(s2n_map_lookup(empty, &key, &val, &key_found));
/* Make the empty map complete */
EXPECT_OK(s2n_map_complete(empty));

EXPECT_SUCCESS(snprintf(valstr, sizeof(valstr), "%05d", 1234));
val.data = (void *) valstr;
val.size = strlen(valstr) + 1;
/* Lookup and expect no result */
EXPECT_OK(s2n_map_lookup(empty, &key, &val, &key_found));
EXPECT_EQUAL(key_found, false);

/* Try to add/put key with zero-size data. Expect failures */
key.size = 0;
EXPECT_ERROR(s2n_map_add(empty, &key, &val));
EXPECT_ERROR(s2n_map_put(empty, &key, &val));
key.size = strlen(keystr) + 1;
/* Done with the empty map */
EXPECT_OK(s2n_map_free(empty));

/* Make the empty map complete */
EXPECT_OK(s2n_map_complete(empty));
/* Expect failure since initial map size is zero */
EXPECT_NULL(map = s2n_map_new_with_initial_capacity(0));

/* Lookup and expect no result */
EXPECT_OK(s2n_map_lookup(empty, &key, &val, &key_found));
EXPECT_EQUAL(key_found, false);
/* Create map with the smallest initial size */
EXPECT_NOT_NULL(map = s2n_map_new_with_initial_capacity(1));

/* Done with the empty map */
EXPECT_OK(s2n_map_free(empty));
/* Insert 8k key value pairs of the form hex(i) -> dec(i) */
for (int i = 0; i < 8192; i++) {
EXPECT_SUCCESS(snprintf(keystr, sizeof(keystr), "%04x", i));
EXPECT_SUCCESS(snprintf(valstr, sizeof(valstr), "%05d", i));

/* Expect failure since initial map size is zero */
EXPECT_NULL(map = s2n_map_new_with_initial_capacity(0));
key.data = (void *) keystr;
key.size = strlen(keystr) + 1;
val.data = (void *) valstr;
val.size = strlen(valstr) + 1;

/* Create map with the smallest initial size */
EXPECT_NOT_NULL(map = s2n_map_new_with_initial_capacity(1));
EXPECT_OK(s2n_map_add(map, &key, &val));
}
EXPECT_OK(s2n_map_size(map, &size));
EXPECT_EQUAL(size, 8192);

/* Insert 8k key value pairs of the form hex(i) -> dec(i) */
for (int i = 0; i < 8192; i++) {
EXPECT_SUCCESS(snprintf(keystr, sizeof(keystr), "%04x", i));
EXPECT_SUCCESS(snprintf(valstr, sizeof(valstr), "%05d", i));
/* Try adding some duplicates */
for (int i = 0; i < 10; i++) {
EXPECT_SUCCESS(snprintf(keystr, sizeof(keystr), "%04x", i));
EXPECT_SUCCESS(snprintf(valstr, sizeof(valstr), "%05d", i));

key.data = (void *) keystr;
key.size = strlen(keystr) + 1;
val.data = (void *) valstr;
val.size = strlen(valstr) + 1;
key.data = (void *) keystr;
key.size = strlen(keystr) + 1;
val.data = (void *) valstr;
val.size = strlen(valstr) + 1;

EXPECT_OK(s2n_map_add(map, &key, &val));
}
EXPECT_ERROR(s2n_map_add(map, &key, &val));
}
EXPECT_OK(s2n_map_size(map, &size));
EXPECT_EQUAL(size, 8192);

/* Try replacing some entries */
for (int i = 0; i < 10; i++) {
EXPECT_SUCCESS(snprintf(keystr, sizeof(keystr), "%04x", i));
EXPECT_SUCCESS(snprintf(valstr, sizeof(valstr), "%05d", i + 1));

/* Try adding some duplicates */
for (int i = 0; i < 10; i++) {
EXPECT_SUCCESS(snprintf(keystr, sizeof(keystr), "%04x", i));
EXPECT_SUCCESS(snprintf(valstr, sizeof(valstr), "%05d", i));
key.data = (void *) keystr;
key.size = strlen(keystr) + 1;
val.data = (void *) valstr;
val.size = strlen(valstr) + 1;

EXPECT_OK(s2n_map_put(map, &key, &val));
}

/* Try a lookup before the map is complete: should fail */
EXPECT_SUCCESS(snprintf(keystr, sizeof(keystr), "%04x", 1));
EXPECT_ERROR(s2n_map_lookup(map, &key, &val, &key_found));

/* Make the map complete */
EXPECT_OK(s2n_map_complete(map));

/* Make sure that add-after-complete fails */
EXPECT_SUCCESS(snprintf(keystr, sizeof(keystr), "%04x", 8193));
EXPECT_SUCCESS(snprintf(valstr, sizeof(valstr), "%05d", 8193));

key.data = (void *) keystr;
key.size = strlen(keystr) + 1;
val.data = (void *) valstr;
val.size = strlen(valstr) + 1;

EXPECT_ERROR(s2n_map_add(map, &key, &val));
}

/* Try replacing some entries */
for (int i = 0; i < 10; i++) {
EXPECT_SUCCESS(snprintf(keystr, sizeof(keystr), "%04x", i));
EXPECT_SUCCESS(snprintf(valstr, sizeof(valstr), "%05d", i + 1));
/* Check for equivalence */
for (int i = 0; i < 8192; i++) {
if (i >= 10) {
EXPECT_SUCCESS(snprintf(keystr, sizeof(keystr), "%04x", i));
EXPECT_SUCCESS(snprintf(valstr, sizeof(valstr), "%05d", i));
} else {
/* The first 10 entries were overwritten with i+1 */
EXPECT_SUCCESS(snprintf(keystr, sizeof(keystr), "%04x", i));
EXPECT_SUCCESS(snprintf(valstr, sizeof(valstr), "%05d", i + 1));
}

key.data = (void *) keystr;
key.size = strlen(keystr) + 1;

EXPECT_OK(s2n_map_lookup(map, &key, &val, &key_found));
EXPECT_EQUAL(key_found, true);

EXPECT_SUCCESS(memcmp(val.data, valstr, strlen(valstr) + 1));
}

/* Check for a key that shouldn't be there */
EXPECT_SUCCESS(snprintf(keystr, sizeof(keystr), "%04x", 8193));
key.data = (void *) keystr;
key.size = strlen(keystr) + 1;
EXPECT_OK(s2n_map_lookup(map, &key, &val, &key_found));
EXPECT_EQUAL(key_found, false);

/* Make the map mutable */
EXPECT_OK(s2n_map_unlock(map));
/* Make sure that add-after-unlock succeeds */
EXPECT_SUCCESS(snprintf(keystr, sizeof(keystr), "%04x", 8193));
EXPECT_SUCCESS(snprintf(valstr, sizeof(valstr), "%05d", 8193));

key.data = (void *) keystr;
key.size = strlen(keystr) + 1;
val.data = (void *) valstr;
val.size = strlen(valstr) + 1;

EXPECT_OK(s2n_map_put(map, &key, &val));
}
EXPECT_OK(s2n_map_add(map, &key, &val));

/* Complete the map again */
EXPECT_OK(s2n_map_complete(map));

/* Check the element added after map unlock */
EXPECT_OK(s2n_map_lookup(map, &key, &val, &key_found));
EXPECT_EQUAL(key_found, true);
EXPECT_SUCCESS(memcmp(val.data, valstr, strlen(valstr) + 1));

EXPECT_OK(s2n_map_free(map));
};

/* s2n_map_iterator test */
{
struct s2n_map *map = s2n_map_new();
EXPECT_NOT_NULL(map);
/* fail to initialize an iterator on a mutable map */
{
DEFER_CLEANUP(struct s2n_map_iterator *iter = NULL, s2n_map_iterator_free_pointer);
EXPECT_ERROR(s2n_map_iterator_new(map, &iter));
};

EXPECT_OK(s2n_map_complete(map));

/* has next is false on an empty map, and next returns an error */
{
DEFER_CLEANUP(struct s2n_map_iterator *iter = NULL, s2n_map_iterator_free_pointer);
EXPECT_OK(s2n_map_iterator_new(map, &iter));

bool has_next = false;
EXPECT_OK(s2n_map_iterator_has_next(iter, &has_next));
EXPECT_FALSE(has_next);

struct s2n_blob value = { 0 };
EXPECT_ERROR(s2n_map_iterator_next(iter, &value));
};

EXPECT_OK(s2n_map_unlock(map));
for (uint8_t i = 0; i < 10; i++) {
struct s2n_blob key = { .size = 1, .data = &i };
struct s2n_blob val = { .size = 1, .data = &i };
EXPECT_OK(s2n_map_put(map, &key, &val));
}
EXPECT_OK(s2n_map_complete(map));

/* Try a lookup before the map is complete: should fail */
EXPECT_SUCCESS(snprintf(keystr, sizeof(keystr), "%04x", 1));
EXPECT_ERROR(s2n_map_lookup(map, &key, &val, &key_found));
/* iterator goes over all elements */
{
bool seen[10] = { 0 };

/* Make the map complete */
EXPECT_OK(s2n_map_complete(map));
DEFER_CLEANUP(struct s2n_map_iterator *iter = NULL, s2n_map_iterator_free_pointer);
EXPECT_OK(s2n_map_iterator_new(map, &iter));

/* Make sure that add-after-complete fails */
EXPECT_SUCCESS(snprintf(keystr, sizeof(keystr), "%04x", 8193));
EXPECT_SUCCESS(snprintf(valstr, sizeof(valstr), "%05d", 8193));
bool has_next = false;
struct s2n_blob value = { 0 };
for (size_t i = 0; i < 10; i++) {
EXPECT_OK(s2n_map_iterator_has_next(iter, &has_next));
EXPECT_TRUE(has_next);

key.data = (void *) keystr;
key.size = strlen(keystr) + 1;
val.data = (void *) valstr;
val.size = strlen(valstr) + 1;
EXPECT_OK(s2n_map_iterator_next(iter, &value));
seen[*value.data] = true;
}

EXPECT_ERROR(s2n_map_add(map, &key, &val));
/* all elements have been iterated over */
EXPECT_OK(s2n_map_iterator_has_next(iter, &has_next));
EXPECT_FALSE(has_next);

/* Check for equivalence */
for (int i = 0; i < 8192; i++) {
if (i >= 10) {
EXPECT_SUCCESS(snprintf(keystr, sizeof(keystr), "%04x", i));
EXPECT_SUCCESS(snprintf(valstr, sizeof(valstr), "%05d", i));
} else {
/* The first 10 entries were overwritten with i+1 */
EXPECT_SUCCESS(snprintf(keystr, sizeof(keystr), "%04x", i));
EXPECT_SUCCESS(snprintf(valstr, sizeof(valstr), "%05d", i + 1));
EXPECT_ERROR(s2n_map_iterator_next(iter, &value));

/* all elements were seen */
for (size_t i = 0; i < 10; i++) {
EXPECT_TRUE(seen[i]);
}
}

key.data = (void *) keystr;
key.size = strlen(keystr) + 1;
EXPECT_OK(s2n_map_free(map));

EXPECT_OK(s2n_map_lookup(map, &key, &val, &key_found));
EXPECT_EQUAL(key_found, true);
/* test first and last slots in table */
{
struct s2n_blob blobs[4] = { 0 };
for (uint8_t i = 0; i < 4; i++) {
s2n_alloc(&blobs[i], 1);
*blobs[i].data = i;
}

EXPECT_SUCCESS(memcmp(val.data, valstr, strlen(valstr) + 1));
}
struct s2n_map *map = s2n_map_new();
EXPECT_NOT_NULL(map);

/* Check for a key that shouldn't be there */
EXPECT_SUCCESS(snprintf(keystr, sizeof(keystr), "%04x", 8193));
key.data = (void *) keystr;
key.size = strlen(keystr) + 1;
EXPECT_OK(s2n_map_lookup(map, &key, &val, &key_found));
EXPECT_EQUAL(key_found, false);
/* set values in map to 0 and 1 */
map->table[0].value = blobs[0];
map->table[0].key = blobs[2];
map->table[map->capacity - 1].value = blobs[1];
map->table[map->capacity - 1].key = blobs[3];

/* Make the map mutable */
EXPECT_OK(s2n_map_unlock(map));
/* Make sure that add-after-unlock succeeds */
EXPECT_SUCCESS(snprintf(keystr, sizeof(keystr), "%04x", 8193));
EXPECT_SUCCESS(snprintf(valstr, sizeof(valstr), "%05d", 8193));
map->size = 2;
EXPECT_OK(s2n_map_complete(map));

key.data = (void *) keystr;
key.size = strlen(keystr) + 1;
val.data = (void *) valstr;
val.size = strlen(valstr) + 1;
DEFER_CLEANUP(struct s2n_map_iterator *iter = NULL, s2n_map_iterator_free_pointer);
EXPECT_OK(s2n_map_iterator_new(map, &iter));
bool seen[2] = { 0 };

EXPECT_OK(s2n_map_add(map, &key, &val));
bool has_next = false;
struct s2n_blob value = { 0 };
for (size_t i = 0; i < 2; i++) {
EXPECT_OK(s2n_map_iterator_has_next(iter, &has_next));
EXPECT_TRUE(has_next);

/* Complete the map again */
EXPECT_OK(s2n_map_complete(map));
EXPECT_OK(s2n_map_iterator_next(iter, &value));
seen[*value.data] = true;
}

/* Check the element added after map unlock */
EXPECT_OK(s2n_map_lookup(map, &key, &val, &key_found));
EXPECT_EQUAL(key_found, true);
EXPECT_SUCCESS(memcmp(val.data, valstr, strlen(valstr) + 1));
/* assert that 0 and 1 were both seen */
EXPECT_TRUE(seen[0] && seen[1]);

EXPECT_OK(s2n_map_free(map));
EXPECT_OK(s2n_map_free(map));
};
};

END_TEST();
}
Loading

0 comments on commit 968e43d

Please sign in to comment.