diff --git a/Makefile b/Makefile index 3aa7dfb..74894ce 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ SUBDIRS := libhashset example test BUILD_ALL := $(patsubst %,build\:%,$(SUBDIRS)) CLEAN_ALL := $(patsubst %,clean\:%,$(SUBDIRS)) -.PHONY: all clean $(BUILD_ALL) $(CLEAN_ALL) +.PHONY: all test clean $(BUILD_ALL) $(CLEAN_ALL) all: $(BUILD_ALL) @@ -14,3 +14,6 @@ $(BUILD_ALL): $(CLEAN_ALL): $(MAKE) -C $(patsubst clean:%,%,$@) clean + +test: $(BUILD_ALL) + $(MAKE) -C test test diff --git a/test/Makefile b/test/Makefile index 4f44c6a..3257f4a 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,16 +1,22 @@ -SUBDIRS := hash-set +SUBDIRS := hash-set hash-map BUILD_ALL := $(patsubst %,build\:%,$(SUBDIRS)) CLEAN_ALL := $(patsubst %,clean\:%,$(SUBDIRS)) +TESTS_ALL := $(patsubst %,rtest\:%,$(SUBDIRS)) -.PHONY: all clean $(BUILD_ALL) $(CLEAN_ALL) +.PHONY: all clean test $(BUILD_ALL) $(CLEAN_ALL) $(TESTS_ALL) all: $(BUILD_ALL) clean: $(CLEAN_ALL) +test: $(TESTS_ALL) + $(BUILD_ALL): $(MAKE) -C $(patsubst build:%,%,$@) $(CLEAN_ALL): $(MAKE) -C $(patsubst clean:%,%,$@) clean + +$(TESTS_ALL): + $(MAKE) -C $(patsubst rtest:%,%,$@) test diff --git a/test/hash-map/Makefile b/test/hash-map/Makefile index fb0a08d..abb0f8c 100644 --- a/test/hash-map/Makefile +++ b/test/hash-map/Makefile @@ -10,7 +10,7 @@ ALL_PATH := $(SRC_PATH) $(BIN_PATH) BIN_FILE := $(BIN_PATH)/test-hash-set$(EXE_SUFFIX) SRC_FILE := $(wildcard $(SRC_PATH)/*.c) -.PHONY: all build clean +.PHONY: all build clean test all: clean build @@ -24,3 +24,6 @@ $(ALL_PATH): clean: rm -vf $(BIN_FILE) + +test: build + ./$(BIN_FILE) diff --git a/test/hash-map/src/main.c b/test/hash-map/src/main.c index 8018811..11be2b0 100644 --- a/test/hash-map/src/main.c +++ b/test/hash-map/src/main.c @@ -35,6 +35,8 @@ int main(void) } RUN_TEST_CASE(1); + RUN_TEST_CASE(2); + RUN_TEST_CASE(3); hash_map_destroy64(hash_set); puts("Tests completed successfully."); diff --git a/test/hash-map/src/tests.c b/test/hash-map/src/tests.c index c7e5fc7..6706742 100644 --- a/test/hash-map/src/tests.c +++ b/test/hash-map/src/tests.c @@ -12,7 +12,7 @@ #include #include -#define TEST_COUNT 4 +#define TEST_COUNT 3 /* ========================================================================= */ /* Utilities */ @@ -41,28 +41,35 @@ while(0) int test_function_1(hash_map64_t *const hash_set) { size_t r, j, cursor, capacity, valid, deleted, limit; - uint64_t key, value; - uint8_t spinner = 0U, *test1, *test2; + uint64_t key, value, *test_data; + uint8_t spinner = 0U, *test_key1, *test_key2; random_t random; random_init(&random); - test1 = (uint8_t*) malloc(TEST_SIZE * sizeof(uint8_t)); - if (!test1) + test_key1 = (uint8_t*) malloc(TEST_SIZE * sizeof(uint8_t)); + if (!test_key1) { abort(); /*malloc has failed!*/ } - test2 = (uint8_t*) malloc(TEST_SIZE * sizeof(uint8_t)); - if (!test2) + test_key2 = (uint8_t*) malloc(TEST_SIZE * sizeof(uint8_t)); + if (!test_key2) + { + abort(); /*malloc has failed!*/ + } + + test_data = (uint64_t*) malloc(TEST_SIZE * sizeof(uint64_t)); + if (!test_data) { abort(); /*malloc has failed!*/ } for (r = 0U; r < 64U; ++r) { - memset(test1, 0, TEST_SIZE * sizeof(uint8_t)); - memset(test2, 0, TEST_SIZE * sizeof(uint8_t)); + memset(test_key1, 0, TEST_SIZE * sizeof(uint8_t)); + memset(test_key2, 0, TEST_SIZE * sizeof(uint8_t)); + memset(test_data, 0, TEST_SIZE * sizeof(uint64_t)); for (j = 0U; j < TEST_SIZE / 3U; ++j) { @@ -71,15 +78,167 @@ int test_function_1(hash_map64_t *const hash_set) { rnd = random_next(&random) % TEST_SIZE; } - while (test1[rnd]); - INVERT(test1[rnd]); + while (test_key1[rnd]); + INVERT(test_key1[rnd]); } for (j = 0U; j < TEST_SIZE; ++j) { - if (test1[j]) + if (test_key1[j]) { - const errno_t error = hash_map_insert64(hash_set, j, 0U); + const errno_t error = hash_map_insert64(hash_set, j, test_data[j] = random_next(&random)); + if (error) + { + printf("Insert operation has failed! (error: %d)\n", error); + return EXIT_FAILURE; + } + if (!(++spinner & 0x0F)) + { + PRINT_SET_INFO(1); + } + } + } + + for (j = 0U; j < TEST_SIZE; ++j) + { + const errno_t error = hash_map_contains64(hash_set, j); + if (error != (test_key1[j] ? 0 : ENOENT)) + { + printf("Contains operation has failed! (error: %d)\n", error); + return EXIT_FAILURE; + } + } + + cursor = 0U; + while (!hash_map_iterate64(hash_set, &cursor, &key, &value)) + { + if ((!test_key1[key]) || test_key2[key]) + { + puts("Iteration error has been detected!"); + return EXIT_FAILURE; + } + INVERT(test_key2[key]); + } + + for (j = 0U; j < TEST_SIZE; ++j) + { + if (test_key1[j] != test_key2[j]) + { + puts("Iteration error has been detected!"); + return EXIT_FAILURE; + } + } + + for (j = 0U; j < TEST_SIZE; ++j) + { + if (test_key1[j]) + { + if (!hash_map_get64(hash_set, j, &value)) + { + if (value != test_data[j]) + { + puts("Value mismatch has been detected!"); + return EXIT_FAILURE; + } + } + else + { + puts("Failed to retrieve the value!"); + return EXIT_FAILURE; + } + } + } + + for (j = 0U; j < TEST_SIZE; ++j) + { + if (test_key1[j]) + { + const errno_t error = hash_map_remove64(hash_set, j); + if (error) + { + printf("Remove operation has failed! (error: %d)\n", error); + return EXIT_FAILURE; + } + if (!(++spinner & 0x0F)) + { + PRINT_SET_INFO(1); + } + } + } + + for (j = 0U; j < TEST_SIZE; ++j) + { + const errno_t error = hash_map_contains64(hash_set, j); + if (error != ENOENT) + { + printf("Contains operation has failed! (error: %d)\n", error); + return EXIT_FAILURE; + } + } + + if (hash_map_size64(hash_set) != 0U) + { + puts("Invalid size!"); + return EXIT_FAILURE; + } + } + + free(test_key1); + free(test_key2); + free(test_data); + + PRINT_SET_INFO(1); + puts("---------"); + + return EXIT_SUCCESS; +} + +/* ========================================================================= */ +/* TEST #2 */ +/* ========================================================================= */ + +int test_function_2(hash_map64_t *const hash_set) +{ + size_t r, j, capacity, valid, deleted, limit; + uint64_t value, *test_val; + uint8_t spinner = 0U, *test_key; + + random_t random; + random_init(&random); + + test_key = (uint8_t*) malloc(TEST_SIZE * sizeof(uint8_t)); + if (!test_key) + { + abort(); /*malloc has failed!*/ + } + + test_val = (uint64_t*) malloc(TEST_SIZE * sizeof(uint64_t)); + if (!test_val) + { + abort(); /*malloc has failed!*/ + } + + for (r = 0U; r < 64U; ++r) + { + memset(test_key, 0, TEST_SIZE * sizeof(uint8_t)); + memset(test_val, 0, TEST_SIZE * sizeof(uint64_t)); + + for (j = 0U; j < TEST_SIZE / 3U; ++j) + { + size_t rnd; + do + { + rnd = random_next(&random) % TEST_SIZE; + } + while (test_key[rnd]); + INVERT(test_key[rnd]); + } + + for (j = 0U; j < TEST_SIZE; ++j) + { + if (test_key[j]) + { + const errno_t error = hash_map_insert64(hash_set, j, test_val[j] = random_next(&random)); if (error) { printf("Insert operation has failed! (error: %d)\n", error); @@ -92,34 +251,14 @@ int test_function_1(hash_map64_t *const hash_set) } } - cursor = 0U; - while (!hash_map_iterate64(hash_set, &cursor, &key, &value)) - { - if ((!test1[key]) || test2[key]) - { - puts("Iteration error has been detected!"); - return EXIT_FAILURE; - } - INVERT(test2[key]); - } - for (j = 0U; j < TEST_SIZE; ++j) { - if (test1[j] != test2[j]) + if (test_key[j]) { - puts("Iteration error has been detected!"); - return EXIT_FAILURE; - } - } - - for (j = 0U; j < TEST_SIZE; ++j) - { - if (test1[j]) - { - const errno_t error = hash_map_remove64(hash_set, j); - if (error) + const errno_t error = hash_map_insert64(hash_set, j, test_val[j] = random_next(&random)); + if (error != EEXIST) { - printf("Remove operation has failed! (error: %d)\n", error); + printf("Insert operation has failed! (error: %d)\n", error); return EXIT_FAILURE; } if (!(++spinner & 0x0F)) @@ -129,18 +268,110 @@ int test_function_1(hash_map64_t *const hash_set) } } - if (hash_map_size64(hash_set) != 0U) + for (j = 0U; j < TEST_SIZE; ++j) { - puts("Invalid size!"); + if (test_key[j]) + { + if (!hash_map_get64(hash_set, j, &value)) + { + if (value != test_val[j]) + { + puts("Value mismatch has been detected!"); + return EXIT_FAILURE; + } + } + else + { + puts("Failed to retrieve the value!"); + return EXIT_FAILURE; + } + } + } + + if (hash_map_clear64(hash_set)) + { + puts("Failed to clear the map!"); return EXIT_FAILURE; } } - free(test1); - free(test2); + free(test_key); + free(test_val); PRINT_SET_INFO(2); puts("---------"); return EXIT_SUCCESS; } + +/* ========================================================================= */ +/* TEST #3 */ +/* ========================================================================= */ + +#define VALUE(X) (((X) ^ UINT64_C(0xB7E151628AED2A6A)) * UINT64_C(65599)) + +int test_function_3(hash_map64_t *const hash_set) +{ + size_t r, cursor, capacity, valid, deleted, limit; + uint8_t spinner = 0U; + clock_t last_update = clock(); + uint64_t key, value; + + random_t random; + random_init(&random); + + for (r = 0U; r < 3U; ++r) + { + for (;;) + { + const uint64_t rnd = random_next(&random) & UINT64_C(0x1FFFFFFFFFFFFFF); + const errno_t error = hash_map_insert64(hash_set, rnd, VALUE(rnd)); + if (error) + { + if (error != EEXIST) + { + printf("Insert operation has failed! (error: %d)\n", error); + return EXIT_FAILURE; + } + else + { + PRINT_SET_INFO(3); + printf("Collision detected! [0x%016" PRIX64 "]\n", rnd); + cursor = 0U; + while (!hash_map_iterate64(hash_set, &cursor, &key, &value)) + { + if (value != VALUE(key)) + { + puts("Value mismatch has been detected!"); + return EXIT_FAILURE; + } + } + puts("Value verification successful."); + break; + } + } + if (!(++spinner & 0x7F)) + { + const clock_t clock_now = clock(); + if ((clock_now < last_update) || (clock_now >= last_update + CLOCKS_PER_SEC)) + { + PRINT_SET_INFO(3); + last_update = clock_now; + } + } + } + + PRINT_SET_INFO(3); + + if (hash_map_clear64(hash_set)) + { + puts("Clear operation has failed!"); + return EXIT_FAILURE; + } + } + + PRINT_SET_INFO(3); + puts("---------"); + + return EXIT_SUCCESS; +} diff --git a/test/hash-map/src/tests.h b/test/hash-map/src/tests.h index 650be00..92a4396 100644 --- a/test/hash-map/src/tests.h +++ b/test/hash-map/src/tests.h @@ -9,5 +9,7 @@ #include int test_function_1(hash_map64_t *const hash_set); +int test_function_2(hash_map64_t *const hash_set); +int test_function_3(hash_map64_t *const hash_set); #endif /*_TEST_TESTS_INCLUDED*/ diff --git a/test/hash-set/Makefile b/test/hash-set/Makefile index fb0a08d..abb0f8c 100644 --- a/test/hash-set/Makefile +++ b/test/hash-set/Makefile @@ -10,7 +10,7 @@ ALL_PATH := $(SRC_PATH) $(BIN_PATH) BIN_FILE := $(BIN_PATH)/test-hash-set$(EXE_SUFFIX) SRC_FILE := $(wildcard $(SRC_PATH)/*.c) -.PHONY: all build clean +.PHONY: all build clean test all: clean build @@ -24,3 +24,6 @@ $(ALL_PATH): clean: rm -vf $(BIN_FILE) + +test: build + ./$(BIN_FILE) diff --git a/test/hash-set/src/tests.c b/test/hash-set/src/tests.c index 0eead94..5bc3d7a 100644 --- a/test/hash-set/src/tests.c +++ b/test/hash-set/src/tests.c @@ -314,7 +314,7 @@ int test_function_3(hash_set64_t *const hash_set) else { PRINT_SET_INFO(3); - printf("Collision detected! [%016" PRIx64 "]\n", rnd); + printf("Collision detected! [0x%016" PRIX64 "]\n", rnd); break; } }