109 lines
2.8 KiB
C++
Executable File
109 lines
2.8 KiB
C++
Executable File
#ifndef GUF_TEST_HPP
|
|
#define GUF_TEST_HPP
|
|
|
|
#include <stack>
|
|
#include <string>
|
|
#include <cstdio>
|
|
#include <iostream>
|
|
#include <chrono>
|
|
#include <iomanip>
|
|
extern "C" {
|
|
#include "guf_common.h"
|
|
#include "guf_assert.h"
|
|
}
|
|
|
|
#define TEST_CHECK(COND) (check((COND), GUF_STRINGIFY(COND), __LINE__, __FILE__))
|
|
|
|
struct Test
|
|
{
|
|
private:
|
|
std::chrono::steady_clock::time_point time_start, time_end;
|
|
|
|
protected:
|
|
std::stack<std::string> check_name_stack;
|
|
std::string full_check_name = "";
|
|
|
|
void push_check_name(const std::string& check_name)
|
|
{
|
|
check_name_stack.push(check_name);
|
|
full_check_name = full_check_name + "::" + check_name;
|
|
}
|
|
|
|
void pop_check_name()
|
|
{
|
|
const size_t sep_idx = full_check_name.rfind("::");
|
|
GUF_ASSERT_RELEASE(sep_idx != std::string::npos);
|
|
full_check_name = full_check_name.substr(0, sep_idx);
|
|
check_name_stack.pop();
|
|
}
|
|
|
|
bool check(bool cond, std::string_view msg, size_t line, std::string_view fname)
|
|
{
|
|
if (!cond) {
|
|
std::cerr << name << full_check_name << ": ";
|
|
std::cerr << "FAILED CHECK (" << msg << ") on line " << line << " in file " << fname << "\n"; \
|
|
++num_failed_checks;
|
|
} else {
|
|
++num_passed_checks;
|
|
}
|
|
return cond;
|
|
}
|
|
|
|
public:
|
|
const std::string name {};
|
|
std::chrono::duration<float, std::milli> runtime_ms {0};
|
|
bool passed {false}, done {false};
|
|
size_t num_failed_checks {0}, num_passed_checks {0};
|
|
|
|
Test(const std::string& nm) : name{nm} {}
|
|
virtual ~Test() = default;
|
|
|
|
size_t total_checks() const
|
|
{
|
|
return num_passed_checks + num_failed_checks;
|
|
}
|
|
|
|
virtual void run() = 0;
|
|
|
|
void before_run()
|
|
{
|
|
time_start = std::chrono::steady_clock::now();
|
|
}
|
|
|
|
void after_run()
|
|
{
|
|
done = true;
|
|
passed = (num_failed_checks == 0);
|
|
|
|
time_end = std::chrono::steady_clock::now();
|
|
runtime_ms = std::chrono::duration_cast<decltype(runtime_ms)>(time_end - time_start);
|
|
}
|
|
|
|
friend std::ostream& operator<<(std::ostream &os, const Test& tst)
|
|
{
|
|
std::ios_base::fmtflags os_flags = os.flags();
|
|
std::streamsize os_precision = os.precision();
|
|
|
|
os << tst.name << ": " << (tst.passed ? "PASS" : "FAIL");
|
|
os << std::fixed << std::setprecision(2);
|
|
os << " (" << tst.num_passed_checks << "/" << tst.total_checks() << ") in " << tst.runtime_ms.count() << " ms";
|
|
|
|
os.precision(os_precision);
|
|
os.flags(os_flags);
|
|
return os;
|
|
}
|
|
};
|
|
|
|
template<>
|
|
struct std::hash<std::unique_ptr<Test>> {
|
|
std::size_t operator()(const std::unique_ptr<Test>& test) const
|
|
{
|
|
if (test.get() == nullptr) {
|
|
return 0;
|
|
}
|
|
return std::hash<std::string>()(test.get()->name);
|
|
}
|
|
};
|
|
|
|
#endif
|