mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54:07 +10:00
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:
13
makefile
13
makefile
@@ -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?"
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
3
tests/README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Tests
|
||||||
|
|
||||||
|
* units - for checking the functionality of a single unit of code
|
||||||
6
tests/makefile
Normal file
6
tests/makefile
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#bridge file
|
||||||
|
|
||||||
|
export CFLAGS+=-DTOY_CC_ENABLED
|
||||||
|
|
||||||
|
all:
|
||||||
|
$(MAKE) -C units -k
|
||||||
1
tests/units/gdb_init
Normal file
1
tests/units/gdb_init
Normal file
@@ -0,0 +1 @@
|
|||||||
|
set breakpoint pending on
|
||||||
86
tests/units/makefile
Normal file
86
tests/units/makefile
Normal 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
52
tests/units/test_array.c
Normal 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
9
tests/units/test_ast.c
Normal 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
89
tests/units/test_bucket.c
Normal 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;
|
||||||
|
}
|
||||||
9
tests/units/test_compiler.c
Normal file
9
tests/units/test_compiler.c
Normal 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
47
tests/units/test_lexer.c
Normal 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;
|
||||||
|
}
|
||||||
9
tests/units/test_parser.c
Normal file
9
tests/units/test_parser.c
Normal 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
167
tests/units/test_print.c
Normal 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
9
tests/units/test_scope.c
Normal 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
150
tests/units/test_stack.c
Normal 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;
|
||||||
|
}
|
||||||
9
tests/units/test_string.c
Normal file
9
tests/units/test_string.c
Normal 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
653
tests/units/test_table.c
Normal 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
9
tests/units/test_value.c
Normal 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
9
tests/units/test_vm.c
Normal 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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user