Add testing context as test case argument & support simple profiling in tests
This commit is contained in:
parent
bc18b03a53
commit
91faa2423e
2 changed files with 61 additions and 6 deletions
|
|
@ -1,13 +1,27 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
|
#include <chrono>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <psemek/util/to_string.hpp>
|
#include <psemek/util/to_string.hpp>
|
||||||
|
|
||||||
namespace psemek::test
|
namespace psemek::test
|
||||||
{
|
{
|
||||||
|
|
||||||
void add_test_case(char const * name, void(*f)());
|
struct context
|
||||||
|
{
|
||||||
|
struct profile_data
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
std::chrono::high_resolution_clock::duration duration;
|
||||||
|
bool ended_with_exception;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<profile_data> profile;
|
||||||
|
};
|
||||||
|
|
||||||
|
void add_test_case(char const * name, void(*f)(context &));
|
||||||
|
|
||||||
struct failure
|
struct failure
|
||||||
: std::exception
|
: std::exception
|
||||||
|
|
@ -27,12 +41,35 @@ namespace psemek::test
|
||||||
std::string location_;
|
std::string location_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct profiler
|
||||||
|
{
|
||||||
|
using clock = std::chrono::high_resolution_clock;
|
||||||
|
|
||||||
|
profiler(std::string name, context & ctx)
|
||||||
|
: name_{std::move(name)}
|
||||||
|
, ctx_{ctx}
|
||||||
|
{
|
||||||
|
start_ = clock::now();
|
||||||
|
}
|
||||||
|
|
||||||
|
~profiler()
|
||||||
|
{
|
||||||
|
auto end = clock::now();
|
||||||
|
ctx_.profile.push_back({name_, end - start_, std::uncaught_exceptions() > 0});
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
clock::time_point start_;
|
||||||
|
std::string name_;
|
||||||
|
context & ctx_;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define test_case(name) \
|
#define test_case(name) \
|
||||||
void name ## _test_case (); \
|
void name ## _test_case (::psemek::test::context &); \
|
||||||
static const auto name ## _test_case_registrator = []{ ::psemek::test::add_test_case(#name, &(name ## _test_case)); return 0; }(); \
|
static const auto name ## _test_case_registrator = []{ ::psemek::test::add_test_case(#name, &(name ## _test_case)); return 0; }(); \
|
||||||
void name ## _test_case ()
|
void name ## _test_case ([[maybe_unused]] ::psemek::test::context & _ctx)
|
||||||
|
|
||||||
#define fail(...) throw ::psemek::test::failure(::psemek::util::to_string(__VA_ARGS__), ::psemek::util::to_string(__FILE__, ":", __LINE__))
|
#define fail(...) throw ::psemek::test::failure(::psemek::util::to_string(__VA_ARGS__), ::psemek::util::to_string(__FILE__, ":", __LINE__))
|
||||||
|
|
||||||
|
|
@ -52,3 +89,6 @@ void name ## _test_case ()
|
||||||
#define expect_gequal(expr1, expr2) if ((expr1) < (expr2)) fail(#expr1, " (", (expr1), ") < ", #expr2, " (", (expr2), ")")
|
#define expect_gequal(expr1, expr2) if ((expr1) < (expr2)) fail(#expr1, " (", (expr1), ") < ", #expr2, " (", (expr2), ")")
|
||||||
|
|
||||||
#define expect_throw(expr, type) do { bool thrown = false; try { (void)(expr); } catch (type const &) { thrown = true; } if (!thrown) fail(#expr, " didn't throw ", #type); } while (false)
|
#define expect_throw(expr, type) do { bool thrown = false; try { (void)(expr); } catch (type const &) { thrown = true; } if (!thrown) fail(#expr, " didn't throw ", #type); } while (false)
|
||||||
|
|
||||||
|
#define test_profile(name) \
|
||||||
|
if (::psemek::test::profiler name ## _profiler(#name, _ctx); true)
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
namespace psemek::test
|
namespace psemek::test
|
||||||
{
|
{
|
||||||
|
|
||||||
static std::map<std::string, void(*)()> tests;
|
static std::map<std::string, void(*)(context &)> tests;
|
||||||
|
|
||||||
static std::string normalize(std::string name)
|
static std::string normalize(std::string name)
|
||||||
{
|
{
|
||||||
|
|
@ -31,7 +31,7 @@ namespace psemek::test
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_test_case(char const * name, void(*f)())
|
void add_test_case(char const * name, void(*f)(context &))
|
||||||
{
|
{
|
||||||
std::string pname = normalize(name);
|
std::string pname = normalize(name);
|
||||||
|
|
||||||
|
|
@ -99,10 +99,12 @@ int main(int argc, char ** argv)
|
||||||
<< '[' << std::setfill(' ') << std::setw(test_index_len) << std::right << i << '/' << test_count << "] "
|
<< '[' << std::setfill(' ') << std::setw(test_index_len) << std::right << i << '/' << test_count << "] "
|
||||||
<< std::left << std::setfill('.') << std::setw(max_name_length + 5) << name;
|
<< std::left << std::setfill('.') << std::setw(max_name_length + 5) << name;
|
||||||
|
|
||||||
|
psemek::test::context ctx;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
auto start = clock::now();
|
auto start = clock::now();
|
||||||
psemek::test::tests[name]();
|
psemek::test::tests[name](ctx);
|
||||||
auto end = clock::now();
|
auto end = clock::now();
|
||||||
std::cout << "ok (" << psemek::util::pretty(end - start, std::chrono::milliseconds{1}) << ")" << std::endl;
|
std::cout << "ok (" << psemek::util::pretty(end - start, std::chrono::milliseconds{1}) << ")" << std::endl;
|
||||||
++success;
|
++success;
|
||||||
|
|
@ -121,6 +123,19 @@ int main(int argc, char ** argv)
|
||||||
{
|
{
|
||||||
std::cout << "failure: (unknown exception)" << std::endl;
|
std::cout << "failure: (unknown exception)" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::size_t max_profile_name_len = 0;
|
||||||
|
for (auto const & p : ctx.profile)
|
||||||
|
max_profile_name_len = std::max(max_profile_name_len, p.name.size());
|
||||||
|
|
||||||
|
for (auto const & p : ctx.profile)
|
||||||
|
{
|
||||||
|
std::cout << indent
|
||||||
|
<< std::setfill(' ') << std::setw(max_profile_name_len + 5) << p.name
|
||||||
|
<< psemek::util::pretty(p.duration, std::chrono::milliseconds{1})
|
||||||
|
<< (p.ended_with_exception ? " (exception)" : "")
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto all_end = clock::now();
|
auto all_end = clock::now();
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue