WIP: Retreived the unit tests (formerly test cases)

Some of these still work, others have just been dummied out for now.

Also added tests for console colors tool, and tweaked it to work
properly.
This commit is contained in:
2026-04-05 18:42:56 +10:00
parent 57fe9bb00d
commit fbb7e1bc54
20 changed files with 1366 additions and 40 deletions

View File

@@ -23,6 +23,10 @@ source:
repl: source repl: source
$(MAKE) -C repl -k $(MAKE) -C repl -k
.PHONY: tests
tests:
$(MAKE) -C tests -k
#util targets #util targets
$(TOY_OUTDIR): $(TOY_OUTDIR):
mkdir $(TOY_OUTDIR) mkdir $(TOY_OUTDIR)
@@ -34,38 +38,41 @@ $(TOY_OBJDIR):
.PHONY: clean .PHONY: clean
clean: clean:
ifeq ($(shell uname),Linux) ifeq ($(shell uname),Linux)
rm -r out
find . -type f -name '*.o' -delete find . -type f -name '*.o' -delete
find . -type f -name '*.a' -delete find . -type f -name '*.a' -delete
find . -type f -name '*.out' -delete
find . -type f -name '*.exe' -delete find . -type f -name '*.exe' -delete
find . -type f -name '*.dll' -delete find . -type f -name '*.dll' -delete
find . -type f -name '*.lib' -delete find . -type f -name '*.lib' -delete
find . -type f -name '*.so' -delete find . -type f -name '*.so' -delete
find . -type f -name '*.dylib' -delete find . -type f -name '*.dylib' -delete
find . -type d -name 'out' -delete
find . -type d -name 'obj' -delete find . -type d -name 'obj' -delete
else ifeq ($(shell uname),NetBSD) else ifeq ($(shell uname),NetBSD)
rm -r out
find . -type f -name '*.o' -delete find . -type f -name '*.o' -delete
find . -type f -name '*.a' -delete find . -type f -name '*.a' -delete
find . -type f -name '*.out' -delete
find . -type f -name '*.exe' -delete find . -type f -name '*.exe' -delete
find . -type f -name '*.dll' -delete find . -type f -name '*.dll' -delete
find . -type f -name '*.lib' -delete find . -type f -name '*.lib' -delete
find . -type f -name '*.so' -delete find . -type f -name '*.so' -delete
find . -type f -name '*.dylib' -delete find . -type f -name '*.dylib' -delete
find . -type d -name 'out' -delete
find . -type d -name 'obj' -delete find . -type d -name 'obj' -delete
else ifeq ($(OS),Windows_NT) else ifeq ($(OS),Windows_NT)
$(RM) *.o *.a *.exe *.dll *.lib *.so *.dylib $(RM) *.o *.a *.exe *.dll *.lib *.so *.dylib
$(RM) out $(RM) out
$(RM) obj $(RM) obj
else ifeq ($(shell uname),Darwin) else ifeq ($(shell uname),Darwin)
rm -r out
find . -type f -name '*.o' -delete find . -type f -name '*.o' -delete
find . -type f -name '*.a' -delete find . -type f -name '*.a' -delete
find . -type f -name '*.out' -delete
find . -type f -name '*.exe' -delete find . -type f -name '*.exe' -delete
find . -type f -name '*.dll' -delete find . -type f -name '*.dll' -delete
find . -type f -name '*.lib' -delete find . -type f -name '*.lib' -delete
find . -type f -name '*.so' -delete find . -type f -name '*.so' -delete
find . -type f -name '*.dylib' -delete find . -type f -name '*.dylib' -delete
find . -type d -name 'out' -delete
find . -type d -name 'obj' -delete find . -type d -name 'obj' -delete
else else
@echo "Deletion failed - what platform is this?" @echo "Deletion failed - what platform is this?"

View File

@@ -21,7 +21,7 @@ REPL_TARGETNAME=repl
ifeq ($(OS),Windows_NT) ifeq ($(OS),Windows_NT)
REPL_TARGETEXT=.exe REPL_TARGETEXT=.exe
else else
REPL_TARGETEXT= REPL_TARGETEXT=.out
endif endif
#linker fix #linker fix

View File

@@ -8,41 +8,42 @@ a printf()'s first argument, like so:
printf(TOY_CC_NOTICE "Hello world" TOY_CC_RESET); printf(TOY_CC_NOTICE "Hello world" TOY_CC_RESET);
NOTE: you need both font AND background for these to work reference: https://stackoverflow.com/questions/4842424/list-of-ansi-color-escape-sequences
*/ */
//platform/compiler-specific instructions //platform/compiler-specific instructions
#if defined(TOY_CC_ENABLED) && ( defined(__linux__) || defined(__MINGW32__) || defined(__GNUC__) ) #if defined(__linux__) || defined(__MINGW32__) || defined(__GNUC__)
//fonts color //fonts color
#define TOY_CC_FONT_BLACK "\033[30;" #define TOY_CC_FONT_BLACK "30"
#define TOY_CC_FONT_RED "\033[31;" #define TOY_CC_FONT_RED "31"
#define TOY_CC_FONT_GREEN "\033[32;" #define TOY_CC_FONT_GREEN "32"
#define TOY_CC_FONT_YELLOW "\033[33;" #define TOY_CC_FONT_YELLOW "33"
#define TOY_CC_FONT_BLUE "\033[34;" #define TOY_CC_FONT_BLUE "34"
#define TOY_CC_FONT_PURPLE "\033[35;" #define TOY_CC_FONT_MAGENTA "35"
#define TOY_CC_FONT_DGREEN "\033[6;" #define TOY_CC_FONT_CYAN "36"
#define TOY_CC_FONT_WHITE "\033[7;" #define TOY_CC_FONT_WHITE "37"
#define TOY_CC_FONT_CYAN "\x1b[36m" #define TOY_CC_FONT_DEFAULT "39"
//background color //background color
#define TOY_CC_BACK_BLACK "40m" #define TOY_CC_BACK_BLACK "40"
#define TOY_CC_BACK_RED "41m" #define TOY_CC_BACK_RED "41"
#define TOY_CC_BACK_GREEN "42m" #define TOY_CC_BACK_GREEN "42"
#define TOY_CC_BACK_YELLOW "43m" #define TOY_CC_BACK_YELLOW "43"
#define TOY_CC_BACK_BLUE "44m" #define TOY_CC_BACK_BLUE "44"
#define TOY_CC_BACK_PURPLE "45m" #define TOY_CC_BACK_MAGENTA "45"
#define TOY_CC_BACK_DGREEN "46m" #define TOY_CC_BACK_CYAN "46"
#define TOY_CC_BACK_WHITE "47m" #define TOY_CC_BACK_WHITE "47"
#define TOY_CC_BACK_DEFAULT "49"
//useful //useful macros
#define TOY_CC_DEBUG TOY_CC_FONT_BLUE TOY_CC_BACK_BLACK #define TOY_CC_DEBUG "\033[" TOY_CC_FONT_BLUE ";" TOY_CC_BACK_DEFAULT "m"
#define TOY_CC_NOTICE TOY_CC_FONT_GREEN TOY_CC_BACK_BLACK #define TOY_CC_NOTICE "\033[" TOY_CC_FONT_GREEN ";" TOY_CC_BACK_DEFAULT "m"
#define TOY_CC_WARN TOY_CC_FONT_YELLOW TOY_CC_BACK_BLACK #define TOY_CC_WARN "\033[" TOY_CC_FONT_YELLOW ";" TOY_CC_BACK_DEFAULT "m"
#define TOY_CC_ERROR TOY_CC_FONT_RED TOY_CC_BACK_BLACK #define TOY_CC_ERROR "\033[" TOY_CC_FONT_RED ";" TOY_CC_BACK_DEFAULT "m"
#define TOY_CC_ASSERT TOY_CC_FONT_PURPLE TOY_CC_BACK_BLACK #define TOY_CC_ASSERT "\033[" TOY_CC_FONT_BLACK ";" TOY_CC_BACK_MAGENTA "m"
#define TOY_CC_RESET "\033[0m" #define TOY_CC_RESET "\033[" "0" "m"
//for unsupported platforms, these become no-ops //for unsupported platforms, these become no-ops
#else #else
@@ -53,10 +54,10 @@ NOTE: you need both font AND background for these to work
#define TOY_CC_FONT_GREEN #define TOY_CC_FONT_GREEN
#define TOY_CC_FONT_YELLOW #define TOY_CC_FONT_YELLOW
#define TOY_CC_FONT_BLUE #define TOY_CC_FONT_BLUE
#define TOY_CC_FONT_PURPLE #define TOY_CC_FONT_MAGENTA
#define TOY_CC_FONT_DGREEN
#define TOY_CC_FONT_WHITE
#define TOY_CC_FONT_CYAN #define TOY_CC_FONT_CYAN
#define TOY_CC_FONT_WHITE
#define TOY_CC_FONT_DEFAULT
//background color //background color
#define TOY_CC_BACK_BLACK #define TOY_CC_BACK_BLACK
@@ -64,16 +65,17 @@ NOTE: you need both font AND background for these to work
#define TOY_CC_BACK_GREEN #define TOY_CC_BACK_GREEN
#define TOY_CC_BACK_YELLOW #define TOY_CC_BACK_YELLOW
#define TOY_CC_BACK_BLUE #define TOY_CC_BACK_BLUE
#define TOY_CC_BACK_PURPLE #define TOY_CC_BACK_MAGENTA
#define TOY_CC_BACK_DGREEN #define TOY_CC_BACK_CYAN
#define TOY_CC_BACK_WHITE #define TOY_CC_BACK_WHITE
#define TOY_CC_BACK_DEFAULT
//useful //useful
#define TOY_CC_DEBUG TOY_CC_FONT_BLUE TOY_CC_BACK_BLACK #define TOY_CC_DEBUG
#define TOY_CC_NOTICE TOY_CC_FONT_GREEN TOY_CC_BACK_BLACK #define TOY_CC_NOTICE
#define TOY_CC_WARN TOY_CC_FONT_YELLOW TOY_CC_BACK_BLACK #define TOY_CC_WARN
#define TOY_CC_ERROR TOY_CC_FONT_RED TOY_CC_BACK_BLACK #define TOY_CC_ERROR
#define TOY_CC_ASSERT TOY_CC_FONT_PURPLE TOY_CC_BACK_BLACK #define TOY_CC_ASSERT
#define TOY_CC_RESET #define TOY_CC_RESET
#endif #endif

3
tests/README.md Normal file
View File

@@ -0,0 +1,3 @@
# Tests
* units - for checking the functionality of a single unit of code

6
tests/makefile Normal file
View File

@@ -0,0 +1,6 @@
#bridge file
export CFLAGS+=-DTOY_CC_ENABLED
all:
$(MAKE) -C units -k

1
tests/units/gdb_init Normal file
View File

@@ -0,0 +1 @@
set breakpoint pending on

86
tests/units/makefile Normal file
View File

@@ -0,0 +1,86 @@
#compiler settings
CC=gcc
CFLAGS+=-std=c17 -g -Wall -Werror -Wextra -Wpedantic -Wformat=2 -Wno-newline-eof
LIBS+=-lm
LDFLAGS+=
ifeq ($(shell uname),Linux)
LDFLAGS=-Wl,--gc-sections
else ifeq ($(shell uname),NetBSD)
LDFLAGS=-Wl,--gc-sections
else ifeq ($(OS),Windows_NT)
LDFLAGS=-Wl,--gc-sections
else ifeq ($(shell uname),Darwin)
LDFLAGS=-Wl,-dead_strip
else
@echo "LDFLAGS set failed - what platform is this?"
endif
#directories
TEST_ROOTDIR=../..
TEST_SOURCEDIR=$(TEST_ROOTDIR)/$(TOY_SOURCEDIR)
TEST_CASESDIR=.
TEST_OUTDIR=out
TEST_OBJDIR=obj
#file names
TEST_SOURCEFILES=$(wildcard $(TEST_SOURCEDIR)/*.c)
TEST_CASESFILES=$(wildcard $(TEST_CASESDIR)/test_*.c)
#build the object files, compile the test cases, and run
all: build-source build-cases build-link build-run
#targets for each step
.PHONY: build-source
build-source: $(TEST_OUTDIR) $(TEST_OBJDIR) $(addprefix $(TEST_OBJDIR)/,$(notdir $(TEST_SOURCEFILES:.c=.o)))
.PHONY: build-cases
build-cases: $(TEST_OUTDIR) $(TEST_OBJDIR) $(addprefix $(TEST_OBJDIR)/,$(notdir $(TEST_CASESFILES:.c=.o)))
.PHONY: build-link
build-link: $(TEST_OUTDIR) $(TEST_OBJDIR) $(addprefix $(TEST_OUTDIR)/,$(notdir $(TEST_CASESFILES:%.c=%.exe)))
.PHONY: build-run
build-run: $(addprefix $(TEST_OUTDIR)/,$(notdir $(TEST_CASESFILES:%.c=%.exe))) $(addprefix $(TEST_OUTDIR)/,$(notdir $(TEST_CASESFILES:%.c=%.run)))
#util targets
$(TEST_OUTDIR):
mkdir $(TEST_OUTDIR)
$(TEST_OBJDIR):
mkdir $(TEST_OBJDIR)
#compilation steps
$(TEST_OBJDIR)/%.o: $(TEST_SOURCEDIR)/%.c
$(CC) -c -o $@ $< $(addprefix -I,$(TEST_SOURCEDIR)) $(CFLAGS) -fdata-sections -ffunction-sections
$(TEST_OBJDIR)/%.o: $(TEST_CASESDIR)/%.c
$(CC) -c -o $@ $< $(addprefix -I,$(TEST_SOURCEDIR) $(TEST_CASESDIR)) $(CFLAGS) -fdata-sections -ffunction-sections
$(TEST_OUTDIR)/%.exe: $(TEST_OBJDIR)/%.o
@$(CC) -o $@ $< $(addprefix $(TEST_OBJDIR)/,$(notdir $(TEST_SOURCEFILES:.c=.o))) $(CFLAGS) $(LIBS) $(LDFLAGS)
.PRECIOUS: $(TEST_OUTDIR)/%.run
$(TEST_OUTDIR)/%.run: $(TEST_OUTDIR)/%.exe
$<
#debugging targets
gdb: build-source build-cases build-link build-run-gdb
.PHONY: build-run-gdb
build-run-gdb: $(addprefix $(TEST_OUTDIR)/,$(notdir $(TEST_CASESFILES:%.c=%.exe))) $(addprefix $(TEST_OUTDIR)/,$(notdir $(TEST_CASESFILES:%.c=%.run-gdb)))
.PRECIOUS: $(TEST_OUTDIR)/%.run-gdb
$(TEST_OUTDIR)/%.run-gdb: $(TEST_OUTDIR)/%.exe
gdb $< -ix gdb_init -ex=run --batch --return-child-result --args "$<"
#valgrind targets
valgrind: build-source build-cases build-link build-run-valgrind
.PHONY: build-run-valgrind
build-run-valgrind: $(addprefix $(TEST_OUTDIR)/,$(notdir $(TEST_CASESFILES:%.c=%.exe))) $(addprefix $(TEST_OUTDIR)/,$(notdir $(TEST_CASESFILES:%.c=%.run-valgrind)))
.PRECIOUS: $(TEST_OUTDIR)/%.run-valgrind
$(TEST_OUTDIR)/%.run-valgrind: $(TEST_OUTDIR)/%.exe
valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes $<

52
tests/units/test_array.c Normal file
View File

@@ -0,0 +1,52 @@
#include "toy_array.h"
#include "toy_console_colors.h"
#include <stdio.h>
int test_array(void) {
//test allocation and free
{
Toy_Array* array = Toy_resizeArray(NULL, TOY_ARRAY_INITIAL_CAPACITY);
array = Toy_resizeArray(array, 0);
}
//test initial data
{
Toy_Array* array = Toy_resizeArray(NULL, TOY_ARRAY_INITIAL_CAPACITY);
//check you can access the memory
array->data[1] = TOY_VALUE_FROM_INTEGER(42);
array = Toy_resizeArray(array, 0);
}
//test multiple arrays (no overlaps or conflicts)
{
Toy_Array* array1 = Toy_resizeArray(NULL, TOY_ARRAY_INITIAL_CAPACITY);
Toy_Array* array2 = Toy_resizeArray(NULL, TOY_ARRAY_INITIAL_CAPACITY);
array1->data[1] = TOY_VALUE_FROM_INTEGER(42);
array2->data[1] = TOY_VALUE_FROM_INTEGER(42);
Toy_resizeArray(array1, 0);
Toy_resizeArray(array2, 0);
}
return 0;
}
int main(void) {
//run each test set, returning the total errors given
int total = 0, res = 0;
{
res = test_array();
total += res;
if (res == 0) {
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
}
}
return total;
}

9
tests/units/test_ast.c Normal file
View File

@@ -0,0 +1,9 @@
#include "toy_ast.h"
#include "toy_console_colors.h"
#include <stdio.h>
int main(void) {
printf(TOY_CC_WARN "Test not yet implemented: %s\n" TOY_CC_RESET, __FILE__);
return -1;
}

89
tests/units/test_bucket.c Normal file
View File

@@ -0,0 +1,89 @@
#include "toy_bucket.h"
#include "toy_console_colors.h"
#include <stdio.h>
int test_buckets(void) {
//test initializing and freeing a bucket
{
//init
Toy_Bucket* bucket = Toy_allocateBucket(sizeof(int) * 32);
//check
if (bucket == NULL || bucket->capacity != 32 * sizeof(int)) {
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to initialize 'Toy_Bucket'\n" TOY_CC_RESET);
return -1;
}
//cleanup
Toy_freeBucket(&bucket);
}
//test partitioning a bucket, several times
{
//init
Toy_Bucket* bucket = Toy_allocateBucket(sizeof(int) * 32);
//grab some memory
Toy_partitionBucket(&bucket, sizeof(int));
Toy_partitionBucket(&bucket, sizeof(int));
Toy_partitionBucket(&bucket, sizeof(int));
Toy_partitionBucket(&bucket, sizeof(int));
//check
if (bucket == NULL || bucket->count != 4 * sizeof(int)) {
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to partition 'Toy_Bucket' correctly: count is %d, expected %d\n" TOY_CC_RESET, (int)(bucket->count), (int)(4*sizeof(int)));
return -1;
}
//cleanup
Toy_freeBucket(&bucket);
}
//test partitioning a bucket, several times, with an internal expansion
{
//init
Toy_Bucket* bucket = Toy_allocateBucket(sizeof(int) * 4);
//grab some memory
Toy_partitionBucket(&bucket, sizeof(int));
Toy_partitionBucket(&bucket, sizeof(int));
Toy_partitionBucket(&bucket, sizeof(int));
Toy_partitionBucket(&bucket, sizeof(int));
Toy_partitionBucket(&bucket, sizeof(int));
Toy_partitionBucket(&bucket, sizeof(int));
//checks - please note that the top-most bucket is what is being filled - older buckets are further along
if (
bucket->capacity != 4 * sizeof(int) ||
bucket->count != 2 * sizeof(int) ||
bucket->next == NULL ||
bucket->next->capacity != 4 * sizeof(int) ||
bucket->next->count != 4 * sizeof(int))
{
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to expand 'Toy_Bucket' correctly\n" TOY_CC_RESET);
return -1;
}
//cleanup
Toy_freeBucket(&bucket);
}
return 0;
}
int main(void) {
//run each test set, returning the total errors given
int total = 0, res = 0;
{
res = test_buckets();
total += res;
if (res == 0) {
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
}
}
return total;
}

View File

@@ -0,0 +1,9 @@
#include "toy_compiler.h"
#include "toy_console_colors.h"
#include <stdio.h>
int main(void) {
printf(TOY_CC_WARN "Test not yet implemented: %s\n" TOY_CC_RESET, __FILE__);
return -1;
}

47
tests/units/test_lexer.c Normal file
View File

@@ -0,0 +1,47 @@
#include "toy_lexer.h"
#include "toy_console_colors.h"
#include <stdio.h>
#include <string.h>
int main(void) {
{
//source code sample to operate on
char* source = "print null;";
//test the lexer
Toy_Lexer lexer;
Toy_bindLexer(&lexer, source);
//get each token
Toy_Token print = Toy_private_scanLexer(&lexer);
Toy_Token null = Toy_private_scanLexer(&lexer);
Toy_Token semi = Toy_private_scanLexer(&lexer);
Toy_Token eof = Toy_private_scanLexer(&lexer);
//test each token is correct
if (strncmp(print.lexeme, "print", print.length)) {
fprintf(stderr, TOY_CC_ERROR "ERROR: print lexeme is wrong: %s" TOY_CC_RESET, print.lexeme);
return -1;
}
if (strncmp(null.lexeme, "null", null.length)) {
fprintf(stderr, TOY_CC_ERROR "ERROR: null lexeme is wrong: %s" TOY_CC_RESET, null.lexeme);
return -1;
}
if (strncmp(semi.lexeme, ";", semi.length)) {
fprintf(stderr, TOY_CC_ERROR "ERROR: semicolon lexeme is wrong: %s" TOY_CC_RESET, semi.lexeme);
return -1;
}
if (eof.type != TOY_TOKEN_EOF) {
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to find EOF token" TOY_CC_RESET);
return -1;
}
}
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
return 0;
}

View File

@@ -0,0 +1,9 @@
#include "toy_parser.h"
#include "toy_console_colors.h"
#include <stdio.h>
int main(void) {
printf(TOY_CC_WARN "Test not yet implemented: %s\n" TOY_CC_RESET, __FILE__);
return -1;
}

167
tests/units/test_print.c Normal file
View File

@@ -0,0 +1,167 @@
#include "toy_print.h"
#include "toy_console_colors.h"
#include <stdio.h>
int counter = 0;
void counterCallback(const char* msg) {
(void)msg;
counter++;
}
int test_callbacks(void) {
//set a custom print callback, invoke it, and reset
{
//setup
Toy_setPrintCallback(counterCallback);
//invoke
Toy_print("");
//check
if (counter != 1) {
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to set print callback\n" TOY_CC_RESET);
return -1;
}
//reset and retry
Toy_resetPrintCallback();
Toy_print("");
if (counter != 1) {
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to reset print callback\n" TOY_CC_RESET);
return -1;
}
//cleanup
counter = 0;
}
//set a custom error callback, invoke it, and reset
{
//setup
Toy_setErrorCallback(counterCallback);
//invoke
Toy_error("");
//check
if (counter != 1) {
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to set error callback\n" TOY_CC_RESET);
return -1;
}
//reset and retry
Toy_resetErrorCallback();
Toy_error("");
if (counter != 1) {
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to reset error callback\n" TOY_CC_RESET);
return -1;
}
//cleanup
counter = 0;
}
//set a custom assert failure callback, invoke it, and reset
{
//setup
Toy_setAssertFailureCallback(counterCallback);
//invoke
Toy_assertFailure("");
//check
if (counter != 1) {
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to set assert failure callback\n" TOY_CC_RESET);
return -1;
}
//reset and retry
Toy_resetAssertFailureCallback();
Toy_assertFailure("");
if (counter != 1) {
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to reset assert failure callback\n" TOY_CC_RESET);
return -1;
}
//cleanup
counter = 0;
}
return 0;
}
int test_console_colors(void) {
//test each font color
{
#define TEST_FONT(value) printf("\033[" value "m" #value TOY_CC_RESET "\n")
TEST_FONT(TOY_CC_FONT_BLACK);
TEST_FONT(TOY_CC_FONT_RED);
TEST_FONT(TOY_CC_FONT_GREEN);
TEST_FONT(TOY_CC_FONT_YELLOW);
TEST_FONT(TOY_CC_FONT_BLUE);
TEST_FONT(TOY_CC_FONT_MAGENTA);
TEST_FONT(TOY_CC_FONT_CYAN);
TEST_FONT(TOY_CC_FONT_WHITE);
TEST_FONT(TOY_CC_FONT_DEFAULT);
#undef TEST_FONT
}
//test each background color
{
#define TEST_BACK(value) printf("\033[" value "m" #value TOY_CC_RESET "\n")
TEST_BACK(TOY_CC_BACK_BLACK);
TEST_BACK(TOY_CC_BACK_RED);
TEST_BACK(TOY_CC_BACK_GREEN);
TEST_BACK(TOY_CC_BACK_YELLOW);
TEST_BACK(TOY_CC_BACK_BLUE);
TEST_BACK(TOY_CC_BACK_MAGENTA);
TEST_BACK(TOY_CC_BACK_CYAN);
TEST_BACK(TOY_CC_BACK_WHITE);
TEST_BACK(TOY_CC_BACK_DEFAULT);
#undef TEST_BACK
}
//test the commonly used shorthands
{
#define TEST_MACRO(value) printf(value #value TOY_CC_RESET "\n")
TEST_MACRO(TOY_CC_DEBUG);
TEST_MACRO(TOY_CC_NOTICE);
TEST_MACRO(TOY_CC_WARN);
TEST_MACRO(TOY_CC_ERROR);
TEST_MACRO(TOY_CC_ASSERT);
TEST_MACRO(TOY_CC_RESET);
#undef TEST_MACRO
}
//This will always return zero, so it needs a visual check
return 0;
}
int main(void) {
//run each test set, returning the total errors given
int total = 0, res = 0;
{
res = test_callbacks();
if (res == 0) {
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
}
total += res;
}
{
res = test_console_colors();
if (res == 0) {
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
}
total += res;
}
return total;
}

9
tests/units/test_scope.c Normal file
View File

@@ -0,0 +1,9 @@
#include "toy_scope.h"
#include "toy_console_colors.h"
#include <stdio.h>
int main(void) {
printf(TOY_CC_WARN "Test not yet implemented: %s\n" TOY_CC_RESET, __FILE__);
return -1;
}

150
tests/units/test_stack.c Normal file
View File

@@ -0,0 +1,150 @@
#include "toy_stack.h"
#include "toy_console_colors.h"
#include <stdio.h>
int test_stack_basics(void) {
//allocate and free the stack
{
Toy_Stack* stack = Toy_allocateStack();
//check if it worked
if (
stack == NULL ||
stack->capacity != 8 ||
stack->count != 0)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to allocate Toy_Stack\n" TOY_CC_RESET);
Toy_freeStack(stack);
return -1;
}
Toy_freeStack(stack);
}
//push, peek and pop stack
{
Toy_Stack* stack = Toy_allocateStack();
//check if it worked (push)
Toy_pushStack(&stack, TOY_VALUE_FROM_INTEGER(42));
Toy_pushStack(&stack, TOY_VALUE_FROM_INTEGER(69));
Toy_pushStack(&stack, TOY_VALUE_FROM_INTEGER(420));
if (
stack == NULL ||
stack->capacity != 8 ||
stack->count != 3)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to push Toy_Stack\n" TOY_CC_RESET);
Toy_freeStack(stack);
return -1;
}
//check if it worked (peek)
Toy_Value top1 = Toy_peekStack(&stack);
if (
TOY_VALUE_IS_INTEGER(top1) != true ||
TOY_VALUE_AS_INTEGER(top1) != 420)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to peek Toy_Stack\n" TOY_CC_RESET);
Toy_freeStack(stack);
return -1;
}
//check if it worked (pop)
Toy_Value top2 = Toy_popStack(&stack);
if (
stack == NULL ||
stack->capacity != 8 ||
stack->count != 2 ||
TOY_VALUE_IS_INTEGER(top2) != true ||
TOY_VALUE_AS_INTEGER(top2) != 420)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to pop Toy_Stack\n" TOY_CC_RESET);
Toy_freeStack(stack);
return -1;
}
//check if it worked (post-pop peek)
Toy_Value top3 = Toy_peekStack(&stack);
if (
TOY_VALUE_IS_INTEGER(top3) != true ||
TOY_VALUE_AS_INTEGER(top3) != 69)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to pop then peek Toy_Stack\n" TOY_CC_RESET);
Toy_freeStack(stack);
return -1;
}
Toy_freeStack(stack);
}
return 0;
}
int test_stack_stress(void) {
//stress the stack
{
Toy_Stack* stack = Toy_allocateStack();
//push 500 values
for (int i = 0; i < 500; i++) {
Toy_pushStack(&stack, TOY_VALUE_FROM_INTEGER(i));
}
//check if it worked
if (
stack == NULL ||
stack->capacity != 512 ||
stack->count != 500)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to stress push the Toy_Stack\n" TOY_CC_RESET);
Toy_freeStack(stack);
return -1;
}
//pop each value
while(stack->count > 0) {
Toy_popStack(&stack); //ignore the results
}
//check if it worked
if (
stack == NULL ||
stack->capacity != TOY_STACK_INITIAL_CAPACITY || //reset to initial capacity
stack->count != 0)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to stress pop the Toy_Stack\n" TOY_CC_RESET);
Toy_freeStack(stack);
return -1;
}
//cleanup
Toy_freeStack(stack);
}
return 0;
}
int main(void) {
//run each test set, returning the total errors given
int total = 0, res = 0;
{
res = test_stack_basics();
if (res == 0) {
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
}
total += res;
}
{
res = test_stack_stress();
if (res == 0) {
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
}
total += res;
}
return total;
}

View File

@@ -0,0 +1,9 @@
#include "toy_string.h"
#include "toy_console_colors.h"
#include <stdio.h>
int main(void) {
printf(TOY_CC_WARN "Test not yet implemented: %s\n" TOY_CC_RESET, __FILE__);
return -1;
}

653
tests/units/test_table.c Normal file
View File

@@ -0,0 +1,653 @@
#include "toy_table.h"
#include "toy_console_colors.h"
#include <stdio.h>
int test_table_allocation(void) {
//allocate and free a table
{
//setup
Toy_Table* table = Toy_allocateTable();
//check
if (table == NULL)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to allocate a table\n" TOY_CC_RESET);
Toy_freeTable(table);
return -1;
}
//free
Toy_freeTable(table);
}
return 0;
}
int test_table_simple_insert_lookup_and_remove(void) {
//simple insert
{
//setup
Toy_Table* table = Toy_allocateTable();
Toy_Value key = TOY_VALUE_FROM_INTEGER(1);
Toy_Value value = TOY_VALUE_FROM_INTEGER(42);
//insert
Toy_insertTable(&table, key, value);
if (table == NULL ||
table->capacity != 8 ||
table->count != 1)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to insert into a table\n" TOY_CC_RESET);
Toy_freeTable(table);
return -1;
}
//lookup
Toy_Value result = Toy_lookupTable(&table, TOY_VALUE_FROM_INTEGER(1));
//check lookup
if (table == NULL ||
table->capacity != 8 ||
table->count != 1 ||
TOY_VALUE_AS_INTEGER(result) != 42)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to lookup from a table\n" TOY_CC_RESET);
Toy_freeTable(table);
return -1;
}
//remove
Toy_removeTable(&table, TOY_VALUE_FROM_INTEGER(1));
//check remove
if (table == NULL ||
table->capacity != 8 ||
table->count != 0)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to remove from a table\n" TOY_CC_RESET);
Toy_freeTable(table);
return -1;
}
//free
Toy_freeTable(table);
}
return 0;
}
//macros are a godsend
#define TEST_ENTRY_STATE(i, k, v, p) \
TOY_VALUE_IS_INTEGER(table->data[i].key) != true || \
TOY_VALUE_AS_INTEGER(table->data[i].key) != k || \
TOY_VALUE_IS_INTEGER(table->data[i].value) != true || \
TOY_VALUE_AS_INTEGER(table->data[i].value) != v || \
table->data[i].psl != p
int test_table_contents_no_expansion(void) {
//single insert
{
//setup
Toy_Table* table = Toy_allocateTable();
//insert a key and value
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(1), TOY_VALUE_FROM_INTEGER(42));
//check the state
if (table == NULL ||
table->capacity != 8 ||
table->count != 1 ||
TEST_ENTRY_STATE(7, 1, 42, 0)
)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: Unrecognized state from table data, single insert {1:42}\n" TOY_CC_RESET);
Toy_freeTable(table);
return -1;
}
//free
Toy_freeTable(table);
}
//multiple inserts, no collisions
{
//setup
Toy_Table* table = Toy_allocateTable();
//inserts
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(1), TOY_VALUE_FROM_INTEGER(42)); //hash: 7
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(2), TOY_VALUE_FROM_INTEGER(69)); //hash: 0
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(3), TOY_VALUE_FROM_INTEGER(420)); //hash: 5
//check the state
if (table == NULL ||
table->capacity != 8 ||
table->count != 3 ||
TEST_ENTRY_STATE(7, 1, 42, 0) ||
TEST_ENTRY_STATE(0, 2, 69, 0) ||
TEST_ENTRY_STATE(5, 3, 420, 0)
)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: Unrecognized state from table data, multiple inserts, no collisions\n" TOY_CC_RESET);
Toy_freeTable(table);
return -1;
}
//free
Toy_freeTable(table);
}
//multiple inserts, with collisions
{
//setup
Toy_Table* table = Toy_allocateTable();
//inserts
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(5), TOY_VALUE_FROM_INTEGER(42)); //hash: 2
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(19), TOY_VALUE_FROM_INTEGER(69)); //hash: 2
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(37), TOY_VALUE_FROM_INTEGER(420)); //hash: 2
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(65), TOY_VALUE_FROM_INTEGER(8891)); //hash: 2
//check the state
if (table == NULL ||
table->capacity != 8 ||
table->count != 4 ||
TEST_ENTRY_STATE(2, 5, 42, 0) ||
TEST_ENTRY_STATE(3, 19, 69, 1) ||
TEST_ENTRY_STATE(4, 37, 420, 2) ||
TEST_ENTRY_STATE(5, 65, 8891, 3)
)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: Unrecognized state from table data, muiltiple inserts, with collisions\n" TOY_CC_RESET);
Toy_freeTable(table);
return -1;
}
//free
Toy_freeTable(table);
}
//multiple inserts, with collisions, modulo wrap
{
//setup
Toy_Table* table = Toy_allocateTable();
//inserts
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(1), TOY_VALUE_FROM_INTEGER(42)); //hash: 7
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(14), TOY_VALUE_FROM_INTEGER(69)); //hash: 7
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(76), TOY_VALUE_FROM_INTEGER(420)); //hash: 7
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(80), TOY_VALUE_FROM_INTEGER(8891)); //hash: 7
//check the state
if (table == NULL ||
table->capacity != 8 ||
table->count != 4 ||
TEST_ENTRY_STATE(7, 1, 42, 0) ||
TEST_ENTRY_STATE(0, 14, 69, 1) ||
TEST_ENTRY_STATE(1, 76, 420, 2) ||
TEST_ENTRY_STATE(2, 80, 8891, 3)
)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: Unrecognized state from table data, muiltiple inserts, with collisions, modulo wrap\n" TOY_CC_RESET);
Toy_freeTable(table);
return -1;
}
//free
Toy_freeTable(table);
}
//lookup, with collisions, modulo wrap
{
//setup
Toy_Table* table = Toy_allocateTable();
//inserts
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(17), TOY_VALUE_FROM_INTEGER(42)); //hash: 7
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(33), TOY_VALUE_FROM_INTEGER(69)); //hash: 7
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(70), TOY_VALUE_FROM_INTEGER(420)); //hash: 7
//lookup
Toy_Value result = Toy_lookupTable(&table, TOY_VALUE_FROM_INTEGER(33));
//check the state
if (table == NULL ||
table->capacity != 8 ||
table->count != 3 ||
TOY_VALUE_IS_INTEGER(result) != true ||
TOY_VALUE_AS_INTEGER(result) != 69
)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: Bad result from table lookup with collisions and modulo wrap\n" TOY_CC_RESET);
Toy_freeTable(table);
return -1;
}
//free
Toy_freeTable(table);
}
//multiple inserts, with collisions, modulo wrap, psl overlap
{
//setup
Toy_Table* table = Toy_allocateTable();
//inserts
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(17), TOY_VALUE_FROM_INTEGER(42)); //hash: 7
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(33), TOY_VALUE_FROM_INTEGER(69)); //hash: 7
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(70), TOY_VALUE_FROM_INTEGER(420)); //hash: 7
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(35), TOY_VALUE_FROM_INTEGER(8891)); //hash: 1
//check the state
if (table == NULL ||
table->capacity != 8 ||
table->count != 4 ||
TEST_ENTRY_STATE(7, 17, 42, 0) ||
TEST_ENTRY_STATE(0, 33, 69, 1) ||
TEST_ENTRY_STATE(1, 70, 420, 2) ||
TEST_ENTRY_STATE(2, 35, 8891, 1)
)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: Unrecognized state from table data, muiltiple inserts, with collisions, modulo wrap, psl overlap\n" TOY_CC_RESET);
Toy_freeTable(table);
return -1;
}
//free
Toy_freeTable(table);
}
//multiple inserts, with collisions, modulo wrap, psl overlap, psl shift
{
//setup
Toy_Table* table = Toy_allocateTable();
//inserts
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(17), TOY_VALUE_FROM_INTEGER(42)); //hash: 7
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(33), TOY_VALUE_FROM_INTEGER(69)); //hash: 7
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(70), TOY_VALUE_FROM_INTEGER(420)); //hash: 7
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(35), TOY_VALUE_FROM_INTEGER(8891)); //hash: 1
//remove
Toy_removeTable(&table, TOY_VALUE_FROM_INTEGER(33));
//check the state
if (table == NULL ||
table->capacity != 8 ||
table->count != 3 ||
TEST_ENTRY_STATE(7, 17, 42, 0) ||
TEST_ENTRY_STATE(0, 70, 420, 1) ||
TEST_ENTRY_STATE(1, 35, 8891, 0)
)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: Unrecognized state from table data, muiltiple inserts, with collisions, modulo wrap, psl overlap, psl shift\n" TOY_CC_RESET);
Toy_freeTable(table);
return -1;
}
//free
Toy_freeTable(table);
}
return 0;
}
int test_table_contents_with_expansions(void) {
//simple expansion
{
//setup
Toy_Table* table = Toy_allocateTable();
//insert a key and value
for (int i = 0; i < 20; i++) {
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(i), TOY_VALUE_FROM_INTEGER(42));
}
//check the state
if (table == NULL ||
table->capacity != 32 ||
table->count != 20
)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to expand table capacity\n" TOY_CC_RESET);
Toy_freeTable(table);
return -1;
}
//free
Toy_freeTable(table);
}
//expansion, multiple inserts, no collisions
{
//setup
Toy_Table* table = Toy_allocateTable();
//inserts
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(0), TOY_VALUE_FROM_INTEGER(42)); //hash: 0
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(35), TOY_VALUE_FROM_INTEGER(42)); //hash: 1
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(19), TOY_VALUE_FROM_INTEGER(42)); //hash: 2
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(8), TOY_VALUE_FROM_INTEGER(42)); //hash: 3
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(10), TOY_VALUE_FROM_INTEGER(42)); //hash: 4
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(3), TOY_VALUE_FROM_INTEGER(42)); //hash: 5
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(28), TOY_VALUE_FROM_INTEGER(42)); //hash: 6
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(1), TOY_VALUE_FROM_INTEGER(42)); //hash: 7
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(6), TOY_VALUE_FROM_INTEGER(42)); //hash: 8
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(93), TOY_VALUE_FROM_INTEGER(42)); //hash: 9
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(85), TOY_VALUE_FROM_INTEGER(42)); //hash: 10
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(9), TOY_VALUE_FROM_INTEGER(42)); //hash: 11
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(11), TOY_VALUE_FROM_INTEGER(42)); //hash: 12
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(22), TOY_VALUE_FROM_INTEGER(42)); //hash: 13
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(13), TOY_VALUE_FROM_INTEGER(42)); //hash: 14
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(17), TOY_VALUE_FROM_INTEGER(42)); //hash: 15
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(43), TOY_VALUE_FROM_INTEGER(42)); //hash: 16
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(4), TOY_VALUE_FROM_INTEGER(42)); //hash: 17
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(5), TOY_VALUE_FROM_INTEGER(42)); //hash: 18
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(7), TOY_VALUE_FROM_INTEGER(42)); //hash: 19
//check the state
if (table == NULL ||
table->capacity != 32 ||
table->count != 20 ||
//effectively, check that each key was placed in the correct position after the expansion
TEST_ENTRY_STATE(0, 0, 42, 0) ||
TEST_ENTRY_STATE(1, 35, 42, 0) ||
TEST_ENTRY_STATE(2, 19, 42, 0) ||
TEST_ENTRY_STATE(3, 8, 42, 0) ||
TEST_ENTRY_STATE(4, 10, 42, 0) ||
TEST_ENTRY_STATE(5, 3, 42, 0) ||
TEST_ENTRY_STATE(6, 28, 42, 0) ||
TEST_ENTRY_STATE(7, 1, 42, 0) ||
TEST_ENTRY_STATE(8, 6, 42, 0) ||
TEST_ENTRY_STATE(9, 93, 42, 0) ||
TEST_ENTRY_STATE(10, 85, 42, 0) ||
TEST_ENTRY_STATE(11, 9, 42, 0) ||
TEST_ENTRY_STATE(12, 11, 42, 0) ||
TEST_ENTRY_STATE(13, 22, 42, 0) ||
TEST_ENTRY_STATE(14, 13, 42, 0) ||
TEST_ENTRY_STATE(15, 17, 42, 0) ||
TEST_ENTRY_STATE(16, 43, 42, 0) ||
TEST_ENTRY_STATE(17, 4, 42, 0) ||
TEST_ENTRY_STATE(18, 5, 42, 0) ||
TEST_ENTRY_STATE(19, 7, 42, 0)
)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: Unrecognized state from table data after expansion, multiple inserts, no collisions\n" TOY_CC_RESET);
Toy_freeTable(table);
return -1;
}
//free
Toy_freeTable(table);
}
//multiple inserts, with collisions
{
//setup
Toy_Table* table = Toy_allocateTable();
//inserts
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(0), TOY_VALUE_FROM_INTEGER(42)); //hash: 0
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(35), TOY_VALUE_FROM_INTEGER(42)); //hash: 1
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(19), TOY_VALUE_FROM_INTEGER(42)); //hash: 2
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(8), TOY_VALUE_FROM_INTEGER(42)); //hash: 3
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(10), TOY_VALUE_FROM_INTEGER(42)); //hash: 4
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(3), TOY_VALUE_FROM_INTEGER(42)); //hash: 5
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(28), TOY_VALUE_FROM_INTEGER(42)); //hash: 6
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(1), TOY_VALUE_FROM_INTEGER(42)); //hash: 7
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(6), TOY_VALUE_FROM_INTEGER(42)); //hash: 8
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(93), TOY_VALUE_FROM_INTEGER(42)); //hash: 9
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(85), TOY_VALUE_FROM_INTEGER(42)); //hash: 10
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(9), TOY_VALUE_FROM_INTEGER(42)); //hash: 11
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(11), TOY_VALUE_FROM_INTEGER(42)); //hash: 12
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(22), TOY_VALUE_FROM_INTEGER(42)); //hash: 13
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(13), TOY_VALUE_FROM_INTEGER(42)); //hash: 14
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(17), TOY_VALUE_FROM_INTEGER(42)); //hash: 15
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(43), TOY_VALUE_FROM_INTEGER(42)); //hash: 16
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(4), TOY_VALUE_FROM_INTEGER(42)); //hash: 17
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(5), TOY_VALUE_FROM_INTEGER(42)); //hash: 18
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(7), TOY_VALUE_FROM_INTEGER(42)); //hash: 19
//insert one more
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(70), TOY_VALUE_FROM_INTEGER(42)); //hash: 15
//check the state
if (table == NULL ||
table->capacity != 32 ||
table->count != 21 ||
TEST_ENTRY_STATE(0, 0, 42, 0) ||
TEST_ENTRY_STATE(1, 35, 42, 0) ||
TEST_ENTRY_STATE(2, 19, 42, 0) ||
TEST_ENTRY_STATE(3, 8, 42, 0) ||
TEST_ENTRY_STATE(4, 10, 42, 0) ||
TEST_ENTRY_STATE(5, 3, 42, 0) ||
TEST_ENTRY_STATE(6, 28, 42, 0) ||
TEST_ENTRY_STATE(7, 1, 42, 0) ||
TEST_ENTRY_STATE(8, 6, 42, 0) ||
TEST_ENTRY_STATE(9, 93, 42, 0) ||
TEST_ENTRY_STATE(10, 85, 42, 0) ||
TEST_ENTRY_STATE(11, 9, 42, 0) ||
TEST_ENTRY_STATE(12, 11, 42, 0) ||
TEST_ENTRY_STATE(13, 22, 42, 0) ||
TEST_ENTRY_STATE(14, 13, 42, 0) ||
TEST_ENTRY_STATE(15, 17, 42, 0) ||
TEST_ENTRY_STATE(16, 70, 42, 1) || //the collision
TEST_ENTRY_STATE(17, 43, 42, 1) ||
TEST_ENTRY_STATE(18, 4, 42, 1) ||
TEST_ENTRY_STATE(19, 5, 42, 1) ||
TEST_ENTRY_STATE(20, 7, 42, 1)
)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: Unrecognized state from table data after expansion, muiltiple inserts, with collisions\n" TOY_CC_RESET);
Toy_freeTable(table);
return -1;
}
//free
Toy_freeTable(table);
}
//multiple inserts, with collisions, modulo wrap
{
//setup
Toy_Table* table = Toy_allocateTable();
//inserts
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(123), TOY_VALUE_FROM_INTEGER(42)); //hash: 20
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(42), TOY_VALUE_FROM_INTEGER(42)); //hash: 21
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(132), TOY_VALUE_FROM_INTEGER(42)); //hash: 22
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(34), TOY_VALUE_FROM_INTEGER(42)); //hash: 23
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(2), TOY_VALUE_FROM_INTEGER(42)); //hash: 24
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(32), TOY_VALUE_FROM_INTEGER(42)); //hash: 25
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(21), TOY_VALUE_FROM_INTEGER(42)); //hash: 26
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(44), TOY_VALUE_FROM_INTEGER(42)); //hash: 27
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(104), TOY_VALUE_FROM_INTEGER(42)); //hash: 28
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(15), TOY_VALUE_FROM_INTEGER(42)); //hash: 29
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(57), TOY_VALUE_FROM_INTEGER(42)); //hash: 30
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(33), TOY_VALUE_FROM_INTEGER(42)); //hash: 31
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(0), TOY_VALUE_FROM_INTEGER(42)); //hash: 32
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(35), TOY_VALUE_FROM_INTEGER(42)); //hash: 33
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(19), TOY_VALUE_FROM_INTEGER(42)); //hash: 34
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(8), TOY_VALUE_FROM_INTEGER(42)); //hash: 35
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(10), TOY_VALUE_FROM_INTEGER(42)); //hash: 36
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(3), TOY_VALUE_FROM_INTEGER(42)); //hash: 37
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(28), TOY_VALUE_FROM_INTEGER(42)); //hash: 38
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(1), TOY_VALUE_FROM_INTEGER(42)); //hash: 39
//insert one more
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(79), TOY_VALUE_FROM_INTEGER(42)); //hash: 23
//check the state
if (table == NULL ||
table->capacity != 32 ||
table->count != 21 ||
TEST_ENTRY_STATE(20, 123, 42, 0) ||
TEST_ENTRY_STATE(21, 42, 42, 0) ||
TEST_ENTRY_STATE(22, 132, 42, 0) ||
TEST_ENTRY_STATE(23, 34, 42, 0) ||
TEST_ENTRY_STATE(24, 79, 42, 1) || //the collision
TEST_ENTRY_STATE(25, 2, 42, 1) ||
TEST_ENTRY_STATE(26, 32, 42, 1) ||
TEST_ENTRY_STATE(27, 21, 42, 1) ||
TEST_ENTRY_STATE(28, 44, 42, 1) ||
TEST_ENTRY_STATE(29, 104, 42, 1) ||
TEST_ENTRY_STATE(30, 15, 42, 1) ||
TEST_ENTRY_STATE(31, 57, 42, 1) ||
TEST_ENTRY_STATE(0, 33, 42, 1) ||
TEST_ENTRY_STATE(1, 0, 42, 1) ||
TEST_ENTRY_STATE(2, 35, 42, 1) ||
TEST_ENTRY_STATE(3, 19, 42, 1) ||
TEST_ENTRY_STATE(4, 8, 42, 1) ||
TEST_ENTRY_STATE(5, 10, 42, 1) ||
TEST_ENTRY_STATE(6, 3, 42, 1) ||
TEST_ENTRY_STATE(7, 28, 42, 1) ||
TEST_ENTRY_STATE(8, 1, 42, 1)
)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: Unrecognized state from table data after expansion, muiltiple inserts, with collisions, modulo wrap\n" TOY_CC_RESET);
Toy_freeTable(table);
return -1;
}
//free
Toy_freeTable(table);
}
//lookup, with collisions, modulo wrap
{
//setup
Toy_Table* table = Toy_allocateTable();
//inserts
for (int i = 0; i < 20; i++) { //enough to expand
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(i), TOY_VALUE_FROM_INTEGER(100 - i));
}
//lookup
Toy_Value result = Toy_lookupTable(&table, TOY_VALUE_FROM_INTEGER(15));
//check the state
if (table == NULL ||
table->capacity != 32 ||
table->count != 20 ||
TOY_VALUE_IS_INTEGER(result) != true ||
TOY_VALUE_AS_INTEGER(result) != 85
)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: Bad result from table lookup after expansion, with collisions and modulo wrap\n" TOY_CC_RESET);
Toy_freeTable(table);
return -1;
}
//free
Toy_freeTable(table);
}
//Skipped: multiple inserts, with collisions, modulo wrap, psl overlap
//Skipped: multiple inserts, with collisions, modulo wrap, psl overlap, psl shift
//Note: since psl overlap and psl shift both work without expansion, I'm leaving these tests unimplemented.
return 0;
}
int test_table_expansions_under_stress(void) {
//multiple expansions, find one value
{
//setup
Toy_Table* table = Toy_allocateTable();
int top = 300;
//insert keys and values
for (int i = 0; i < 400; i++) {
Toy_insertTable(&table, TOY_VALUE_FROM_INTEGER(i), TOY_VALUE_FROM_INTEGER(top - i));
}
Toy_Value result = Toy_lookupTable(&table, TOY_VALUE_FROM_INTEGER(265));
//check the state
if (table == NULL ||
table->capacity != 512 ||
table->count != 400 ||
TOY_VALUE_IS_INTEGER(result) != true ||
TOY_VALUE_AS_INTEGER(result) != 35
)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: Table expansions under stress failed\n" TOY_CC_RESET);
Toy_freeTable(table);
return -1;
}
//free
Toy_freeTable(table);
}
return 0;
}
int main(void) {
//run each test set, returning the total errors given
int total = 0, res = 0;
{
res = test_table_allocation();
if (res == 0) {
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
}
total += res;
}
{
res = test_table_simple_insert_lookup_and_remove();
if (res == 0) {
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
}
total += res;
}
{
res = test_table_contents_no_expansion();
if (res == 0) {
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
}
total += res;
}
{
res = test_table_contents_with_expansions();
if (res == 0) {
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
}
total += res;
}
{
res = test_table_expansions_under_stress();
if (res == 0) {
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
}
total += res;
}
return total;
}

9
tests/units/test_value.c Normal file
View File

@@ -0,0 +1,9 @@
#include "toy_value.h"
#include "toy_console_colors.h"
#include <stdio.h>
int main(void) {
printf(TOY_CC_WARN "Test not yet implemented: %s\n" TOY_CC_RESET, __FILE__);
return -1;
}

9
tests/units/test_vm.c Normal file
View File

@@ -0,0 +1,9 @@
#include "toy_vm.h"
#include "toy_console_colors.h"
#include <stdio.h>
int main(void) {
printf(TOY_CC_WARN "Test not yet implemented: %s\n" TOY_CC_RESET, __FILE__);
return -1;
}