2022-12-01 16:47:11 +01:00

411 lines
9.0 KiB
C

/******************************************************************************/
/* HashSet for C99, by LoRd_MuldeR <MuldeR2@GMX.de> */
/* This work has been released under the CC0 1.0 Universal license! */
/******************************************************************************/
#include "tests.h"
#include <random_in.h>
#include <stdio.h>
#include <inttypes.h>
#include <time.h>
#include <string.h>
#include <errno.h>
#define TEST_COUNT 4
/* ========================================================================= */
/* Utilities */
/* ========================================================================= */
#define UNUSED(X) ((void)X)
#define INVERT(X) do { (X) = (!(X)); } while(0)
#define PRINT_SET_INFO(X) do \
{\
if (!hash_set_info64(hash_set, &capacity, &valid, &deleted, &limit)) \
{ \
fprintf(stdout, "[SET %d/%d] capacity: %010zu, valid: %010zu, deleted: %010zu, limit: %010zu\n", (X), TEST_COUNT, capacity, valid, deleted, limit); \
fflush(stdout); \
} \
} \
while(0)
/* ========================================================================= */
/* TEST #1 */
/* ========================================================================= */
#define MAXIMUM 425984U
static int dump_callback(const size_t index, const char status, const uint64_t item)
{
#ifndef NDEBUG
printf("%016zX: %c -> %016" PRIX64 "\n", index, status, item);
#else
UNUSED(index); UNUSED(status); UNUSED(item);
#endif
return 1;
}
int test_function_1(hash_set64_t *const hash_set)
{
size_t r, capacity, valid, deleted, limit;
uint64_t i;
uint8_t spinner = 0U;
for (r = 0U; r < 5U; ++r)
{
for (i = 0; i < MAXIMUM; ++i)
{
if ((i != 3167U) && (i != 9887U) && (i != 185903U) && (i != 387083U))
{
const errno_t error = hash_set_insert64(hash_set, i);
if (error)
{
printf("Insert operation has failed! (error: %d)\n", error);
return EXIT_FAILURE;
}
}
if (!(++spinner & 0x0F))
{
PRINT_SET_INFO(1);
}
}
if (hash_set_size64(hash_set) != MAXIMUM - 4U)
{
puts("Invalid size!");
return EXIT_FAILURE;
}
for (i = 0; i < MAXIMUM; ++i)
{
if ((i != 3167U) && (i != 9887U) && (i != 387083U))
{
const errno_t error = hash_set_insert64(hash_set, i);
if (error != ((i != 185903U) ? EEXIST : 0))
{
printf("Insert operation has failed! (error: %d)\n", error);
return EXIT_FAILURE;
}
}
}
if (hash_set_size64(hash_set) != MAXIMUM - 3U)
{
puts("Invalid size!");
return EXIT_FAILURE;
}
for (i = 0; i < MAXIMUM; ++i)
{
const errno_t error = hash_set_contains64(hash_set, i);
if (error != ((i != 3167U) && (i != 9887U) && (i != 387083U)) ? 0 : ENOENT)
{
printf("Contains operation has failed! (error: %d)\n", error);
return EXIT_FAILURE;
}
}
if (hash_set_dump64(hash_set, dump_callback))
{
puts("Dump operation has failed!");
return EXIT_FAILURE;
}
for (i = 0; i < MAXIMUM; ++i)
{
if ((i != 3167U) && (i != 9887U) && (i != 216263U) && (i != 387083U))
{
const errno_t error = hash_set_remove64(hash_set, i);
if (error)
{
printf("Remove operation has failed! (error: %d)\n", error);
return EXIT_FAILURE;
}
}
if (!(++spinner & 0x0F))
{
PRINT_SET_INFO(1);
}
}
if (hash_set_size64(hash_set) != 1U)
{
puts("Invalid size!");
return EXIT_FAILURE;
}
for (i = 0; i < MAXIMUM; ++i)
{
const errno_t error = hash_set_contains64(hash_set, i);
if (error != ((i != 216263U) ? ENOENT : 0))
{
printf("Contains operation has failed! (error: %d)\n", error);
return EXIT_FAILURE;
}
}
if (!hash_set_remove64(hash_set, 9887U))
{
puts("Final remove operation has failed!");
return EXIT_FAILURE;
}
if (hash_set_remove64(hash_set, 216263U))
{
puts("Final remove operation has failed!");
return EXIT_FAILURE;
}
if (hash_set_size64(hash_set) != 0U)
{
puts("Invalid size!");
return EXIT_FAILURE;
}
PRINT_SET_INFO(1);
puts("---------");
}
return EXIT_SUCCESS;
}
/* ========================================================================= */
/* TEST #2 */
/* ========================================================================= */
#define TEST_SIZE 499979U
int test_function_2(hash_set64_t *const hash_set)
{
size_t r, j, cursor, capacity, valid, deleted, limit;
uint64_t value;
uint8_t spinner = 0U, *test1, *test2;
random_t random;
random_init(&random);
test1 = (uint8_t*) malloc(TEST_SIZE * sizeof(uint8_t));
if (!test1)
{
abort(); /*malloc has failed!*/
}
test2 = (uint8_t*) malloc(TEST_SIZE * sizeof(uint8_t));
if (!test2)
{
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));
for (j = 0U; j < TEST_SIZE / 3U; ++j)
{
size_t rnd;
do
{
rnd = random_next(&random) % TEST_SIZE;
}
while (test1[rnd]);
INVERT(test1[rnd]);
}
for (j = 0U; j < TEST_SIZE; ++j)
{
if (test1[j])
{
const errno_t error = hash_set_insert64(hash_set, j);
if (error)
{
printf("Insert operation has failed! (error: %d)\n", error);
return EXIT_FAILURE;
}
if (!(++spinner & 0x0F))
{
PRINT_SET_INFO(2);
}
}
}
cursor = 0U;
while (!hash_set_iterate64(hash_set, &cursor, &value))
{
if ((!test1[value]) || test2[value])
{
puts("Iteration error has been detected!");
return EXIT_FAILURE;
}
INVERT(test2[value]);
}
for (j = 0U; j < TEST_SIZE; ++j)
{
if (test1[j] != test2[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_set_remove64(hash_set, j);
if (error)
{
printf("Remove operation has failed! (error: %d)\n", error);
return EXIT_FAILURE;
}
if (!(++spinner & 0x0F))
{
PRINT_SET_INFO(2);
}
}
}
if (hash_set_size64(hash_set) != 0U)
{
puts("Invalid size!");
return EXIT_FAILURE;
}
}
free(test1);
free(test2);
PRINT_SET_INFO(2);
puts("---------");
return EXIT_SUCCESS;
}
/* ========================================================================= */
/* TEST #3 */
/* ========================================================================= */
int test_function_3(hash_set64_t *const hash_set)
{
size_t r, capacity, valid, deleted, limit;
uint8_t spinner = 0U;
clock_t last_update = clock();
random_t random;
random_init(&random);
for (r = 0U; r < 3U; ++r)
{
for (;;)
{
const uint64_t rnd = random_next(&random) & UINT64_C(0x3FFFFFFFFFFFFFF);
const errno_t error = hash_set_insert64(hash_set, 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);
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_set_clear64(hash_set))
{
puts("Clear operation has failed!");
return EXIT_FAILURE;
}
}
PRINT_SET_INFO(3);
puts("---------");
return EXIT_SUCCESS;
}
/* ========================================================================= */
/* TEST #4 */
/* ========================================================================= */
#define LIMIT (((uint64_t)UINT32_MAX) >> 2)
int test_function_4(hash_set64_t *const hash_set)
{
size_t capacity, valid, deleted, limit;
uint64_t value;
uint8_t spinner = 0U;
clock_t last_update = clock();
for (value = 0U; value < LIMIT; ++value)
{
const errno_t error = hash_set_insert64(hash_set, value);
if (error)
{
PRINT_SET_INFO(4);
printf("Insert operation has failed! (error: %d)\n", error);
return EXIT_FAILURE;
}
if (!(++spinner & 0x7F))
{
const clock_t clock_now = clock();
if ((clock_now < last_update) || (clock_now >= last_update + CLOCKS_PER_SEC))
{
PRINT_SET_INFO(4);
last_update = clock_now;
}
}
}
for (value = 0U; value < LIMIT; ++value)
{
const errno_t error = hash_set_remove64(hash_set, value);
if (error)
{
PRINT_SET_INFO(4);
printf("Remove operation has failed! (error: %d)\n", error);
return EXIT_FAILURE;
}
if (!(++spinner & 0x7F))
{
const clock_t clock_now = clock();
if ((clock_now < last_update) || (clock_now >= last_update + CLOCKS_PER_SEC))
{
PRINT_SET_INFO(4);
last_update = clock_now;
}
}
}
if (hash_set_size64(hash_set) != 0U)
{
puts("Invalid size!");
return EXIT_FAILURE;
}
PRINT_SET_INFO(4);
puts("---------");
return EXIT_SUCCESS;
}