76 lines
2.5 KiB
C
76 lines
2.5 KiB
C
|
|
/**
|
||
|
|
* @file symtab.c
|
||
|
|
* @brief Tests the fixed-capacity open-addressed symbol table.
|
||
|
|
*/
|
||
|
|
|
||
|
|
#include <stdio.h>
|
||
|
|
|
||
|
|
#include <akbasic/error.h>
|
||
|
|
#include <akbasic/symtab.h>
|
||
|
|
|
||
|
|
#include "testutil.h"
|
||
|
|
|
||
|
|
static akbasic_SymbolTable TABLE;
|
||
|
|
|
||
|
|
int main(void)
|
||
|
|
{
|
||
|
|
void *value = NULL;
|
||
|
|
int64_t ivalue = 0;
|
||
|
|
char key[32];
|
||
|
|
int marker_a = 1;
|
||
|
|
int marker_b = 2;
|
||
|
|
int i = 0;
|
||
|
|
|
||
|
|
TEST_REQUIRE_OK(akbasic_error_register());
|
||
|
|
TEST_REQUIRE_OK(akbasic_symtab_init(&TABLE, 16));
|
||
|
|
|
||
|
|
/* Round-trip both payloads. */
|
||
|
|
TEST_REQUIRE_OK(akbasic_symtab_set(&TABLE, "A#", &marker_a, 42));
|
||
|
|
TEST_REQUIRE_OK(akbasic_symtab_get(&TABLE, "A#", &value, &ivalue));
|
||
|
|
TEST_REQUIRE(value == &marker_a, "wrong pointer payload");
|
||
|
|
TEST_REQUIRE_INT(ivalue, 42);
|
||
|
|
|
||
|
|
/* Replacing an existing key must not grow the table. */
|
||
|
|
TEST_REQUIRE_OK(akbasic_symtab_set(&TABLE, "A#", &marker_b, 43));
|
||
|
|
TEST_REQUIRE_OK(akbasic_symtab_get(&TABLE, "A#", &value, &ivalue));
|
||
|
|
TEST_REQUIRE(value == &marker_b, "replacement did not take");
|
||
|
|
TEST_REQUIRE_INT(ivalue, 43);
|
||
|
|
TEST_REQUIRE_INT(TABLE.count, 1);
|
||
|
|
|
||
|
|
/* A miss is AKERR_KEY, not a crash and not a silent NULL. */
|
||
|
|
TEST_REQUIRE_STATUS(akbasic_symtab_get(&TABLE, "B$", &value, &ivalue), AKERR_KEY);
|
||
|
|
|
||
|
|
/*
|
||
|
|
* Collisions. Sixteen distinct keys in a sixteen-slot table guarantees the
|
||
|
|
* probe sequence is exercised, and the last insert has exactly one slot to
|
||
|
|
* find.
|
||
|
|
*/
|
||
|
|
TEST_REQUIRE_OK(akbasic_symtab_clear(&TABLE));
|
||
|
|
for ( i = 0; i < 16; i++ ) {
|
||
|
|
snprintf(key, sizeof(key), "V%d#", i);
|
||
|
|
TEST_REQUIRE_OK(akbasic_symtab_set(&TABLE, key, NULL, i));
|
||
|
|
}
|
||
|
|
for ( i = 0; i < 16; i++ ) {
|
||
|
|
snprintf(key, sizeof(key), "V%d#", i);
|
||
|
|
TEST_REQUIRE_OK(akbasic_symtab_get(&TABLE, key, NULL, &ivalue));
|
||
|
|
TEST_REQUIRE_INT(ivalue, i);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Seventeenth key into a sixteen-slot table: full, and it says so. */
|
||
|
|
TEST_REQUIRE_STATUS(akbasic_symtab_set(&TABLE, "OVERFLOW#", NULL, 0), AKBASIC_ERR_BOUNDS);
|
||
|
|
|
||
|
|
/* Clear keeps the capacity but drops the contents. */
|
||
|
|
TEST_REQUIRE_OK(akbasic_symtab_clear(&TABLE));
|
||
|
|
TEST_REQUIRE_INT(TABLE.count, 0);
|
||
|
|
TEST_REQUIRE_INT(TABLE.capacity, 16);
|
||
|
|
TEST_REQUIRE_STATUS(akbasic_symtab_get(&TABLE, "V0#", NULL, NULL), AKERR_KEY);
|
||
|
|
|
||
|
|
/* Argument validation. */
|
||
|
|
TEST_REQUIRE_STATUS(akbasic_symtab_init(NULL, 16), AKERR_NULLPOINTER);
|
||
|
|
TEST_REQUIRE_STATUS(akbasic_symtab_init(&TABLE, 0), AKBASIC_ERR_BOUNDS);
|
||
|
|
TEST_REQUIRE_STATUS(akbasic_symtab_init(&TABLE, AKBASIC_SYMTAB_MAX_SLOTS + 1),
|
||
|
|
AKBASIC_ERR_BOUNDS);
|
||
|
|
|
||
|
|
return akbasic_test_failures;
|
||
|
|
}
|