Created
September 20, 2024 11:29
-
-
Save basp1/03ba289feae91fbe0fbb0ab0a73925cf to your computer and use it in GitHub Desktop.
Simple unit-testing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <zero_test.h> | |
#include <vector> | |
namespace example::test { | |
ZERO_DEFINE_TEST_SUITE(test_example); | |
ZERO_DEFINE_TEST(test_example, name1) { | |
std::vector<int> v; | |
v.reserve(10); | |
v.push_back(1); | |
v.push_back(2); | |
ZERO_ASSERT_EQ(static_cast<size_t>(10), v.capacity()); | |
ZERO_ASSERT_EQ(static_cast<size_t>(2), v.size()); | |
ZERO_ASSERT(v[0] < v[1]); | |
} | |
ZERO_DEFINE_TEST(test_example, name2) { | |
const std::vector v{1, 2, 3}; | |
ZERO_ASSERT_EQ(1, v[0]); | |
ZERO_ASSERT_EQ(2, v[1]); | |
ZERO_ASSERT_EQ(3, v[2]); | |
ZERO_ASSERT(v.size() <= v.capacity()); | |
} | |
} | |
int main(int argc, char **argv) { | |
bool ok = zero_test::zero_test::run_all(); | |
return ok ? 0 : -1; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <iostream> | |
#include <vector> | |
namespace zero_test { | |
class zero_test_case { | |
public: | |
virtual ~zero_test_case() = default; | |
int passed = 0; | |
int failed = 0; | |
int total = 0; | |
const char *name; | |
const bool dummy; | |
public: | |
explicit zero_test_case(const char *name, bool dummy = false) : name(name), dummy(dummy) {} | |
void assert_true(bool cond) { | |
total += 1; | |
if (dummy) { | |
std::cout << '?'; | |
return; | |
} | |
if (cond) { | |
passed += 1; | |
std::cout << '.'; | |
} else { | |
failed += 1; | |
std::cout << '!'; | |
} | |
} | |
void assert_true(bool cond, const char *filename, int line) { | |
total += 1; | |
if (dummy) { | |
std::cout << '?'; | |
return; | |
} | |
if (cond) { | |
passed += 1; | |
std::cout << '.'; | |
} else { | |
failed += 1; | |
std::cout << '!' << std::endl; | |
std::cout << " ====> " << filename << ':' << line << std::endl; | |
} | |
} | |
void assert_false(bool cond) { | |
assert_true(!cond); | |
} | |
void assert_false(bool cond, const char *filename, int line) { | |
assert_true(!cond, filename, line); | |
} | |
template<typename T> | |
void assert_equal(T a, T b) { | |
assert_true(a == b); | |
} | |
template<typename T> | |
void assert_equal(T a, T b, const char *filename, int line) { | |
assert_true(a == b, filename, line); | |
} | |
virtual void run() = 0; | |
}; | |
class zero_test_suite { | |
public: | |
virtual ~zero_test_suite() = default; | |
int total_asserts = 0; | |
int passed_asserts = 0; | |
int failed_asserts = 0; | |
int passed_cases = 0; | |
int failed_cases = 0; | |
std::vector<zero_test_case *> cases; | |
const char *name; | |
public: | |
zero_test_suite() : name(nullptr) {} | |
explicit zero_test_suite(const char *name) : name(name) {} | |
void add(zero_test_case *test) { | |
cases.push_back(test); | |
} | |
virtual void run() { | |
total_asserts = passed_asserts = failed_asserts = passed_cases = failed_cases = 0; | |
if (nullptr != name) { | |
std::cout << name << ": " << std::endl; | |
} | |
for (auto &test: cases) { | |
try { | |
test->run(); | |
} catch (...) { | |
if (!test->dummy) { | |
std::cout << "E"; | |
std::cout << std::endl << " ====> Exception in \"" << test->name << "\"" << std::endl; | |
test->failed += 1; | |
} | |
} | |
std::cout << ' '; | |
total_asserts += test->total; | |
passed_asserts += test->passed; | |
failed_asserts += test->failed; | |
if (test->failed > 0) { | |
failed_cases++; | |
} else { | |
passed_cases++; | |
} | |
} | |
std::cout << std::endl; | |
} | |
}; | |
inline class zero_test { | |
public: | |
static inline std::vector<zero_test_suite *> suites; | |
public: | |
zero_test() = default; | |
static void add(zero_test_suite *test) { | |
suites.push_back(test); | |
} | |
static bool run_all() { | |
int passed_suites = 0; | |
int failed_suites = 0; | |
int passed_cases = 0; | |
int failed_cases = 0; | |
int total_asserts = 0; | |
int passed_asserts = 0; | |
int failed_asserts = 0; | |
for (auto &suite: suites) { | |
suite->run(); | |
total_asserts += suite->total_asserts; | |
passed_asserts += suite->passed_asserts; | |
failed_asserts += suite->failed_asserts; | |
passed_cases += suite->passed_cases; | |
failed_cases += suite->failed_cases; | |
if (suite->failed_cases > 0) { | |
failed_suites++; | |
} else { | |
passed_suites++; | |
} | |
} | |
std::cout << std::endl; | |
std::cout << "Suites: " << passed_suites << '/' << (passed_suites + failed_suites) << std::endl; | |
std::cout << "Cases: " << passed_cases << '/' << (passed_cases + failed_cases) << std::endl; | |
std::cout << "Asserts: " << passed_asserts << '/' << total_asserts << std::endl; | |
if (failed_asserts > 0) { | |
printf("\n %c[0;31m ====> FAILED <====%c[0m\n", 27, 27); | |
return false; | |
} | |
printf("\n %c[0;32m PASSED %c[0m\n", 27, 27); | |
return true; | |
} | |
} zero_test_instance; | |
} | |
#define ZERO_TEST_SHORTNAME zero_test::zero_test | |
#define ZERO_TEST_INSTANCE_SHORTNAME zero_test::zero_test_instance | |
#define ZERO_TEST_SUITE_SHORTNAME zero_test::zero_test_suite | |
#define ZERO_TEST_CASE_SHORTNAME zero_test::zero_test_case | |
#define ZERO_ASSERT(A) assert_true(A, __FILE__, __LINE__) | |
#define ZERO_ASSERT_EQ(A, B) assert_equal(A, B, __FILE__, __LINE__) | |
#define ZERO_ASSERT_APPROX(A, B) assert_true(std::abs((A) - (B)) < 1e-8, __FILE__, __LINE__) | |
#define ZERO_DEFINE_TEST_SUITE(NAME) struct NAME : public ZERO_TEST_SUITE_SHORTNAME { \ | |
NAME() : ZERO_TEST_SUITE_SHORTNAME(#NAME) { ZERO_TEST_INSTANCE_SHORTNAME.add(this); } \ | |
} NAME##_instance; | |
#define ZERO_DEFINE_TEST(SUITE, NAME) struct SUITE ## _ ## NAME : public ZERO_TEST_CASE_SHORTNAME { \ | |
SUITE ## _ ## NAME() : ZERO_TEST_CASE_SHORTNAME(#SUITE "_" #NAME) { SUITE ## _instance . add(this); } \ | |
virtual void run(); \ | |
} SUITE ## _ ## NAME ## _instance; \ | |
void SUITE ## _ ## NAME :: run() | |
#define ZERO_DEFINE_TEST_MOCK(SUITE, NAME) struct SUITE ## _ ## NAME : public ZERO_TEST_CASE_SHORTNAME { \ | |
SUITE ## _ ## NAME() : ZERO_TEST_CASE_SHORTNAME(#NAME, true) { SUITE ## _instance . add(this); } \ | |
virtual void run(); \ | |
} SUITE ## _ ## NAME ## _instance; \ | |
void SUITE ## _ ## NAME :: run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment