diff --git a/CMakeLists.txt b/CMakeLists.txt index 20ea83b..a00c23b 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,9 +2,9 @@ cmake_minimum_required(VERSION 3.12) set(PROJECT_NAME libguf) 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} PRIVATE src) @@ -12,46 +12,60 @@ set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_EXTENSIONS OFF) set(CMAKE_C_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_STANDARD 20) + if (NOT DEFINED CMAKE_RUNTIME_OUTPUT_DIRECTORY) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin) endif () -add_executable(libguf_test ${SOURCES} src/guf_test.c src/guf_test_dict_impl.c) -target_include_directories(libguf_test PRIVATE src) +add_executable(libguf_example src/test/guf_example.c src/test/guf_dict_impl.c) +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) - message("-- Configure libguf_test...") + message(STATUS "Configure libguf_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) - 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} $<$: ${DBG_FLAGS}>) - target_link_options(libguf_test PRIVATE ${WARNING_FLAGS_C} $<$: ${DBG_FLAGS}> ) + target_compile_options(libguf_test PRIVATE ${WARNING_FLAGS_CXX} $<$: ${DBG_FLAGS}>) + target_link_options(libguf_test PRIVATE ${WARNING_FLAGS_CXX} $<$: ${DBG_FLAGS}> ) message(STATUS "Configured libguf_test") endif() +if (TARGET libguf_example) + message(STATUS "Configure libguf_example...") + + target_compile_options(libguf_example PRIVATE ${WARNING_FLAGS_C} $<$: ${DBG_FLAGS}>) + target_link_options(libguf_example PRIVATE ${WARNING_FLAGS_C} $<$: ${DBG_FLAGS}> ) + + message(STATUS "Configured libguf_example") +endif() + diff --git a/dbuf_tests.py b/dbuf_tests.py deleted file mode 100644 index d2ff4c8..0000000 --- a/dbuf_tests.py +++ /dev/null @@ -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 \ No newline at end of file diff --git a/src/guf_dict.h b/src/guf_dict.h index 29151d7..b0770a5 100755 --- a/src/guf_dict.h +++ b/src/guf_dict.h @@ -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 *)); #endif + // #define GUF_DICT_IMPL /* DEBUGGGGGGGGG */ #if defined(GUF_DICT_IMPL) || defined(GUF_DICT_IMPL_STATIC) diff --git a/src/guf_rand.h b/src/guf_rand.h index e501664..f654dde 100644 --- a/src/guf_rand.h +++ b/src/guf_rand.h @@ -1,6 +1,8 @@ #ifndef GUF_RAND_H #define GUF_RAND_H +#include "guf_common.h" + #if defined(GUF_IMPL_STATIC) || defined(GUF_STATIC) #define GUF_FN_KEYWORDS static #else diff --git a/test/data_01.txt b/src/test/data/data_01.txt similarity index 100% rename from test/data_01.txt rename to src/test/data/data_01.txt diff --git a/src/test/guf_dbuf_impl.c b/src/test/guf_dbuf_impl.c new file mode 100644 index 0000000..01b9545 --- /dev/null +++ b/src/test/guf_dbuf_impl.c @@ -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" diff --git a/src/test/guf_dbuf_impl.h b/src/test/guf_dbuf_impl.h new file mode 100644 index 0000000..14b4d9d --- /dev/null +++ b/src/test/guf_dbuf_impl.h @@ -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 diff --git a/src/guf_test_dict_impl.c b/src/test/guf_dict_impl.c similarity index 94% rename from src/guf_test_dict_impl.c rename to src/test/guf_dict_impl.c index 96c59c4..ff7615c 100644 --- a/src/guf_test_dict_impl.c +++ b/src/test/guf_dict_impl.c @@ -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_EQ guf_cstr_const_eq diff --git a/src/guf_test_dict_impl.h b/src/test/guf_dict_impl.h similarity index 100% rename from src/guf_test_dict_impl.h rename to src/test/guf_dict_impl.h diff --git a/src/guf_test.c b/src/test/guf_example.c similarity index 99% rename from src/guf_test.c rename to src/test/guf_example.c index 6d61b1c..5574243 100644 --- a/src/guf_test.c +++ b/src/test/guf_example.c @@ -4,6 +4,7 @@ #include #include "guf_init.h" /* Must be included once */ + #include "guf_alloc_libc.h" #include "guf_cstr.h" @@ -46,7 +47,7 @@ #define GUF_IMPL_STATIC #include "guf_rand.h" -#include "guf_test_dict_impl.h" +#include "guf_dict_impl.h" int main(void) { diff --git a/src/test/guf_rand_impl.c b/src/test/guf_rand_impl.c new file mode 100644 index 0000000..51c6b8f --- /dev/null +++ b/src/test/guf_rand_impl.c @@ -0,0 +1,2 @@ +#define GUF_IMPL +#include "guf_rand.h" diff --git a/src/test/guf_test.cpp b/src/test/guf_test.cpp new file mode 100644 index 0000000..d7007fe --- /dev/null +++ b/src/test/guf_test.cpp @@ -0,0 +1,321 @@ +#include +#include +#include +#include +#include +#include +#include + +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 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::size_t operator()(const std::unique_ptr& test) + { + if (!test.get()) { + return 0; + } + return std::hash()(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 dbuf_to_vec(dbuf_int *dbuf) + { + std::vector 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 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 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::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::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(delta_t); + + done = true; + passed = (num_failed_checks == 0); + return passed; + } +}; + +// TODO: use std::unordered_set maybe +std::unordered_map> g_tests {}; + +void init_dbuf_tests() +{ + if (std::unique_ptr test = std::make_unique("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; +} \ No newline at end of file diff --git a/testgen.py b/testgen.py deleted file mode 100644 index 29d4946..0000000 --- a/testgen.py +++ /dev/null @@ -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)