add some basic unit test infra to allow testing together with impl
parent
cc8452e265
commit
d359e46818
|
@ -37,6 +37,8 @@
|
|||
#ifndef OSTD_RANGE_HH
|
||||
#define OSTD_RANGE_HH
|
||||
|
||||
#include "ostd/unit_test.hh"
|
||||
|
||||
#include <cstddef>
|
||||
#include <new>
|
||||
#include <tuple>
|
||||
|
@ -1328,6 +1330,17 @@ inline auto range(T v) {
|
|||
return detail::number_range<T>(v);
|
||||
}
|
||||
|
||||
OSTD_UNIT_TEST(range, {
|
||||
auto r = range(5, 10, 2);
|
||||
fail_if(r.empty() || (r.front() != 5));
|
||||
r.pop_front();
|
||||
fail_if(r.empty() || (r.front() != 7));
|
||||
r.pop_front();
|
||||
fail_if(r.empty() || (r.front() != 9));
|
||||
r.pop_front();
|
||||
fail_if(!r.empty());
|
||||
});
|
||||
|
||||
namespace detail {
|
||||
template<typename T>
|
||||
struct reverse_range: input_range<reverse_range<T>> {
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
/** @defgroup Testing
|
||||
*
|
||||
* @brief Reusable unit test infrastructure.
|
||||
*
|
||||
* This module defines header-only infra for unit tests that can be used to
|
||||
* integrate tests directly where the implementation is. All you really need
|
||||
* to do then is enable a macro, include the file you're testing and compile
|
||||
* into an executable.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @file unit_test.hh
|
||||
*
|
||||
* @brief The unit test infrastructure implementation.
|
||||
*
|
||||
* Include this at the very beginning in the files you want to define unit
|
||||
* tests in. It has no dependencies within libostd.
|
||||
*
|
||||
* @copyright See COPYING.md in the project tree for further information.
|
||||
*/
|
||||
|
||||
#ifndef OSTD_UNIT_TEST_HH
|
||||
#define OSTD_UNIT_TEST_HH
|
||||
|
||||
#ifdef OSTD_BUILD_TESTS
|
||||
#include <cstdio>
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <stdexcept>
|
||||
#endif
|
||||
|
||||
namespace ostd {
|
||||
namespace test {
|
||||
|
||||
/** @addtogroup Testing
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifdef OSTD_BUILD_TESTS
|
||||
|
||||
#define OSTD_TEST_MODULE_STRINGIFY(x) #x
|
||||
#define OSTD_TEST_MODULE_STR(x) OSTD_TEST_MODULE_STRINGIFY(x)
|
||||
#define OSTD_TEST_MODULE OSTD_TEST_MODULE_STR(OSTD_BUILD_TESTS)
|
||||
|
||||
static std::vector<void (*)()> test_cases;
|
||||
|
||||
static bool add_test(std::string testn, void (*func)()) {
|
||||
if (testn == OSTD_TEST_MODULE) {
|
||||
test_cases.push_back(func);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#define OSTD_UNIT_TEST(module, body) \
|
||||
static bool test_case_##module##_##__LINE__ = \
|
||||
ostd::test::add_test(#module, []() { using namespace ostd::test; body });
|
||||
|
||||
struct test_error {};
|
||||
|
||||
void fail_if(bool b) {
|
||||
if (b) {
|
||||
throw test_error{};
|
||||
}
|
||||
}
|
||||
|
||||
void fail_if_not(bool b) {
|
||||
if (!b) {
|
||||
throw test_error{};
|
||||
}
|
||||
}
|
||||
|
||||
void run() {
|
||||
int succ = 0, fail = 0;
|
||||
for (auto &f: test_cases) {
|
||||
try {
|
||||
f();
|
||||
} catch (test_error) {
|
||||
++fail;
|
||||
continue;
|
||||
}
|
||||
++succ;
|
||||
}
|
||||
#if defined(_WIN32) || defined(WIN32)
|
||||
printf(
|
||||
"%s...\t%d out of %d (%d failures)\n",
|
||||
OSTD_TEST_MODULE, succ, succ + fail, fail
|
||||
);
|
||||
#else
|
||||
printf(
|
||||
"%s...\t%s\033[1m%d out of %d\033[0m (%d failures)\n",
|
||||
OSTD_TEST_MODULE, fail ? "\033[91m" : "\033[92m",
|
||||
succ, succ + fail, fail
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
#else /* OSTD_BUILD_TESTS */
|
||||
|
||||
#define OSTD_UNIT_TEST(module, body)
|
||||
|
||||
#endif /* OSTD_BUILD_TESTS */
|
||||
|
||||
/** @} */
|
||||
|
||||
} /* namespace test */
|
||||
} /* namespace ostd */
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */
|
|
@ -36,17 +36,12 @@ int main() {
|
|||
/* do not change past this point */
|
||||
|
||||
int nsuccess = 0, nfailed = 0;
|
||||
std::string modname = nullptr;
|
||||
std::string modname;
|
||||
|
||||
auto print_result = [&](string_range fmsg = nullptr) {
|
||||
auto print_error = [&](string_range fmsg) {
|
||||
write(modname, "...\t");
|
||||
if (!fmsg.empty()) {
|
||||
writeln(COLOR_RED, COLOR_BOLD, '(', fmsg, ')', COLOR_END);
|
||||
++nfailed;
|
||||
} else {
|
||||
writeln(COLOR_GREEN, COLOR_BOLD, "(success)", COLOR_END);
|
||||
++nsuccess;
|
||||
}
|
||||
writeln(COLOR_RED, COLOR_BOLD, '(', fmsg, ')', COLOR_END);
|
||||
++nfailed;
|
||||
};
|
||||
|
||||
filesystem::directory_iterator ds{testdir};
|
||||
|
@ -70,7 +65,7 @@ int main() {
|
|||
|
||||
auto cxxcmd = appender<std::string>();
|
||||
format(
|
||||
cxxcmd, "%s %s%s%s -o %s %s", compiler, testdir,
|
||||
cxxcmd, "%s %s%s%s -o %s %s ", compiler, testdir,
|
||||
char(filesystem::path::preferred_separator),
|
||||
p.filename(), exepath, cxxflags
|
||||
);
|
||||
|
@ -78,20 +73,24 @@ int main() {
|
|||
cxxcmd.get() += ' ';
|
||||
cxxcmd.get() += userflags;
|
||||
}
|
||||
cxxcmd.get() += ' ';
|
||||
cxxcmd.get() += "-DOSTD_BUILD_TESTS=";
|
||||
cxxcmd.get() += modname;
|
||||
|
||||
int ret = system(cxxcmd.get().data());
|
||||
if (ret) {
|
||||
print_result("compile errror");
|
||||
print_error("compile errror");
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = system(exepath.data());
|
||||
if (ret) {
|
||||
print_result("runtime error");
|
||||
print_error("runtime error");
|
||||
continue;
|
||||
}
|
||||
|
||||
remove(exepath.data());
|
||||
print_result();
|
||||
++nsuccess;
|
||||
}
|
||||
|
||||
writeln("\n", COLOR_BLUE, COLOR_BOLD, "testing done:", COLOR_END);
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
#define OSTD_BUILD_TESTS range
|
||||
|
||||
#include <ostd/unit_test.hh>
|
||||
#include <ostd/range.hh>
|
||||
|
||||
int main() {
|
||||
ostd::test::run();
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue