Add C++ tests
This commit is contained in:
parent
4c35d180e8
commit
c1e125dfcb
@ -2,9 +2,9 @@ cmake_minimum_required(VERSION 3.12)
|
|||||||
set(PROJECT_NAME libguf)
|
set(PROJECT_NAME libguf)
|
||||||
project(${PROJECT_NAME})
|
project(${PROJECT_NAME})
|
||||||
|
|
||||||
set(SOURCES src/guf_str.c)
|
# set(SOURCES src/guf_str.c)
|
||||||
|
|
||||||
add_library(${PROJECT_NAME} STATIC ${SOURCES})
|
# add_library(${PROJECT_NAME} STATIC ${SOURCES})
|
||||||
# target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}}/lib/guf)
|
# target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}}/lib/guf)
|
||||||
# target_include_directories(${PROJECT_NAME} PRIVATE src)
|
# target_include_directories(${PROJECT_NAME} PRIVATE src)
|
||||||
|
|
||||||
@ -12,46 +12,60 @@ set(CMAKE_C_STANDARD_REQUIRED ON)
|
|||||||
set(CMAKE_C_EXTENSIONS OFF)
|
set(CMAKE_C_EXTENSIONS OFF)
|
||||||
set(CMAKE_C_STANDARD 17)
|
set(CMAKE_C_STANDARD 17)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
|
||||||
if (NOT DEFINED CMAKE_RUNTIME_OUTPUT_DIRECTORY)
|
if (NOT DEFINED CMAKE_RUNTIME_OUTPUT_DIRECTORY)
|
||||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin)
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
add_executable(libguf_test ${SOURCES} src/guf_test.c src/guf_test_dict_impl.c)
|
add_executable(libguf_example src/test/guf_example.c src/test/guf_dict_impl.c)
|
||||||
target_include_directories(libguf_test PRIVATE src)
|
target_include_directories(libguf_example PRIVATE src src/test)
|
||||||
|
|
||||||
|
add_executable(libguf_test src/test/guf_test.cpp src/test/guf_dict_impl.c src/test/guf_dbuf_impl.c src/test/guf_rand_impl.c)
|
||||||
|
target_include_directories(libguf_test PRIVATE src src/test)
|
||||||
|
|
||||||
|
if (NOT DEFINED MSVC)
|
||||||
|
set(WARNING_FLAGS_C -Wall -Wextra -Wpedantic -Wvla -Wshadow -Wundef -Wmisleading-indentation -Wnull-dereference -Wswitch-default -Wconversion -Wno-sign-conversion -Wdouble-promotion -Wno-unused-function)
|
||||||
|
set(WARNING_FLAGS_CXX -Wall -Wextra -Wpedantic -Wvla -Wshadow -Wundef -Wmisleading-indentation -Wnull-dereference -Wshadow -Wundef -Wstrict-overflow=5 -Wsign-promo -Wcast-align -Wcast-qual -Woverloaded-virtual -Wredundant-decls -Wctor-dtor-privacy -Wdisabled-optimization -Wformat=2 -Winit-self -Wswitch-default -Wno-unused-function)
|
||||||
|
set(DBG_FLAGS -fsanitize=undefined,address -g3 -glldb -Og)
|
||||||
|
else ()
|
||||||
|
set(WARNING_FLAGS_C /W4)
|
||||||
|
set(WARNING_FLAGS_CXX /W4)
|
||||||
|
set(DBG_FLAGS /fsanitize=address)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
if (NOT DEFINED CMAKE_DEBUG_POSTFIX)
|
||||||
|
set(CMAKE_DEBUG_POSTFIX _dbg)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
set_target_properties(libguf_example libguf_test PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})
|
||||||
|
|
||||||
|
include(CheckIPOSupported)
|
||||||
|
check_ipo_supported(RESULT ipo_available)
|
||||||
|
if (ipo_available AND (CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo"))
|
||||||
|
message(STATUS "LTO enabled")
|
||||||
|
set_target_properties(libguf_example libguf_test PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE)
|
||||||
|
else()
|
||||||
|
message(STATUS "LTO disabled")
|
||||||
|
endif()
|
||||||
|
|
||||||
if (TARGET libguf_test)
|
if (TARGET libguf_test)
|
||||||
message("-- Configure libguf_test...")
|
message(STATUS "Configure libguf_test...")
|
||||||
|
|
||||||
if (NOT DEFINED MSVC)
|
target_compile_options(libguf_test PRIVATE ${WARNING_FLAGS_CXX} $<$<CONFIG:Debug>: ${DBG_FLAGS}>)
|
||||||
set(WARNING_FLAGS_C -Wall -Wextra -Wpedantic -Wvla -Wshadow -Wundef -Wmisleading-indentation -Wnull-dereference -Wswitch-default -Wconversion -Wno-sign-conversion -Wdouble-promotion -Wno-unused-function)
|
target_link_options(libguf_test PRIVATE ${WARNING_FLAGS_CXX} $<$<CONFIG:Debug>: ${DBG_FLAGS}> )
|
||||||
else ()
|
|
||||||
set(WARNING_FLAGS_CXX /W4)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
include(CheckIPOSupported)
|
|
||||||
check_ipo_supported(RESULT ipo_available)
|
|
||||||
if (ipo_available AND (CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo"))
|
|
||||||
message(STATUS "LTO enabled")
|
|
||||||
set_target_properties(${PROJECT_NAME} PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE)
|
|
||||||
else()
|
|
||||||
message(STATUS "LTO disabled")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (NOT DEFINED CMAKE_DEBUG_POSTFIX)
|
|
||||||
set(CMAKE_DEBUG_POSTFIX _dbg)
|
|
||||||
endif ()
|
|
||||||
set_target_properties(libguf_test PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})
|
|
||||||
|
|
||||||
if (NOT DEFINED MSVC)
|
|
||||||
set(DBG_FLAGS -fsanitize=undefined,address -g3 -glldb -Og)
|
|
||||||
else ()
|
|
||||||
set(DBG_FLAGS /fsanitize=address)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_compile_options(libguf_test PRIVATE ${WARNING_FLAGS_C} $<$<CONFIG:Debug>: ${DBG_FLAGS}>)
|
|
||||||
target_link_options(libguf_test PRIVATE ${WARNING_FLAGS_C} $<$<CONFIG:Debug>: ${DBG_FLAGS}> )
|
|
||||||
|
|
||||||
message(STATUS "Configured libguf_test")
|
message(STATUS "Configured libguf_test")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (TARGET libguf_example)
|
||||||
|
message(STATUS "Configure libguf_example...")
|
||||||
|
|
||||||
|
target_compile_options(libguf_example PRIVATE ${WARNING_FLAGS_C} $<$<CONFIG:Debug>: ${DBG_FLAGS}>)
|
||||||
|
target_link_options(libguf_example PRIVATE ${WARNING_FLAGS_C} $<$<CONFIG:Debug>: ${DBG_FLAGS}> )
|
||||||
|
|
||||||
|
message(STATUS "Configured libguf_example")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
190
dbuf_tests.py
190
dbuf_tests.py
@ -1,190 +0,0 @@
|
|||||||
from functools import partial
|
|
||||||
from testgen import gen_test_struct, gen_res_str
|
|
||||||
|
|
||||||
DEFAULT_N = 4
|
|
||||||
test_funs = list()
|
|
||||||
|
|
||||||
def test_push(is_str = False, n = DEFAULT_N):
|
|
||||||
buf = list()
|
|
||||||
for i in range(n):
|
|
||||||
if is_str:
|
|
||||||
buf.append("element at index " + str(i))
|
|
||||||
else:
|
|
||||||
buf.append(i)
|
|
||||||
|
|
||||||
name = ""
|
|
||||||
if is_str:
|
|
||||||
name = "str"
|
|
||||||
return gen_test_struct(f"tst_push{name}", f"guf_dbuf_test: push {name}", gen_res_str(buf))
|
|
||||||
|
|
||||||
test_funs.append(partial(test_push, False))
|
|
||||||
test_funs.append(partial(test_push, True))
|
|
||||||
|
|
||||||
|
|
||||||
def test_insert_empty_front():
|
|
||||||
buf = list()
|
|
||||||
buf.insert(0, 3141)
|
|
||||||
return gen_test_struct("tst_insert_empty_front", "guf_dbuf_test: insert empty front", gen_res_str(buf))
|
|
||||||
|
|
||||||
test_funs.append(test_insert_empty_front)
|
|
||||||
|
|
||||||
def test_insert_empty_back():
|
|
||||||
buf = list()
|
|
||||||
buf.insert(1, 3141)
|
|
||||||
return gen_test_struct("tst_insert_empty_back", "guf_dbuf_test: insert empty back", gen_res_str(buf))
|
|
||||||
|
|
||||||
test_funs.append(test_insert_empty_back)
|
|
||||||
|
|
||||||
def test_insert(is_str = False, n = DEFAULT_N):
|
|
||||||
buf = list()
|
|
||||||
for i in range(n):
|
|
||||||
if i % 7 == 0:
|
|
||||||
idx = len(buf)
|
|
||||||
elif i % 2 == 0:
|
|
||||||
idx = 1
|
|
||||||
else:
|
|
||||||
assert(len(buf) > 0)
|
|
||||||
idx = len(buf) - 1
|
|
||||||
if is_str:
|
|
||||||
buf.insert(idx, f"element at index {idx}")
|
|
||||||
else:
|
|
||||||
buf.insert(idx, i)
|
|
||||||
|
|
||||||
if is_str:
|
|
||||||
start = "pi" * 64
|
|
||||||
end = "euler" * 64
|
|
||||||
else:
|
|
||||||
start = 3141
|
|
||||||
end = 2718
|
|
||||||
|
|
||||||
buf.insert(0, start)
|
|
||||||
buf.insert(len(buf), end)
|
|
||||||
|
|
||||||
buf.insert(1, start * 2)
|
|
||||||
buf.insert(len(buf) - 1, end * 2)
|
|
||||||
|
|
||||||
name = "int"
|
|
||||||
if is_str:
|
|
||||||
name = "str"
|
|
||||||
|
|
||||||
return gen_test_struct(f"tst_insert{name}", f"guf_dbuf_test: insert {name}", gen_res_str(buf))
|
|
||||||
|
|
||||||
test_funs.append(partial(test_insert, False))
|
|
||||||
test_funs.append(partial(test_insert, True))
|
|
||||||
|
|
||||||
def test_erase(is_str = False, n = DEFAULT_N):
|
|
||||||
buf = list()
|
|
||||||
for i in range(n):
|
|
||||||
if is_str:
|
|
||||||
buf.append("element at index " + str(i))
|
|
||||||
else:
|
|
||||||
buf.append(i)
|
|
||||||
|
|
||||||
for i, elem in enumerate(buf):
|
|
||||||
if i % 2 == 0:
|
|
||||||
del elem
|
|
||||||
|
|
||||||
name = "int"
|
|
||||||
if is_str:
|
|
||||||
name = "str"
|
|
||||||
|
|
||||||
return gen_test_struct(f"tst_erase{name}", f"guf_dbuf_test: erase {name}", gen_res_str(buf))
|
|
||||||
|
|
||||||
test_funs.append(partial(test_erase, False))
|
|
||||||
test_funs.append(partial(test_erase, True))
|
|
||||||
|
|
||||||
def test_erase_all(is_str = False, n = DEFAULT_N):
|
|
||||||
buf = list()
|
|
||||||
for i in range(n):
|
|
||||||
if is_str:
|
|
||||||
buf.append("element at index " + str(i))
|
|
||||||
else:
|
|
||||||
buf.append(i)
|
|
||||||
|
|
||||||
for i, elem in enumerate(buf):
|
|
||||||
del elem
|
|
||||||
|
|
||||||
name = "int"
|
|
||||||
if is_str:
|
|
||||||
name = "str"
|
|
||||||
return gen_test_struct(f"tst_remove{name}", f"guf_dbuf_test: erase {name} all", gen_res_str(buf))
|
|
||||||
|
|
||||||
test_funs.append(partial(test_erase_all, False))
|
|
||||||
test_funs.append(partial(test_erase_all, True))
|
|
||||||
|
|
||||||
def test_pop(is_str = False, n = DEFAULT_N):
|
|
||||||
buf = list()
|
|
||||||
|
|
||||||
for i in range(n):
|
|
||||||
if is_str:
|
|
||||||
buf.append("element at index " + str(i))
|
|
||||||
else:
|
|
||||||
buf.append(i)
|
|
||||||
|
|
||||||
new_buf = list()
|
|
||||||
for i in range(len(buf)):
|
|
||||||
new_buf.append(buf.pop())
|
|
||||||
|
|
||||||
new_buf.append(len(buf))
|
|
||||||
|
|
||||||
name = "int"
|
|
||||||
if is_str:
|
|
||||||
name = "str"
|
|
||||||
return gen_test_struct(f"tst_pop{name}", f"guf_dbuf_test: pop {name}", gen_res_str(buf))
|
|
||||||
|
|
||||||
test_funs.append(partial(test_pop, False))
|
|
||||||
test_funs.append(partial(test_pop, True))
|
|
||||||
|
|
||||||
def test_front_back(is_str = False, n = DEFAULT_N):
|
|
||||||
buf = list()
|
|
||||||
new_buf = list()
|
|
||||||
for i in range(n):
|
|
||||||
if is_str:
|
|
||||||
buf.append("element at index " + str(i))
|
|
||||||
else:
|
|
||||||
buf.append(i)
|
|
||||||
|
|
||||||
if i % 2:
|
|
||||||
new_buf.append(buf[0]) # front
|
|
||||||
else:
|
|
||||||
new_buf.append(buf[-1]) # back
|
|
||||||
|
|
||||||
if is_str:
|
|
||||||
new_buf[0] = "first elem"
|
|
||||||
new_buf[-1] = "last elem"
|
|
||||||
else:
|
|
||||||
new_buf[0] = 12345
|
|
||||||
new_buf[-1] = 54321
|
|
||||||
|
|
||||||
new_buf.append(len(new_buf))
|
|
||||||
|
|
||||||
name = "int"
|
|
||||||
if is_str:
|
|
||||||
name = "str"
|
|
||||||
return gen_test_struct(f"tst_front_back{name}", f"guf_dbuf_test: front() back() {name}", gen_res_str(new_buf))
|
|
||||||
|
|
||||||
test_funs.append(partial(test_front_back, False))
|
|
||||||
test_funs.append(partial(test_front_back, True))
|
|
||||||
|
|
||||||
def test_at(is_str = False, n = DEFAULT_N):
|
|
||||||
buf = list()
|
|
||||||
for i in range(n):
|
|
||||||
if is_str:
|
|
||||||
buf.append("element at index " + str(i))
|
|
||||||
else:
|
|
||||||
buf.append(i)
|
|
||||||
|
|
||||||
new_buf = list()
|
|
||||||
for elem in reversed(buf):
|
|
||||||
new_buf.append(elem * 2)
|
|
||||||
|
|
||||||
name = "int"
|
|
||||||
if is_str:
|
|
||||||
name = "str"
|
|
||||||
return gen_test_struct(f"tst_at{name}", f"guf_dbuf_test: at() {name}", gen_res_str(new_buf))
|
|
||||||
|
|
||||||
test_funs.append(partial(test_at, False))
|
|
||||||
test_funs.append(partial(test_at, True))
|
|
||||||
|
|
||||||
def all_tests():
|
|
||||||
return test_funs
|
|
||||||
@ -156,6 +156,7 @@ GUF_DICT_FN_KEYWORDS ptrdiff_t GUF_CAT(GUF_DICT_NAME, _iter_to_idx)(const GUF_DI
|
|||||||
GUF_DICT_FN_KEYWORDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _find_val_if)(GUF_DICT_NAME *ht, GUF_CAT(GUF_DICT_NAME, _iter) begin, GUF_CAT(GUF_DICT_NAME, _iter) end, bool (*predicate)(const GUF_DICT_VAL_T *));
|
GUF_DICT_FN_KEYWORDS GUF_CAT(GUF_DICT_NAME, _iter) GUF_CAT(GUF_DICT_NAME, _find_val_if)(GUF_DICT_NAME *ht, GUF_CAT(GUF_DICT_NAME, _iter) begin, GUF_CAT(GUF_DICT_NAME, _iter) end, bool (*predicate)(const GUF_DICT_VAL_T *));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// #define GUF_DICT_IMPL /* DEBUGGGGGGGGG */
|
// #define GUF_DICT_IMPL /* DEBUGGGGGGGGG */
|
||||||
|
|
||||||
#if defined(GUF_DICT_IMPL) || defined(GUF_DICT_IMPL_STATIC)
|
#if defined(GUF_DICT_IMPL) || defined(GUF_DICT_IMPL_STATIC)
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
#ifndef GUF_RAND_H
|
#ifndef GUF_RAND_H
|
||||||
#define GUF_RAND_H
|
#define GUF_RAND_H
|
||||||
|
|
||||||
|
#include "guf_common.h"
|
||||||
|
|
||||||
#if defined(GUF_IMPL_STATIC) || defined(GUF_STATIC)
|
#if defined(GUF_IMPL_STATIC) || defined(GUF_STATIC)
|
||||||
#define GUF_FN_KEYWORDS static
|
#define GUF_FN_KEYWORDS static
|
||||||
#else
|
#else
|
||||||
|
|||||||
28
src/test/guf_dbuf_impl.c
Normal file
28
src/test/guf_dbuf_impl.c
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#include "guf_dbuf_impl.h"
|
||||||
|
|
||||||
|
#define GUF_CNT_NAME dbuf_int
|
||||||
|
#define GUF_T int
|
||||||
|
#define GUF_T_IS_INTEGRAL_TYPE
|
||||||
|
#define GUF_IMPL
|
||||||
|
#include "guf_dbuf.h"
|
||||||
|
|
||||||
|
#define GUF_CNT_NAME dbuf_float
|
||||||
|
#define GUF_T float
|
||||||
|
#define GUF_T_IS_INTEGRAL_TYPE
|
||||||
|
#define GUF_IMPL
|
||||||
|
#include "guf_dbuf.h"
|
||||||
|
|
||||||
|
#define GUF_T guf_cstr_heap
|
||||||
|
#define GUF_CNT_NAME dbuf_heap_cstr
|
||||||
|
#define GUF_T_COPY guf_cstr_heap_copy
|
||||||
|
#define GUF_T_MOVE guf_cstr_heap_move
|
||||||
|
#define GUF_T_FREE guf_cstr_heap_free
|
||||||
|
#define GUF_T_EQ guf_cstr_heap_eq
|
||||||
|
#define GUF_IMPL
|
||||||
|
#include "guf_dbuf.h"
|
||||||
|
|
||||||
|
#define GUF_T guf_cstr_const
|
||||||
|
#define GUF_CNT_NAME dbuf_const_cstr
|
||||||
|
#define GUF_T_EQ guf_cstr_const_eq
|
||||||
|
#define GUF_IMPL
|
||||||
|
#include "guf_dbuf.h"
|
||||||
29
src/test/guf_dbuf_impl.h
Normal file
29
src/test/guf_dbuf_impl.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#ifndef GUF_DBUF_IMPL_H
|
||||||
|
#define GUF_DBUF_IMPL_H
|
||||||
|
|
||||||
|
#include "guf_cstr.h"
|
||||||
|
|
||||||
|
#define GUF_CNT_NAME dbuf_int
|
||||||
|
#define GUF_T int
|
||||||
|
#define GUF_T_IS_INTEGRAL_TYPE
|
||||||
|
#include "guf_dbuf.h"
|
||||||
|
|
||||||
|
#define GUF_CNT_NAME dbuf_float
|
||||||
|
#define GUF_T float
|
||||||
|
#define GUF_T_IS_INTEGRAL_TYPE
|
||||||
|
#include "guf_dbuf.h"
|
||||||
|
|
||||||
|
#define GUF_T guf_cstr_heap
|
||||||
|
#define GUF_CNT_NAME dbuf_heap_cstr
|
||||||
|
#define GUF_T_COPY guf_cstr_heap_copy
|
||||||
|
#define GUF_T_MOVE guf_cstr_heap_move
|
||||||
|
#define GUF_T_FREE guf_cstr_heap_free
|
||||||
|
#define GUF_T_EQ guf_cstr_heap_eq
|
||||||
|
#include "guf_dbuf.h"
|
||||||
|
|
||||||
|
#define GUF_T guf_cstr_const
|
||||||
|
#define GUF_CNT_NAME dbuf_const_cstr
|
||||||
|
#define GUF_T_EQ guf_cstr_const_eq
|
||||||
|
#include "guf_dbuf.h"
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -1,4 +1,4 @@
|
|||||||
#include "guf_test_dict_impl.h"
|
#include "guf_dict_impl.h"
|
||||||
|
|
||||||
#define GUF_DICT_KEY_T guf_cstr_const
|
#define GUF_DICT_KEY_T guf_cstr_const
|
||||||
#define GUF_DICT_KEY_T_EQ guf_cstr_const_eq
|
#define GUF_DICT_KEY_T_EQ guf_cstr_const_eq
|
||||||
@ -4,6 +4,7 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include "guf_init.h" /* Must be included once */
|
#include "guf_init.h" /* Must be included once */
|
||||||
|
|
||||||
#include "guf_alloc_libc.h"
|
#include "guf_alloc_libc.h"
|
||||||
#include "guf_cstr.h"
|
#include "guf_cstr.h"
|
||||||
|
|
||||||
@ -46,7 +47,7 @@
|
|||||||
#define GUF_IMPL_STATIC
|
#define GUF_IMPL_STATIC
|
||||||
#include "guf_rand.h"
|
#include "guf_rand.h"
|
||||||
|
|
||||||
#include "guf_test_dict_impl.h"
|
#include "guf_dict_impl.h"
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
2
src/test/guf_rand_impl.c
Normal file
2
src/test/guf_rand_impl.c
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#define GUF_IMPL
|
||||||
|
#include "guf_rand.h"
|
||||||
321
src/test/guf_test.cpp
Normal file
321
src/test/guf_test.cpp
Normal file
@ -0,0 +1,321 @@
|
|||||||
|
#include <vector>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <string>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <iostream>
|
||||||
|
#include <chrono>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#include "guf_init.h"
|
||||||
|
#include "guf_alloc_libc.h"
|
||||||
|
#include "guf_dbuf_impl.h"
|
||||||
|
#include "guf_dict_impl.h"
|
||||||
|
#include "guf_rand.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Test
|
||||||
|
{
|
||||||
|
const std::string name {};
|
||||||
|
std::chrono::duration<float, std::milli> runtime_ms {0};
|
||||||
|
bool passed {false}, done {false};
|
||||||
|
size_t num_failed_checks {0}, num_passed_checks {0};
|
||||||
|
|
||||||
|
Test(std::string& name) : name{name} {}
|
||||||
|
virtual ~Test() = default;
|
||||||
|
|
||||||
|
bool operator==(const Test &other) const {return name == other.name;}
|
||||||
|
|
||||||
|
size_t total_checks() const {return num_passed_checks + num_failed_checks;}
|
||||||
|
|
||||||
|
virtual bool run() = 0;
|
||||||
|
|
||||||
|
friend std::ostream& operator<<(std::ostream &os, const Test& tst)
|
||||||
|
{
|
||||||
|
std::ios_base::fmtflags os_flags = os.flags();
|
||||||
|
std::streamsize os_precision = os.precision();
|
||||||
|
|
||||||
|
os << tst.name << ": " << (tst.passed ? "PASS" : "FAIL");
|
||||||
|
os << std::fixed << std::setprecision(2);
|
||||||
|
os << " (" << tst.num_passed_checks << "/" << tst.total_checks() << ") in " << tst.runtime_ms.count() << " ms";
|
||||||
|
|
||||||
|
os.precision(os_precision);
|
||||||
|
os.flags(os_flags);
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct std::hash<std::unique_ptr<Test>> {
|
||||||
|
std::size_t operator()(const std::unique_ptr<Test>& test)
|
||||||
|
{
|
||||||
|
if (!test.get()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return std::hash<std::string>()(test.get()->name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#define GUF_TEST_CHECK(COND, MSG, TEST_OBJ_PTR) do { \
|
||||||
|
if (!(COND)) { \
|
||||||
|
std::cerr << this->name << ": FAILED CHECK " << MSG << " (line " << __LINE__ << " file " << __FILE__ << ")\n"; \
|
||||||
|
TEST_OBJ_PTR->num_failed_checks++; \
|
||||||
|
} else { \
|
||||||
|
TEST_OBJ_PTR->num_passed_checks++; \
|
||||||
|
} \
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
|
||||||
|
struct DbufIntTest : public Test
|
||||||
|
{
|
||||||
|
DbufIntTest(std::string name) : Test(name) {};
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::vector<int> dbuf_to_vec(dbuf_int *dbuf)
|
||||||
|
{
|
||||||
|
std::vector<int> vec;
|
||||||
|
GUF_CNT_FOREACH(dbuf, dbuf_int, it) {
|
||||||
|
vec.push_back(*it.ptr);
|
||||||
|
}
|
||||||
|
return vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_push(dbuf_int *dbuf, int n)
|
||||||
|
{
|
||||||
|
std::vector<int> vec = dbuf_to_vec(dbuf);
|
||||||
|
|
||||||
|
GUF_TEST_CHECK(std::ssize(vec) == dbuf->size, "test_push(): initial size", this);
|
||||||
|
|
||||||
|
for (int i = 0; i < n; ++i) {
|
||||||
|
dbuf_int_push_val(dbuf, i);
|
||||||
|
vec.push_back(i);
|
||||||
|
GUF_TEST_CHECK(*dbuf_int_back(dbuf) == vec.back(), "test_push(): equal while pushing", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
ptrdiff_t i = 0;
|
||||||
|
GUF_CNT_FOREACH(dbuf, dbuf_int, it) {
|
||||||
|
GUF_TEST_CHECK(*it.ptr == vec.at(i++), "test_push(): equal forward iteration", this);
|
||||||
|
}
|
||||||
|
GUF_TEST_CHECK(i == dbuf->size, "test_push(): size after iterating", this);
|
||||||
|
|
||||||
|
i = dbuf->size - 1;
|
||||||
|
GUF_CNT_FOREACH_REVERSE(dbuf, dbuf_int, rit) {
|
||||||
|
GUF_TEST_CHECK(*rit.ptr == vec.at(i--), "test_push(): equal reverse iteration", this);
|
||||||
|
}
|
||||||
|
GUF_TEST_CHECK(i == -1, "test_push(): size after reverse iteration", this);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_insert_remove(int n)
|
||||||
|
{
|
||||||
|
dbuf_int dbuf = {};
|
||||||
|
dbuf_int_init(&dbuf, 0, &guf_allocator_libc);
|
||||||
|
std::vector<int> vec = dbuf_to_vec(&dbuf);
|
||||||
|
|
||||||
|
guf_err err = GUF_ERR_NONE;
|
||||||
|
dbuf_int_try_erase(&dbuf, 0, &err);
|
||||||
|
GUF_TEST_CHECK(err == GUF_ERR_IDX_RANGE, "test_remove(): erase empty test 1", this);
|
||||||
|
|
||||||
|
err = GUF_ERR_NONE;
|
||||||
|
dbuf_int_try_erase(&dbuf, 12, &err);
|
||||||
|
GUF_TEST_CHECK(err == GUF_ERR_IDX_RANGE, "test_remove(): erase empty test 2", this);
|
||||||
|
|
||||||
|
err = GUF_ERR_NONE;
|
||||||
|
dbuf_int_try_front(&dbuf, &err);
|
||||||
|
GUF_TEST_CHECK(err == GUF_ERR_IDX_RANGE, "test_remove(): erase empty test 3", this);
|
||||||
|
|
||||||
|
err = GUF_ERR_NONE;
|
||||||
|
dbuf_int_try_back(&dbuf, &err);
|
||||||
|
GUF_TEST_CHECK(err == GUF_ERR_IDX_RANGE, "test_remove(): erase empty back 4", this);
|
||||||
|
|
||||||
|
err = GUF_ERR_NONE;
|
||||||
|
dbuf_int_try_at(&dbuf, 0, &err);
|
||||||
|
GUF_TEST_CHECK(err == GUF_ERR_IDX_RANGE, "test_remove(): erase empty back 5", this);
|
||||||
|
|
||||||
|
for (int i = 0; i < n; ++i) {
|
||||||
|
dbuf_int_insert_val(&dbuf, i, i);
|
||||||
|
dbuf_int_insert_val(&dbuf, i * 2, 0);
|
||||||
|
dbuf_int_insert_val(&dbuf, i * 4, dbuf.size);
|
||||||
|
|
||||||
|
vec.insert(vec.begin() + i, i);
|
||||||
|
vec.insert(vec.begin(), i * 2);
|
||||||
|
vec.insert(vec.end(), i * 4);
|
||||||
|
}
|
||||||
|
GUF_TEST_CHECK(std::ssize(vec) == dbuf.size, "test_remove(): size after insert", this);
|
||||||
|
|
||||||
|
// Iterate
|
||||||
|
dbuf_int_iter it_dbuf = dbuf_int_begin(&dbuf);
|
||||||
|
std::vector<int>::const_iterator it_vec = vec.begin();
|
||||||
|
while (!dbuf_int_iter_is_end(&dbuf, it_dbuf) && it_vec != vec.end()) {
|
||||||
|
GUF_TEST_CHECK(*it_dbuf.ptr == *it_vec, "test_remove(): iterate equal", this);
|
||||||
|
it_dbuf = dbuf_int_iter_next(&dbuf, it_dbuf, 1);
|
||||||
|
std::advance(it_vec, 1);
|
||||||
|
}
|
||||||
|
GUF_TEST_CHECK(dbuf_int_iter_is_end(&dbuf, it_dbuf) && it_vec == vec.end(), "test_remove(): iterate equal 2", this);
|
||||||
|
|
||||||
|
// Step iterate.
|
||||||
|
it_dbuf = dbuf_int_begin(&dbuf);
|
||||||
|
it_vec = vec.begin();
|
||||||
|
while (!dbuf_int_iter_is_end(&dbuf, it_dbuf) && it_vec != vec.end()) {
|
||||||
|
GUF_TEST_CHECK(*it_dbuf.ptr == *it_vec, "test_remove(): iterate step equal", this);
|
||||||
|
it_dbuf = dbuf_int_iter_next(&dbuf, it_dbuf, 7);
|
||||||
|
|
||||||
|
if (dbuf_int_iter_is_end(&dbuf, it_dbuf)) {
|
||||||
|
it_vec = vec.end();
|
||||||
|
} else {
|
||||||
|
std::advance(it_vec, 7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GUF_TEST_CHECK(dbuf_int_iter_is_end(&dbuf, it_dbuf) && it_vec == vec.end(), "test_remove(): iterat step equal 2", this);
|
||||||
|
|
||||||
|
// Reverse iterate.
|
||||||
|
dbuf_int_iter rit_dbuf = dbuf_int_rbegin(&dbuf);
|
||||||
|
std::vector<int>::const_reverse_iterator rit_vec = vec.crbegin();
|
||||||
|
while (!dbuf_int_iter_is_end(&dbuf, rit_dbuf) && rit_vec != vec.crend()) {
|
||||||
|
GUF_TEST_CHECK(*rit_dbuf.ptr == *rit_vec, "test_remove(): reverse iterate equal", this);
|
||||||
|
rit_dbuf = dbuf_int_iter_next(&dbuf, rit_dbuf, 1);
|
||||||
|
std::advance(rit_vec, 1);
|
||||||
|
}
|
||||||
|
GUF_TEST_CHECK(dbuf_int_iter_is_end(&dbuf, rit_dbuf) && rit_vec == vec.rend(), "test_remove(): reverse iterate equal 2", this);
|
||||||
|
|
||||||
|
// Reverse iterate step.
|
||||||
|
rit_dbuf = dbuf_int_rbegin(&dbuf);
|
||||||
|
rit_vec = vec.crbegin();
|
||||||
|
while (!dbuf_int_iter_is_end(&dbuf, rit_dbuf) && rit_vec != vec.crend()) {
|
||||||
|
GUF_TEST_CHECK(*rit_dbuf.ptr == *rit_vec, "test_remove(): reverse iterate step equal", this);
|
||||||
|
rit_dbuf = dbuf_int_iter_next(&dbuf, rit_dbuf, 4);
|
||||||
|
if (dbuf_int_iter_is_end(&dbuf, rit_dbuf)) {
|
||||||
|
rit_vec = vec.rend();
|
||||||
|
} else {
|
||||||
|
std::advance(rit_vec, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GUF_TEST_CHECK(dbuf_int_iter_is_end(&dbuf, rit_dbuf) && rit_vec == vec.rend(), "test_remove(): reverse iterate step equal 2", this);
|
||||||
|
|
||||||
|
|
||||||
|
GUF_TEST_CHECK(dbuf.size == std::ssize(vec), "test_remove(): size equal", this);
|
||||||
|
for (ptrdiff_t i = 0; i < dbuf.size; i += 8) {
|
||||||
|
dbuf_int_erase(&dbuf, i);
|
||||||
|
dbuf_int_erase(&dbuf, 0);
|
||||||
|
dbuf_int_pop(&dbuf);
|
||||||
|
|
||||||
|
vec.erase(vec.begin() + i);
|
||||||
|
vec.erase(vec.begin() + 0);
|
||||||
|
vec.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
GUF_TEST_CHECK(dbuf.size == std::ssize(vec), "test_remove(): size equal after remove", this);
|
||||||
|
|
||||||
|
for (ptrdiff_t i = 0; i < dbuf.size; i += 8) {
|
||||||
|
GUF_TEST_CHECK(*dbuf_int_at(&dbuf, i) == vec.at(i), "test_remove(): equal after remove", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ptrdiff_t size = dbuf.size;
|
||||||
|
for (ptrdiff_t i = 0; i < size; ++i) {
|
||||||
|
int a = dbuf_int_pop_cpy(&dbuf, GUF_CPY_VALUE);
|
||||||
|
int b = vec.back();
|
||||||
|
GUF_TEST_CHECK(a == b, "test_remove(): equal pop", this);
|
||||||
|
vec.pop_back();
|
||||||
|
}
|
||||||
|
GUF_TEST_CHECK(dbuf.size == 0 && vec.size() == 0, "test_remove(): equal after removing all", this);
|
||||||
|
|
||||||
|
dbuf_int_free(&dbuf, NULL);
|
||||||
|
GUF_TEST_CHECK(dbuf.size == 0 && dbuf.capacity == 0 && !dbuf.data, "test_remove(): state after free", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
bool run() override
|
||||||
|
{
|
||||||
|
if (done) {
|
||||||
|
return passed;
|
||||||
|
}
|
||||||
|
auto t0 = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
|
dbuf_int dbuf {};
|
||||||
|
dbuf_int_init(&dbuf, 0, &guf_allocator_libc);
|
||||||
|
|
||||||
|
test_push(&dbuf, 256);
|
||||||
|
test_push(&dbuf, 128);
|
||||||
|
test_push(&dbuf, 17);
|
||||||
|
GUF_TEST_CHECK(dbuf.size == (256 + 128 + 17), "run(): size after push", this);
|
||||||
|
|
||||||
|
dbuf_int_free(&dbuf, NULL);
|
||||||
|
GUF_TEST_CHECK(dbuf.size == 0 && dbuf.capacity == 0 && dbuf.data == NULL, "run(): size after free", this);
|
||||||
|
|
||||||
|
dbuf_int_init(&dbuf, 24, &guf_allocator_libc);
|
||||||
|
GUF_TEST_CHECK(dbuf.size == 0 && dbuf.capacity == 24 && dbuf.data, "run(): capacity after init with capacity", this);
|
||||||
|
|
||||||
|
test_push(&dbuf, 365);
|
||||||
|
test_push(&dbuf, 4);
|
||||||
|
test_push(&dbuf, 25);
|
||||||
|
test_push(&dbuf, 64);
|
||||||
|
GUF_TEST_CHECK(dbuf.size == (365 + 4 + 25 + 64), "run(): size after push", this);
|
||||||
|
|
||||||
|
dbuf_int_free(&dbuf, NULL);
|
||||||
|
GUF_TEST_CHECK(dbuf.size == 0 && dbuf.capacity == 0 && dbuf.data == NULL, "run(): size after free", this);
|
||||||
|
|
||||||
|
test_insert_remove(4);
|
||||||
|
test_insert_remove(5);
|
||||||
|
test_insert_remove(6);
|
||||||
|
test_insert_remove(7);
|
||||||
|
test_insert_remove(8);
|
||||||
|
test_insert_remove(9);
|
||||||
|
test_insert_remove(10);
|
||||||
|
test_insert_remove(11);
|
||||||
|
test_insert_remove(16);
|
||||||
|
test_insert_remove(17);
|
||||||
|
test_insert_remove(31);
|
||||||
|
test_insert_remove(32);
|
||||||
|
test_insert_remove(33);
|
||||||
|
test_insert_remove(64);
|
||||||
|
test_insert_remove(128);
|
||||||
|
test_insert_remove(400);
|
||||||
|
test_insert_remove(401);
|
||||||
|
test_insert_remove(512);
|
||||||
|
test_insert_remove(513);
|
||||||
|
test_insert_remove(601);
|
||||||
|
test_insert_remove(2048);
|
||||||
|
test_insert_remove(2049);
|
||||||
|
|
||||||
|
const auto delta_t = std::chrono::high_resolution_clock::now() - t0;
|
||||||
|
runtime_ms = std::chrono::duration_cast<decltype(runtime_ms)>(delta_t);
|
||||||
|
|
||||||
|
done = true;
|
||||||
|
passed = (num_failed_checks == 0);
|
||||||
|
return passed;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: use std::unordered_set maybe
|
||||||
|
std::unordered_map<std::string, std::unique_ptr<Test>> g_tests {};
|
||||||
|
|
||||||
|
void init_dbuf_tests()
|
||||||
|
{
|
||||||
|
if (std::unique_ptr<Test> test = std::make_unique<DbufIntTest>("DbufIntTest"); test.get() != NULL) {
|
||||||
|
g_tests.insert({test.get()->name, std::move(test)});
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("test is NULL");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
init_dbuf_tests();
|
||||||
|
|
||||||
|
bool all_passed = true;
|
||||||
|
|
||||||
|
for (auto& [name, test] : g_tests) {
|
||||||
|
if (Test *tst = test.get(); test.get() != NULL) {
|
||||||
|
tst->run();
|
||||||
|
std::cout << "- " << *tst << "\n";
|
||||||
|
all_passed = all_passed && tst->passed;
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("tst is NULL");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return all_passed ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||||
|
}
|
||||||
29
testgen.py
29
testgen.py
@ -1,29 +0,0 @@
|
|||||||
import textwrap
|
|
||||||
import dbuf_tests
|
|
||||||
|
|
||||||
def gen_test_struct(test_fn_name: str, name: str, expected_output: str) -> str:
|
|
||||||
return textwrap.dedent(f"""
|
|
||||||
(guf_test) {{
|
|
||||||
.test_fn = {test_fn_name}, .name = "{name}",
|
|
||||||
.expected_output = "{expected_output}",
|
|
||||||
.output = NULL,
|
|
||||||
.passed = false,
|
|
||||||
.runtime_ms = 0,
|
|
||||||
}}""")
|
|
||||||
|
|
||||||
def gen_res_str(buf):
|
|
||||||
res = ""
|
|
||||||
for elem in buf:
|
|
||||||
res += str(elem) + ","
|
|
||||||
res = res[:-1]
|
|
||||||
return res
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
test_array_definition = "static const guf_test dbuf_tests[] = {"
|
|
||||||
for test_fn in dbuf_tests.all_tests():
|
|
||||||
test_array_definition += textwrap.indent(test_fn() + ",", " ")
|
|
||||||
|
|
||||||
test_array_definition += "\n};"
|
|
||||||
|
|
||||||
print(test_array_definition)
|
|
||||||
Loading…
x
Reference in New Issue
Block a user