Add math_ckdint tests

This commit is contained in:
jun 2025-05-13 21:14:20 +02:00
parent c4f3616b23
commit 1dba7661e6
5 changed files with 275 additions and 9 deletions

View File

@ -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) 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) 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) target_include_directories(libguf_test PRIVATE src src/test)
set_target_properties(libguf_example libguf_test PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) set_target_properties(libguf_example libguf_test PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})

View File

@ -0,0 +1,2 @@
#define GUF_MATH_CKDINT_IMPL
#include "guf_math_ckdint.h"

View File

@ -1,4 +1,4 @@
#include <unordered_set> #include <vector>
#include <string> #include <string>
#include <cstdio> #include <cstdio>
#include <iostream> #include <iostream>
@ -7,35 +7,45 @@
#include "test_dict.hpp" #include "test_dict.hpp"
#include "test_utf8.hpp" #include "test_utf8.hpp"
#include "test_str.hpp" #include "test_str.hpp"
#include "test_ckdint.hpp"
extern "C" extern "C"
{ {
#include "guf_assert.h" #include "guf_assert.h"
#include "guf_math.h" #include "guf_math.h"
} }
static std::unordered_set<std::unique_ptr<Test>> g_tests {}; static std::vector<std::unique_ptr<Test>> g_tests {};
static void init_tests() static void init_tests()
{ {
std::unique_ptr<Test> test = std::make_unique<DbufIntTest>("DbufIntTest"); std::unique_ptr<Test> test;
test = std::make_unique<CkdIntTest>("CkdIntTest");
GUF_ASSERT_RELEASE(test.get())
g_tests.push_back(std::move(test));
test = std::make_unique<DbufIntTest>("DbufIntTest");
GUF_ASSERT_RELEASE(test.get()); GUF_ASSERT_RELEASE(test.get());
g_tests.insert(std::move(test)); g_tests.push_back(std::move(test));
test = std::make_unique<DbufCstringTest>("DbufCstringTest"); test = std::make_unique<DbufCstringTest>("DbufCstringTest");
GUF_ASSERT_RELEASE(test.get()); GUF_ASSERT_RELEASE(test.get());
g_tests.insert(std::move(test)); g_tests.push_back(std::move(test));
test = std::make_unique<DictSvToIntTest>("DictSvToIntTest"); test = std::make_unique<DictSvToIntTest>("DictSvToIntTest");
GUF_ASSERT_RELEASE(test.get()); GUF_ASSERT_RELEASE(test.get());
g_tests.insert(std::move(test)); g_tests.push_back(std::move(test));
test = std::make_unique<UTF8Test>("UTF8Test"); test = std::make_unique<UTF8Test>("UTF8Test");
GUF_ASSERT_RELEASE(test.get()); GUF_ASSERT_RELEASE(test.get());
g_tests.insert(std::move(test)); g_tests.push_back(std::move(test));
test = std::make_unique<StrTest>("StrTest"); test = std::make_unique<StrTest>("StrTest");
GUF_ASSERT_RELEASE(test.get()) GUF_ASSERT_RELEASE(test.get())
g_tests.insert(std::move(test)); g_tests.push_back(std::move(test));
} }
int main() int main()

242
src/test/test_ckdint.cpp Normal file
View File

@ -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<int8_t>(a), static_cast<int8_t>(b), &saturated) == GUF_MATH_CKD_OVERFLOW);
TEST_CHECK(saturated == INT8_MAX);
TEST_CHECK(guf_saturating_add_i8(static_cast<int8_t>(b), static_cast<int8_t>(a), &saturated2) == GUF_MATH_CKD_OVERFLOW);
TEST_CHECK(saturated == saturated2);
int8_t wrapped, wrapped2;
TEST_CHECK(guf_wrapping_add_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &wrapped) == GUF_MATH_CKD_OVERFLOW);
TEST_CHECK(static_cast<int32_t>(wrapped) == INT8_MIN + (add_res % (INT8_MAX + 1)));
TEST_CHECK(guf_wrapping_add_i8(static_cast<int8_t>(b), static_cast<int8_t>(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<int8_t>(a), static_cast<int8_t>(b), &saturated) == GUF_MATH_CKD_UNDERFLOW);
TEST_CHECK(saturated == INT8_MIN);
TEST_CHECK(guf_saturating_add_i8(static_cast<int8_t>(b), static_cast<int8_t>(a), &saturated2) == GUF_MATH_CKD_UNDERFLOW);
TEST_CHECK(saturated == saturated2);
int8_t wrapped, wrapped2;
TEST_CHECK(guf_wrapping_add_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &wrapped) == GUF_MATH_CKD_UNDERFLOW);
TEST_CHECK(static_cast<int32_t>(wrapped) == INT8_MAX - (-add_res % (-INT8_MIN + 1)));
TEST_CHECK(guf_wrapping_add_i8(static_cast<int8_t>(b), static_cast<int8_t>(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<int8_t>(a), static_cast<int8_t>(b), &saturated) == GUF_MATH_CKD_SUCCESS);
TEST_CHECK(static_cast<int32_t>(saturated) == add_res);
TEST_CHECK(guf_saturating_add_i8(static_cast<int8_t>(b), static_cast<int8_t>(a), &saturated2) == GUF_MATH_CKD_SUCCESS);
TEST_CHECK(saturated == saturated2);
int8_t wrapped, wrapped2;
TEST_CHECK(guf_wrapping_add_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &wrapped) == GUF_MATH_CKD_SUCCESS);
TEST_CHECK(static_cast<int32_t>(wrapped) == add_res);
TEST_CHECK(guf_wrapping_add_i8(static_cast<int8_t>(b), static_cast<int8_t>(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<int8_t>(a), static_cast<int8_t>(b), &saturated) == GUF_MATH_CKD_OVERFLOW);
TEST_CHECK(saturated == INT8_MAX);
int8_t wrapped;
TEST_CHECK(guf_wrapping_sub_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &wrapped) == GUF_MATH_CKD_OVERFLOW);
TEST_CHECK(static_cast<int32_t>(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<int8_t>(a), static_cast<int8_t>(b), &saturated) == GUF_MATH_CKD_UNDERFLOW);
TEST_CHECK(saturated == INT8_MIN);
int8_t wrapped;
TEST_CHECK(guf_wrapping_sub_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &wrapped) == GUF_MATH_CKD_UNDERFLOW);
TEST_CHECK(static_cast<int32_t>(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<int8_t>(a), static_cast<int8_t>(b), &saturated) == GUF_MATH_CKD_SUCCESS);
TEST_CHECK(static_cast<int32_t>(saturated) == sub_res);
int8_t wrapped;
TEST_CHECK(guf_wrapping_sub_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &wrapped) == GUF_MATH_CKD_SUCCESS);
TEST_CHECK(static_cast<int32_t>(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<int8_t>(a), static_cast<int8_t>(b), &saturated) == GUF_MATH_CKD_OVERFLOW);
TEST_CHECK(saturated == INT8_MAX);
TEST_CHECK(guf_saturating_mul_i8(static_cast<int8_t>(b), static_cast<int8_t>(a), &saturated2) == GUF_MATH_CKD_OVERFLOW);
TEST_CHECK(saturated == saturated2);
int8_t wrapped, wrapped2;
TEST_CHECK(guf_wrapping_mul_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &wrapped) == GUF_MATH_CKD_OVERFLOW);
TEST_CHECK(guf_wrapping_mul_i8(static_cast<int8_t>(b), static_cast<int8_t>(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<int8_t>(a), static_cast<int8_t>(b), &saturated) == GUF_MATH_CKD_UNDERFLOW);
TEST_CHECK(saturated == INT8_MIN);
TEST_CHECK(guf_saturating_mul_i8(static_cast<int8_t>(b), static_cast<int8_t>(a), &saturated2) == GUF_MATH_CKD_UNDERFLOW);
TEST_CHECK(saturated == saturated2);
int8_t wrapped, wrapped2;
TEST_CHECK(guf_wrapping_mul_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &wrapped) == GUF_MATH_CKD_UNDERFLOW);
TEST_CHECK(guf_wrapping_mul_i8(static_cast<int8_t>(b), static_cast<int8_t>(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<int8_t>(a), static_cast<int8_t>(b), &saturated) == GUF_MATH_CKD_SUCCESS);
TEST_CHECK(static_cast<int32_t>(saturated) == mul_res);
TEST_CHECK(guf_saturating_mul_i8(static_cast<int8_t>(b), static_cast<int8_t>(a), &saturated2) == GUF_MATH_CKD_SUCCESS);
TEST_CHECK(saturated == saturated2);
int8_t wrapped, wrapped2;
TEST_CHECK(guf_wrapping_mul_i8(static_cast<int8_t>(a), static_cast<int8_t>(b), &wrapped) == GUF_MATH_CKD_SUCCESS);
TEST_CHECK(static_cast<int32_t>(wrapped) == mul_res);
TEST_CHECK(guf_wrapping_mul_i8(static_cast<int8_t>(b), static_cast<int8_t>(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<uint8_t>(a), static_cast<uint8_t>(b), &saturated) == GUF_MATH_CKD_OVERFLOW);
TEST_CHECK(saturated == UINT8_MAX);
uint8_t wrapped;
TEST_CHECK(guf_wrapping_add_u8(static_cast<uint8_t>(a), static_cast<uint8_t>(b), &wrapped) == GUF_MATH_CKD_OVERFLOW);
TEST_CHECK(static_cast<int32_t>(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<uint8_t>(a), static_cast<uint8_t>(b), &saturated) == GUF_MATH_CKD_SUCCESS);
TEST_CHECK(static_cast<int32_t>(saturated) == add_res);
uint8_t wrapped;
TEST_CHECK(guf_wrapping_add_u8(static_cast<uint8_t>(a), static_cast<uint8_t>(b), &wrapped) == GUF_MATH_CKD_SUCCESS);
TEST_CHECK(static_cast<int32_t>(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<uint8_t>(a), static_cast<uint8_t>(b), &saturated) == GUF_MATH_CKD_UNDERFLOW);
TEST_CHECK(saturated == 0);
uint8_t wrapped;
TEST_CHECK(guf_wrapping_sub_u8(static_cast<uint8_t>(a), static_cast<uint8_t>(b), &wrapped) == GUF_MATH_CKD_UNDERFLOW);
TEST_CHECK(wrapped == static_cast<uint8_t>(static_cast<uint8_t>(a) - static_cast<uint8_t>(b)));
} else {
TEST_CHECK(ckd_sub == GUF_MATH_CKD_SUCCESS);
uint8_t saturated;
TEST_CHECK(guf_saturating_sub_u8(static_cast<uint8_t>(a), static_cast<uint8_t>(b), &saturated) == GUF_MATH_CKD_SUCCESS);
TEST_CHECK(static_cast<int32_t>(saturated) == sub_res);
uint8_t wrapped;
TEST_CHECK(guf_wrapping_sub_u8(static_cast<uint8_t>(a), static_cast<uint8_t>(b), &wrapped) == GUF_MATH_CKD_SUCCESS);
TEST_CHECK(static_cast<int32_t>(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<uint8_t>(a), static_cast<uint8_t>(b), &saturated) == GUF_MATH_CKD_OVERFLOW);
TEST_CHECK(saturated == UINT8_MAX);
uint8_t wrapped;
TEST_CHECK(guf_wrapping_mul_u8(static_cast<uint8_t>(a), static_cast<uint8_t>(b), &wrapped) == GUF_MATH_CKD_OVERFLOW);
TEST_CHECK(wrapped == static_cast<uint8_t>(static_cast<uint8_t>(a) * static_cast<uint8_t>(b)));
} else {
TEST_CHECK(ckd_mul == GUF_MATH_CKD_SUCCESS);
uint8_t saturated;
TEST_CHECK(guf_saturating_mul_u8(static_cast<uint8_t>(a), static_cast<uint8_t>(b), &saturated) == GUF_MATH_CKD_SUCCESS);
TEST_CHECK(static_cast<int32_t>(saturated) == mul_res);
uint8_t wrapped;
TEST_CHECK(guf_wrapping_mul_u8(static_cast<uint8_t>(a), static_cast<uint8_t>(b), &wrapped) == GUF_MATH_CKD_SUCCESS);
TEST_CHECK(static_cast<int32_t>(wrapped) == mul_res);
}
}
}
}

12
src/test/test_ckdint.hpp Normal file
View File

@ -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();
};