WIP: moving things around
This commit is contained in:
parent
d99b1ac98d
commit
99035d8a0f
24 changed files with 1251 additions and 111 deletions
|
@ -10,6 +10,7 @@
|
|||
<file path="$PROJECT_DIR$/include" />
|
||||
<file path="$PROJECT_DIR$/lib" />
|
||||
<file path="$PROJECT_DIR$/src" />
|
||||
<file path="$PROJECT_DIR$/test" />
|
||||
<file path="$PROJECT_DIR$/tests" />
|
||||
</sourceRoots>
|
||||
</component>
|
||||
|
|
|
@ -11,12 +11,11 @@ set(CMAKE_C_STANDARD_REQUIRED ON)
|
|||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
set(CMAKE_C_OUTPUT_EXTENSION .o)
|
||||
|
||||
# Set source and header file locations
|
||||
set(SOURCE_DIR src)
|
||||
set(HEADER_DIR include)
|
||||
set(SOURCE_DIR .)
|
||||
set(HEADER_DIR . test)
|
||||
|
||||
set(COMMON_CMAKE_C_FLAGS "-Wall -Wextra -Wpedantic")
|
||||
set(CMAKE_C_FLAGS_DEBUG "-DSPARSEMAP_DIAGNOSTIC -DDEBUG -g -O0")
|
||||
set(CMAKE_C_FLAGS_DEBUG "-DSPARSEMAP_DIAGNOSTIC -DDEBUG -g -Og")
|
||||
set(CMAKE_C_FLAGS_PROFILE "-DSPARSEMAP_DIAGNOSTIC -DDEBUG -g -Og -fsanitize=address,leak,object-size,pointer-compare,pointer-subtract,null,return,bounds,pointer-overflow,undefined -fsanitize-address-use-after-scope")
|
||||
set(CMAKE_C_FLAGS_RELEASE "-Ofast")
|
||||
|
||||
|
@ -50,37 +49,37 @@ set_target_properties(sparsemap PROPERTIES
|
|||
target_include_directories(sparsemap PRIVATE ${HEADER_DIR})
|
||||
|
||||
# Add ex_1 program
|
||||
add_executable(ex_1 examples/ex_1.c tests/munit.c lib/common.c)
|
||||
add_executable(ex_1 test/ex_1.c test/munit.c test/common.c)
|
||||
target_link_libraries(ex_1 PRIVATE sparsemap)
|
||||
target_include_directories(ex_1 PRIVATE ${HEADER_DIR})
|
||||
add_custom_target(run_ex_1 COMMAND ex_1 WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
|
||||
# Add ex_2 program
|
||||
add_executable(ex_2 examples/ex_2.c tests/munit.c lib/common.c)
|
||||
add_executable(ex_2 test/ex_2.c test/munit.c test/common.c)
|
||||
target_link_libraries(ex_2 PRIVATE sparsemap)
|
||||
target_include_directories(ex_2 PRIVATE ${HEADER_DIR})
|
||||
add_custom_target(run_ex_2 COMMAND ex_2 WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
|
||||
# Add ex_3 program
|
||||
add_executable(ex_3 examples/ex_3.c tests/munit.c lib/common.c)
|
||||
add_executable(ex_3 test/ex_3.c test/munit.c test/common.c)
|
||||
target_link_libraries(ex_3 PRIVATE sparsemap)
|
||||
target_include_directories(ex_3 PRIVATE ${HEADER_DIR})
|
||||
add_custom_target(run_ex_3 COMMAND ex_3 WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
|
||||
# Add ex_4 program
|
||||
add_executable(ex_4 examples/ex_4.c tests/munit.c lib/common.c)
|
||||
add_executable(ex_4 test/ex_4.c test/munit.c test/common.c)
|
||||
target_link_libraries(ex_4 PRIVATE sparsemap)
|
||||
target_include_directories(ex_4 PRIVATE ${HEADER_DIR})
|
||||
add_custom_target(run_ex_4 COMMAND ex_4 WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
|
||||
# Add test program
|
||||
add_executable(test tests/test.c tests/munit.c lib/common.c)
|
||||
add_executable(test test/test.c test/munit.c test/common.c)
|
||||
target_link_libraries(test PRIVATE sparsemap)
|
||||
target_include_directories(test PRIVATE ${HEADER_DIR})
|
||||
add_custom_target(run_test COMMAND test WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
|
||||
# Add soak program
|
||||
add_executable(soak tests/soak.c lib/common.c lib/tdigest.c lib/roaring.c)
|
||||
add_executable(soak test/soak.c test/common.c test/tdigest.c test/roaring.c)
|
||||
target_link_libraries(soak PRIVATE sparsemap)
|
||||
target_include_directories(soak PRIVATE ${HEADER_DIR} lib)
|
||||
target_link_libraries(soak PUBLIC m)
|
||||
|
|
138
Makefile
138
Makefile
|
@ -1,106 +1,68 @@
|
|||
# Build type (debug, sanitize, or release)
|
||||
BUILD_TYPE := debug
|
||||
|
||||
OBJS = sparsemap.o
|
||||
COMMON_CFLAGS = -Wall -Wextra -Wpedantic -std=c11 -fPIC -I.
|
||||
CFLAGS_DEBUG = $(COMMON_CFLAGS) -Og -g -DSPARSEMAP_DIAGNOSTIC -DDEBUG
|
||||
CFLAGS_SANITIZE = $(COMMON_CFLAGS) -Og -g -DSPARSEMAP_DIAGNOSTIC -DDEBUG -fsanitize=address,leak,object-size,pointer-compare,pointer-subtract,null,return,bounds,pointer-overflow,undefined -fsanitize-address-use-after-scope -std=c11
|
||||
CFLAGS_RELEASE = $(COMMON_CFLAGS) -Ofast
|
||||
CFLAGS_TEST = $(COMMON_CFLAGS) -Og -g -DDEBUG -I. -Itest
|
||||
CFLAGS := $(if $(filter debug,$(BUILD_TYPE)),$(CFLAGS_DEBUG), \
|
||||
$(if $(filter release,$(BUILD_TYPE)),$(CFLAGS_RELEASE), \
|
||||
$(if $(filter sanitize,$(BUILD_TYPE)),$(CFLAGS_SANITIZE), \
|
||||
$(error Unknown build type: $(BUILD_TYPE)))))
|
||||
|
||||
LDFLAGS = -lm
|
||||
LDFLAGS_VERBOSE = -Wl,-v
|
||||
|
||||
SRCS = $(wildcard *.c)
|
||||
OBJS = $(SRCS:.c=.o)
|
||||
STATIC_LIB = libsparsemap.a
|
||||
SHARED_LIB = libsparsemap.so
|
||||
TEST_TARGETS = test/test test/soak test/ex_1 test/ex_2 test/ex_3 test/ex_4
|
||||
TEST_SRCS = $(filter-out $(wildcard test/ex_*) test/midl.c $(TEST_TARGETS:=.c), $(wildcard test/*.c))
|
||||
TEST_OBJS = $(TEST_SRCS:.c=.o)
|
||||
TEST_DEPS = $(filter-out $(TEST_TARGETS:=.h), $(TEST_SRCS:.c=.h))
|
||||
|
||||
LIBS = -lm
|
||||
#CFLAGS = -Wall -Wextra -Wpedantic -Of -std=c11 -Iinclude/ -fPIC
|
||||
#CFLAGS = -Wall -Wextra -Wpedantic -Og -g -std=c11 -Iinclude/ -fPIC
|
||||
CFLAGS = -DSPARSEMAP_DIAGNOSTIC -DDEBUG -Wall -Wextra -Wpedantic -O0 -g -std=c11 -Iinclude/ -fPIC
|
||||
#CFLAGS = -DSPARSEMAP_DIAGNOSTIC -DDEBUG -Wall -Wextra -Ofast -g -std=c11 -Iinclude/ -fPIC
|
||||
#CFLAGS = -Wall -Wextra -Wpedantic -Og -g -std=c11 -Iinclude/ -fPIC
|
||||
#CFLAGS = -Wall -Wextra -Wpedantic -Ofast -g -std=c11 -Iinclude/ -fPIC
|
||||
#CFLAGS = -DSPARSEMAP_DIAGNOSTIC -DDEBUG -Wall -Wextra -Wpedantic -Og -g -fsanitize=address,leak,object-size,pointer-compare,pointer-subtract,null,return,bounds,pointer-overflow,undefined -fsanitize-address-use-after-scope -std=c11 -Iinclude/ -fPIC
|
||||
#CFLAGS = -Wall -Wextra -Wpedantic -Og -g -fsanitize=all -fhardened -std=c11 -Iinclude/ -fPIC
|
||||
# Targets
|
||||
all: $(STATIC_LIB) $(SHARED_LIB)
|
||||
|
||||
TEST_FLAGS = -DDEBUG -Wall -Wextra -Wpedantic -O0 -g -std=c11 -Iinclude/ -Itests/ -fPIC
|
||||
#TEST_FLAGS = -Wall -Wextra -Wpedantic -Ofast -g -std=c11 -Iinclude/ -Itests/ -fPIC
|
||||
#TEST_FLAGS = -Wall -Wextra -Wpedantic -Og -g -std=c11 -Iinclude/ -Itests/ -fPIC
|
||||
#TEST_FLAGS = -DDEBUG -Wall -Wextra -Wpedantic -Og -g -fsanitize=address,leak,object-size,pointer-compare,pointer-subtract,null,return,bounds,pointer-overflow,undefined -fsanitize-address-use-after-scope -std=c11 -Iinclude/ -fPIC
|
||||
|
||||
TESTS = tests/test tests/soak
|
||||
TEST_OBJS = tests/test.o lib/munit.o lib/tdigest.o lib/common.o
|
||||
LIB_OBJS = lib/munit.o lib/tdigest.o lib/common.o lib/roaring.o
|
||||
EXAMPLES = examples/ex_1 examples/ex_2 examples/ex_3 examples/ex_4
|
||||
|
||||
.PHONY: all shared static clean test examples mls
|
||||
|
||||
all: static shared
|
||||
|
||||
static: $(STATIC_LIB)
|
||||
|
||||
shared: $(SHARED_LIB)
|
||||
info:
|
||||
$(info TEST_SRCS: $(TEST_SRCS))
|
||||
$(info TEST_OBJS: $(TEST_OBJS))
|
||||
$(info TEST_DEPS: $(TEST_DEPS))
|
||||
|
||||
$(STATIC_LIB): $(OBJS)
|
||||
ar rcs $(STATIC_LIB) $?
|
||||
ar rcs libsparsemap.a $(OBJS)
|
||||
|
||||
$(SHARED_LIB): $(OBJS)
|
||||
$(CC) $(CFLAGS) -o $@ $? -shared
|
||||
$(CC) -shared -o libsparsemap.so $(OBJS) $(LDFLAGS)
|
||||
|
||||
examples: $(STATIC_LIB) $(EXAMPLES) $(TEST_OBJS)
|
||||
check: $(TEST_TARGETS)
|
||||
|
||||
mls: examples/mls
|
||||
test/test: $(TEST_OBJS) $(STATIC_LIB) test/test.o
|
||||
$(CC) $^ $(LDFLAGS) -o $@
|
||||
|
||||
tests: $(TESTS)
|
||||
test/soak: $(TEST_OBJS) $(STATIC_LIB) test/soak.o
|
||||
$(CC) $^ $(LDFLAGS) -o $@
|
||||
|
||||
test: tests
|
||||
env ASAN_OPTIONS=detect_leaks=1 LSAN_OPTIONS=verbosity=1:log_threads=1 ./tests/test
|
||||
test/ex_1: test/ex_1.o $(STATIC_LIB)
|
||||
$(CC) $^ $(LDFLAGS) -o $@
|
||||
|
||||
soak: tests
|
||||
env ASAN_OPTIONS=detect_leaks=1 LSAN_OPTIONS=verbosity=1:log_threads=1 ./tests/soak
|
||||
test/ex_2: test/ex_2.o $(STATIC_LIB)
|
||||
$(CC) $^ $(LDFLAGS) -o $@
|
||||
|
||||
fuzzer: tests
|
||||
env ASAN_OPTIONS=detect_leaks=1 LSAN_OPTIONS=verbosity=1:log_threads=1 ./tests/fuzzer ./crash.case
|
||||
test/ex_3: test/ex_3.o $(STATIC_LIB)
|
||||
$(CC) $^ $(LDFLAGS) -o $@
|
||||
|
||||
tests/test: $(TEST_OBJS) $(LIB_OBJS) $(STATIC_LIB)
|
||||
$(CC) $^ $(LIBS) -o $@ $(TEST_FLAGS)
|
||||
test/ex_4: test/ex_4.o $(STATIC_LIB)
|
||||
$(CC) $^ $(LDFLAGS) -o $@
|
||||
|
||||
$(TEST_OBJS): $(TEST_SRCS) $(TEST_DEPS)
|
||||
$(CC) $(CFLAGS_TEST) -c $(subst .o,.c,$@) -o $@
|
||||
|
||||
$(OBJS): $(SRCS)
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
rm -f $(OBJS)
|
||||
rm -f examples/main.c
|
||||
rm -f $(STATIC_LIB) $(SHARED_LIB)
|
||||
rm -f $(TESTS) tests/*.o
|
||||
rm -f $(EXAMPLES) examples/*.o
|
||||
|
||||
format:
|
||||
clang-format -i src/sparsemap.c include/sparsemap.h examples/ex_*.c tests/soak.c tests/test.c tests/midl.c lib/common.c include/common.h
|
||||
# clang-format -i include/*.h src/*.c tests/*.c tests/*.h examples/*.c
|
||||
|
||||
%.o: src/%.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $^
|
||||
|
||||
lib/%.o: tests/%.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $^
|
||||
|
||||
tests/%.o: tests/%.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $^
|
||||
|
||||
examples/%.o: examples/%.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $^
|
||||
|
||||
examples/ex_1: $(LIB_OBJS) examples/ex_1.o $(STATIC_LIB)
|
||||
$(CC) $^ $(LIBS) -o $@ $(TEST_FLAGS)
|
||||
|
||||
examples/ex_2: $(LIB_OBJS) examples/ex_2.o $(STATIC_LIB)
|
||||
$(CC) $^ $(LIBS) -o $@ $(TEST_FLAGS)
|
||||
|
||||
examples/ex_3: $(LIB_OBJS) examples/ex_3.o $(STATIC_LIB)
|
||||
$(CC) $^ $(LIBS) -o $@ $(TEST_FLAGS)
|
||||
|
||||
examples/ex_4: $(LIB_OBJS) examples/ex_4.o $(STATIC_LIB)
|
||||
$(CC) $^ $(LIBS) -o $@ $(TEST_FLAGS)
|
||||
|
||||
tests/soak: $(LIB_OBJS) tests/soak.o $(STATIC_LIB)
|
||||
$(CC) $^ $(LIBS) -o $@ $(TEST_FLAGS)
|
||||
|
||||
tests/fuzzer: $(LIB_OBJS) tests/fuzzer.o $(STATIC_LIB)
|
||||
$(CC) $^ $(LIBS) -o $@ $(TEST_FLAGS) -DFUZZ_DEBUG
|
||||
|
||||
todo:
|
||||
rg -i 'todo|gsb|abort'
|
||||
|
||||
# cp src/sparsemap.c /tmp && clang-tidy src/sparsemap.c -fix -fix-errors -checks="readability-braces-around-statements" -- -DDEBUG -DSPARSEMAP_DIAGNOSTIC -DSPARSEMAP_ASSERT -Wall -Wextra -Wpedantic -Og -g -std=c11 -Iinclude/ -fPIC
|
||||
|
||||
# clear; make clean examples test && env ASAN_OPTIONS=detect_leaks=1 LSAN_OPTIONS=verbosity=1:log_threads=1 ./tests/test
|
||||
|
||||
# clear; make clean examples test && env ASAN_OPTIONS=detect_leaks=1 LSAN_OPTIONS=verbosity=1:log_threads=1 ./examples/soak
|
||||
rm -f libsparsemap.a libsparsemap.so $(OBJS) $(TEST_OBJS) \
|
||||
test/test test/soak test/ex_1 test/ex_2 test/ex_3 test/ex_4
|
||||
|
|
112
Makefile_
Normal file
112
Makefile_
Normal file
|
@ -0,0 +1,112 @@
|
|||
|
||||
OBJS = sparsemap.o
|
||||
STATIC_LIB = libsparsemap.a
|
||||
SHARED_LIB = libsparsemap.so
|
||||
|
||||
LIBS = -lm
|
||||
#CFLAGS = -Wall -Wextra -Wpedantic -Of -std=c11 -Iinclude/ -fPIC
|
||||
#CFLAGS = -Wall -Wextra -Wpedantic -Og -g -std=c11 -Iinclude/ -fPIC
|
||||
CFLAGS = -DSPARSEMAP_DIAGNOSTIC -DDEBUG -Wall -Wextra -Wpedantic -O0 -g -std=c11 -Iinclude/ -fPIC
|
||||
#CFLAGS = -DSPARSEMAP_DIAGNOSTIC -DDEBUG -Wall -Wextra -Ofast -g -std=c11 -Iinclude/ -fPIC
|
||||
#CFLAGS = -Wall -Wextra -Wpedantic -Og -g -std=c11 -Iinclude/ -fPIC
|
||||
#CFLAGS = -Wall -Wextra -Wpedantic -Ofast -g -std=c11 -Iinclude/ -fPIC
|
||||
#CFLAGS = -DSPARSEMAP_DIAGNOSTIC -DDEBUG -Wall -Wextra -Wpedantic -Og -g -fsanitize=address,leak,object-size,pointer-compare,pointer-subtract,null,return,bounds,pointer-overflow,undefined -fsanitize-address-use-after-scope -std=c11 -Iinclude/ -fPIC
|
||||
#CFLAGS = -Wall -Wextra -Wpedantic -Og -g -fsanitize=all -fhardened -std=c11 -Iinclude/ -fPIC
|
||||
|
||||
TEST_FLAGS = -DDEBUG -Wall -Wextra -Wpedantic -O0 -g -std=c11 -Iinclude/ -Ilib/ -fPIC
|
||||
#TEST_FLAGS = -Wall -Wextra -Wpedantic -Ofast -g -std=c11 -Iinclude/ -Ilib/ -fPIC
|
||||
#TEST_FLAGS = -Wall -Wextra -Wpedantic -Og -g -std=c11 -Iinclude/ -Ilib/ -fPIC
|
||||
#TEST_FLAGS = -DDEBUG -Wall -Wextra -Wpedantic -Og -g -fsanitize=address,leak,object-size,pointer-compare,pointer-subtract,null,return,bounds,pointer-overflow,undefined -fsanitize-address-use-after-scope -std=c11 -Iinclude/ -fPIC
|
||||
|
||||
TESTS = tests/test tests/soak
|
||||
LIB_SRCS = $(wildcard lib/*.c)
|
||||
LIB_OBJS = $(SRCS:.c=.o)
|
||||
EXAMPLES = examples/ex_1 examples/ex_2 examples/ex_3 examples/ex_4
|
||||
|
||||
.PHONY: all shared static clean test examples mls
|
||||
|
||||
all: static shared
|
||||
|
||||
static: $(STATIC_LIB)
|
||||
|
||||
shared: $(SHARED_LIB)
|
||||
|
||||
$(STATIC_LIB): $(OBJS)
|
||||
ar rcs $(STATIC_LIB) $?
|
||||
|
||||
$(SHARED_LIB): $(OBJS)
|
||||
$(CC) $(CFLAGS) -o $@ $? -shared
|
||||
|
||||
examples: $(STATIC_LIB) $(LIB_OBJS) $(EXAMPLES)
|
||||
|
||||
mls: examples/mls
|
||||
|
||||
tests: $(TESTS)
|
||||
|
||||
test: tests
|
||||
env ASAN_OPTIONS=detect_leaks=1 LSAN_OPTIONS=verbosity=1:log_threads=1 ./tests/test
|
||||
|
||||
soak: tests
|
||||
env ASAN_OPTIONS=detect_leaks=1 LSAN_OPTIONS=verbosity=1:log_threads=1 ./tests/soak
|
||||
|
||||
fuzzer: tests
|
||||
env ASAN_OPTIONS=detect_leaks=1 LSAN_OPTIONS=verbosity=1:log_threads=1 ./tests/fuzzer ./crash.case
|
||||
|
||||
lib/common.o: lib/common.h
|
||||
lib/munit.o: lib/munit.h
|
||||
lib/tdigest.o: lib/tdigest.h
|
||||
lib/roaring.o: lib/roaring.h
|
||||
lib/qc.o: lib/qc.h
|
||||
|
||||
tests/test: $(LIB_OBJS) $(STATIC_LIB) tests/test.o
|
||||
$(CC) $^ $(LIBS) -o $@ $(TEST_FLAGS)
|
||||
|
||||
clean:
|
||||
rm -f $(OBJS)
|
||||
rm -f examples/main.c
|
||||
rm -f $(STATIC_LIB) $(SHARED_LIB)
|
||||
rm -f $(TESTS) tests/*.o lib/*.o
|
||||
rm -f $(EXAMPLES) examples/*.o
|
||||
|
||||
format:
|
||||
clang-format -i src/sparsemap.c include/sparsemap.h examples/ex_*.c tests/soak.c tests/test.c tests/midl.c lib/common.c include/common.h
|
||||
# clang-format -i include/*.h src/*.c tests/*.c tests/*.h examples/*.c
|
||||
|
||||
%.o: src/%.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $^
|
||||
|
||||
lib/%.o: lib/%.c
|
||||
$(CC) $(TEST_CFLAGS) -c -o $@ $^
|
||||
|
||||
tests/%.o: tests/%.c
|
||||
$(CC) $(TEST_CFLAGS) -c -o $@ $^
|
||||
|
||||
examples/%.o: examples/%.c
|
||||
$(CC) $(TEST_CFLAGS) -c -o $@ $^
|
||||
|
||||
examples/ex_1: $(TEST_OBJS) examples/ex_1.o $(STATIC_LIB)
|
||||
$(CC) $^ $(LIBS) -o $@ $(TEST_FLAGS)
|
||||
|
||||
examples/ex_2: $(TEST_OBJS) examples/ex_2.o $(STATIC_LIB)
|
||||
$(CC) $^ $(LIBS) -o $@ $(TEST_FLAGS)
|
||||
|
||||
examples/ex_3: $(TEST_OBJS) examples/ex_3.o $(STATIC_LIB)
|
||||
$(CC) $^ $(LIBS) -o $@ $(TEST_FLAGS)
|
||||
|
||||
examples/ex_4: $(TEST_OBJS) examples/ex_4.o $(STATIC_LIB)
|
||||
$(CC) $^ $(LIBS) -o $@ $(TEST_FLAGS)
|
||||
|
||||
tests/soak: $(TEST_OBJS) tests/soak.o $(STATIC_LIB)
|
||||
$(CC) $^ $(LIBS) -o $@ $(TEST_FLAGS)
|
||||
|
||||
tests/fuzzer: $(TEST_OBJS) tests/fuzzer.o $(STATIC_LIB)
|
||||
$(CC) $^ $(LIBS) -o $@ $(TEST_FLAGS) -DFUZZ_DEBUG
|
||||
|
||||
todo:
|
||||
rg -i 'todo|gsb|abort'
|
||||
|
||||
# cp src/sparsemap.c /tmp && clang-tidy src/sparsemap.c -fix -fix-errors -checks="readability-braces-around-statements" -- -DDEBUG -DSPARSEMAP_DIAGNOSTIC -DSPARSEMAP_ASSERT -Wall -Wextra -Wpedantic -Og -g -std=c11 -Iinclude/ -fPIC
|
||||
|
||||
# clear; make clean examples test && env ASAN_OPTIONS=detect_leaks=1 LSAN_OPTIONS=verbosity=1:log_threads=1 ./tests/test
|
||||
|
||||
# clear; make clean examples test && env ASAN_OPTIONS=detect_leaks=1 LSAN_OPTIONS=verbosity=1:log_threads=1 ./examples/soak
|
|
@ -18,8 +18,8 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#include "../include/common.h"
|
||||
#include "../include/sparsemap.h"
|
||||
#include <common.h>
|
||||
#include <sparsemap.h>
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wvariadic-macros"
|
||||
|
@ -122,7 +122,7 @@ shuffle(int *array, size_t n)
|
|||
}
|
||||
}
|
||||
|
||||
int
|
||||
static int
|
||||
compare_ints(const void *a, const void *b)
|
||||
{
|
||||
return *(const int *)a - *(const int *)b;
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
#include "../include/sparsemap.h"
|
||||
#include <sparsemap.h>
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wvariadic-macros"
|
|
@ -4,7 +4,7 @@
|
|||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../include/sparsemap.h"
|
||||
#include <sparsemap.h>
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wvariadic-macros"
|
|
@ -3,7 +3,7 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../include/sparsemap.h"
|
||||
#include <sparsemap.h>
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wvariadic-macros"
|
785
test/qc.c
Normal file
785
test/qc.c
Normal file
|
@ -0,0 +1,785 @@
|
|||
/********************************************************************
|
||||
* Copyright (c) 2014, Andrea Zito
|
||||
* All rights reserved.
|
||||
*
|
||||
* License: BSD3
|
||||
********************************************************************/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "qc.h"
|
||||
|
||||
// TODO: fix these...
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wimplicit-function-declaration"
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
#pragma GCC diagnostic ignored "-Wint-conversion"
|
||||
#pragma GCC diagnostic ignored "-Wpedantic"
|
||||
|
||||
typedef void (*QCC_genRaw)(void *ptr);
|
||||
typedef void (*QCC_genRawR)(void *ptr, void *from, void *to);
|
||||
|
||||
struct QCC_Stamp {
|
||||
char *label;
|
||||
int n;
|
||||
struct QCC_Stamp *next;
|
||||
};
|
||||
|
||||
typedef struct QCC_Result {
|
||||
QCC_TestStatus status;
|
||||
QCC_Stamp *stamps;
|
||||
QCC_GenValue **arguments;
|
||||
int argumentsN;
|
||||
} QCC_Result;
|
||||
|
||||
enum QCC_deref_type { NONE, LONG, INT, FLOAT, DOUBLE, CHAR };
|
||||
|
||||
void
|
||||
QCC_init(int seed)
|
||||
{
|
||||
if (seed) {
|
||||
srandom(seed);
|
||||
} else {
|
||||
srandom(time(NULL));
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Generators helper functions
|
||||
***********************************************************************/
|
||||
static char *
|
||||
QCC_showSimpleValue(void *value, enum QCC_deref_type dt, int maxsize, const char *format)
|
||||
{
|
||||
char *vc = malloc(sizeof(char) * (maxsize + 1));
|
||||
|
||||
switch (dt) {
|
||||
case LONG:
|
||||
snprintf(vc, maxsize + 1, format, *(long *)value);
|
||||
break;
|
||||
case INT:
|
||||
snprintf(vc, maxsize + 1, format, *(int *)value);
|
||||
break;
|
||||
case FLOAT:
|
||||
snprintf(vc, maxsize + 1, format, *(float *)value);
|
||||
break;
|
||||
case DOUBLE:
|
||||
snprintf(vc, maxsize + 1, format, *(double *)value);
|
||||
break;
|
||||
case CHAR:
|
||||
snprintf(vc, maxsize + 1, format, *(char *)value);
|
||||
break;
|
||||
default:
|
||||
snprintf(vc, maxsize + 1, format, *(int *)value);
|
||||
break;
|
||||
}
|
||||
vc[maxsize] = 0;
|
||||
return vc;
|
||||
}
|
||||
|
||||
static void
|
||||
QCC_freeSimpleValue(void *value)
|
||||
{
|
||||
free(value);
|
||||
}
|
||||
|
||||
QCC_GenValue *
|
||||
QCC_initGenValue(void *value, int n, QCC_showValue show, QCC_freeValue free)
|
||||
{
|
||||
QCC_GenValue *gv = malloc(sizeof(QCC_GenValue));
|
||||
*gv = (QCC_GenValue) { .value = value, .n = n, .show = show, .free = free };
|
||||
|
||||
return gv;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Generators implementations
|
||||
***********************************************************************/
|
||||
|
||||
static char *
|
||||
QCC_showLong(void *value, int len)
|
||||
{
|
||||
return QCC_showSimpleValue(value, LONG, 21, "%ld");
|
||||
}
|
||||
|
||||
void
|
||||
QCC_genLongAtR(long *l, long *from, long *to)
|
||||
{
|
||||
long _from = *from;
|
||||
long _to = *to;
|
||||
unsigned long n = _to - _from;
|
||||
|
||||
if (n > RAND_MAX) {
|
||||
_from = _from + n / 2 - RAND_MAX / 2;
|
||||
_to = _from + n / 2 + RAND_MAX / 2;
|
||||
n = _to - _from;
|
||||
}
|
||||
*l = (random() % n) + _from;
|
||||
}
|
||||
|
||||
void
|
||||
QCC_genLongAt(long *l)
|
||||
{
|
||||
long from = QCC_LONG_FROM;
|
||||
long to = QCC_LONG_TO;
|
||||
QCC_genLongAtR(l, &from, &to);
|
||||
}
|
||||
|
||||
QCC_GenValue *
|
||||
QCC_genLongR(long from, long to)
|
||||
{
|
||||
long *v = malloc(sizeof(long));
|
||||
QCC_genLongAtR(v, &from, &to);
|
||||
|
||||
return QCC_initGenValue(v, 1, QCC_showLong, QCC_freeSimpleValue);
|
||||
}
|
||||
|
||||
QCC_GenValue *
|
||||
QCC_genLong()
|
||||
{
|
||||
return QCC_genLongR(QCC_LONG_FROM, QCC_LONG_TO);
|
||||
}
|
||||
|
||||
static char *
|
||||
QCC_showInt(void *value, int len)
|
||||
{
|
||||
return QCC_showSimpleValue(value, INT, 11, "%d");
|
||||
}
|
||||
|
||||
void
|
||||
QCC_genIntAtR(int *i, int *from, int *to)
|
||||
{
|
||||
int n = *to - *from;
|
||||
*i = (random() % n) + *from;
|
||||
}
|
||||
|
||||
void
|
||||
QCC_genIntAt(int *i)
|
||||
{
|
||||
int from = QCC_INT_FROM;
|
||||
int to = QCC_INT_TO;
|
||||
QCC_genIntAtR(i, &from, &to);
|
||||
}
|
||||
|
||||
QCC_GenValue *
|
||||
QCC_genIntR(int from, int to)
|
||||
{
|
||||
int *v = malloc(sizeof(int));
|
||||
QCC_genIntAtR(v, &from, &to);
|
||||
|
||||
return QCC_initGenValue(v, 1, QCC_showInt, QCC_freeSimpleValue);
|
||||
}
|
||||
|
||||
QCC_GenValue *
|
||||
QCC_genInt()
|
||||
{
|
||||
return QCC_genIntR(QCC_INT_FROM, QCC_INT_TO);
|
||||
}
|
||||
|
||||
static char *
|
||||
QCC_showDouble(void *value, int len)
|
||||
{
|
||||
return QCC_showSimpleValue(value, DOUBLE, 50, "%.12e");
|
||||
}
|
||||
|
||||
void
|
||||
QCC_genDoubleAtR(double *d, double *from, double *to)
|
||||
{
|
||||
double r = (double)random() / (double)RAND_MAX;
|
||||
*d = *from + (*to - *from) * r;
|
||||
}
|
||||
|
||||
void
|
||||
QCC_genDoubleAt(double *d)
|
||||
{
|
||||
double from = QCC_DOUBLE_FROM;
|
||||
double to = QCC_DOUBLE_TO;
|
||||
QCC_genDoubleAtR(d, &from, &to);
|
||||
}
|
||||
|
||||
QCC_GenValue *
|
||||
QCC_genDoubleR(double from, double to)
|
||||
{
|
||||
double *v = malloc(sizeof(double));
|
||||
QCC_genDoubleAtR(v, &from, &to);
|
||||
return QCC_initGenValue(v, 1, QCC_showDouble, QCC_freeSimpleValue);
|
||||
}
|
||||
|
||||
QCC_GenValue *
|
||||
QCC_genDouble()
|
||||
{
|
||||
return QCC_genDoubleR(QCC_DOUBLE_FROM, QCC_DOUBLE_TO);
|
||||
}
|
||||
|
||||
static char *
|
||||
QCC_showFloat(void *value, int len)
|
||||
{
|
||||
return QCC_showSimpleValue(value, FLOAT, 50, "%.12e");
|
||||
}
|
||||
|
||||
void
|
||||
QCC_genFloatAtR(float *f, float *from, float *to)
|
||||
{
|
||||
float r = (float)random() / (float)RAND_MAX;
|
||||
*f = *from + (*to - *from) * r;
|
||||
}
|
||||
|
||||
void
|
||||
QCC_genFloatAt(float *f)
|
||||
{
|
||||
float from = QCC_FLOAT_FROM;
|
||||
float to = QCC_FLOAT_TO;
|
||||
QCC_genFloatAtR(f, &from, &to);
|
||||
}
|
||||
|
||||
QCC_GenValue *
|
||||
QCC_genFloatR(float from, float to)
|
||||
{
|
||||
float *v = malloc(sizeof(float));
|
||||
QCC_genFloatAtR(v, &from, &to);
|
||||
|
||||
return QCC_initGenValue(v, 1, QCC_showFloat, QCC_freeSimpleValue);
|
||||
}
|
||||
|
||||
QCC_GenValue *
|
||||
QCC_genFloat()
|
||||
{
|
||||
return QCC_genFloatR(QCC_FLOAT_FROM, QCC_FLOAT_TO);
|
||||
}
|
||||
|
||||
static char *
|
||||
QCC_showBoolean(void *value, int len)
|
||||
{
|
||||
QCC_Boolean *b = (QCC_Boolean *)value;
|
||||
|
||||
if (*b) {
|
||||
return strdup("TRUE");
|
||||
} else {
|
||||
return strdup("FALSE");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
QCC_genBooleanAt(QCC_Boolean *b)
|
||||
{
|
||||
double r = (double)random() / (double)RAND_MAX;
|
||||
*b = r > 0.5 ? QCC_TRUE : QCC_FALSE;
|
||||
}
|
||||
|
||||
QCC_GenValue *
|
||||
QCC_genBoolean()
|
||||
{
|
||||
QCC_Boolean *v = malloc(sizeof(QCC_Boolean));
|
||||
QCC_genBooleanAt(v);
|
||||
|
||||
return QCC_initGenValue(v, 1, QCC_showBoolean, QCC_freeSimpleValue);
|
||||
}
|
||||
|
||||
static char *
|
||||
QCC_showChar(void *value, int len)
|
||||
{
|
||||
return QCC_showSimpleValue(value, CHAR, 3, "'%c'");
|
||||
}
|
||||
|
||||
void
|
||||
QCC_genCharAt(char *c)
|
||||
{
|
||||
*c = (char)(random() % 93) + 33;
|
||||
}
|
||||
|
||||
QCC_GenValue *
|
||||
QCC_genChar()
|
||||
{
|
||||
char *v = malloc(sizeof(char));
|
||||
QCC_genCharAt(v);
|
||||
|
||||
return QCC_initGenValue(v, 1, QCC_showChar, QCC_freeSimpleValue);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Array generators implementations
|
||||
***********************************************************************/
|
||||
|
||||
QCC_GenValue *
|
||||
QCC_genArrayOf(int len, QCC_genRaw elemGen, size_t elemSize, QCC_showValue show, QCC_freeValue free)
|
||||
{
|
||||
int n = random() % len;
|
||||
uint8_t *arr = malloc(n * elemSize);
|
||||
|
||||
int p, i;
|
||||
for (i = 0, p = 0; i < n; i++, p += elemSize)
|
||||
elemGen(arr + p);
|
||||
|
||||
return QCC_initGenValue(arr, n, show, free);
|
||||
}
|
||||
|
||||
QCC_GenValue *
|
||||
QCC_genArrayOfR(int len, QCC_genRawR elemGen, void *from, void *to, size_t elemSize, QCC_showValue show, QCC_freeValue free)
|
||||
{
|
||||
int n = random() % len;
|
||||
uint8_t *arr = malloc(n * elemSize);
|
||||
|
||||
int p, i;
|
||||
for (i = 0, p = 0; i < n; i++, p += elemSize)
|
||||
elemGen(arr + p, from, to);
|
||||
|
||||
return QCC_initGenValue(arr, n, show, free);
|
||||
}
|
||||
|
||||
static char *
|
||||
QCC_showString(void *value, int len)
|
||||
{
|
||||
return QCC_showSimpleValue(value, NONE, len, "%s");
|
||||
}
|
||||
|
||||
QCC_GenValue *
|
||||
QCC_genStringL(int len)
|
||||
{
|
||||
QCC_GenValue *s = QCC_genArrayOf(len, (QCC_genRaw)QCC_genCharAt, sizeof(char), QCC_showString, QCC_freeSimpleValue);
|
||||
((char *)s->value)[s->n - 1] = '\0';
|
||||
return s;
|
||||
}
|
||||
|
||||
QCC_GenValue *
|
||||
QCC_genString()
|
||||
{
|
||||
return QCC_genStringL(50);
|
||||
}
|
||||
|
||||
static char *
|
||||
QCC_showSimpleArray(void *value, size_t elemSize, QCC_showValue showValue, int len)
|
||||
{
|
||||
char **valStr = malloc(sizeof(char *) * len);
|
||||
int valStrLen = 0;
|
||||
int i;
|
||||
for (i = 0; i < len; i++) {
|
||||
valStr[i] = showValue(((uint8_t *)value) + (i * elemSize), 1);
|
||||
valStrLen += strlen(valStr[i]);
|
||||
}
|
||||
|
||||
int totStrLen = valStrLen + 2 + 2 * len + 1;
|
||||
char *str = malloc(sizeof(char) * totStrLen);
|
||||
sprintf(str, "[");
|
||||
int currLen = 1;
|
||||
for (i = 0; i < len; i++) {
|
||||
if (i == 0) {
|
||||
sprintf(str + currLen, "%s", valStr[i]);
|
||||
} else {
|
||||
sprintf(str + currLen, ", %s", valStr[i]);
|
||||
currLen += 2;
|
||||
}
|
||||
currLen += strlen(valStr[i]);
|
||||
free(valStr[i]);
|
||||
}
|
||||
sprintf(str + currLen, "]");
|
||||
free(valStr);
|
||||
return str;
|
||||
}
|
||||
|
||||
static char *
|
||||
QCC_showArrayLong(void *value, int n)
|
||||
{
|
||||
return QCC_showSimpleArray(value, sizeof(long), QCC_showLong, n);
|
||||
}
|
||||
|
||||
QCC_GenValue *
|
||||
QCC_genArrayLongLR(int len, long from, long to)
|
||||
{
|
||||
return QCC_genArrayOfR(len, (QCC_genRawR)QCC_genLongAtR, &from, &to, sizeof(long), QCC_showArrayLong, QCC_freeSimpleValue);
|
||||
}
|
||||
|
||||
QCC_GenValue *
|
||||
QCC_genArrayLongL(int len)
|
||||
{
|
||||
return QCC_genArrayOf(len, (QCC_genRaw)QCC_genLongAt, sizeof(long), QCC_showArrayLong, QCC_freeSimpleValue);
|
||||
}
|
||||
|
||||
QCC_GenValue *
|
||||
QCC_genArrayLong()
|
||||
{
|
||||
return QCC_genArrayOf(50, (QCC_genRaw)QCC_genLongAt, sizeof(long), QCC_showArrayLong, QCC_freeSimpleValue);
|
||||
}
|
||||
|
||||
static char *
|
||||
QCC_showArrayInt(void *value, int n)
|
||||
{
|
||||
return QCC_showSimpleArray(value, sizeof(int), QCC_showInt, n);
|
||||
}
|
||||
|
||||
QCC_GenValue *
|
||||
QCC_genArrayIntLR(int len, int from, int to)
|
||||
{
|
||||
return QCC_genArrayOfR(len, (QCC_genRawR)QCC_genIntAtR, &from, &to, sizeof(int), QCC_showArrayInt, QCC_freeSimpleValue);
|
||||
}
|
||||
|
||||
QCC_GenValue *
|
||||
QCC_genArrayIntL(int len)
|
||||
{
|
||||
return QCC_genArrayOf(len, (QCC_genRaw)QCC_genIntAt, sizeof(int), QCC_showArrayInt, QCC_freeSimpleValue);
|
||||
}
|
||||
|
||||
QCC_GenValue *
|
||||
QCC_genArrayInt()
|
||||
{
|
||||
return QCC_genArrayOf(50, (QCC_genRaw)QCC_genIntAt, sizeof(int), QCC_showArrayInt, QCC_freeSimpleValue);
|
||||
}
|
||||
|
||||
static char *
|
||||
QCC_showArrayDouble(void *value, int n)
|
||||
{
|
||||
return QCC_showSimpleArray(value, sizeof(double), QCC_showDouble, n);
|
||||
}
|
||||
|
||||
QCC_GenValue *
|
||||
QCC_genArrayDoubleLR(int len, double from, double to)
|
||||
{
|
||||
return QCC_genArrayOfR(len, (QCC_genRawR)QCC_genDoubleAtR, &from, &to, sizeof(double), QCC_showArrayDouble, QCC_freeSimpleValue);
|
||||
}
|
||||
|
||||
QCC_GenValue *
|
||||
QCC_genArrayDoubleL(int len)
|
||||
{
|
||||
return QCC_genArrayOf(len, (QCC_genRaw)QCC_genDoubleAt, sizeof(double), QCC_showArrayDouble, QCC_freeSimpleValue);
|
||||
}
|
||||
|
||||
QCC_GenValue *
|
||||
QCC_genArrayDouble()
|
||||
{
|
||||
return QCC_genArrayOf(50, (QCC_genRaw)QCC_genDoubleAt, sizeof(double), QCC_showArrayDouble, QCC_freeSimpleValue);
|
||||
}
|
||||
|
||||
static char *
|
||||
QCC_showArrayFloat(void *value, int n)
|
||||
{
|
||||
return QCC_showSimpleArray(value, sizeof(float), QCC_showFloat, n);
|
||||
}
|
||||
|
||||
QCC_GenValue *
|
||||
QCC_genArrayFloatLR(int len, float from, float to)
|
||||
{
|
||||
return QCC_genArrayOfR(len, (QCC_genRawR)QCC_genFloatAtR, &from, &to, sizeof(float), QCC_showArrayFloat, QCC_freeSimpleValue);
|
||||
}
|
||||
|
||||
QCC_GenValue *
|
||||
QCC_genArrayFloatL(int len)
|
||||
{
|
||||
return QCC_genArrayOf(len, (QCC_genRaw)QCC_genFloatAt, sizeof(float), QCC_showArrayFloat, QCC_freeSimpleValue);
|
||||
}
|
||||
|
||||
QCC_GenValue *
|
||||
QCC_genArrayFloat()
|
||||
{
|
||||
return QCC_genArrayOf(50, (QCC_genRaw)QCC_genFloatAt, sizeof(float), QCC_showArrayFloat, QCC_freeSimpleValue);
|
||||
}
|
||||
|
||||
static char *
|
||||
QCC_showArrayBoolean(void *value, int n)
|
||||
{
|
||||
return QCC_showSimpleArray(value, sizeof(QCC_Boolean), QCC_showBoolean, n);
|
||||
}
|
||||
|
||||
QCC_GenValue *
|
||||
QCC_genArrayBooleanL(int len)
|
||||
{
|
||||
return QCC_genArrayOf(len, (QCC_genRaw)QCC_genBooleanAt, sizeof(QCC_Boolean), QCC_showArrayBoolean, QCC_freeSimpleValue);
|
||||
}
|
||||
|
||||
QCC_GenValue *
|
||||
QCC_genArrayBoolean()
|
||||
{
|
||||
return QCC_genArrayOf(50, (QCC_genRaw)QCC_genBooleanAt, sizeof(QCC_Boolean), QCC_showArrayBoolean, QCC_freeSimpleValue);
|
||||
}
|
||||
|
||||
static char *
|
||||
QCC_showArrayChar(void *value, int n)
|
||||
{
|
||||
return QCC_showSimpleArray(value, sizeof(char), QCC_showChar, n);
|
||||
}
|
||||
|
||||
QCC_GenValue *
|
||||
QCC_genArrayCharL(int len)
|
||||
{
|
||||
return QCC_genArrayOf(len, (QCC_genRaw)QCC_genCharAt, sizeof(char), QCC_showArrayChar, QCC_freeSimpleValue);
|
||||
}
|
||||
|
||||
QCC_GenValue *
|
||||
QCC_genArrayChar()
|
||||
{
|
||||
return QCC_genArrayOf(50, (QCC_genRaw)QCC_genCharAt, sizeof(char), QCC_showArrayChar, QCC_freeSimpleValue);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Convenience functions
|
||||
***********************************************************************/
|
||||
QCC_TestStatus
|
||||
QCC_not(QCC_TestStatus propStatus)
|
||||
{
|
||||
switch (propStatus) {
|
||||
case QCC_OK:
|
||||
return QCC_FAIL;
|
||||
case QCC_FAIL:
|
||||
return QCC_OK;
|
||||
case QCC_NOTHING:
|
||||
return QCC_NOTHING;
|
||||
default:
|
||||
return QCC_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
QCC_TestStatus
|
||||
QCC_and(QCC_TestStatus prop1Status, QCC_TestStatus prop2Status)
|
||||
{
|
||||
switch (prop1Status) {
|
||||
case QCC_OK:
|
||||
return prop2Status;
|
||||
case QCC_FAIL:
|
||||
return QCC_FAIL;
|
||||
case QCC_NOTHING:
|
||||
return QCC_NOTHING;
|
||||
default:
|
||||
return QCC_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
QCC_TestStatus
|
||||
QCC_or(QCC_TestStatus prop1Status, QCC_TestStatus prop2Status)
|
||||
{
|
||||
switch (prop1Status) {
|
||||
case QCC_OK:
|
||||
return QCC_OK;
|
||||
case QCC_FAIL:
|
||||
case QCC_NOTHING:
|
||||
return prop2Status;
|
||||
default:
|
||||
return QCC_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
QCC_TestStatus
|
||||
QCC_xor(QCC_TestStatus prop1Status, QCC_TestStatus prop2Status)
|
||||
{
|
||||
switch (prop1Status) {
|
||||
case QCC_OK:
|
||||
return QCC_not(prop2Status);
|
||||
case QCC_FAIL:
|
||||
return prop2Status;
|
||||
case QCC_NOTHING:
|
||||
return QCC_NOTHING;
|
||||
default:
|
||||
return QCC_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Categorization function
|
||||
***********************************************************************/
|
||||
void
|
||||
QCC_freeStamp(QCC_Stamp *stamps)
|
||||
{
|
||||
QCC_Stamp *tstamps;
|
||||
QCC_Stamp *curr;
|
||||
for (tstamps = stamps; tstamps != NULL;) {
|
||||
curr = tstamps;
|
||||
tstamps = tstamps->next;
|
||||
free(curr->label);
|
||||
free(curr);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
QCC_insertOrdStamp(QCC_Stamp **stamps, QCC_Stamp *s)
|
||||
{
|
||||
QCC_Stamp *new = malloc(sizeof(QCC_Stamp));
|
||||
*new = (QCC_Stamp) { .label = strdup(s->label), .n = s->n, .next = NULL };
|
||||
|
||||
QCC_Stamp *tstamp = *stamps;
|
||||
QCC_Stamp **pre = stamps;
|
||||
while (tstamp) {
|
||||
if (tstamp->n < new->n) {
|
||||
break;
|
||||
} else {
|
||||
pre = &tstamp->next;
|
||||
tstamp = tstamp->next;
|
||||
}
|
||||
}
|
||||
*pre = new;
|
||||
new->next = tstamp;
|
||||
}
|
||||
|
||||
static QCC_Stamp *
|
||||
QCC_sortStamp(QCC_Stamp *stamps)
|
||||
{
|
||||
QCC_Stamp *sortedStamps = NULL;
|
||||
QCC_Stamp *tstamp;
|
||||
for (tstamp = stamps; tstamp != NULL; tstamp = tstamp->next) {
|
||||
QCC_insertOrdStamp(&sortedStamps, tstamp);
|
||||
}
|
||||
return sortedStamps;
|
||||
}
|
||||
|
||||
static void
|
||||
QCC_labelN(QCC_Stamp **stamps, char *label, int n)
|
||||
{
|
||||
QCC_Stamp *ptr = *stamps;
|
||||
QCC_Stamp *pre = NULL;
|
||||
QCC_Stamp *new;
|
||||
|
||||
while (ptr) {
|
||||
if (strcmp(ptr->label, label) == 0) {
|
||||
(ptr->n)++;
|
||||
return;
|
||||
}
|
||||
pre = ptr;
|
||||
ptr = ptr->next;
|
||||
}
|
||||
|
||||
new = malloc(sizeof(QCC_Stamp));
|
||||
*new = (QCC_Stamp) { .label = strdup(label), .n = 1, .next = NULL };
|
||||
|
||||
if (pre) {
|
||||
pre->next = new;
|
||||
} else {
|
||||
*stamps = new;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
QCC_label(QCC_Stamp **stamps, char *label)
|
||||
{
|
||||
return QCC_labelN(stamps, label, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
QCC_mergeLabels(QCC_Stamp **dst, QCC_Stamp *src)
|
||||
{
|
||||
for (; src != NULL; src = src->next)
|
||||
QCC_labelN(dst, src->label, src->n);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Testing functions
|
||||
***********************************************************************/
|
||||
void
|
||||
QCC_freeGenValues(QCC_GenValue **arguments, int argumentsN)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < argumentsN; i++) {
|
||||
arguments[i]->free(arguments[i]->value);
|
||||
free(arguments[i]);
|
||||
}
|
||||
if (arguments)
|
||||
free(arguments);
|
||||
}
|
||||
|
||||
void
|
||||
QCC_freeResult(QCC_Result *res)
|
||||
{
|
||||
QCC_freeStamp(res->stamps);
|
||||
QCC_freeGenValues(res->arguments, res->argumentsN);
|
||||
}
|
||||
|
||||
QCC_Result
|
||||
QCC_vforAll(QCC_property prop, int genNum, va_list genP)
|
||||
{ // QCC_gen *genLst,
|
||||
QCC_GenValue **vals = NULL;
|
||||
if (genNum) {
|
||||
int i;
|
||||
vals = malloc(sizeof(QCC_GenValue *) * genNum);
|
||||
for (i = 0; i < genNum; i++) {
|
||||
QCC_gen gen = va_arg(genP, QCC_gen);
|
||||
vals[i] = gen();
|
||||
}
|
||||
}
|
||||
|
||||
QCC_Stamp *stamps = NULL;
|
||||
QCC_TestStatus status = prop(vals, genNum, &stamps);
|
||||
return (QCC_Result) { .status = status, .stamps = stamps, .arguments = vals, .argumentsN = genNum };
|
||||
}
|
||||
|
||||
QCC_Result
|
||||
QCC_forAll(QCC_property prop, int genNum, ...)
|
||||
{ // QCC_gen *genLst,
|
||||
va_list genP;
|
||||
QCC_Result res;
|
||||
va_start(genP, genNum);
|
||||
res = QCC_vforAll(prop, genNum, genP);
|
||||
va_end(genP);
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
QCC_printStamps(QCC_Stamp *stamps, int n)
|
||||
{
|
||||
QCC_Stamp *sortedStamps = QCC_sortStamp(stamps);
|
||||
QCC_Stamp *tstamps;
|
||||
for (tstamps = sortedStamps; tstamps != NULL; tstamps = tstamps->next)
|
||||
printf("%.2f%%\t%s\n", (tstamps->n / (float)n) * 100, tstamps->label);
|
||||
if (sortedStamps)
|
||||
QCC_freeStamp(sortedStamps);
|
||||
}
|
||||
|
||||
static void
|
||||
QCC_printArguments(QCC_GenValue **arguments, int argumentsN)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < argumentsN; i++) {
|
||||
char *s = arguments[i]->show(arguments[i]->value, arguments[i]->n);
|
||||
printf("%s\n", s);
|
||||
free(s);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
QCC_testForAll(int num, int maxFail, QCC_property prop, int genNum, ...)
|
||||
{
|
||||
va_list genP;
|
||||
int succ = 0;
|
||||
int fail = 0;
|
||||
|
||||
QCC_Result res = { .status = QCC_OK };
|
||||
QCC_Stamp *stamps = NULL;
|
||||
while (succ < num && fail < maxFail) {
|
||||
va_start(genP, genNum);
|
||||
res = QCC_vforAll(prop, genNum, genP);
|
||||
va_end(genP);
|
||||
|
||||
if (res.status == QCC_FAIL) {
|
||||
break;
|
||||
} else {
|
||||
if (res.status == QCC_OK) {
|
||||
succ++;
|
||||
QCC_mergeLabels(&stamps, res.stamps);
|
||||
} else
|
||||
fail++;
|
||||
QCC_freeResult(&res);
|
||||
}
|
||||
}
|
||||
|
||||
if (succ == num) {
|
||||
printf("%d test passed (%d)!\n", succ, fail);
|
||||
QCC_printStamps(stamps, succ);
|
||||
if (stamps)
|
||||
QCC_freeStamp(stamps);
|
||||
return 0;
|
||||
} else if (res.status == QCC_FAIL) {
|
||||
printf("Falsifiable after %d test\n", succ + 1);
|
||||
QCC_printArguments(res.arguments, res.argumentsN);
|
||||
QCC_freeResult(&res);
|
||||
if (stamps)
|
||||
QCC_freeStamp(stamps);
|
||||
return 1;
|
||||
} else if (fail >= maxFail) {
|
||||
printf("Gave up after %d tests!\n", succ);
|
||||
QCC_printStamps(stamps, succ);
|
||||
if (stamps)
|
||||
QCC_freeStamp(stamps);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
280
test/qc.h
Normal file
280
test/qc.h
Normal file
|
@ -0,0 +1,280 @@
|
|||
/********************************************************************
|
||||
* Copyright (c) 2014, Andrea Zito
|
||||
* All rights reserved.
|
||||
*
|
||||
* License: BSD3
|
||||
********************************************************************/
|
||||
|
||||
#ifndef QUICKCHECK4C_C
|
||||
#define QUICKCHECK4C_C
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Default ranges used for type generation */
|
||||
#define QCC_LONG_FROM -RAND_MAX / 2
|
||||
#define QCC_LONG_TO RAND_MAX / 2
|
||||
#define QCC_INT_FROM -RAND_MAX / 2
|
||||
#define QCC_INT_TO RAND_MAX / 2
|
||||
#define QCC_DOUBLE_FROM ((double)-(RAND_MAX / 2))
|
||||
#define QCC_DOUBLE_TO ((double)(RAND_MAX / 2))
|
||||
#define QCC_FLOAT_FROM ((float)-(RAND_MAX / 2))
|
||||
#define QCC_FLOAT_TO ((float)(RAND_MAX / 2))
|
||||
|
||||
/**
|
||||
* Explicit definition of a boolean type compatible with
|
||||
* normal C boolean interpretation.
|
||||
*/
|
||||
typedef enum { QCC_TRUE = 1, QCC_FALSE = 0 } QCC_Boolean;
|
||||
|
||||
/**
|
||||
* Enumerator defining the evaluation of a property.
|
||||
* QCC_OK represent a satisfied property.
|
||||
* QCC_FAIL represent a falsified property.
|
||||
* QCC_NOTHING indicates a property that didn't fail
|
||||
* but should NOT be considered in the successes count or
|
||||
* categorization (used by QCC_IMPLY)
|
||||
*/
|
||||
typedef enum { QCC_OK = 1, QCC_FAIL = 0, QCC_NOTHING = -1 } QCC_TestStatus;
|
||||
|
||||
/**
|
||||
* Convenince macro to extract generated values inside a property.
|
||||
* Es: int a = *QCC_getValue(vals, 0, int*)
|
||||
*
|
||||
* @param vals A QCC_GenValue array
|
||||
* @param idx Index of the value to extract
|
||||
* @param type Type of the generated value
|
||||
*/
|
||||
#define QCC_getValue(vals, idx, type) ((type)vals[idx]->value)
|
||||
|
||||
/**
|
||||
* Signature of function used to represent values in a human readable
|
||||
* fashion.
|
||||
* Calling this function allocates memory that must be freed by the caller.
|
||||
*
|
||||
* @param value Pointer to the value to show
|
||||
* @param len Lenght of the data (used to keep track of array lengths)
|
||||
* @return String representation of the value.
|
||||
*/
|
||||
typedef char *(*QCC_showValue)(void *value, int len);
|
||||
|
||||
/**
|
||||
* Signature of function used to free generated values.
|
||||
*
|
||||
* @param value Pointer to the value to free
|
||||
*/
|
||||
typedef void (*QCC_freeValue)(void *value);
|
||||
|
||||
/**
|
||||
* Structure defining a generated value.
|
||||
* It specifies the value itself (alongside its length in case
|
||||
* of arrays), a function pointer for getting a human readable
|
||||
* string representation of the value and a function pointer to
|
||||
* free the memory allocated for the value.
|
||||
*
|
||||
* @param value Pointer to the memory allocated for the value
|
||||
* @param n Length of the value (1 for simple types, length for arrays)
|
||||
* @param show Function to get string representation of the value
|
||||
* @param free Function to free the memory of the value
|
||||
*/
|
||||
typedef struct QCC_GenValue {
|
||||
void *value;
|
||||
int n;
|
||||
QCC_showValue show;
|
||||
QCC_freeValue free;
|
||||
} QCC_GenValue;
|
||||
|
||||
/**
|
||||
* Opaque structure used to categorize test instances.
|
||||
* See QCC_property and QCC_label.
|
||||
*/
|
||||
typedef struct QCC_Stamp QCC_Stamp;
|
||||
|
||||
/**
|
||||
* Signature of functions used to generate random values
|
||||
*/
|
||||
typedef QCC_GenValue *(*QCC_gen)();
|
||||
|
||||
/**
|
||||
* Signature of property functions.
|
||||
*
|
||||
* @param vals Array of generated random values
|
||||
* @param len Number of generated values
|
||||
* @param stamp Used to categorize test instances via QCC_label
|
||||
*/
|
||||
typedef QCC_TestStatus (*QCC_property)(QCC_GenValue **vals, int len, QCC_Stamp **stamps);
|
||||
|
||||
/**
|
||||
* Implements logic implication.
|
||||
* The implication is satisfied if both the precondition and the property are
|
||||
* satisfied.
|
||||
* In case the precondition is not satisfied the special QCC_NOTHING value is
|
||||
* returned, indicating that the current test should not be considered as a
|
||||
* success.
|
||||
*
|
||||
* @param precondition A boolean condition
|
||||
* @param property A QCC_property to evaluate iff the precondition is satisfied
|
||||
* @return QCC_TestStatus
|
||||
*/
|
||||
#define QCC_imply(precondition, property) precondition ? property : QCC_NOTHING
|
||||
|
||||
/**
|
||||
* Convenience function to express property conjunction.
|
||||
* The function returns:
|
||||
* - QCC_OK iff prop1Status == prop2Status == QCC_OK
|
||||
* - QCC_FAIL iff prop1Status == QCC_FAIL || prop2Status == QCC_FAIL
|
||||
* - QCC_NOTHING iff prop1Status != QCC_FAIL && prop2Status != QCC_FAIL &&
|
||||
* (prop1Status == QCC_NOTHING || prop2Status == QCC_NOTHING)
|
||||
*
|
||||
* @param prop1Status The evaluation status of property 1
|
||||
* @param prop2Status The evaluation status of property 2
|
||||
* @return The evaluation status of the conjunction of property 1 and property 2
|
||||
*/
|
||||
QCC_TestStatus QCC_and(QCC_TestStatus prop1Status, QCC_TestStatus prop2Status);
|
||||
|
||||
/**
|
||||
* Convenience function to express property disjunction.
|
||||
* The function returns:
|
||||
* - QCC_OK iff prop1Status == QCC_OK || prop2Status == QCC_OK
|
||||
* - QCC_FAIL iff prop1Status == QCC_FAIL && prop2Status == QCC_FAIL
|
||||
* - QCC_NOTHING iff prop1Status != QCC_OK && prop2Status != QCC_OK &&
|
||||
* (prop1Status == QCC_NOTHING || prop2Status == QCC_NOTHING)
|
||||
*
|
||||
* @param prop1Status The evaluation status of property 1
|
||||
* @param prop2Status The evaluation status of property 2
|
||||
* @return The evaluation status of the disjunction of property 1 and property 2
|
||||
*/
|
||||
QCC_TestStatus QCC_or(QCC_TestStatus prop1Status, QCC_TestStatus prop2Status);
|
||||
|
||||
/**
|
||||
* Convenience function to express property exclusive disjunction.
|
||||
* The function returns:
|
||||
* - QCC_OK iff (prop1Status == QCC_OK && prop2Status == QCC_FAIL) ||
|
||||
* (prop1Status == QCC_FAIL && prop2Status == QCC_OK)
|
||||
* - QCC_FAIL iff prop1Status == prop2Status != QCC_NOTHING
|
||||
* - QCC_NOTHING iff prop1Status == QCC_NOTHING || prop2Status = QCC_NOTHING
|
||||
*
|
||||
* @param prop1Status The evaluation status of property 1
|
||||
* @param prop2Status The evaluation status of property 2
|
||||
* @return The evaluation status of the exclusive disjunction of property 1 and
|
||||
* property 2
|
||||
*/
|
||||
QCC_TestStatus QCC_xor(QCC_TestStatus prop1Status, QCC_TestStatus prop2Status);
|
||||
|
||||
/**
|
||||
* Convenience function to express property negation.
|
||||
* The function returns:
|
||||
* - QCC_OK iff propStatus == QCC_FAIL
|
||||
* - QCC_FAIL iff propStatus == QCC_OK
|
||||
* - QCC_NOTHING iff propStatus == QCC_NOTHING
|
||||
*/
|
||||
QCC_TestStatus QCC_not(QCC_TestStatus propStatus);
|
||||
|
||||
/**
|
||||
* Initialize the random generator using a specific seed.
|
||||
*
|
||||
* @param seed The seed to use or 0 to automatically select seed
|
||||
*/
|
||||
void QCC_init(int seed);
|
||||
|
||||
/**
|
||||
* Adds a label to the test stamps.
|
||||
*
|
||||
* @param stamps Stamps associated to the current test
|
||||
* @param label Label to add to the test stamps
|
||||
*/
|
||||
void QCC_label(QCC_Stamp **stamps, char *label);
|
||||
|
||||
/**
|
||||
* Test a property for num times allowing at most maxFail unsuccesful
|
||||
* argument generation.
|
||||
*
|
||||
* If all num test succede, the function outputs a success string and
|
||||
* return 0. If argument generation fails maxFail time before a success
|
||||
* string is printed reporting the number of success test cases and return -1.
|
||||
*
|
||||
* In both cases any label label gathered during test evaluation is printed
|
||||
* alongside its distribution.
|
||||
*
|
||||
* If a set of arguments falsifying the property is found, the testing is
|
||||
* interrupted immediately and a failure string is printed alongside the
|
||||
* set of arguments which caused the failure.
|
||||
*
|
||||
* @parm num Number of successful test to perform
|
||||
* @parm maxFail Maximum number of unsuccessful argument generation
|
||||
* (i.e. unsatisfied implication precondition)
|
||||
* @parm prop Property to test
|
||||
* @parm genNum Number of generators specified as vararg
|
||||
* @param ... genNum QCC_gen function to use as generators
|
||||
* @return 0 (all num test passed),
|
||||
* -1 (gave up after maxFail unsuccessful arguments generation),
|
||||
* 1 (property falsified)
|
||||
*/
|
||||
int QCC_testForAll(int num, int maxFail, QCC_property prop, int genNum, ...);
|
||||
|
||||
/*************************************************************
|
||||
* Helper function for generator definitions
|
||||
*************************************************************/
|
||||
|
||||
/**
|
||||
* Initialize a QCC_GenValue using the specified parameters
|
||||
*
|
||||
* @param value Raw generated balue
|
||||
* @param n Length of the value in case of an array (1 should be used otherwise)
|
||||
* @param show Pointer to a QCC_ShowValue function to use for displaying the raw
|
||||
* value
|
||||
* @param free Pointer to a QCC_FreeValue function to use for free the raw value
|
||||
* memory
|
||||
* @return Initialized QCC_GenValue
|
||||
*/
|
||||
QCC_GenValue *QCC_initGenValue(void *value, int n, QCC_showValue show, QCC_freeValue free);
|
||||
|
||||
/*************************************************************
|
||||
* Simple types generators
|
||||
*************************************************************/
|
||||
QCC_GenValue *QCC_genLong();
|
||||
QCC_GenValue *QCC_genLongR(long from, long to);
|
||||
|
||||
QCC_GenValue *QCC_genInt();
|
||||
QCC_GenValue *QCC_genIntR(int from, int to);
|
||||
|
||||
QCC_GenValue *QCC_genDouble();
|
||||
QCC_GenValue *QCC_genDoubleR(double from, double to);
|
||||
|
||||
QCC_GenValue *QCC_genFloat();
|
||||
QCC_GenValue *QCC_genFloatR(float from, float to);
|
||||
|
||||
QCC_GenValue *QCC_genBoolean();
|
||||
QCC_GenValue *QCC_genChar();
|
||||
|
||||
/*************************************************************
|
||||
* Array types generators
|
||||
*************************************************************/
|
||||
QCC_GenValue *QCC_genString();
|
||||
QCC_GenValue *QCC_genStringL(int len);
|
||||
|
||||
QCC_GenValue *QCC_genArrayLong();
|
||||
QCC_GenValue *QCC_genArrayLongL(int len);
|
||||
QCC_GenValue *QCC_genArrayLongLR(int len, long from, long to);
|
||||
|
||||
QCC_GenValue *QCC_genArrayInt();
|
||||
QCC_GenValue *QCC_genArrayIntL(int len);
|
||||
QCC_GenValue *QCC_genArrayIntLR(int len, int from, int to);
|
||||
|
||||
QCC_GenValue *QCC_genArrayDouble();
|
||||
QCC_GenValue *QCC_genArrayDoubleL(int len);
|
||||
QCC_GenValue *QCC_genArrayDoubleLR(int len, double from, double to);
|
||||
|
||||
QCC_GenValue *QCC_genArrayFloat();
|
||||
QCC_GenValue *QCC_genArrayFloatL(int len);
|
||||
QCC_GenValue *QCC_genArrayFloatLR(int len, float from, float to);
|
||||
|
||||
QCC_GenValue *QCC_genArrayBoolean();
|
||||
QCC_GenValue *QCC_genArrayBooleanL(int len);
|
||||
|
||||
QCC_GenValue *QCC_genArrayChar();
|
||||
QCC_GenValue *QCC_genArrayCharL(int len);
|
||||
|
||||
QCC_GenValue *QCC_genArrayString();
|
||||
QCC_GenValue *QCC_genArrayStringL(int len, int strLen);
|
||||
#endif
|
|
@ -10,10 +10,10 @@
|
|||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../include/common.h"
|
||||
#include "../include/roaring.h"
|
||||
#include "../include/sparsemap.h"
|
||||
#include "../include/tdigest.h"
|
||||
#include <common.h>
|
||||
#include <roaring.h>
|
||||
#include <sparsemap.h>
|
||||
#include <tdigest.h>
|
||||
|
||||
#include "midl.c"
|
||||
|
|
@ -15,9 +15,10 @@
|
|||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../include/sparsemap.h"
|
||||
#include "common.h"
|
||||
#include "munit.h"
|
||||
#include <sparsemap.h>
|
||||
#include <common.h>
|
||||
#include <munit.h>
|
||||
#include <qc.h>
|
||||
|
||||
#define munit_free free
|
||||
|
Loading…
Reference in a new issue