From 4b97d8bcdad920f91a5a81338bd84e053a9b06fa Mon Sep 17 00:00:00 2001 From: Alibek Omarov Date: Tue, 5 Nov 2019 11:21:40 +0300 Subject: [PATCH] public: add simple C89-compatible testing framework (wip) --- public/tests/test_unittest.c | 24 ++++++++++ public/unittest.h | 87 ++++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 public/tests/test_unittest.c create mode 100644 public/unittest.h diff --git a/public/tests/test_unittest.c b/public/tests/test_unittest.c new file mode 100644 index 00000000..6e16a195 --- /dev/null +++ b/public/tests/test_unittest.c @@ -0,0 +1,24 @@ +#include "unittest.h" +#include + +TEST_FIRST(helloworld) +{ +} + +TEST3(hw2, helloworld, "Hello, World") +{ +} + +TEST(nonsense, hw2) +{ + if( !( sin( 0 ) != 0.0 )) + _self->status = 1; +} + +TEST(sense, nonsense) +{ + if( !( sin( 0 ) == 0.0 ) ) + _self->status = 1; +} + +IMPLEMENT_MAIN(sense, "self-testing") diff --git a/public/unittest.h b/public/unittest.h new file mode 100644 index 00000000..015f458a --- /dev/null +++ b/public/unittest.h @@ -0,0 +1,87 @@ +/* +unittest.h - simple unnamed unit testing framework +Copyright (C) 2019 a1batross + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ +#ifndef UNITTEST_H +#define UNITTEST_H + +#include + +struct unittest_s; +typedef void (*pfnTest_t)( struct unittest_s *_self ); +typedef struct unittest_s +{ + int status; // 0 if succeeded otherwise failed, you can use it as return code + const char *name; + pfnTest_t pfn; + struct unittest_s *next; +} unittest_t; + +#define TEST_FIRST_FUNC3(_name, _pfn, _readname) \ + unittest_t _name = { 0, ( _readname ), ( _pfn ), NULL } + +#define TEST_FIRST_FUNC2(_name, _pfn) \ + TEST_FIRST_FUNC3(_name, _pfn, #_name) + +#define TEST_FUNC4(_name, _prevname, _pfn, _readname) \ + unittest_t _name = { 0, ( _readname ), ( _pfn ), &( _prevname ) } + +#define TEST_FUNC3(_name, _prevname, _pfn) \ + TEST_FUNC4(_name, _prevname, _pfn, #_name) + +#define DECLARE_TEST_FUNC(_name) \ + void fn ## _name( struct unittest_s *_self ) + +#define TEST3(_name, _prevname, _readname) \ + DECLARE_TEST_FUNC(_name); \ + TEST_FUNC4(_name, _prevname, fn ## _name, _readname ); \ + DECLARE_TEST_FUNC(_name) + // { + // your code goes here; + // } + +#define TEST(_name, _prevname) \ + TEST3(_name, _prevname, #_name) + +#define TEST_FIRST2(_name, _readname) \ + DECLARE_TEST_FUNC(_name); \ + TEST_FIRST_FUNC3(_name, fn ## _name, _readname); \ + DECLARE_TEST_FUNC(_name) + +#define TEST_FIRST(_name) \ + TEST_FIRST2(_name, #_name) + +#define IMPLEMENT_RUNNER(_fnname, _lasttest, _msgfunc, _msg ) \ + void _fnname( void ) \ + { \ + unittest_t *last = &(_lasttest); \ + int failed = 0, total = 0; \ + _msgfunc( "Starting to test '%s'\n", _msg ); \ + for( ; last; last = last->next ) \ + { \ + _msgfunc( "Checking '%s'\t\t: ", last->name ); \ + last->pfn( last ); \ + if( last->status ) \ + { \ + _msgfunc( "FAIL %d\n", last->status ); \ + failed++; \ + } \ + else _msgfunc( "PASS\n" ); \ + total++; \ + } \ + _msgfunc( "Summary: %d failed from %d total\n", failed, total ); \ + } + +#define IMPLEMENT_MAIN(_lasttest, _msg) IMPLEMENT_RUNNER(main, _lasttest, printf, _msg) + +#endif // UNITTEST_H