diff options
| author | Martin BaĆinka <marun1@email.cz> | 2021-04-29 08:40:06 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-04-29 09:40:06 +0300 |
| commit | 35eb7753d29a9ad14b145a09c057a88131d6ede0 (patch) | |
| tree | ebe2b69d32e12126c8a1e49c5e1d0012044c2bfa /tests | |
| parent | 951f522b13b1ea0068345369a98d18d862b29582 (diff) | |
| download | libfixmath-35eb7753d29a9ad14b145a09c057a88131d6ede0.tar.gz | |
New unittests (#28)
Refactor unittests
Diffstat (limited to 'tests')
| -rwxr-xr-x | tests/run_tests | 2 | ||||
| -rw-r--r-- | tests/tests.c | 51 | ||||
| -rw-r--r-- | tests/tests.cmake | 44 | ||||
| -rw-r--r-- | tests/tests.h | 80 | ||||
| -rw-r--r-- | tests/tests_basic.c | 246 | ||||
| -rw-r--r-- | tests/tests_basic.h | 10 | ||||
| -rw-r--r-- | tests/tests_lerp.c | 33 | ||||
| -rw-r--r-- | tests/tests_lerp.h | 6 | ||||
| -rw-r--r-- | tests/tests_sqrt.c | 37 | ||||
| -rw-r--r-- | tests/tests_sqrt.h | 6 |
10 files changed, 515 insertions, 0 deletions
diff --git a/tests/run_tests b/tests/run_tests new file mode 100755 index 0000000..bca1d68 --- /dev/null +++ b/tests/run_tests @@ -0,0 +1,2 @@ +#!/bin/env bash +for i in $(ls -1 tests_*); do ./$i; done diff --git a/tests/tests.c b/tests/tests.c new file mode 100644 index 0000000..cef9710 --- /dev/null +++ b/tests/tests.c @@ -0,0 +1,51 @@ +#include "tests.h" +#include "tests_basic.h" +#include "tests_lerp.h" +#include "tests_sqrt.h" +#include <stdio.h> + +const fix16_t testcases[] = { + // Small numbers + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10, + + // Integer numbers + 0x10000, -0x10000, 0x20000, -0x20000, 0x30000, -0x30000, 0x40000, -0x40000, + 0x50000, -0x50000, 0x60000, -0x60000, + + // Fractions (1/2, 1/4, 1/8) + 0x8000, -0x8000, 0x4000, -0x4000, 0x2000, -0x2000, + + // Problematic carry + 0xFFFF, -0xFFFF, 0x1FFFF, -0x1FFFF, 0x3FFFF, -0x3FFFF, + + // Smallest and largest values + 0x7FFFFFFF, 0x80000000, + + // Large random numbers + 831858892, 574794913, 2147272293, -469161054, -961611615, 1841960234, + 1992698389, 520485404, 560523116, -2094993050, -876897543, -67813629, + 2146227091, 509861939, -1073573657, + + // Small random numbers + -14985, 30520, -83587, 41129, 42137, 58537, -2259, 84142, -28283, 90914, + 19865, 33191, 81844, -66273, -63215, -44459, -11326, 84295, 47515, -39324, + + // Tiny random numbers + -171, -359, 491, 844, 158, -413, -422, -737, -575, -330, -376, 435, -311, + 116, 715, -1024, -487, 59, 724, 993 +}; + +unsigned stack_depth = 0; + +int main() +{ + printf("\033[1;34m\nVARIANT: \033[39m"STR2(PREFIX)"\033[0m\n"); + TEST(test_abs()); + TEST(test_add()); + TEST(test_mul()); + TEST(test_div()); + TEST(test_sub()); + TEST(test_sqrt()); + TEST(test_lerp()); + return 0; +} diff --git a/tests/tests.cmake b/tests/tests.cmake new file mode 100644 index 0000000..56aefe3 --- /dev/null +++ b/tests/tests.cmake @@ -0,0 +1,44 @@ +file(GLOB tests-srcs tests/*.c tests/*.h) + +set(ro64 PREFIX=ro64) +set(no64 PREFIX=no64 FIXMATH_NO_ROUNDING) +set(rn64 PREFIX=rn64 FIXMATH_NO_OVERFLOW) +set(nn64 PREFIX=nn64 FIXMATH_NO_ROUNDING FIXMATH_NO_OVERFLOW) +set(ro32 PREFIX=ro32 FIXMATH_NO_64BIT) +set(no32 PREFIX=no32 FIXMATH_NO_ROUNDING FIXMATH_NO_64BIT) +set(rn32 PREFIX=rn32 FIXMATH_NO_OVERFLOW FIXMATH_NO_64BIT) +set(nn32 PREFIX=nn32 FIXMATH_NO_OVERFLOW FIXMATH_NO_ROUNDING FIXMATH_NO_64BIT) +set(ro08 PREFIX=ro08 FIXMATH_OPTIMIZE_8BIT) +set(no08 PREFIX=no08 FIXMATH_NO_ROUNDING FIXMATH_OPTIMIZE_8BIT) +set(rn08 PREFIX=rn08 FIXMATH_NO_OVERFLOW FIXMATH_OPTIMIZE_8BIT) +set(nn08 PREFIX=nn08 FIXMATH_NO_OVERFLOW FIXMATH_NO_ROUNDING FIXMATH_OPTIMIZE_8BIT) + +configure_file(tests/run_tests ${CMAKE_BINARY_DIR}/run_tests COPYONLY) + +add_custom_target(tests) + +function(create_variant name defs) + add_library(libfixmath_${name} STATIC ${libfixmath-srcs}) + target_compile_definitions(libfixmath_${name} PRIVATE ${defs}) + add_executable(tests_${name} ${tests-srcs}) + target_link_libraries(tests_${name} PRIVATE libfixmath_${name} m) + target_include_directories(tests_${name} PRIVATE ${CMAKE_SOURCE_DIR}) + target_compile_definitions(tests_${name} PRIVATE ${defs}) + add_dependencies(tests tests_${name}) +endfunction() + + +create_variant("ro64" "${ro64}") +create_variant("no64" "${no64}") +create_variant("rn64" "${rn64}") +create_variant("nn64" "${nn64}") +create_variant("ro32" "${ro32}") +create_variant("no32" "${no32}") +create_variant("rn32" "${rn32}") +create_variant("nn32" "${nn32}") +create_variant("ro08" "${ro08}") +create_variant("no08" "${no08}") +create_variant("rn08" "${rn08}") +create_variant("nn08" "${nn08}") + + diff --git a/tests/tests.h b/tests/tests.h new file mode 100644 index 0000000..6be58db --- /dev/null +++ b/tests/tests.h @@ -0,0 +1,80 @@ +#ifndef TESTS_H +#define TESTS_H + +#include <libfixmath/fix16.h> +#include <math.h> +#include <stdio.h> +#include <stdlib.h> + +extern unsigned stack_depth; + +#define delta(a, b) (((a) >= (b)) ? (a) - (b) : (b) - (a)) + +#define COMMENT(x) printf("\n----" x "----\n"); +#define STR(x) #x +#define STR2(x) STR(x) +#define TEST(x) \ + do \ + { \ + ++stack_depth; \ + if ((x)) \ + { \ + fflush(stdout); \ + fflush(stderr); \ + fprintf(stdout, \ + "\033[31;1m FAILED:\033[22;39m%*s" #x \ + " \033[0mat: " __FILE__ ":" STR2(__LINE__) " \n", \ + stack_depth, ""); \ + --stack_depth; \ + return 1; \ + } \ + else \ + { \ + fflush(stdout); \ + fflush(stderr); \ + printf("\033[32;1m OK:\033[22;39m%*s" #x "\n\033[0m", \ + stack_depth, ""); \ + } \ + --stack_depth; \ + } while (0) + +#define ASSERT_NEAR_DOUBLE(a, b, eps, ...) \ + do \ + { \ + if ((delta((a), (b)) >= (eps))) \ + { \ + fflush(stdout); \ + fflush(stderr); \ + fprintf(stdout, \ + "\033[31;1m FAILED:\033[22;39m%*sASSERT_NEAR a: %f, b: " \ + "%f, eps: %f\033[0m at: %s(), " __FILE__ \ + ":" STR2(__LINE__) "\n", \ + stack_depth, "", (a), (b), (eps), __func__); \ + fprintf(stdout, " %*s", stack_depth, ""); \ + fprintf(stdout, __VA_ARGS__); \ + return 1; \ + } \ + } while (0) + +#define ASSERT_EQ_INT(a, b) \ + do \ + { \ + if ((a) != (b)) \ + { \ + fflush(stdout); \ + fflush(stderr); \ + fprintf(stdout, \ + "\033[31;1m FAILED:\033[22;39m%*sASSERT_EQ a: %i, b: " \ + "%i\033[0m at: %s(), " __FILE__ ":" STR2(__LINE__) "\n", \ + stack_depth, "", (a), (b), __func__); \ + return 1; \ + } \ + } while (0) + +extern const fix16_t testcases[102]; + +#define TESTCASES_COUNT (sizeof(testcases) / sizeof(testcases[0])) + +#define delta(a, b) (((a) >= (b)) ? (a) - (b) : (b) - (a)) + +#endif // TESTS_H diff --git a/tests/tests_basic.c b/tests/tests_basic.c new file mode 100644 index 0000000..6037ae2 --- /dev/null +++ b/tests/tests_basic.c @@ -0,0 +1,246 @@ +#include "tests_basic.h" +#include "tests.h" + +int test_abs_short(void) +{ + for (unsigned i = 0; i < TESTCASES_COUNT; ++i) + { + fix16_t a = testcases[i]; + double fa = fix16_to_dbl(a); + fix16_t result = fix16_abs(a); + double fresult = fabs(fa); + double min = fix16_to_dbl(fix16_minimum); + if (fa <= min) + { +#ifndef FIXMATH_NO_OVERFLOW + ASSERT_EQ_INT(result, fix16_overflow); +#endif + } + else + { + ASSERT_NEAR_DOUBLE(fresult, fix16_to_dbl(result), + fix16_to_dbl(fix16_eps), "in: %f", fa); + } + } + return 0; +} + +int test_abs(void) +{ + TEST(test_abs_short()); + return 0; +} + +int test_add_short(void) +{ + for (unsigned i = 0; i < TESTCASES_COUNT; ++i) + { + for (unsigned j = 0; j < TESTCASES_COUNT; ++j) + { + fix16_t a = testcases[i]; + fix16_t b = testcases[j]; + fix16_t result = fix16_add(a, b); + + double fa = fix16_to_dbl(a); + double fb = fix16_to_dbl(b); + double fresult = fa + fb; + + double max = fix16_to_dbl(fix16_maximum); + double min = fix16_to_dbl(fix16_minimum); + if ((fa + fb > max) || (fa + fb < min)) + { +#ifndef FIXMATH_NO_OVERFLOW + ASSERT_EQ_INT(result, fix16_overflow); +#endif + } + else + { + ASSERT_NEAR_DOUBLE(fresult, fix16_to_dbl(result), + fix16_to_dbl(fix16_eps), "%f + %f", fa, fb); + } + } + } + return 0; +} + +int test_add(void) +{ + TEST(test_add_short()); + return 0; +} + +int test_mul_specific(void) +{ + ASSERT_EQ_INT(fix16_mul(fix16_from_int(5), fix16_from_int(5)), + fix16_from_int(25)); + ASSERT_EQ_INT(fix16_mul(fix16_from_int(-5), fix16_from_int(5)), + fix16_from_int(-25)); + ASSERT_EQ_INT(fix16_mul(fix16_from_int(-5), fix16_from_int(-5)), + fix16_from_int(25)); + ASSERT_EQ_INT(fix16_mul(fix16_from_int(5), fix16_from_int(-5)), + fix16_from_int(-25)); + + ASSERT_EQ_INT(fix16_mul(0, 10), 0); + ASSERT_EQ_INT(fix16_mul(2, 0x8000), 1); + ASSERT_EQ_INT(fix16_mul(-2, 0x8000), -1); +#ifndef FIXMATH_NO_ROUNDING + ASSERT_EQ_INT(fix16_mul(3, 0x8000), 2); + ASSERT_EQ_INT(fix16_mul(2, 0x7FFF), 1); + ASSERT_EQ_INT(fix16_mul(-2, 0x8001), -1); + ASSERT_EQ_INT(fix16_mul(-3, 0x8000), -2); + ASSERT_EQ_INT(fix16_mul(-2, 0x7FFF), -1); + ASSERT_EQ_INT(fix16_mul(2, 0x8001), 1); +#endif + return 0; +} + +int test_mul_short() +{ + for (unsigned i = 0; i < TESTCASES_COUNT; ++i) + { + for (unsigned j = 0; j < TESTCASES_COUNT; ++j) + { + fix16_t a = testcases[i]; + fix16_t b = testcases[j]; + fix16_t result = fix16_mul(a, b); + + double fa = fix16_to_dbl(a); + double fb = fix16_to_dbl(b); + double fresult = fa * fb; + + double max = fix16_to_dbl(fix16_maximum); + double min = fix16_to_dbl(fix16_minimum); + + if (fa * fb > max || fa * fb < min) + { +#ifndef FIXMATH_NO_OVERFLOW + ASSERT_EQ_INT(result, fix16_overflow); +#endif + } + else + { + ASSERT_NEAR_DOUBLE(fresult, fix16_to_dbl(result), + fix16_to_dbl(fix16_eps), "%f * %f", fa, fb); + } + } + } + return 0; +} + +int test_mul(void) +{ + TEST(test_mul_specific()); + TEST(test_mul_short()); + return 0; +} + +int test_div_specific() +{ + ASSERT_EQ_INT(fix16_div(fix16_from_int(15), fix16_from_int(5)), + fix16_from_int(3)); + ASSERT_EQ_INT(fix16_div(fix16_from_int(-15), fix16_from_int(5)), + fix16_from_int(-3)); + ASSERT_EQ_INT(fix16_div(fix16_from_int(-15), fix16_from_int(-5)), + fix16_from_int(3)); + ASSERT_EQ_INT(fix16_div(fix16_from_int(15), fix16_from_int(-5)), + fix16_from_int(-3)); + +#ifndef FIXMATH_NO_ROUNDING + ASSERT_EQ_INT(fix16_div(0, 10), 0); + ASSERT_EQ_INT(fix16_div(1, fix16_from_int(2)), 1); + ASSERT_EQ_INT(fix16_div(-1, fix16_from_int(2)), -1); + ASSERT_EQ_INT(fix16_div(1, fix16_from_int(-2)), -1); + ASSERT_EQ_INT(fix16_div(-1, fix16_from_int(-2)), 1); + ASSERT_EQ_INT(fix16_div(3, fix16_from_int(2)), 2); + ASSERT_EQ_INT(fix16_div(-3, fix16_from_int(2)), -2); + ASSERT_EQ_INT(fix16_div(3, fix16_from_int(-2)), -2); + ASSERT_EQ_INT(fix16_div(-3, fix16_from_int(-2)), 2); + ASSERT_EQ_INT(fix16_div(2, 0x7FFF), 4); + ASSERT_EQ_INT(fix16_div(-2, 0x7FFF), -4); + ASSERT_EQ_INT(fix16_div(2, 0x8001), 4); + ASSERT_EQ_INT(fix16_div(-2, 0x8001), -4); +#endif + + return 0; +} + +int test_div_short() +{ + for (unsigned i = 0; i < TESTCASES_COUNT; ++i) + { + for (unsigned j = 0; j < TESTCASES_COUNT; ++j) + { + fix16_t a = testcases[i]; + fix16_t b = testcases[j]; + // We don't require a solution for /0 :) + if (b == 0) + continue; + fix16_t result = fix16_div(a, b); + + double fa = fix16_to_dbl(a); + double fb = fix16_to_dbl(b); + double fresult = fa / fb; + + double max = fix16_to_dbl(fix16_maximum); + double min = fix16_to_dbl(fix16_minimum); + + if ((fa / fb) > max || (fa / fb) < min) + { +#ifndef FIXMATH_NO_OVERFLOW + ASSERT_EQ_INT(result, fix16_overflow); +#endif + } + else + { + ASSERT_NEAR_DOUBLE(fresult, fix16_to_dbl(result), + fix16_to_dbl(fix16_eps), "%i / %i \n", a, b); + } + } + } + return 0; +} + +int test_div(void) +{ + TEST(test_div_specific()); + TEST(test_div_short()); + return 0; +} + +int test_sub_short() +{ + for (unsigned i = 0; i < TESTCASES_COUNT; ++i) + { + for (unsigned j = 0; j < TESTCASES_COUNT; ++j) + { + fix16_t a = testcases[i]; + fix16_t b = testcases[j]; + fix16_t result = fix16_sub(a, b); + + double fa = fix16_to_dbl(a); + double fb = fix16_to_dbl(b); + double fresult = fa - fb; + + double max = fix16_to_dbl(fix16_maximum); + double min = fix16_to_dbl(fix16_minimum); + if ((fa - fb > max) || (fa - fb < min)) + { +#ifndef FIXMATH_NO_OVERFLOW + ASSERT_EQ_INT(result, fix16_overflow); +#endif + } + else + { + ASSERT_NEAR_DOUBLE(fresult, fix16_to_dbl(result), + fix16_to_dbl(fix16_eps), "%f - %f", fa, fb); + } + } + } + return 0; +} + +int test_sub() +{ + TEST(test_sub_short()); + return 0; +} diff --git a/tests/tests_basic.h b/tests/tests_basic.h new file mode 100644 index 0000000..a51f283 --- /dev/null +++ b/tests/tests_basic.h @@ -0,0 +1,10 @@ +#ifndef TESTS_BASIC_H +#define TESTS_BASIC_H + +int test_abs(void); +int test_add(void); +int test_mul(void); +int test_div(void); +int test_sub(); + +#endif // TESTS_BASIC_H diff --git a/tests/tests_lerp.c b/tests/tests_lerp.c new file mode 100644 index 0000000..b3a04f6 --- /dev/null +++ b/tests/tests_lerp.c @@ -0,0 +1,33 @@ +#include "tests_lerp.h" +#include "tests.h" + +int test_lerp() +{ + ASSERT_EQ_INT(fix16_lerp8(0, 2, 0), 0); + ASSERT_EQ_INT(fix16_lerp8(0, 2, 127), 0); + ASSERT_EQ_INT(fix16_lerp8(0, 2, 128), 1); + ASSERT_EQ_INT(fix16_lerp8(0, 2, 255), 1); + ASSERT_EQ_INT(fix16_lerp8(fix16_minimum, fix16_maximum, 0), fix16_minimum); + ASSERT_EQ_INT(fix16_lerp8(fix16_minimum, fix16_maximum, 255), + (fix16_maximum - (1 << 24))); + ASSERT_EQ_INT(fix16_lerp8(-fix16_maximum, fix16_maximum, 128), 0); + + ASSERT_EQ_INT(fix16_lerp16(0, 2, 0), 0); + ASSERT_EQ_INT(fix16_lerp16(0, 2, 0x7fff), 0); + ASSERT_EQ_INT(fix16_lerp16(0, 2, 0x8000), 1); + ASSERT_EQ_INT(fix16_lerp16(0, 2, 0xffff), 1); + ASSERT_EQ_INT(fix16_lerp16(fix16_minimum, fix16_maximum, 0), fix16_minimum); + ASSERT_EQ_INT(fix16_lerp16(fix16_minimum, fix16_maximum, 0xffff), + (fix16_maximum - (1 << 16))); + ASSERT_EQ_INT(fix16_lerp16(-fix16_maximum, fix16_maximum, 0x8000), 0); + + ASSERT_EQ_INT(fix16_lerp32(0, 2, 0), 0); + ASSERT_EQ_INT(fix16_lerp32(0, 2, 0x7fffffff), 0); + ASSERT_EQ_INT(fix16_lerp32(0, 2, 0x80000000), 1); + ASSERT_EQ_INT(fix16_lerp32(0, 2, 0xffffffff), 1); + ASSERT_EQ_INT(fix16_lerp32(fix16_minimum, fix16_maximum, 0), fix16_minimum); + ASSERT_EQ_INT(fix16_lerp32(fix16_minimum, fix16_maximum, 0xffffffff), + (fix16_maximum - 1)); + ASSERT_EQ_INT(fix16_lerp32(-fix16_maximum, fix16_maximum, 0x80000000), 0); + return 0; +} diff --git a/tests/tests_lerp.h b/tests/tests_lerp.h new file mode 100644 index 0000000..ab261dd --- /dev/null +++ b/tests/tests_lerp.h @@ -0,0 +1,6 @@ +#ifndef TESTS_LERP_H +#define TESTS_LERP_H + +int test_lerp(); + +#endif // TESTS_LERP_H diff --git a/tests/tests_sqrt.c b/tests/tests_sqrt.c new file mode 100644 index 0000000..8faf016 --- /dev/null +++ b/tests/tests_sqrt.c @@ -0,0 +1,37 @@ +#include "tests_sqrt.h" +#include "tests.h" + +int test_sqrt_specific() +{ + ASSERT_EQ_INT(fix16_sqrt(fix16_from_int(16)), fix16_from_int(4)); + ASSERT_EQ_INT(fix16_sqrt(fix16_from_int(100)), fix16_from_int(10)); + ASSERT_EQ_INT(fix16_sqrt(fix16_from_int(1)), fix16_from_int(1)); +#ifndef FIXMATH_NO_ROUNDING + ASSERT_EQ_INT(fix16_sqrt(214748302), 3751499); + ASSERT_EQ_INT(fix16_sqrt(214748303), 3751499); + ASSERT_EQ_INT(fix16_sqrt(214748359), 3751499); + ASSERT_EQ_INT(fix16_sqrt(214748360), 3751500); +#endif + return 0; +} + +int test_sqrt_short() +{ + for (unsigned i = 0; i < TESTCASES_COUNT; ++i) + { + fix16_t a = testcases[i]; + double fa = fix16_to_dbl(a); + fix16_t result = fix16_sqrt(a); + double fresult = sqrt(fa); + ASSERT_NEAR_DOUBLE(fresult, fix16_to_dbl(result), fix16_to_dbl(1), + "in: %f", fa); + } + return 0; +} + +int test_sqrt() +{ + TEST(test_sqrt_specific()); + TEST(test_sqrt_short()); + return 0; +} diff --git a/tests/tests_sqrt.h b/tests/tests_sqrt.h new file mode 100644 index 0000000..d0e108d --- /dev/null +++ b/tests/tests_sqrt.h @@ -0,0 +1,6 @@ +#ifndef TESTS_SQRT_H +#define TESTS_SQRT_H + +int test_sqrt(); + +#endif // TESTS_SQRT_H |
