Skip to content

Commit

Permalink
tests: lib: hashmap: tests for hashmap library
Browse files Browse the repository at this point in the history
Add tests for public API of `<zephyr/sys/hash_map.h>`

Signed-off-by: Chris Friedt <cfriedt@meta.com>
  • Loading branch information
cfriedt authored and carlescufi committed Feb 22, 2023
1 parent 0bda7b3 commit e607684
Show file tree
Hide file tree
Showing 14 changed files with 458 additions and 0 deletions.
10 changes: 10 additions & 0 deletions tests/lib/hash_map/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Copyright (c) 2022 Meta
#
# SPDX-License-Identifier: Apache-2.0

cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(hash_map)

FILE(GLOB app_sources src/*.c)
target_sources(app PRIVATE ${app_sources})
24 changes: 24 additions & 0 deletions tests/lib/hash_map/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copyright (c) 2022 Meta
#
# SPDX-License-Identifier: Apache-2.0

config TEST_LIB_HASH_MAP_MAX_ENTRIES
int "Maximum number of Hashmap entries"
default 40
help
When benchmarking the performance of the Hashmap, it helps to be able
to vary the number of entries to insert or remove from the hash table
in a convenient way. This option translates to MANY in the test sources.

CONFIG_TEST_LIB_HASH_MAP_MAX_ENTRIES

Of course, using realloc(), we are limited by the amount of available
heap memory. For test scenarios using the Minimal C library, the heap
size is controlled via

CONFIG_MINIMAL_LIBC_MALLOC_ARENA_SIZE

For native_posix_64, the number of entries can be configured
independently of the arena size since the native libc is used.

source "Kconfig.zephyr"
15 changes: 15 additions & 0 deletions tests/lib/hash_map/prj.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright (c) 2022 Meta
#
# SPDX-License-Identifier: Apache-2.0

CONFIG_ZTEST=y
CONFIG_ZTEST_NEW_API=y

CONFIG_MINIMAL_LIBC_MALLOC_ARENA_SIZE=8192
CONFIG_NEWLIB_LIBC_MIN_REQUIRED_HEAP_SIZE=8192
CONFIG_PICOLIBC_HEAP_SIZE=8192

CONFIG_SYS_HASH_FUNC32=y
CONFIG_SYS_HASH_MAP=y

CONFIG_TEST_LIB_HASH_MAP_MAX_ENTRIES=40
33 changes: 33 additions & 0 deletions tests/lib/hash_map/src/_main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright (c) 2022 Meta
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <stdlib.h>

#include <zephyr/ztest.h>
#include <zephyr/sys/hash_map.h>

#include "_main.h"

SYS_HASHMAP_DEFINE(map);
SYS_HASHMAP_DEFAULT_DEFINE_ADVANCED(custom_load_factor_map, sys_hash32, realloc,
SYS_HASHMAP_CONFIG(SIZE_MAX, CUSTOM_LOAD_FACTOR));

static void *setup(void)
{
printk("CONFIG_TEST_LIB_HASH_MAP_MAX_ENTRIES: %u\n", CONFIG_TEST_LIB_HASH_MAP_MAX_ENTRIES);

return NULL;
}

static void after(void *arg)
{
ARG_UNUSED(arg);

(void)sys_hashmap_clear(&map, NULL, NULL);
(void)sys_hashmap_clear(&custom_load_factor_map, NULL, NULL);
}

ZTEST_SUITE(hash_map, NULL, setup, NULL, after, NULL);
18 changes: 18 additions & 0 deletions tests/lib/hash_map/src/_main.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright (c) 2022 Meta
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef ZEPHYR_TESTS_LIB_HASH_MAP_SRC_MAIN_H_
#define ZEPHYR_TESTS_LIB_HASH_MAP_SRC_MAIN_H_

#include <zephyr/sys/hash_map.h>

#define MANY CONFIG_TEST_LIB_HASH_MAP_MAX_ENTRIES
#define CUSTOM_LOAD_FACTOR 42

extern struct sys_hashmap map;
extern struct sys_hashmap custom_load_factor_map;

#endif
52 changes: 52 additions & 0 deletions tests/lib/hash_map/src/clear.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright (c) 2022 Meta
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/ztest.h>
#include <zephyr/sys/hash_map.h>

#include "_main.h"

ZTEST(hash_map, test_clear_no_callback)
{
const size_t N = 10;

zassert_true(sys_hashmap_is_empty(&map));
for (size_t i = 0; i < N; ++i) {
zassert_equal(1, sys_hashmap_insert(&map, i, i, NULL));
}

zassert_equal(N, sys_hashmap_size(&map));

sys_hashmap_clear(&map, NULL, NULL);
zassert_true(sys_hashmap_is_empty(&map));
}

static void clear_callback(uint64_t key, uint64_t value, void *cookie)
{
bool *cleared = (bool *)cookie;

zassert_true(key < 10);
cleared[key] = true;
}

ZTEST(hash_map, test_clear_callback)
{
bool cleared[10] = {0};

zassert_true(sys_hashmap_is_empty(&map));
for (size_t i = 0; i < ARRAY_SIZE(cleared); ++i) {
zassert_equal(1, sys_hashmap_insert(&map, i, i, NULL));
}

zassert_equal(ARRAY_SIZE(cleared), sys_hashmap_size(&map));

sys_hashmap_clear(&map, clear_callback, cleared);
zassert_true(sys_hashmap_is_empty(&map));

for (size_t i = 0; i < ARRAY_SIZE(cleared); ++i) {
zassert_true(cleared[i], "entry %zu was not cleared", i + 1);
}
}
22 changes: 22 additions & 0 deletions tests/lib/hash_map/src/empty.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright (c) 2022 Meta
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <stdlib.h>

#include <zephyr/ztest.h>
#include <zephyr/sys/hash_map.h>

#include "_main.h"

ZTEST(hash_map, test_empty)
{
/* test size 0 */
zassert_true(sys_hashmap_is_empty(&map));

/* test size 1 */
zassume_equal(1, sys_hashmap_insert(&map, 1, 1, NULL));
zassert_false(sys_hashmap_is_empty(&map));
}
36 changes: 36 additions & 0 deletions tests/lib/hash_map/src/foreach.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2022 Meta
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/ztest.h>
#include <zephyr/sys/hash_map.h>

#include "_main.h"

static void foreach_callback(uint64_t key, uint64_t value, void *cookie)
{
bool *called = (bool *)cookie;

zassert_true(key < 10);
called[key] = true;
}

ZTEST(hash_map, test_foreach)
{
bool called[10] = {0};

zassert_true(sys_hashmap_is_empty(&map));

for (size_t i = 0; i < ARRAY_SIZE(called); ++i) {
zassert_equal(1, sys_hashmap_insert(&map, i, i, NULL));
}

zassert_equal(ARRAY_SIZE(called), sys_hashmap_size(&map));

sys_hashmap_foreach(&map, foreach_callback, called);
for (size_t i = 0; i < ARRAY_SIZE(called); ++i) {
zassert_true(called[i], "entry %zu was not called", i + 1);
}
}
49 changes: 49 additions & 0 deletions tests/lib/hash_map/src/get.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (c) 2022 Meta
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/ztest.h>
#include <zephyr/sys/hash_map.h>

#include "_main.h"

ZTEST(hash_map, test_get_true)
{
int ret;
uint64_t value = 0x42;

zassert_true(sys_hashmap_is_empty(&map));
zassert_equal(1, sys_hashmap_insert(&map, 0, 0, NULL));
zassert_true(sys_hashmap_get(&map, 0, NULL));
zassert_true(sys_hashmap_get(&map, 0, &value));
zassert_equal(0, value);

for (size_t i = 1; i < MANY; ++i) {
ret = sys_hashmap_insert(&map, i, i, NULL);
zassert_equal(1, ret, "failed to insert (%zu, %zu): %d", i, i, ret);
}

for (size_t i = 0; i < MANY; ++i) {
zassert_true(sys_hashmap_get(&map, i, NULL));
}
}

ZTEST(hash_map, test_get_false)
{
int ret;
uint64_t value = 0x42;

zassert_true(sys_hashmap_is_empty(&map));

zassert_false(sys_hashmap_get(&map, 73, &value));
zassert_equal(value, 0x42);

for (size_t i = 0; i < MANY; ++i) {
ret = sys_hashmap_insert(&map, i, i, NULL);
zassert_equal(1, ret, "failed to insert (%zu, %zu): %d", i, i, ret);
}

zassert_false(sys_hashmap_get(&map, 0x4242424242424242ULL, NULL));
}
59 changes: 59 additions & 0 deletions tests/lib/hash_map/src/insert.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright (c) 2022 Meta
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <stdlib.h>

#include <zephyr/ztest.h>
#include <zephyr/sys/hash_map.h>

#include "_main.h"

ZTEST(hash_map, test_insert_no_replacement)
{
zassert_true(sys_hashmap_is_empty(&map));

zassert_equal(1, sys_hashmap_insert(&map, 1, 1, NULL));
zassert_equal(1, sys_hashmap_size(&map));
zassert_true(sys_hashmap_contains_key(&map, 1));

zassert_equal(1, sys_hashmap_insert(&map, 2, 2, NULL));
zassert_equal(2, sys_hashmap_size(&map));
zassert_true(sys_hashmap_contains_key(&map, 2));
}

ZTEST(hash_map, test_insert_replacement)
{
uint64_t old_value;

zassert_true(sys_hashmap_is_empty(&map));

zassert_equal(1, sys_hashmap_insert(&map, 1, 1, NULL));
zassert_equal(1, sys_hashmap_size(&map));
zassert_true(sys_hashmap_contains_key(&map, 1));

old_value = 0x42;
zassert_equal(0, sys_hashmap_insert(&map, 1, 2, &old_value));
zassert_equal(1, old_value);
zassert_equal(1, sys_hashmap_size(&map));
zassert_true(sys_hashmap_contains_key(&map, 1));
}

ZTEST(hash_map, test_insert_many)
{
int ret;

zassert_true(sys_hashmap_is_empty(&map));

for (size_t i = 0; i < MANY; ++i) {
ret = sys_hashmap_insert(&map, i, i, NULL);
zassert_equal(1, ret, "failed to insert (%zu, %zu): %d", i, i, ret);
zassert_equal(i + 1, sys_hashmap_size(&map));
}

for (size_t i = 0; i < MANY; ++i) {
zassert_true(sys_hashmap_contains_key(&map, i));
}
}
57 changes: 57 additions & 0 deletions tests/lib/hash_map/src/load_factor.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright (c) 2022 Meta
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/ztest.h>
#include <zephyr/sys/hash_map.h>

#include "_main.h"

ZTEST(hash_map, test_load_factor_default)
{
int ret;
uint32_t load_factor;

zassert_true(sys_hashmap_is_empty(&map));
zassert_equal(0, sys_hashmap_load_factor(&map));

for (size_t i = 0; i < MANY; ++i) {
ret = sys_hashmap_insert(&map, i, i, NULL);
zassert_equal(1, ret, "failed to insert (%zu, %zu): %d", i, i, ret);
load_factor = sys_hashmap_load_factor(&map);
zassert_true(load_factor > 0 && load_factor <= SYS_HASHMAP_DEFAULT_LOAD_FACTOR);
}

for (size_t i = MANY; i > 0; --i) {
zassert_equal(true, sys_hashmap_remove(&map, i - 1, NULL));
load_factor = sys_hashmap_load_factor(&map);
zassert_true(load_factor <= SYS_HASHMAP_DEFAULT_LOAD_FACTOR);
}
}

ZTEST(hash_map, test_load_factor_custom)
{
int ret;
uint32_t load_factor;
struct sys_hashmap *const map = &custom_load_factor_map;

zassert_equal(map->config->load_factor, CUSTOM_LOAD_FACTOR);

zassert_true(sys_hashmap_is_empty(map));
zassert_equal(0, sys_hashmap_load_factor(map));

for (size_t i = 0; i < MANY; ++i) {
ret = sys_hashmap_insert(map, i, i, NULL);
zassert_equal(1, ret, "failed to insert (%zu, %zu): %d", i, i, ret);
load_factor = sys_hashmap_load_factor(map);
zassert_true(load_factor > 0 && load_factor <= CUSTOM_LOAD_FACTOR);
}

for (size_t i = MANY; i > 0; --i) {
zassert_equal(true, sys_hashmap_remove(map, i - 1, NULL));
load_factor = sys_hashmap_load_factor(map);
zassert_true(load_factor >= 0 && load_factor <= CUSTOM_LOAD_FACTOR);
}
}
Loading

0 comments on commit e607684

Please sign in to comment.