From 835e1fcd131c63ee2b3b647e327b33a3bfb369e3 Mon Sep 17 00:00:00 2001 From: Mitya Selivanov Date: Sat, 2 Sep 2023 20:59:29 +0200 Subject: [Linux] Change build system; Remove CMake --- source/tests/_static.c | 55 ++++++++ source/tests/array_ref.test.c | 65 ++++++++++ source/tests/async_function.test.c | 132 +++++++++++++++++++ source/tests/atomic.test.c | 218 +++++++++++++++++++++++++++++++ source/tests/bench.test.c | 41 ++++++ source/tests/bigint.test.c | 108 ++++++++++++++++ source/tests/condition_variable.test.c | 84 ++++++++++++ source/tests/cpp.cpp | 13 ++ source/tests/dynamic_array.test.c | 174 +++++++++++++++++++++++++ source/tests/file.test.c | 220 ++++++++++++++++++++++++++++++++ source/tests/input_buffer.test.c | 105 +++++++++++++++ source/tests/input_stream.test.c | 23 ++++ source/tests/lower_bound.test.c | 178 ++++++++++++++++++++++++++ source/tests/main.test.c | 9 ++ source/tests/mersenne_twister_64.test.c | 38 ++++++ source/tests/move_back.test.c | 148 +++++++++++++++++++++ source/tests/mutex.test.c | 79 ++++++++++++ source/tests/secure_random.test.c | 24 ++++ source/tests/sha256.test.c | 42 ++++++ source/tests/signals.cpp | 29 +++++ source/tests/string_ref.test.c | 23 ++++ source/tests/test_duration.test.c | 19 +++ source/tests/thread.test.c | 91 +++++++++++++ source/tests/too_many_assertions.c | 13 ++ source/tests/too_many_tests.c | 14 ++ 25 files changed, 1945 insertions(+) create mode 100644 source/tests/_static.c create mode 100644 source/tests/array_ref.test.c create mode 100644 source/tests/async_function.test.c create mode 100644 source/tests/atomic.test.c create mode 100644 source/tests/bench.test.c create mode 100644 source/tests/bigint.test.c create mode 100644 source/tests/condition_variable.test.c create mode 100644 source/tests/cpp.cpp create mode 100644 source/tests/dynamic_array.test.c create mode 100644 source/tests/file.test.c create mode 100644 source/tests/input_buffer.test.c create mode 100644 source/tests/input_stream.test.c create mode 100644 source/tests/lower_bound.test.c create mode 100644 source/tests/main.test.c create mode 100644 source/tests/mersenne_twister_64.test.c create mode 100644 source/tests/move_back.test.c create mode 100644 source/tests/mutex.test.c create mode 100644 source/tests/secure_random.test.c create mode 100644 source/tests/sha256.test.c create mode 100644 source/tests/signals.cpp create mode 100644 source/tests/string_ref.test.c create mode 100644 source/tests/test_duration.test.c create mode 100644 source/tests/thread.test.c create mode 100644 source/tests/too_many_assertions.c create mode 100644 source/tests/too_many_tests.c (limited to 'source/tests') diff --git a/source/tests/_static.c b/source/tests/_static.c new file mode 100644 index 0000000..4b7543d --- /dev/null +++ b/source/tests/_static.c @@ -0,0 +1,55 @@ +#include "array_ref.test.c" +#undef KIT_TEST_FILE + +#include "async_function.test.c" +#undef KIT_TEST_FILE + +#include "bigint.test.c" +#undef KIT_TEST_FILE + +#include "condition_variable.test.c" +#undef KIT_TEST_FILE + +#include "dynamic_array.test.c" +#undef KIT_TEST_FILE + +#include "file.test.c" +#undef KIT_TEST_FILE + +#include "input_buffer.test.c" +#undef KIT_TEST_FILE + +#include "input_stream.test.c" +#undef KIT_TEST_FILE + +#include "lower_bound.test.c" +#undef KIT_TEST_FILE + +#include "mersenne_twister_64.test.c" +#undef KIT_TEST_FILE + +#include "move_back.test.c" +#undef KIT_TEST_FILE + +#include "mutex.test.c" +#undef KIT_TEST_FILE + +#include "secure_random.test.c" +#undef KIT_TEST_FILE + +#include "sha256.test.c" +#undef KIT_TEST_FILE + +#include "string_ref.test.c" +#undef KIT_TEST_FILE + +#include "test_duration.test.c" +#undef KIT_TEST_FILE + +#include "thread.test.c" +#undef KIT_TEST_FILE + +#include "bench.test.c" +#undef KIT_TEST_FILE + +#include "main.test.c" diff --git a/source/tests/array_ref.test.c b/source/tests/array_ref.test.c new file mode 100644 index 0000000..da20aa0 --- /dev/null +++ b/source/tests/array_ref.test.c @@ -0,0 +1,65 @@ +#include "../kit/array_ref.h" + +#define KIT_TEST_FILE array_ref +#include "../kit_test/test.h" + +TEST("array ref const wrap") { + int foo[] = { 1, 2, 3 }; + AR_WRAP(ref, int, foo); + + REQUIRE(ref.size == 3); + REQUIRE(ref.values[0] == 1); + REQUIRE(ref.values[1] == 2); + REQUIRE(ref.values[2] == 3); +} + +TEST("array ref wrap") { + int foo[] = { 1, 2, 3 }; + AR_MUT_WRAP(ref, int, foo); + + REQUIRE(ref.size == 3); + REQUIRE(ref.values[0] == 1); + REQUIRE(ref.values[1] == 2); + REQUIRE(ref.values[2] == 3); + + ref.values[1] = 42; + REQUIRE(ref.values[1] == 42); +} + +TEST("array ref equal") { + int foo[] = { 1, 2, 3, 4, 5, 6, 7 }; + int bar[] = { 3, 4, 5 }; + + AR(int) foo_ref = { .size = 3, .values = foo + 2 }; + AR(int) bar_ref = { .size = 3, .values = bar }; + + REQUIRE(AR_EQUAL(foo_ref, bar_ref)); +} + +static int compare(int const *left, int const *right) { + return *left - *right; +} + +TEST("array ref compare") { + int foo[] = { 1, 2, 3, 5 }; + int bar[] = { 1, 2, 4, 5 }; + + AR(int) foo_ref = { .size = 3, .values = foo }; + AR(int) bar_ref = { .size = 3, .values = bar }; + + REQUIRE(AR_COMPARE(foo_ref, bar_ref, compare) < 0); + REQUIRE(AR_COMPARE(bar_ref, foo_ref, compare) > 0); + REQUIRE(AR_COMPARE(foo_ref, foo_ref, compare) == 0); +} + +TEST("array ref different element sizes") { + int foo[] = { 1, 2, 3 }; + char bar[] = { 1, 2, 3 }; + + AR(int) foo_ref = { .size = 3, .values = foo }; + AR(char) bar_ref = { .size = 3, .values = bar }; + + REQUIRE(!AR_EQUAL(foo_ref, bar_ref)); + REQUIRE(AR_COMPARE(foo_ref, bar_ref, compare) > 0); + REQUIRE(AR_COMPARE(bar_ref, foo_ref, compare) < 0); +} diff --git a/source/tests/async_function.test.c b/source/tests/async_function.test.c new file mode 100644 index 0000000..35ce0ce --- /dev/null +++ b/source/tests/async_function.test.c @@ -0,0 +1,132 @@ +#include "../kit/async_function.h" + +#define KIT_TEST_FILE async_function +#include "../kit_test/test.h" + +AF_STATE(int, test_foo, ); +static AF_DECL(test_foo); + +CORO_IMPL(test_foo) { + AF_RETURN(42); +} +CORO_END + +AF_STATE(int, test_bar, ); +static AF_DECL(test_bar); + +CORO_IMPL(test_bar) { + AF_YIELD_VOID; + AF_RETURN(42); +} +CORO_END + +STATIC_CORO(int, test_gen, int i; int min; int max;) { + for (self->i = self->min; self->i < self->max; self->i++) + AF_YIELD(self->i); + AF_RETURN(self->max); +} +CORO_END + +STATIC_CORO_VOID(test_task, ) { + AF_YIELD_VOID; + AF_YIELD_VOID; + AF_RETURN_VOID; +} +CORO_END + +STATIC_CORO_VOID(test_nest_task, AF_TYPE(test_task) promise;) { + AF_INIT(self->promise, test_task, ); + AF_AWAIT(self->promise); + AF_AWAIT(self->promise); + AF_AWAIT(self->promise); +} +CORO_END + +STATIC_CORO(int, test_nest_generator, AF_TYPE(test_gen) promise;) { + AF_INIT(self->promise, test_gen, .min = 1, .max = 3); + AF_YIELD_AWAIT(self->promise); +} +CORO_END + +TEST("coroutine create") { + AF_CREATE(promise, test_foo, ); + REQUIRE(!AF_FINISHED(promise)); +} + +TEST("coroutine init") { + AF_TYPE(test_foo) promise; + AF_INIT(promise, test_foo, ); + REQUIRE(!AF_FINISHED(promise)); +} + +TEST("coroutine init with value") { + AF_TYPE(test_foo) promise; + AF_INIT(promise, test_foo, .return_value = 42); + REQUIRE(promise.return_value == 42); + REQUIRE(!AF_FINISHED(promise)); +} + +TEST("coroutine create with value") { + AF_CREATE(promise, test_foo, .return_value = -1); + REQUIRE(promise.return_value == -1); + REQUIRE(!AF_FINISHED(promise)); +} + +TEST("coroutine execute and return") { + AF_CREATE(promise, test_foo, ); + REQUIRE(AF_NEXT(promise) == 42); + REQUIRE(AF_FINISHED(promise)); +} + +TEST("coroutine execute two steps") { + AF_CREATE(promise, test_bar, .return_value = 0); + AF_EXECUTE(promise); + REQUIRE(promise.return_value == 0); + AF_EXECUTE(promise); + REQUIRE(promise.return_value == 42); +} + +TEST("coroutine generator") { + int i; + AF_CREATE(promise, test_gen, .min = 10, .max = 15); + for (i = 0; i <= 5; i++) REQUIRE(AF_NEXT(promise) == 10 + i); +} + +TEST("coroutine status finished") { + AF_CREATE(promise, test_bar, ); + REQUIRE(!AF_FINISHED(promise)); + AF_EXECUTE(promise); + REQUIRE(!AF_FINISHED(promise)); + AF_EXECUTE(promise); + REQUIRE(AF_FINISHED(promise)); +} + +TEST("coroutine task") { + AF_CREATE(promise, test_task, ); + AF_EXECUTE(promise); + REQUIRE(!AF_FINISHED(promise)); + AF_EXECUTE(promise); + REQUIRE(!AF_FINISHED(promise)); + AF_EXECUTE(promise); + REQUIRE(AF_FINISHED(promise)); +} + +TEST("coroutine nested task") { + AF_CREATE(promise, test_nest_task, ); + AF_EXECUTE(promise); + REQUIRE(!AF_FINISHED(promise)); + AF_EXECUTE(promise); + REQUIRE(!AF_FINISHED(promise)); + AF_EXECUTE(promise); + REQUIRE(AF_FINISHED(promise)); +} + +TEST("coroutine nested generator") { + AF_CREATE(promise, test_nest_generator, ); + REQUIRE(AF_NEXT(promise) == 1); + REQUIRE(AF_NEXT(promise) == 2); + REQUIRE(AF_NEXT(promise) == 3); + REQUIRE(!AF_FINISHED(promise)); + AF_EXECUTE(promise); + REQUIRE(AF_FINISHED(promise)); +} diff --git a/source/tests/atomic.test.c b/source/tests/atomic.test.c new file mode 100644 index 0000000..c1831a3 --- /dev/null +++ b/source/tests/atomic.test.c @@ -0,0 +1,218 @@ +#include "../kit/atomic.h" +#include "../kit/thread.h" + +#define KIT_TEST_FILE atomic +#include "../kit_test/test.h" + +TEST("atomic store and load") { + ATOMIC(int) value; + atomic_store_explicit(&value, 20, memory_order_relaxed); + REQUIRE(atomic_load_explicit(&value, memory_order_relaxed) == 20); +} + +TEST("atomic exchange") { + ATOMIC(int) value; + atomic_store_explicit(&value, 20, memory_order_relaxed); + REQUIRE(atomic_exchange_explicit(&value, 42, + memory_order_relaxed) == 20); + REQUIRE(atomic_load_explicit(&value, memory_order_relaxed) == 42); +} + +TEST("atomic fetch add") { + ATOMIC(int) value; + atomic_store_explicit(&value, 20, memory_order_relaxed); + REQUIRE(atomic_fetch_add_explicit(&value, 22, + memory_order_relaxed) == 20); + REQUIRE(atomic_load_explicit(&value, memory_order_relaxed) == 42); +} + +enum { THREAD_COUNT = 20, TICK_COUNT = 10000 }; + +static int test_8_(void *p) { + ptrdiff_t i; + ATOMIC(int8_t) *x = (ATOMIC(int8_t) *) p; + + for (i = 0; i < TICK_COUNT; i++) { + atomic_fetch_add_explicit(x, 20, memory_order_relaxed); + thrd_yield(); + atomic_fetch_add_explicit(x, 22, memory_order_relaxed); + thrd_yield(); + atomic_fetch_add_explicit(x, -42, memory_order_relaxed); + thrd_yield(); + } + + return 0; +} + +TEST("atomic types") { + ATOMIC(int8_t) b_1; + ATOMIC(int8_t) b_2; + ATOMIC(int16_t) i16; + ATOMIC(int32_t) i32; + ATOMIC(int64_t) i64; + + atomic_store_explicit(&b_1, 42, memory_order_relaxed); + atomic_store_explicit(&b_2, 43, memory_order_relaxed); + atomic_store_explicit(&i16, 4242, memory_order_relaxed); + atomic_store_explicit(&i32, 42424242, memory_order_relaxed); + atomic_store_explicit(&i64, 4242424242424242ll, + memory_order_relaxed); + + atomic_fetch_add_explicit(&b_1, -20, memory_order_relaxed); + atomic_fetch_add_explicit(&b_2, -20, memory_order_relaxed); + atomic_fetch_add_explicit(&i16, -2020, memory_order_relaxed); + atomic_fetch_add_explicit(&i32, -20202020, memory_order_relaxed); + atomic_fetch_add_explicit(&i64, -2020202020202020ll, + memory_order_relaxed); + + REQUIRE(atomic_exchange_explicit(&b_1, 0, memory_order_relaxed) == + 22); + REQUIRE(atomic_exchange_explicit(&b_2, 0, memory_order_relaxed) == + 23); + REQUIRE(atomic_exchange_explicit(&i16, 0, memory_order_relaxed) == + 2222); + REQUIRE(atomic_exchange_explicit(&i32, 0, memory_order_relaxed) == + 22222222); + REQUIRE(atomic_exchange_explicit(&i64, 0, memory_order_relaxed) == + 2222222222222222ll); + + REQUIRE(atomic_load_explicit(&b_1, memory_order_relaxed) == 0); + REQUIRE(atomic_load_explicit(&b_2, memory_order_relaxed) == 0); + REQUIRE(atomic_load_explicit(&i16, memory_order_relaxed) == 0); + REQUIRE(atomic_load_explicit(&i32, memory_order_relaxed) == 0); + REQUIRE(atomic_load_explicit(&i64, memory_order_relaxed) == 0ll); +} + +TEST("atomic byte concurrency") { + ptrdiff_t i; + + ATOMIC(int8_t) foo; + ATOMIC(int8_t) bar; + + atomic_store_explicit(&foo, 42, memory_order_relaxed); + atomic_store_explicit(&bar, 43, memory_order_relaxed); + + thrd_t threads[THREAD_COUNT]; + for (i = 0; i < THREAD_COUNT; i++) + REQUIRE_EQ(thrd_create(threads + i, test_8_, + (void *) ((i % 2) ? &foo : &bar)), + thrd_success); + for (i = 0; i < THREAD_COUNT; i++) thrd_join(threads[i], NULL); + + REQUIRE(atomic_load_explicit(&foo, memory_order_relaxed) == 42); + REQUIRE(atomic_load_explicit(&bar, memory_order_relaxed) == 43); +} + +static int test_16_(void *p) { + ptrdiff_t i; + + ATOMIC(int16_t) *x = (ATOMIC(int16_t) *) p; + + for (i = 0; i < TICK_COUNT; i++) { + atomic_fetch_add_explicit(x, 2020, memory_order_relaxed); + thrd_yield(); + atomic_fetch_add_explicit(x, 2222, memory_order_relaxed); + thrd_yield(); + atomic_fetch_add_explicit(x, -4242, memory_order_relaxed); + thrd_yield(); + } + + return 0; +} + +TEST("atomic int16 concurrency") { + ptrdiff_t i; + + ATOMIC(int16_t) foo; + ATOMIC(int16_t) bar; + + atomic_store_explicit(&foo, 42, memory_order_relaxed); + atomic_store_explicit(&bar, 43, memory_order_relaxed); + + thrd_t threads[THREAD_COUNT]; + for (i = 0; i < THREAD_COUNT; i++) + REQUIRE_EQ(thrd_create(threads + i, test_16_, + (void *) ((i % 2) ? &foo : &bar)), + thrd_success); + for (i = 0; i < THREAD_COUNT; i++) thrd_join(threads[i], NULL); + + REQUIRE(atomic_load_explicit(&foo, memory_order_relaxed) == 42); + REQUIRE(atomic_load_explicit(&bar, memory_order_relaxed) == 43); +} + +static int test_32_(void *p) { + ptrdiff_t i; + + ATOMIC(int32_t) *x = (ATOMIC(int32_t) *) p; + + for (i = 0; i < TICK_COUNT; i++) { + atomic_fetch_add_explicit(x, 202020, memory_order_relaxed); + thrd_yield(); + atomic_fetch_add_explicit(x, 222222, memory_order_relaxed); + thrd_yield(); + atomic_fetch_add_explicit(x, -424242, memory_order_relaxed); + thrd_yield(); + } + + return 0; +} + +TEST("atomic int32 concurrency") { + ptrdiff_t i; + + ATOMIC(int32_t) foo; + ATOMIC(int32_t) bar; + + atomic_store_explicit(&foo, 42, memory_order_relaxed); + atomic_store_explicit(&bar, 43, memory_order_relaxed); + + thrd_t threads[THREAD_COUNT]; + for (i = 0; i < THREAD_COUNT; i++) + REQUIRE_EQ(thrd_create(threads + i, test_32_, + (void *) ((i % 2) ? &foo : &bar)), + thrd_success); + for (i = 0; i < THREAD_COUNT; i++) thrd_join(threads[i], NULL); + + REQUIRE(atomic_load_explicit(&foo, memory_order_relaxed) == 42); + REQUIRE(atomic_load_explicit(&bar, memory_order_relaxed) == 43); +} + +static int test_64_(void *p) { + ptrdiff_t i; + + ATOMIC(int64_t) *x = (ATOMIC(int64_t) *) p; + + for (i = 0; i < TICK_COUNT; i++) { + atomic_fetch_add_explicit(x, 20202020202020ll, + memory_order_relaxed); + thrd_yield(); + atomic_fetch_add_explicit(x, 22222222222222ll, + memory_order_relaxed); + thrd_yield(); + atomic_fetch_add_explicit(x, -42424242424242ll, + memory_order_relaxed); + thrd_yield(); + } + + return 0; +} + +TEST("atomic int64 concurrency") { + ptrdiff_t i; + + ATOMIC(int64_t) foo; + ATOMIC(int64_t) bar; + + atomic_store_explicit(&foo, 42, memory_order_relaxed); + atomic_store_explicit(&bar, 43, memory_order_relaxed); + + thrd_t threads[THREAD_COUNT]; + for (i = 0; i < THREAD_COUNT; i++) + REQUIRE_EQ(thrd_create(threads + i, test_64_, + (void *) ((i % 2) ? &foo : &bar)), + thrd_success); + for (i = 0; i < THREAD_COUNT; i++) thrd_join(threads[i], NULL); + + REQUIRE(atomic_load_explicit(&foo, memory_order_relaxed) == 42); + REQUIRE(atomic_load_explicit(&bar, memory_order_relaxed) == 43); +} diff --git a/source/tests/bench.test.c b/source/tests/bench.test.c new file mode 100644 index 0000000..92e216d --- /dev/null +++ b/source/tests/bench.test.c @@ -0,0 +1,41 @@ +#define KIT_TEST_FILE bench +#include "../kit_test/bench.h" + +struct test_foo_ { + double f; +}; + +BENCHMARK("foo") { + + /* Benchmark setup. + */ + + BENCHMARK_BEGIN; + { + /* Measured code snippet. + */ + + int x = 0; + struct test_foo_ f = { 0. }; + + for (int i = 0; i < 100000; i++) { + x += (1 << 1); + x ^= i; + f.f += 0.1; + } + + DO_NOT_OPTIMIZE(x); + DO_NOT_OPTIMIZE(f); + } + BENCHMARK_END; +} + +BENCHMARK("bar") { + BENCHMARK_REPEAT(10); + BENCHMARK_REPEAT(100); + + BENCHMARK_BEGIN; + BENCHMARK_END; +} + +BENCHMARK("empty") { } diff --git a/source/tests/bigint.test.c b/source/tests/bigint.test.c new file mode 100644 index 0000000..c8ac44f --- /dev/null +++ b/source/tests/bigint.test.c @@ -0,0 +1,108 @@ +#define KIT_BIGINT_SIZE 256 +#include "../kit/bigint.h" + +#define KIT_TEST_FILE bigint +#include "../kit_test/test.h" + +#if __STDC_VERSION__ >= 199901L +static_assert(sizeof(bigint_t) == 256, "KIT_BIGINT_SIZE check"); +#endif + +TEST("bigint bin hex") { + REQUIRE(bi_equal(HEX("10"), BIN("10000"))); + REQUIRE(bi_equal(HEX("20"), BIN("100000"))); + REQUIRE(bi_equal(HEX("40"), BIN("1000000"))); + REQUIRE(bi_equal(HEX("80"), BIN("10000000"))); + REQUIRE(bi_equal(HEX("310"), BIN("1100010000"))); + REQUIRE(bi_equal(HEX("420"), BIN("10000100000"))); + REQUIRE(bi_equal(HEX("540"), BIN("10101000000"))); + REQUIRE(bi_equal(HEX("780"), BIN("11110000000"))); +} + +TEST("bigint hex add") { + REQUIRE(bi_equal( + bi_add(HEX("4242424242424242424242424242424242424242"), + HEX("1111111111111111111111111111111111111111")), + HEX("5353535353535353535353535353535353535353"))); +} + +TEST("bigint hex sub") { + REQUIRE(bi_equal( + bi_sub(HEX("4242424242424242424242424242424242424242"), + HEX("1111111111111111111111111111111111111111")), + HEX("3131313131313131313131313131313131313131"))); +} + +TEST("bigint base58") { + REQUIRE(bi_equal(BASE58("31"), bi_uint32(58 * 2))); +} + +TEST("bigint base58 add") { + REQUIRE(bi_equal( + bi_add(BASE58("4242424242424242424242424242424242424242"), + BASE58("2222222222222222222222222222222222222222")), + BASE58("5353535353535353535353535353535353535353"))); +} + +TEST("bigint base58 sub") { + REQUIRE(bi_equal( + bi_sub(BASE58("4242424242424242424242424242424242424242"), + BASE58("2222222222222222222222222222222222222222")), + BASE58("3131313131313131313131313131313131313131"))); +} + +TEST("bigint base58 mul") { + REQUIRE(bi_equal(bi_mul(BASE58("2111111111111111111111"), + BASE58("foofoofoofoofoo")), + BASE58("foofoofoofoofoo111111111111111111111"))); +} + +TEST("bigint div") { + REQUIRE(bi_equal(bi_div(bi_int32(-1), bi_int32(-1)).quotient, + bi_int32(1))); + REQUIRE(bi_equal(bi_div(bi_int32(-1), bi_int32(-1)).remainder, + bi_int32(0))); + REQUIRE(bi_equal(bi_div(bi_int32(-3), bi_int32(2)).quotient, + bi_int32(-2))); + REQUIRE(bi_equal(bi_div(bi_int32(-3), bi_int32(2)).remainder, + bi_int32(1))); + REQUIRE(bi_equal(bi_div(bi_int32(3), bi_int32(-2)).quotient, + bi_int32(-1))); + REQUIRE(bi_equal(bi_div(bi_int32(3), bi_int32(-2)).remainder, + bi_int32(1))); + REQUIRE(bi_equal(bi_div(bi_int32(-3), bi_int32(4)).quotient, + bi_int32(-1))); + REQUIRE(bi_equal(bi_div(bi_int32(-3), bi_int32(4)).remainder, + bi_int32(3))); + REQUIRE(bi_equal(bi_div(bi_int32(3), bi_int32(-4)).quotient, + bi_int32(0))); + REQUIRE(bi_equal(bi_div(bi_int32(3), bi_int32(-4)).remainder, + bi_int32(3))); + + REQUIRE( + bi_equal(bi_div(HEX("100"), HEX("10")).quotient, HEX("10"))); + + REQUIRE(bi_equal(bi_div(bi_mul(BASE58("foofoofoofoofoofoo"), + BASE58("barbarbarbarbarbar")), + BASE58("barbarbarbarbarbar")) + .quotient, + BASE58("foofoofoofoofoofoo"))); + + REQUIRE(bi_equal(bi_div(bi_mul(BASE58("foofoofoofoofoofoofoofoo"), + BASE58("barbarbarbarbarbar")), + BASE58("barbarbarbarbarbar")) + .quotient, + BASE58("foofoofoofoofoofoofoofoo"))); + + REQUIRE(bi_equal( + bi_div( + bi_mul(BASE58("foofoofoofoofoofoofoofoofoofoofoofoofoofoofo" + "ofoofoofoo"), + BASE58("barbarbarbarbarbarbarbarbarbarbarbarbarbarba" + "rbar")), + BASE58("barbarbarbarbarbarbarbarbarbarbarbarbarbarbarbar")) + .quotient, + BASE58( + "foofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoo"))); +} + diff --git a/source/tests/condition_variable.test.c b/source/tests/condition_variable.test.c new file mode 100644 index 0000000..dfbe4a6 --- /dev/null +++ b/source/tests/condition_variable.test.c @@ -0,0 +1,84 @@ +#include "../kit/condition_variable.h" +#include "../kit/thread.h" + +#define KIT_TEST_FILE condition_variable +#include "../kit_test/test.h" + +typedef struct { + mtx_t m; + int in; + int out; + cnd_t send; + cnd_t receive; + int value; +} cnd_test_data_t; + +static int cnd_test_run(void *p) { + cnd_test_data_t *data = (cnd_test_data_t *) p; + + mtx_lock(&data->m); + data->value = 20; + data->out = 1; + mtx_unlock(&data->m); + + cnd_broadcast(&data->send); + + mtx_lock(&data->m); + if (data->in == 0) + cnd_wait(&data->receive, &data->m); + data->in = 0; + data->value = 22; + data->out = 1; + mtx_unlock(&data->m); + + cnd_broadcast(&data->send); + + return 0; +} + +TEST("condition variable") { + int i; + int ok = 1; + + for (i = 0; i < 10; i++) { + cnd_test_data_t data; + + data.in = 0; + data.out = 0; + data.value = 0; + + ok = ok && (mtx_init(&data.m, mtx_plain) == thrd_success); + ok = ok && (cnd_init(&data.send) == thrd_success); + ok = ok && (cnd_init(&data.receive) == thrd_success); + + thrd_t t; + ok = ok && (thrd_create(&t, cnd_test_run, &data) == thrd_success); + + ok = ok && (mtx_lock(&data.m) == thrd_success); + if (data.out == 0) + ok = ok && (cnd_wait(&data.send, &data.m) == thrd_success); + data.out = 0; + int x = data.value; + data.in = 1; + ok = ok && (mtx_unlock(&data.m) == thrd_success); + + ok = ok && (cnd_broadcast(&data.receive) == thrd_success); + + ok = ok && (mtx_lock(&data.m) == thrd_success); + if (data.out == 0) + ok = ok && (cnd_wait(&data.send, &data.m) == thrd_success); + data.out = 0; + x += data.value; + ok = ok && (mtx_unlock(&data.m) == thrd_success); + + ok = ok && (thrd_join(t, NULL) == thrd_success); + + mtx_destroy(&data.m); + cnd_destroy(&data.send); + cnd_destroy(&data.receive); + + ok = ok && (x == 42); + } + + REQUIRE(ok); +} diff --git a/source/tests/cpp.cpp b/source/tests/cpp.cpp new file mode 100644 index 0000000..8b762e4 --- /dev/null +++ b/source/tests/cpp.cpp @@ -0,0 +1,13 @@ +#include "../kit_test/test.h" + +TEST("foo") { + REQUIRE(20 + 22 == 42); +} + +TEST("bar") { + REQUIRE(true); +} + +int main(int argc, char **argv) { + return run_tests(argc, argv); +} diff --git a/source/tests/dynamic_array.test.c b/source/tests/dynamic_array.test.c new file mode 100644 index 0000000..8701e6c --- /dev/null +++ b/source/tests/dynamic_array.test.c @@ -0,0 +1,174 @@ +#include "../kit/dynamic_array.h" + +#define KIT_TEST_FILE dynamic_array +#include "../kit_test/test.h" + +TEST("dynamic array empty") { + DA_CREATE(v, char, 0); + + REQUIRE(v.size == 0); + + DA_DESTROY(v); +} + +TEST("dynamic array resize") { + DA_CREATE(v, char, 0); + DA_RESIZE(v, 10); + + REQUIRE(v.size == 10); + + DA_DESTROY(v); +} + +TEST("dynamic array grow") { + DA_CREATE(v, char, 2); + DA_RESIZE(v, 10); + + REQUIRE(v.size == 10); + + DA_DESTROY(v); +} + +TEST("dynamic array diminish") { + DA_CREATE(v, char, 10); + DA_RESIZE(v, 9); + + REQUIRE(v.size == 9); + + DA_DESTROY(v); +} + +TEST("dynamic array of chars") { + DA_CREATE(v, char, 100); + + REQUIRE(v.size == 100); + REQUIRE(v.capacity >= 100); + REQUIRE(v.values != NULL); + + DA_DESTROY(v); +} + +TEST("dynamic array push") { + DA_CREATE(v, char, 0); + DA_APPEND(v, 'x'); + + REQUIRE(v.size == 1); + REQUIRE(v.values[0] == 'x'); + + DA_DESTROY(v); +} + +TEST("dynamic array insert front") { + DA_CREATE(v, char, 3); + + v.values[0] = 'a'; + v.values[1] = 'b'; + v.values[2] = 'c'; + + DA_INSERT(v, 0, 'x'); + + REQUIRE(v.size == 4); + REQUIRE(v.values[0] == 'x'); + REQUIRE(v.values[1] == 'a'); + REQUIRE(v.values[2] == 'b'); + REQUIRE(v.values[3] == 'c'); + + DA_DESTROY(v); +} + +TEST("dynamic array insert back") { + DA_CREATE(v, char, 3); + + v.values[0] = 'a'; + v.values[1] = 'b'; + v.values[2] = 'c'; + + DA_INSERT(v, 3, 'x'); + + REQUIRE(v.size == 4); + REQUIRE(v.values[0] == 'a'); + REQUIRE(v.values[1] == 'b'); + REQUIRE(v.values[2] == 'c'); + REQUIRE(v.values[3] == 'x'); + + DA_DESTROY(v); +} + +TEST("dynamic array insert middle") { + DA_CREATE(v, char, 3); + + v.values[0] = 'a'; + v.values[1] = 'b'; + v.values[2] = 'c'; + + DA_INSERT(v, 2, 'x'); + + REQUIRE(v.size == 4); + REQUIRE(v.values[0] == 'a'); + REQUIRE(v.values[1] == 'b'); + REQUIRE(v.values[2] == 'x'); + REQUIRE(v.values[3] == 'c'); + + DA_DESTROY(v); +} + +TEST("dynamic array erase front") { + DA_CREATE(v, char, 3); + + v.values[0] = 'a'; + v.values[1] = 'b'; + v.values[2] = 'c'; + + DA_ERASE(v, 0); + + REQUIRE(v.size == 2); + REQUIRE(v.values[0] == 'b'); + REQUIRE(v.values[1] == 'c'); + + DA_DESTROY(v); +} + +TEST("dynamic array erase back") { + DA_CREATE(v, char, 3); + + v.values[0] = 'a'; + v.values[1] = 'b'; + v.values[2] = 'c'; + + DA_ERASE(v, 2); + + REQUIRE(v.size == 2); + REQUIRE(v.values[0] == 'a'); + REQUIRE(v.values[1] == 'b'); + + DA_DESTROY(v); +} + +TEST("dynamic array erase middle") { + DA_CREATE(v, char, 3); + + v.values[0] = 'a'; + v.values[1] = 'b'; + v.values[2] = 'c'; + + DA_ERASE(v, 1); + + REQUIRE(v.size == 2); + REQUIRE(v.values[0] == 'a'); + REQUIRE(v.values[1] == 'c'); + + DA_DESTROY(v); +} + +TEST("dynamic array of ints") { + DA_CREATE(v, int, 10); + DA_RESIZE(v, 5); + v.values[4] = 42; + DA_APPEND(v, 43); + + REQUIRE(v.size == 6); + REQUIRE(v.values[4] == 42); + REQUIRE(v.values[5] == 43); + + DA_DESTROY(v); +} diff --git a/source/tests/file.test.c b/source/tests/file.test.c new file mode 100644 index 0000000..e72df83 --- /dev/null +++ b/source/tests/file.test.c @@ -0,0 +1,220 @@ +#include "../kit/file.h" +#include "../kit/string_ref.h" +#include + +#define KIT_TEST_FILE file +#include "../kit_test/test.h" + +TEST("file path cache") { + kit_allocator_t alloc = kit_alloc_default(); + + string_t user = path_user(alloc); + string_t cache = path_cache(alloc); + + DA_RESIZE(cache, cache.size + 1); + cache.values[cache.size - 1] = '\0'; + DA_RESIZE(cache, cache.size - 1); + + string_t expected = +#if defined(_WIN32) && !defined(__CYGWIN__) + path_join(WRAP_STR(user), SZ("AppData" PATH_DELIM "Local"), + alloc); +#elif defined(__APPLE__) + path_join(WRAP_STR(user), SZ("Library" PATH_DELIM "Caches"), + alloc); +#else + path_join(WRAP_STR(user), SZ(".cache"), alloc); +#endif + + REQUIRE(AR_EQUAL(cache, expected)); + + DA_DESTROY(user); + DA_DESTROY(cache); + DA_DESTROY(expected); +} + +TEST("file path normalize one") { + str_t foo = SZ("foo/bar/../baz"); + str_t foo_norm = SZ("foo" PATH_DELIM "baz"); + + string_t bar = path_norm(foo, kit_alloc_default()); + + REQUIRE(AR_EQUAL(foo_norm, bar)); + + DA_DESTROY(bar); +} + +TEST("file path normalize two") { + str_t foo = SZ("foo/bar/../../baz"); + str_t foo_norm = SZ("baz"); + + string_t bar = path_norm(foo, kit_alloc_default()); + + REQUIRE(AR_EQUAL(foo_norm, bar)); + + DA_DESTROY(bar); +} + +TEST("file path normalize parent") { + str_t foo = SZ("../baz"); + str_t foo_norm = SZ(".." PATH_DELIM "baz"); + + string_t bar = path_norm(foo, kit_alloc_default()); + + REQUIRE(AR_EQUAL(foo_norm, bar)); + + DA_DESTROY(bar); +} + +TEST("file path normalize double parent") { + str_t foo = SZ("foo/../../baz"); + str_t foo_norm = SZ(".." PATH_DELIM "baz"); + + string_t bar = path_norm(foo, kit_alloc_default()); + + REQUIRE(AR_EQUAL(foo_norm, bar)); + + DA_DESTROY(bar); +} + +TEST("file path normalize windows delim") { + str_t foo = SZ("foo\\bar\\..\\baz"); + str_t foo_norm = SZ("foo" PATH_DELIM "baz"); + + string_t bar = path_norm(foo, kit_alloc_default()); + + REQUIRE(AR_EQUAL(foo_norm, bar)); + + DA_DESTROY(bar); +} + +TEST("file path join no delim") { + str_t foo = SZ("foo"); + str_t bar = SZ("bar"); + str_t joined = SZ("foo" PATH_DELIM "bar"); + + string_t foobar = path_join(foo, bar, kit_alloc_default()); + + REQUIRE(AR_EQUAL(joined, foobar)); + + DA_DESTROY(foobar); +} + +TEST("file path join delim left") { + str_t foo = SZ("foo/"); + str_t bar = SZ("bar"); + str_t joined = SZ("foo" PATH_DELIM "bar"); + + string_t foobar = path_join(foo, bar, kit_alloc_default()); + + REQUIRE(AR_EQUAL(joined, foobar)); + + DA_DESTROY(foobar); +} + +TEST("file path join delim right") { + str_t foo = SZ("foo"); + str_t bar = SZ("/bar"); + str_t joined = SZ("foo" PATH_DELIM "bar"); + + string_t foobar = path_join(foo, bar, kit_alloc_default()); + + REQUIRE(AR_EQUAL(joined, foobar)); + + DA_DESTROY(foobar); +} + +TEST("file path join delim both") { + str_t foo = SZ("foo/"); + str_t bar = SZ("/bar"); + str_t joined = SZ("foo" PATH_DELIM "bar"); + + string_t foobar = path_join(foo, bar, kit_alloc_default()); + + REQUIRE(AR_EQUAL(joined, foobar)); + + DA_DESTROY(foobar); +} + +TEST("file path user") { + string_t user = path_user(kit_alloc_default()); + + REQUIRE(user.size > 0); + + DA_DESTROY(user); +} + +TEST("file path index relative") { + str_t foobar = SZ("foo/bar"); + str_t foo = SZ("foo"); + str_t bar = SZ("bar"); + + REQUIRE(AR_EQUAL(path_index(foobar, 0), foo)); + REQUIRE(AR_EQUAL(path_index(foobar, 1), bar)); + REQUIRE(path_index(foobar, 2).size == 0); +} + +TEST("file path index absolute") { + str_t foobar = SZ("/foo/bar"); + str_t foo = SZ("foo"); + str_t bar = SZ("bar"); + + REQUIRE(AR_EQUAL(path_index(foobar, 0), foo)); + REQUIRE(AR_EQUAL(path_index(foobar, 1), bar)); + REQUIRE(path_index(foobar, 2).size == 0); +} + +TEST("file path index windows disk name") { + str_t foobar = SZ("c:\\foo\\bar"); + str_t disk = SZ("c:"); + str_t foo = SZ("foo"); + str_t bar = SZ("bar"); + + REQUIRE(AR_EQUAL(path_index(foobar, 0), disk)); + REQUIRE(AR_EQUAL(path_index(foobar, 1), foo)); + REQUIRE(AR_EQUAL(path_index(foobar, 2), bar)); + REQUIRE(path_index(foobar, 3).size == 0); +} + +TEST("file path take relative") { + str_t foobar = SZ("foo/bar/"); + str_t foo = SZ("foo"); + str_t bar = SZ("foo/bar"); + str_t bar_end = SZ("foo/bar/"); + + REQUIRE(AR_EQUAL(path_take(foobar, 0), foo)); + REQUIRE(AR_EQUAL(path_take(foobar, 1), bar)); + REQUIRE(AR_EQUAL(path_take(foobar, 2), bar_end)); +} + +TEST("file path take absolute") { + str_t foobar = SZ("/foo/bar"); + str_t foo = SZ("/foo"); + str_t bar = SZ("/foo/bar"); + + REQUIRE(AR_EQUAL(path_take(foobar, 0), foo)); + REQUIRE(AR_EQUAL(path_take(foobar, 1), bar)); +} + +TEST("file path take windows disk name") { + str_t foobar = SZ("c:\\foo\\bar"); + str_t disk = SZ("c:"); + str_t foo = SZ("c:\\foo"); + str_t bar = SZ("c:\\foo\\bar"); + + REQUIRE(AR_EQUAL(path_take(foobar, 0), disk)); + REQUIRE(AR_EQUAL(path_take(foobar, 1), foo)); + REQUIRE(AR_EQUAL(path_take(foobar, 2), bar)); +} + +TEST("file create folder") { } + +TEST("file create folder recursive") { } + +TEST("file remove") { } + +TEST("file remove folder") { } + +TEST("file remove recursive") { } + +TEST("file enum folder") { } diff --git a/source/tests/input_buffer.test.c b/source/tests/input_buffer.test.c new file mode 100644 index 0000000..3cd84b6 --- /dev/null +++ b/source/tests/input_buffer.test.c @@ -0,0 +1,105 @@ +#include "../kit/input_buffer.h" + +#define KIT_TEST_FILE input_buffer +#include "../kit_test/test.h" + +TEST("input buffer read once") { + str_t text = { .size = 3, .values = "foo" }; + is_handle_t in = IS_WRAP_STRING(text); + ib_handle_t first = IB_WRAP(in); + + ib_handle_t second = ib_read(first, 3); + + REQUIRE(second.status == KIT_OK); + REQUIRE(second.data.size == 3); + REQUIRE(AR_EQUAL(text, second.data)); + + ib_destroy(second); + ib_destroy(first); + is_destroy(in); +} + +TEST("input buffer read again") { + str_t text = { .size = 6, .values = "foobar" }; + str_t foo = { .size = 3, .values = "foo" }; + is_handle_t in = IS_WRAP_STRING(text); + ib_handle_t first = IB_WRAP(in); + + ib_handle_t second = ib_read(first, 3); + ib_handle_t third = ib_read(first, 3); + + REQUIRE(AR_EQUAL(foo, second.data)); + REQUIRE(AR_EQUAL(foo, third.data)); + + ib_destroy(third); + ib_destroy(second); + ib_destroy(first); + is_destroy(in); +} + +TEST("input buffer read twice") { + str_t text = { .size = 6, .values = "foobar" }; + str_t foo = { .size = 3, .values = "foo" }; + str_t bar = { .size = 3, .values = "bar" }; + is_handle_t in = IS_WRAP_STRING(text); + ib_handle_t first = IB_WRAP(in); + + ib_handle_t second = ib_read(first, 3); + ib_handle_t third = ib_read(second, 3); + + REQUIRE(AR_EQUAL(foo, second.data)); + REQUIRE(AR_EQUAL(bar, third.data)); + + ib_destroy(third); + ib_destroy(second); + ib_destroy(first); + is_destroy(in); +} + +static int is_integer_(str_t const data) { + for (ptrdiff_t i = 0; i < data.size; i++) + if (data.values[i] < '0' || data.values[i] > '9') + return 0; + return 1; +} + +TEST("input buffer read integer once") { + str_t text = { .size = 9, .values = "31415 foo" }; + str_t num = { .size = 5, .values = "31415" }; + is_handle_t in = IS_WRAP_STRING(text); + ib_handle_t first = IB_WRAP(in); + + ib_handle_t second = ib_read_while(first, is_integer_); + + REQUIRE(second.status == KIT_OK); + REQUIRE(second.data.size == 5); + REQUIRE(AR_EQUAL(num, second.data)); + + ib_destroy(second); + ib_destroy(first); + is_destroy(in); +} + +TEST("input buffer read integer twice") { + str_t text = { .size = 6, .values = "314 15" }; + str_t num_0 = { .size = 3, .values = "314" }; + str_t num_1 = { .size = 2, .values = "15" }; + is_handle_t in = IS_WRAP_STRING(text); + ib_handle_t first = IB_WRAP(in); + + ib_handle_t second = ib_read_while(first, is_integer_); + ib_handle_t third = ib_read(second, 1); + ib_handle_t fourth = ib_read_while(third, is_integer_); + + REQUIRE(fourth.status == KIT_OK); + REQUIRE(second.data.size == 3); + REQUIRE(fourth.data.size == 2); + REQUIRE(AR_EQUAL(num_0, second.data)); + REQUIRE(AR_EQUAL(num_1, fourth.data)); + + ib_destroy(first); + ib_destroy(second); + ib_destroy(third); + ib_destroy(fourth); + is_destroy(in); +} diff --git a/source/tests/input_stream.test.c b/source/tests/input_stream.test.c new file mode 100644 index 0000000..61c2254 --- /dev/null +++ b/source/tests/input_stream.test.c @@ -0,0 +1,23 @@ +#include "../kit/input_stream.h" + +#define KIT_TEST_FILE input_stream +#include "../kit_test/test.h" + +TEST("input stream wrap string") { + char foo[] = "test"; + char bar[] = "test"; + + str_t foo_ref = { .size = sizeof(foo) - 1, .values = foo }; + str_t bar_ref = { .size = sizeof(bar) - 1, .values = bar }; + + is_handle_t in = IS_WRAP_STRING(foo_ref); + + char buf[4]; + out_str_t buf_ref = { .size = sizeof(buf), .values = buf }; + + REQUIRE(IS_READ(in, buf_ref) == buf_ref.size); + REQUIRE(AR_EQUAL(foo_ref, bar_ref)); + REQUIRE(AR_EQUAL(buf_ref, bar_ref)); + + is_destroy(in); +} diff --git a/source/tests/lower_bound.test.c b/source/tests/lower_bound.test.c new file mode 100644 index 0000000..3b62325 --- /dev/null +++ b/source/tests/lower_bound.test.c @@ -0,0 +1,178 @@ +#include "../kit/lower_bound.h" +#include "../kit/array_ref.h" + +#define KIT_TEST_FILE lower_bound +#include "../kit_test/test.h" + +static int kit_less_int(int left, int right) { + return left < right; +} + +static int kit_less_int_ref(int const *left, int const *right) { + return *left < *right; +} + +TEST("lower bound empty") { + AR(int) ref = { .size = 0, .values = NULL }; + + ptrdiff_t index; + LOWER_BOUND(index, ref, 42, kit_less_int); + REQUIRE(index == 0); +} + +TEST("lower bound single left") { + int const v[1] = { 42 }; + AR(int) ref = { .size = 1, .values = v }; + + ptrdiff_t index; + LOWER_BOUND(index, ref, 42, kit_less_int); + REQUIRE(index == 0); +} + +TEST("lower bound single right") { + int const v[1] = { 42 }; + AR(int) ref = { .size = 1, .values = v }; + + ptrdiff_t index; + LOWER_BOUND(index, ref, 43, kit_less_int); + REQUIRE(index == 1); +} + +TEST("lower bound first of four") { + int const v[4] = { 1, 2, 3, 4 }; + AR(int) ref = { .size = 4, .values = v }; + + ptrdiff_t index; + LOWER_BOUND(index, ref, 1, kit_less_int); + REQUIRE(index == 0); +} + +TEST("lower bound second of four") { + int const v[4] = { 1, 2, 3, 4 }; + AR(int) ref = { .size = 4, .values = v }; + + ptrdiff_t index; + LOWER_BOUND(index, ref, 2, kit_less_int); + REQUIRE(index == 1); +} + +TEST("lower bound third of four") { + int const v[4] = { 1, 2, 3, 4 }; + AR(int) ref = { .size = 4, .values = v }; + + ptrdiff_t index; + LOWER_BOUND(index, ref, 3, kit_less_int); + REQUIRE(index == 2); +} + +TEST("lower bound forth of four") { + int const v[4] = { 1, 2, 3, 4 }; + AR(int) ref = { .size = 4, .values = v }; + + ptrdiff_t index; + LOWER_BOUND(index, ref, 4, kit_less_int); + REQUIRE(index == 3); +} + +TEST("lower bound fifth of four") { + int const v[4] = { 1, 2, 3, 4 }; + AR(int) ref = { .size = 4, .values = v }; + + ptrdiff_t index; + LOWER_BOUND(index, ref, 5, kit_less_int); + REQUIRE(index == 4); +} + +TEST("lower bound first of five") { + int const v[5] = { 1, 2, 3, 4, 5 }; + AR(int) ref = { .size = 5, .values = v }; + + ptrdiff_t index; + LOWER_BOUND(index, ref, 1, kit_less_int); + REQUIRE(index == 0); +} + +TEST("lower bound second of five") { + int const v[5] = { 1, 2, 3, 4, 5 }; + AR(int) ref = { .size = 5, .values = v }; + + ptrdiff_t index; + LOWER_BOUND(index, ref, 2, kit_less_int); + REQUIRE(index == 1); +} + +TEST("lower bound third of five") { + int const v[5] = { 1, 2, 3, 4, 5 }; + AR(int) ref = { .size = 5, .values = v }; + + ptrdiff_t index; + LOWER_BOUND(index, ref, 3, kit_less_int); + REQUIRE(index == 2); +} + +TEST("lower bound forth of five") { + int const v[5] = { 1, 2, 3, 4, 5 }; + AR(int) ref = { .size = 5, .values = v }; + + ptrdiff_t index; + LOWER_BOUND(index, ref, 4, kit_less_int); + REQUIRE(index == 3); +} + +TEST("lower bound fifth of five") { + int const v[5] = { 1, 2, 3, 4, 5 }; + AR(int) ref = { .size = 5, .values = v }; + + ptrdiff_t index; + LOWER_BOUND(index, ref, 5, kit_less_int); + REQUIRE(index == 4); +} + +TEST("lower bound sixth of five") { + int const v[5] = { 1, 2, 3, 4, 5 }; + AR(int) ref = { .size = 5, .values = v }; + + ptrdiff_t index; + LOWER_BOUND(index, ref, 6, kit_less_int); + REQUIRE(index == 5); +} + +TEST("lower bound ref first of four") { + int const v[4] = { 1, 2, 3, 4 }; + int const value = 1; + AR(int) ref = { .size = 4, .values = v }; + + ptrdiff_t index; + LOWER_BOUND_REF(index, ref, &value, kit_less_int_ref); + REQUIRE(index == 0); +} + +TEST("lower bound ref second of four") { + int const v[4] = { 1, 2, 3, 4 }; + int const value = 2; + AR(int) ref = { .size = 4, .values = v }; + + ptrdiff_t index; + LOWER_BOUND_REF(index, ref, &value, kit_less_int_ref); + REQUIRE(index == 1); +} + +TEST("lower bound ref fifth of five") { + int const v[5] = { 1, 2, 3, 4, 5 }; + int const value = 5; + AR(int) ref = { .size = 5, .values = v }; + + ptrdiff_t index; + LOWER_BOUND_REF(index, ref, &value, kit_less_int_ref); + REQUIRE(index == 4); +} + +TEST("lower bound ref sixth of five") { + int const v[5] = { 1, 2, 3, 4, 5 }; + int const value = 6; + AR(int) ref = { .size = 5, .values = v }; + + ptrdiff_t index; + LOWER_BOUND_REF(index, ref, &value, kit_less_int_ref); + REQUIRE(index == 5); +} diff --git a/source/tests/main.test.c b/source/tests/main.test.c new file mode 100644 index 0000000..2a41d4b --- /dev/null +++ b/source/tests/main.test.c @@ -0,0 +1,9 @@ +#include "../kit_test/bench.h" +#include "../kit_test/test.h" + +int main(int argc, char **argv) { + int status = run_tests(argc, argv); + if (status == 0) + status = run_benchmarks(argc, argv); + return status; +} diff --git a/source/tests/mersenne_twister_64.test.c b/source/tests/mersenne_twister_64.test.c new file mode 100644 index 0000000..6bf5b9c --- /dev/null +++ b/source/tests/mersenne_twister_64.test.c @@ -0,0 +1,38 @@ +#include "../kit/mersenne_twister_64.h" +#include "../kit/secure_random.h" + +#define KIT_TEST_FILE mersenne_twister_64 +#include "../kit_test/test.h" + +enum { SIZE = 1000 }; + +TEST("mt64 same seeds") { + ptrdiff_t i; + uint64_t seed; + secure_random(sizeof seed, &seed); + + mt64_state_t foo, bar; + mt64_init(&foo, seed); + mt64_init(&bar, seed); + + int ok = 1; + for (i = 0; i < SIZE; i++) + ok = ok && mt64_generate(&foo) == mt64_generate(&bar); + + REQUIRE(ok); +} + +TEST("mt64 different seeds") { + ptrdiff_t i; + + mt64_state_t foo, bar; + mt64_init(&foo, 42); + mt64_init(&bar, 4242424242); + + ptrdiff_t difference_count = 0; + for (i = 0; i < SIZE; i++) + if (mt64_generate(&foo) != mt64_generate(&bar)) + difference_count++; + + REQUIRE(difference_count > SIZE / 2); +} diff --git a/source/tests/move_back.test.c b/source/tests/move_back.test.c new file mode 100644 index 0000000..f08d190 --- /dev/null +++ b/source/tests/move_back.test.c @@ -0,0 +1,148 @@ +#include "../kit/move_back.h" + +#define KIT_TEST_FILE move_back +#include "../kit_test/test.h" + +static int is_equal(int const x, int const y) { + return x == y; +} + +static int is_equal_ref(int const *const x, int const y) { + return *x == y; +} + +static int is_even(int const x, int const _) { + return (x % 2) == 0; +} + +static int is_even_ref(int const *const x, int const _) { + return (*x % 2) == 0; +} + +TEST("move back val") { + int v[] = { 1, 2, 2, 2, 1, 1 }; + + struct { + int size; + int *values; + } ref = { .size = sizeof v / sizeof *v, .values = v }; + + MOVE_BACK(ref.size, ref, 2, is_equal); + + REQUIRE_EQ(ref.size, 3); + REQUIRE_EQ(v[0], 1); + REQUIRE_EQ(v[1], 1); + REQUIRE_EQ(v[2], 1); +} + +TEST("move back ref val") { + int v[] = { 1, 2, 2, 2, 1, 1 }; + + struct { + int size; + int *values; + } ref = { .size = sizeof v / sizeof *v, .values = v }; + + MOVE_BACK_REF(ref.size, ref, 2, is_equal_ref); + + REQUIRE(ref.size == 3); + REQUIRE(v[0] == 1); + REQUIRE(v[1] == 1); + REQUIRE(v[2] == 1); +} + +TEST("move back 1") { + int v[] = { 1, 2, 3, 4, 5, 6 }; + + struct { + int size; + int *values; + } ref = { .size = sizeof v / sizeof *v, .values = v }; + + MOVE_BACK(ref.size, ref, 0, is_even); + + REQUIRE(ref.size == 3); + REQUIRE(v[0] == 1); + REQUIRE(v[1] == 5); + REQUIRE(v[2] == 3); +} + +TEST("move back 2") { + int v[] = { 2, 4, 6, 1, 3, 5 }; + + struct { + int size; + int *values; + } ref = { .size = sizeof v / sizeof *v, .values = v }; + + MOVE_BACK(ref.size, ref, 0, is_even); + + REQUIRE(ref.size == 3); + REQUIRE(v[0] == 5); + REQUIRE(v[1] == 3); + REQUIRE(v[2] == 1); +} + +TEST("move back 3") { + int v[] = { 1, 3, 5, 2, 4, 6 }; + + struct { + int size; + int *values; + } ref = { .size = sizeof v / sizeof *v, .values = v }; + + MOVE_BACK(ref.size, ref, 0, is_even); + + REQUIRE(ref.size == 3); + REQUIRE(v[0] == 1); + REQUIRE(v[1] == 3); + REQUIRE(v[2] == 5); +} + +TEST("move back ref 1") { + int v[] = { 1, 2, 3, 4, 5, 6 }; + + struct { + int size; + int *values; + } ref = { .size = sizeof v / sizeof *v, .values = v }; + + MOVE_BACK_REF(ref.size, ref, 0, is_even_ref); + + REQUIRE(ref.size == 3); + REQUIRE(v[0] == 1); + REQUIRE(v[1] == 5); + REQUIRE(v[2] == 3); +} + +TEST("move back ref 2") { + int v[] = { 2, 4, 6, 1, 3, 5 }; + + struct { + int size; + int *values; + } ref = { .size = sizeof v / sizeof *v, .values = v }; + + MOVE_BACK_REF(ref.size, ref, 0, is_even_ref); + + REQUIRE(ref.size == 3); + REQUIRE(v[0] == 5); + REQUIRE(v[1] == 3); + REQUIRE(v[2] == 1); +} + +TEST("move back ref 3") { + int v[] = { 1, 3, 5, 2, 4, 6 }; + + struct { + int size; + int *values; + } ref = { .size = sizeof v / sizeof *v, .values = v }; + + MOVE_BACK_REF(ref.size, ref, 0, is_even_ref); + + REQUIRE(ref.size == 3); + REQUIRE(v[0] == 1); + REQUIRE(v[1] == 3); + REQUIRE(v[2] == 5); +} diff --git a/source/tests/mutex.test.c b/source/tests/mutex.test.c new file mode 100644 index 0000000..ce26991 --- /dev/null +++ b/source/tests/mutex.test.c @@ -0,0 +1,79 @@ +#include "../kit/mutex.h" +#include "../kit/thread.h" + +#define KIT_TEST_FILE mutex +#include "../kit_test/test.h" + +enum { SLEEP = 400000000, TICK_COUNT = 200, THREAD_COUNT = 100 }; + +typedef struct { + mtx_t lock; + int value; +} mtx_test_data_t; + +static int mtx_test_run(void *data) { + int i; + mtx_test_data_t *x = (mtx_test_data_t *) data; + for (i = 0; i < TICK_COUNT; i++) { + mtx_lock(&x->lock); + + x->value += i; + thrd_yield(); + x->value -= i + 42; + thrd_yield(); + x->value += i + 20; + thrd_yield(); + x->value += 22 - i; + + mtx_unlock(&x->lock); + } + return 0; +} + +TEST("mutex lock") { + ptrdiff_t i; + + mtx_test_data_t data; + thrd_t pool[THREAD_COUNT]; + data.value = 42; + REQUIRE(mtx_init(&data.lock, mtx_plain) == thrd_success); + + for (i = 0; i < THREAD_COUNT; i++) + thrd_create(pool + i, mtx_test_run, &data); + for (i = 0; i < THREAD_COUNT; i++) thrd_join(pool[i], NULL); + + mtx_destroy(&data.lock); + REQUIRE(data.value == 42); +} + +static int test_lock(void *data) { + mtx_t *m = (mtx_t *) data; + mtx_lock(m); + + struct timespec sec = { .tv_sec = 0, .tv_nsec = SLEEP }; + thrd_sleep(&sec, NULL); + + mtx_unlock(m); + + return 0; +} + +TEST("mutex try lock") { + mtx_t m; + REQUIRE(mtx_init(&m, mtx_plain) == thrd_success); + + thrd_t t; + REQUIRE(thrd_create(&t, test_lock, &m) == thrd_success); + + struct timespec sec = { .tv_sec = 0, .tv_nsec = SLEEP / 2 }; + REQUIRE(thrd_sleep(&sec, NULL) == thrd_success); + + REQUIRE(mtx_trylock(&m) == thrd_busy); + + REQUIRE(thrd_join(t, NULL) == thrd_success); + + REQUIRE(mtx_trylock(&m) == thrd_success); + REQUIRE(mtx_unlock(&m) == thrd_success); + + mtx_destroy(&m); +} diff --git a/source/tests/secure_random.test.c b/source/tests/secure_random.test.c new file mode 100644 index 0000000..22bdd37 --- /dev/null +++ b/source/tests/secure_random.test.c @@ -0,0 +1,24 @@ +#include "../kit/secure_random.h" +#include + +#define KIT_TEST_FILE secure_random +#include "../kit_test/test.h" + +TEST("secure random") { + int i, j; + + int v[20]; + memset(v, 0, sizeof v); + + secure_random(40, v); + secure_random(40, v + 10); + + int repeats = 0; + + for (i = 1; i < sizeof v / sizeof *v; i++) + for (j = 0; j < i; j++) + if (v[i] == v[j]) + repeats++; + + REQUIRE(repeats == 0); +} diff --git a/source/tests/sha256.test.c b/source/tests/sha256.test.c new file mode 100644 index 0000000..0f751df --- /dev/null +++ b/source/tests/sha256.test.c @@ -0,0 +1,42 @@ +#include "../kit/sha256.h" +#include "../kit/array_ref.h" + +#define KIT_TEST_FILE sha256_64 +#include "../kit_test/test.h" + +#include + +TEST("sha256") { + uint8_t text1[] = "abc"; + uint8_t text2[] = + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; + + uint8_t text3[1000000]; + memset(text3, 'a', sizeof text3); + + uint8_t hash1[] = { + 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, + 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, + 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad + }; + uint8_t hash2[] = { + 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, + 0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, + 0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1 + }; + uint8_t hash3[] = { + 0xcd, 0xc7, 0x6e, 0x5c, 0x99, 0x14, 0xfb, 0x92, 0x81, 0xa1, 0xc7, + 0xe2, 0x84, 0xd7, 0x3e, 0x67, 0xf1, 0x80, 0x9a, 0x48, 0xa4, 0x97, + 0x20, 0x0e, 0x04, 0x6d, 0x39, 0xcc, 0xc7, 0x11, 0x2c, 0xd0 + }; + + REQUIRE(ar_equal_bytes(1, SHA256_BLOCK_SIZE, + sha256((sizeof text1) - 1, text1).v, 1, + SHA256_BLOCK_SIZE, hash1)); + REQUIRE(ar_equal_bytes(1, SHA256_BLOCK_SIZE, + sha256((sizeof text2) - 1, text2).v, 1, + SHA256_BLOCK_SIZE, hash2)); + REQUIRE(ar_equal_bytes(1, SHA256_BLOCK_SIZE, + sha256(sizeof text3, text3).v, 1, + SHA256_BLOCK_SIZE, hash3)); +} diff --git a/source/tests/signals.cpp b/source/tests/signals.cpp new file mode 100644 index 0000000..0f6d77a --- /dev/null +++ b/source/tests/signals.cpp @@ -0,0 +1,29 @@ +#include "../kit_test/test.h" + +#include +#include + +/* FIXME + * MSVC tests fail in GitHub Actions. + */ + +TEST("c++ exception") { + throw std::exception(); +} + +TEST("abort") { + abort(); +} + +TEST("invalid access") { + *(volatile int *) nullptr = 42; +} + +int main(int argc, char **argv) { +#ifndef _MSC_VER + if (run_tests(argc, argv) != 1) + return 1; +#endif + + return 0; +} diff --git a/source/tests/string_ref.test.c b/source/tests/string_ref.test.c new file mode 100644 index 0000000..2891f16 --- /dev/null +++ b/source/tests/string_ref.test.c @@ -0,0 +1,23 @@ +#include "../kit/string_ref.h" + +#define KIT_TEST_FILE string_ref +#include "../kit_test/test.h" + +TEST("static string wrap") { + str_t ref = SZ("foo bar"); + + REQUIRE(ref.size == 7); + REQUIRE(ref.values[0] == 'f'); + REQUIRE(ref.values[1] == 'o'); + REQUIRE(ref.values[2] == 'o'); + REQUIRE(ref.values[3] == ' '); + REQUIRE(ref.values[4] == 'b'); + REQUIRE(ref.values[5] == 'a'); + REQUIRE(ref.values[6] == 'r'); +} + +TEST("string literal") { + str_t foo = SZ("foo"); + str_t bar = foo; + (void) bar; +} diff --git a/source/tests/test_duration.test.c b/source/tests/test_duration.test.c new file mode 100644 index 0000000..27384b4 --- /dev/null +++ b/source/tests/test_duration.test.c @@ -0,0 +1,19 @@ +#define KIT_TEST_FILE test_duration +#include "../kit_test/test.h" + +#if defined(_WIN32) && !defined(__CYGWIN__) +__declspec(dllimport) void __stdcall Sleep(unsigned long timeout); +static void kit_sleep(int ms) { + Sleep(ms); +} +#else +# include +# include +static void kit_sleep(int ms) { + usleep(ms * 1000); +} +#endif + +TEST("test duration") { + kit_sleep(100); +} diff --git a/source/tests/thread.test.c b/source/tests/thread.test.c new file mode 100644 index 0000000..50f7c04 --- /dev/null +++ b/source/tests/thread.test.c @@ -0,0 +1,91 @@ +#include "../kit/thread.h" + +#define KIT_TEST_FILE thread +#include "../kit_test/test.h" + +static int test_nothing(void *_) { + return 0; +} + +static int test_run(void *data) { + int *n = (int *) data; + return *n + 20; +} + +static int test_exit(void *data) { + int *n = (int *) data; + + *n = 1; + thrd_exit(3); + *n = 2; + return 4; +} + +static int test_yield(void *data) { + thrd_yield(); + return 0; +} + +static int test_sleep(void *data) { + struct timespec t = { .tv_sec = 0, .tv_nsec = 10000000 }; + thrd_sleep(&t, NULL); + return 0; +} + +TEST("thread run") { + thrd_t t; + int data = 22; + int result; + REQUIRE(thrd_create(&t, test_run, &data) == thrd_success); + REQUIRE(thrd_join(t, &result) == thrd_success); + REQUIRE(result == 42); +} + +TEST("thread stack size") { + thrd_t foo; + REQUIRE(thrd_create_with_stack(&foo, test_nothing, NULL, 30000) == + thrd_success); + REQUIRE(thrd_join(foo, NULL) == thrd_success); +} + +TEST("thread equal") { + thrd_t foo, bar; + REQUIRE(thrd_create(&foo, test_nothing, NULL) == thrd_success); + REQUIRE(thrd_create(&bar, test_nothing, NULL) == thrd_success); + REQUIRE(thrd_equal(foo, foo)); + REQUIRE(!thrd_equal(foo, bar)); + REQUIRE(!thrd_equal(foo, thrd_current())); + REQUIRE(thrd_join(foo, NULL) == thrd_success); + REQUIRE(thrd_join(bar, NULL) == thrd_success); +} + +TEST("thread exit") { + thrd_t foo; + int data; + int result; + REQUIRE(thrd_create(&foo, test_exit, &data) == thrd_success); + REQUIRE(thrd_join(foo, &result) == thrd_success); + REQUIRE(data == 1); + REQUIRE(result == 3); +} + +TEST("thread yield") { + thrd_t foo; + REQUIRE(thrd_create(&foo, test_yield, NULL) == thrd_success); + REQUIRE(thrd_join(foo, NULL) == thrd_success); +} + +TEST("thread sleep") { + thrd_t foo; + REQUIRE(thrd_create(&foo, test_sleep, NULL) == thrd_success); + REQUIRE(thrd_join(foo, NULL) == thrd_success); +} + +TEST("thread detach") { + thrd_t foo; + REQUIRE(thrd_create(&foo, test_nothing, NULL) == thrd_success); + REQUIRE(thrd_detach(foo) == thrd_success); + + struct timespec t = { .tv_sec = 0, .tv_nsec = 10000000 }; + thrd_sleep(&t, NULL); +} diff --git a/source/tests/too_many_assertions.c b/source/tests/too_many_assertions.c new file mode 100644 index 0000000..662207d --- /dev/null +++ b/source/tests/too_many_assertions.c @@ -0,0 +1,13 @@ +#include "../kit_test/test.h" + +TEST("foo") { + int i; + for (i = 0; i <= KIT_TEST_ASSERTIONS_LIMIT; i++) REQUIRE(1); +} + +int main(int argc, char **argv) { + if (run_tests(argc, argv) != 1) + return 1; + + return 0; +} diff --git a/source/tests/too_many_tests.c b/source/tests/too_many_tests.c new file mode 100644 index 0000000..d4842e4 --- /dev/null +++ b/source/tests/too_many_tests.c @@ -0,0 +1,14 @@ +#include "../kit_test/test.h" + +void bar(int index, kit_test_report_fn report) { } + +int main(int argc, char **argv) { + int i; + for (i = 0; i <= KIT_TESTS_SIZE_LIMIT; i++) + test_register("foo", __FILE__, bar); + + if (run_tests(argc, argv) != 1) + return 1; + + return 0; +} -- cgit v1.2.3