From 1dba7661e6354ad710a0388bb93d669b4400998f Mon Sep 17 00:00:00 2001 From: jun <83899451+zeichensystem@users.noreply.github.com> Date: Tue, 13 May 2025 21:14:20 +0200 Subject: [PATCH] Add math_ckdint tests --- CMakeLists.txt | 2 +- src/test/impls/ckdint_impl.c | 2 + src/test/test.cpp | 26 ++-- src/test/test_ckdint.cpp | 242 +++++++++++++++++++++++++++++++++++ src/test/test_ckdint.hpp | 12 ++ 5 files changed, 275 insertions(+), 9 deletions(-) create mode 100644 src/test/impls/ckdint_impl.c create mode 100644 src/test/test_ckdint.cpp create mode 100644 src/test/test_ckdint.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 672c22d..990ce53 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,7 +30,7 @@ endif () add_executable(libguf_example src/test/example.c src/test/impls/str_impl.c src/test/impls/dict_impl.c src/test/impls/linalg_impl.c) target_include_directories(libguf_example PRIVATE src src/test) -add_executable(libguf_test src/test/test.cpp src/test/test_dbuf.cpp src/test/test_dict.cpp src/test/test_str.cpp src/test/test_utf8.cpp src/test/impls/init_impl.c src/test/impls/dbuf_impl.c src/test/impls/str_impl.c src/test/impls/dict_impl.c src/test/impls/rand_impl.c src/test/impls/sort_impl.c src/test/impls/linalg_impl.c) +add_executable(libguf_test src/test/test.cpp src/test/test_dbuf.cpp src/test/test_dict.cpp src/test/test_str.cpp src/test/test_ckdint.cpp src/test/test_utf8.cpp src/test/impls/init_impl.c src/test/impls/dbuf_impl.c src/test/impls/str_impl.c src/test/impls/dict_impl.c src/test/impls/rand_impl.c src/test/impls/sort_impl.c src/test/impls/linalg_impl.c src/test/impls/ckdint_impl.c) target_include_directories(libguf_test PRIVATE src src/test) set_target_properties(libguf_example libguf_test PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) diff --git a/src/test/impls/ckdint_impl.c b/src/test/impls/ckdint_impl.c new file mode 100644 index 0000000..856029d --- /dev/null +++ b/src/test/impls/ckdint_impl.c @@ -0,0 +1,2 @@ +#define GUF_MATH_CKDINT_IMPL +#include "guf_math_ckdint.h" diff --git a/src/test/test.cpp b/src/test/test.cpp index 634f6f1..0a1a236 100644 --- a/src/test/test.cpp +++ b/src/test/test.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -7,35 +7,45 @@ #include "test_dict.hpp" #include "test_utf8.hpp" #include "test_str.hpp" +#include "test_ckdint.hpp" + extern "C" { #include "guf_assert.h" #include "guf_math.h" } -static std::unordered_set> g_tests {}; +static std::vector> g_tests {}; static void init_tests() { - std::unique_ptr test = std::make_unique("DbufIntTest"); + std::unique_ptr test; + + test = std::make_unique("CkdIntTest"); + GUF_ASSERT_RELEASE(test.get()) + g_tests.push_back(std::move(test)); + + test = std::make_unique("DbufIntTest"); GUF_ASSERT_RELEASE(test.get()); - g_tests.insert(std::move(test)); + g_tests.push_back(std::move(test)); test = std::make_unique("DbufCstringTest"); GUF_ASSERT_RELEASE(test.get()); - g_tests.insert(std::move(test)); + g_tests.push_back(std::move(test)); test = std::make_unique("DictSvToIntTest"); GUF_ASSERT_RELEASE(test.get()); - g_tests.insert(std::move(test)); + g_tests.push_back(std::move(test)); test = std::make_unique("UTF8Test"); GUF_ASSERT_RELEASE(test.get()); - g_tests.insert(std::move(test)); + g_tests.push_back(std::move(test)); test = std::make_unique("StrTest"); GUF_ASSERT_RELEASE(test.get()) - g_tests.insert(std::move(test)); + g_tests.push_back(std::move(test)); + + } int main() diff --git a/src/test/test_ckdint.cpp b/src/test/test_ckdint.cpp new file mode 100644 index 0000000..adbb423 --- /dev/null +++ b/src/test/test_ckdint.cpp @@ -0,0 +1,242 @@ +#include "test_ckdint.hpp" + +extern "C" +{ + #include "guf_math_ckdint.h" +} + +/* + CkdIntTest: +*/ + +void CkdIntTest::run() +{ + push_check_name("test_ckd"); + test_ckd(); + pop_check_name(); + + push_check_name("test_ckd_uint"); + test_ckd_uint(); + pop_check_name(); +} + +void CkdIntTest::test_ckd() +{ + for (int32_t a = INT8_MIN; a <= INT8_MAX; ++a) { + for (int32_t b = INT8_MIN; b <= INT8_MAX; ++b) { + const int32_t add_res = a + b; + const guf_math_ckd_result ckd_add = guf_ckd_add_i8(a, b); + TEST_CHECK(ckd_add == guf_ckd_add_i8(b, a)); + if (add_res > INT8_MAX) { + TEST_CHECK(ckd_add == GUF_MATH_CKD_OVERFLOW); + int8_t saturated, saturated2; + TEST_CHECK(guf_saturating_add_i8(static_cast(a), static_cast(b), &saturated) == GUF_MATH_CKD_OVERFLOW); + TEST_CHECK(saturated == INT8_MAX); + TEST_CHECK(guf_saturating_add_i8(static_cast(b), static_cast(a), &saturated2) == GUF_MATH_CKD_OVERFLOW); + TEST_CHECK(saturated == saturated2); + + int8_t wrapped, wrapped2; + TEST_CHECK(guf_wrapping_add_i8(static_cast(a), static_cast(b), &wrapped) == GUF_MATH_CKD_OVERFLOW); + TEST_CHECK(static_cast(wrapped) == INT8_MIN + (add_res % (INT8_MAX + 1))); + TEST_CHECK(guf_wrapping_add_i8(static_cast(b), static_cast(a), &wrapped2) == GUF_MATH_CKD_OVERFLOW); + TEST_CHECK(wrapped == wrapped2); + } + else if (add_res < INT8_MIN) { + TEST_CHECK(ckd_add == GUF_MATH_CKD_UNDERFLOW); + int8_t saturated, saturated2; + TEST_CHECK(guf_saturating_add_i8(static_cast(a), static_cast(b), &saturated) == GUF_MATH_CKD_UNDERFLOW); + TEST_CHECK(saturated == INT8_MIN); + TEST_CHECK(guf_saturating_add_i8(static_cast(b), static_cast(a), &saturated2) == GUF_MATH_CKD_UNDERFLOW); + TEST_CHECK(saturated == saturated2); + + int8_t wrapped, wrapped2; + TEST_CHECK(guf_wrapping_add_i8(static_cast(a), static_cast(b), &wrapped) == GUF_MATH_CKD_UNDERFLOW); + TEST_CHECK(static_cast(wrapped) == INT8_MAX - (-add_res % (-INT8_MIN + 1))); + TEST_CHECK(guf_wrapping_add_i8(static_cast(b), static_cast(a), &wrapped2) == GUF_MATH_CKD_UNDERFLOW); + TEST_CHECK(wrapped == wrapped2); + } + else { + TEST_CHECK(ckd_add == GUF_MATH_CKD_SUCCESS); + int8_t saturated, saturated2; + TEST_CHECK(guf_saturating_add_i8(static_cast(a), static_cast(b), &saturated) == GUF_MATH_CKD_SUCCESS); + TEST_CHECK(static_cast(saturated) == add_res); + TEST_CHECK(guf_saturating_add_i8(static_cast(b), static_cast(a), &saturated2) == GUF_MATH_CKD_SUCCESS); + TEST_CHECK(saturated == saturated2); + + int8_t wrapped, wrapped2; + TEST_CHECK(guf_wrapping_add_i8(static_cast(a), static_cast(b), &wrapped) == GUF_MATH_CKD_SUCCESS); + TEST_CHECK(static_cast(wrapped) == add_res); + TEST_CHECK(guf_wrapping_add_i8(static_cast(b), static_cast(a), &wrapped2) == GUF_MATH_CKD_SUCCESS); + TEST_CHECK(wrapped == wrapped2); + } + + const int32_t sub_res = a - b; + const guf_math_ckd_result ckd_sub = guf_ckd_sub_i8(a, b); + if (sub_res > INT8_MAX) { + TEST_CHECK(ckd_sub == GUF_MATH_CKD_OVERFLOW); + int8_t saturated; + TEST_CHECK(guf_saturating_sub_i8(static_cast(a), static_cast(b), &saturated) == GUF_MATH_CKD_OVERFLOW); + TEST_CHECK(saturated == INT8_MAX); + int8_t wrapped; + TEST_CHECK(guf_wrapping_sub_i8(static_cast(a), static_cast(b), &wrapped) == GUF_MATH_CKD_OVERFLOW); + TEST_CHECK(static_cast(wrapped) == INT8_MIN + (sub_res % (INT8_MAX + 1))); + } else if (sub_res < INT8_MIN) { + TEST_CHECK(ckd_sub == GUF_MATH_CKD_UNDERFLOW); + int8_t saturated; + TEST_CHECK(guf_saturating_sub_i8(static_cast(a), static_cast(b), &saturated) == GUF_MATH_CKD_UNDERFLOW); + TEST_CHECK(saturated == INT8_MIN); + int8_t wrapped; + TEST_CHECK(guf_wrapping_sub_i8(static_cast(a), static_cast(b), &wrapped) == GUF_MATH_CKD_UNDERFLOW); + TEST_CHECK(static_cast(wrapped) == INT8_MAX - (-sub_res % (-INT8_MIN + 1))); + } else { + TEST_CHECK(ckd_sub == GUF_MATH_CKD_SUCCESS); + int8_t saturated; + TEST_CHECK(guf_saturating_sub_i8(static_cast(a), static_cast(b), &saturated) == GUF_MATH_CKD_SUCCESS); + TEST_CHECK(static_cast(saturated) == sub_res); + int8_t wrapped; + TEST_CHECK(guf_wrapping_sub_i8(static_cast(a), static_cast(b), &wrapped) == GUF_MATH_CKD_SUCCESS); + TEST_CHECK(static_cast(wrapped) == sub_res); + } + + const int32_t mul_res = a * b; + const guf_math_ckd_result ckd_mul = guf_ckd_mul_i8(a, b); + TEST_CHECK(ckd_mul == guf_ckd_mul_i8(b, a)); + if (mul_res > INT8_MAX) { + TEST_CHECK(ckd_mul == GUF_MATH_CKD_OVERFLOW); + int8_t saturated, saturated2; + TEST_CHECK(guf_saturating_mul_i8(static_cast(a), static_cast(b), &saturated) == GUF_MATH_CKD_OVERFLOW); + TEST_CHECK(saturated == INT8_MAX); + + TEST_CHECK(guf_saturating_mul_i8(static_cast(b), static_cast(a), &saturated2) == GUF_MATH_CKD_OVERFLOW); + TEST_CHECK(saturated == saturated2); + + int8_t wrapped, wrapped2; + TEST_CHECK(guf_wrapping_mul_i8(static_cast(a), static_cast(b), &wrapped) == GUF_MATH_CKD_OVERFLOW); + TEST_CHECK(guf_wrapping_mul_i8(static_cast(b), static_cast(a), &wrapped2) == GUF_MATH_CKD_OVERFLOW); + TEST_CHECK(wrapped == wrapped2); + // TODO: check wrapped + } else if (mul_res < INT8_MIN) { + TEST_CHECK(ckd_mul == GUF_MATH_CKD_UNDERFLOW); + int8_t saturated, saturated2; + TEST_CHECK(guf_saturating_mul_i8(static_cast(a), static_cast(b), &saturated) == GUF_MATH_CKD_UNDERFLOW); + TEST_CHECK(saturated == INT8_MIN); + + TEST_CHECK(guf_saturating_mul_i8(static_cast(b), static_cast(a), &saturated2) == GUF_MATH_CKD_UNDERFLOW); + TEST_CHECK(saturated == saturated2); + + int8_t wrapped, wrapped2; + TEST_CHECK(guf_wrapping_mul_i8(static_cast(a), static_cast(b), &wrapped) == GUF_MATH_CKD_UNDERFLOW); + TEST_CHECK(guf_wrapping_mul_i8(static_cast(b), static_cast(a), &wrapped2) == GUF_MATH_CKD_UNDERFLOW); + TEST_CHECK(wrapped == wrapped2); + // TODO: check wrapped + } else { + TEST_CHECK(ckd_mul == GUF_MATH_CKD_SUCCESS); + int8_t saturated, saturated2; + TEST_CHECK(guf_saturating_mul_i8(static_cast(a), static_cast(b), &saturated) == GUF_MATH_CKD_SUCCESS); + TEST_CHECK(static_cast(saturated) == mul_res); + + TEST_CHECK(guf_saturating_mul_i8(static_cast(b), static_cast(a), &saturated2) == GUF_MATH_CKD_SUCCESS); + TEST_CHECK(saturated == saturated2); + + int8_t wrapped, wrapped2; + TEST_CHECK(guf_wrapping_mul_i8(static_cast(a), static_cast(b), &wrapped) == GUF_MATH_CKD_SUCCESS); + TEST_CHECK(static_cast(wrapped) == mul_res); + TEST_CHECK(guf_wrapping_mul_i8(static_cast(b), static_cast(a), &wrapped2) == GUF_MATH_CKD_SUCCESS); + TEST_CHECK(wrapped == wrapped2); + } + } + } + + int8_t mul_i8_res = -1; + TEST_CHECK(guf_wrapping_mul_i8(42, 5, &mul_i8_res) == GUF_MATH_CKD_OVERFLOW); + TEST_CHECK(mul_i8_res == -46); + mul_i8_res = -1; + TEST_CHECK(guf_wrapping_mul_i8(5, 42, &mul_i8_res) == GUF_MATH_CKD_OVERFLOW); + TEST_CHECK(mul_i8_res == -46); + + int32_t mul_i32_res = -1; + TEST_CHECK(guf_wrapping_mul_i32(42002718, 314159265, &mul_i32_res) == GUF_MATH_CKD_OVERFLOW); + TEST_CHECK(mul_i32_res == -972735522); + mul_i32_res = -1; + TEST_CHECK(guf_wrapping_mul_i32(314159265, 42002718, &mul_i32_res) == GUF_MATH_CKD_OVERFLOW); + TEST_CHECK(mul_i32_res == -972735522); + + ptrdiff_t ptrdiff_res = -1234; + TEST_CHECK(guf_saturating_add_ptrdiff_t(PTRDIFF_MAX, 1, &ptrdiff_res) == GUF_MATH_CKD_OVERFLOW); + TEST_CHECK(ptrdiff_res == PTRDIFF_MAX); + TEST_CHECK(guf_saturating_add_ptrdiff_t(PTRDIFF_MIN, -1, &ptrdiff_res) == GUF_MATH_CKD_UNDERFLOW); + TEST_CHECK(ptrdiff_res == PTRDIFF_MIN); + + TEST_CHECK(guf_saturating_mul_ptrdiff_t(PTRDIFF_MAX, 2, &ptrdiff_res) == GUF_MATH_CKD_OVERFLOW); + TEST_CHECK(ptrdiff_res == PTRDIFF_MAX); + TEST_CHECK(guf_saturating_mul_ptrdiff_t(PTRDIFF_MIN, 2, &ptrdiff_res) == GUF_MATH_CKD_UNDERFLOW); + TEST_CHECK(ptrdiff_res == PTRDIFF_MIN); +} + +void CkdIntTest::test_ckd_uint() +{ + for (int32_t a = 0; a <= UINT8_MAX; ++a) { + for (int32_t b = 0; b <= UINT8_MAX; ++b) { + const int32_t add_res = a + b; + const guf_math_ckd_result ckd_add = guf_ckd_add_u8(a, b); + if (add_res > UINT8_MAX) { + TEST_CHECK(ckd_add == GUF_MATH_CKD_OVERFLOW); + uint8_t saturated; + TEST_CHECK(guf_saturating_add_u8(static_cast(a), static_cast(b), &saturated) == GUF_MATH_CKD_OVERFLOW); + TEST_CHECK(saturated == UINT8_MAX); + uint8_t wrapped; + TEST_CHECK(guf_wrapping_add_u8(static_cast(a), static_cast(b), &wrapped) == GUF_MATH_CKD_OVERFLOW); + TEST_CHECK(static_cast(wrapped) == 0 + (add_res % (UINT8_MAX + 1))); + } + else { + TEST_CHECK(ckd_add == GUF_MATH_CKD_SUCCESS); + uint8_t saturated; + TEST_CHECK(guf_saturating_add_u8(static_cast(a), static_cast(b), &saturated) == GUF_MATH_CKD_SUCCESS); + TEST_CHECK(static_cast(saturated) == add_res); + uint8_t wrapped; + TEST_CHECK(guf_wrapping_add_u8(static_cast(a), static_cast(b), &wrapped) == GUF_MATH_CKD_SUCCESS); + TEST_CHECK(static_cast(wrapped) == add_res); + } + + const int32_t sub_res = a - b; + const guf_math_ckd_result ckd_sub = guf_ckd_sub_u8(a, b); + if (sub_res < 0) { + TEST_CHECK(ckd_sub == GUF_MATH_CKD_UNDERFLOW); + uint8_t saturated; + TEST_CHECK(guf_saturating_sub_u8(static_cast(a), static_cast(b), &saturated) == GUF_MATH_CKD_UNDERFLOW); + TEST_CHECK(saturated == 0); + uint8_t wrapped; + TEST_CHECK(guf_wrapping_sub_u8(static_cast(a), static_cast(b), &wrapped) == GUF_MATH_CKD_UNDERFLOW); + TEST_CHECK(wrapped == static_cast(static_cast(a) - static_cast(b))); + } else { + TEST_CHECK(ckd_sub == GUF_MATH_CKD_SUCCESS); + uint8_t saturated; + TEST_CHECK(guf_saturating_sub_u8(static_cast(a), static_cast(b), &saturated) == GUF_MATH_CKD_SUCCESS); + TEST_CHECK(static_cast(saturated) == sub_res); + uint8_t wrapped; + TEST_CHECK(guf_wrapping_sub_u8(static_cast(a), static_cast(b), &wrapped) == GUF_MATH_CKD_SUCCESS); + TEST_CHECK(static_cast(wrapped) == sub_res); + } + + const int32_t mul_res = a * b; + const guf_math_ckd_result ckd_mul = guf_ckd_mul_u8(a, b); + if (mul_res > UINT8_MAX) { + TEST_CHECK(ckd_mul == GUF_MATH_CKD_OVERFLOW); + uint8_t saturated; + TEST_CHECK(guf_saturating_mul_u8(static_cast(a), static_cast(b), &saturated) == GUF_MATH_CKD_OVERFLOW); + TEST_CHECK(saturated == UINT8_MAX); + uint8_t wrapped; + TEST_CHECK(guf_wrapping_mul_u8(static_cast(a), static_cast(b), &wrapped) == GUF_MATH_CKD_OVERFLOW); + TEST_CHECK(wrapped == static_cast(static_cast(a) * static_cast(b))); + } else { + TEST_CHECK(ckd_mul == GUF_MATH_CKD_SUCCESS); + uint8_t saturated; + TEST_CHECK(guf_saturating_mul_u8(static_cast(a), static_cast(b), &saturated) == GUF_MATH_CKD_SUCCESS); + TEST_CHECK(static_cast(saturated) == mul_res); + uint8_t wrapped; + TEST_CHECK(guf_wrapping_mul_u8(static_cast(a), static_cast(b), &wrapped) == GUF_MATH_CKD_SUCCESS); + TEST_CHECK(static_cast(wrapped) == mul_res); + } + } + } +} \ No newline at end of file diff --git a/src/test/test_ckdint.hpp b/src/test/test_ckdint.hpp new file mode 100644 index 0000000..0f45f9b --- /dev/null +++ b/src/test/test_ckdint.hpp @@ -0,0 +1,12 @@ +#pragma once +#include "test.hpp" + +struct CkdIntTest : public Test +{ + CkdIntTest(const std::string& name) : Test(name) {}; + void run() override; + +private: + void test_ckd(); + void test_ckd_uint(); +};