aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorMartin Baƙinka <marun1@email.cz>2021-04-29 08:40:06 +0200
committerGitHub <noreply@github.com>2021-04-29 09:40:06 +0300
commit35eb7753d29a9ad14b145a09c057a88131d6ede0 (patch)
treeebe2b69d32e12126c8a1e49c5e1d0012044c2bfa /tests
parent951f522b13b1ea0068345369a98d18d862b29582 (diff)
downloadlibfixmath-35eb7753d29a9ad14b145a09c057a88131d6ede0.tar.gz
New unittests (#28)
Refactor unittests
Diffstat (limited to 'tests')
-rwxr-xr-xtests/run_tests2
-rw-r--r--tests/tests.c51
-rw-r--r--tests/tests.cmake44
-rw-r--r--tests/tests.h80
-rw-r--r--tests/tests_basic.c246
-rw-r--r--tests/tests_basic.h10
-rw-r--r--tests/tests_lerp.c33
-rw-r--r--tests/tests_lerp.h6
-rw-r--r--tests/tests_sqrt.c37
-rw-r--r--tests/tests_sqrt.h6
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