Compare commits
6 Commits
bcc7cb68c6
...
40d4608477
| Author | SHA1 | Date |
|---|---|---|
|
|
40d4608477 | |
|
|
78d1f1cca8 | |
|
|
8a1d6385ef | |
|
|
2e3f1dc43d | |
|
|
690aa93af9 | |
|
|
8f722d6908 |
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace cc::helper {
|
||||
|
||||
|
|
@ -52,7 +54,7 @@ namespace cc::helper {
|
|||
auto dist1 = std::distance(first1, last1);
|
||||
auto dist2 = std::distance(first2, last2);
|
||||
|
||||
if (max_dist < dist1 || max_dist < dist2) throw std::invalid_argument("Distance between iterators does not fit inbetween other "
|
||||
if (max_dist < dist1 || max_dist < dist2) throw std::invalid_argument("Distance between iterators does not fit in between other "
|
||||
"(Range 1: " + std::to_string(dist1) + "/" + std::to_string(std::distance(first1, end1)) + ", " +
|
||||
"Range 2: " + std::to_string(dist2) + "/" + std::to_string(std::distance(first2, end2)) + ")");
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
cmake_minimum_required(VERSION 3.26)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
|
||||
add_library(test_common INTERFACE)
|
||||
target_include_directories(test_common INTERFACE common_helper)
|
||||
target_link_libraries(test_common INTERFACE const_container)
|
||||
target_compile_options(test_common INTERFACE -fconcepts-diagnostics-depth=2) # for debugging
|
||||
|
||||
add_subdirectory(const_vector)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,227 @@
|
|||
//
|
||||
// Created by Patrick Maschek on 08/04/2024.
|
||||
//
|
||||
|
||||
#ifndef CONST_CONTAINER_TEST_HPP_
|
||||
#define CONST_CONTAINER_TEST_HPP_
|
||||
|
||||
#include <any>
|
||||
#include <array>
|
||||
#include <concepts>
|
||||
#include <iostream>
|
||||
#include <ranges>
|
||||
#include <tuple>
|
||||
#include <numeric>
|
||||
|
||||
#define TEST_FAIL(msg) ret_val_s { "", ReturnCode::FAILED, msg }
|
||||
#define TEST_PASS() ret_val_s { "", ReturnCode::PASSED, nullptr }
|
||||
#define TEST_PASS_MSG(msg) ret_val_s { "", ReturnCode::PASSED, msg }
|
||||
#define TEST_SKIP() ret_val_s { "", ReturnCode::SKIPPED, nullptr }
|
||||
|
||||
|
||||
enum class EvalFlag { RUNTIME, CONSTEVAL, RUNTIME_CONSTEVAL };
|
||||
enum class ReturnCode { FAILED = -1, PASSED = 0, SKIPPED = 1, NOT_EVALUATED = 2 };
|
||||
|
||||
|
||||
template<typename Suite>
|
||||
struct quick_test_def;
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, ReturnCode rc);
|
||||
|
||||
|
||||
struct ret_val_s {
|
||||
const char *test_name = "";
|
||||
ReturnCode val = ReturnCode::FAILED;
|
||||
const char *msg = "";
|
||||
};
|
||||
|
||||
template<std::size_t Nr>
|
||||
struct ret_val {
|
||||
const char * name;
|
||||
std::array<ret_val_s, Nr> vals;
|
||||
|
||||
[[nodiscard]] constexpr inline std::size_t size() const { return vals.size(); }
|
||||
|
||||
constexpr inline ret_val_s& operator[](std::size_t i) { return vals[i]; }
|
||||
constexpr inline const ret_val_s& operator[](std::size_t i) const { return vals[i]; }
|
||||
};
|
||||
|
||||
class test_definition {
|
||||
public:
|
||||
[[nodiscard]] virtual constexpr ret_val_s evaluate() const = 0;
|
||||
|
||||
[[nodiscard]] virtual const char *name() const = 0;
|
||||
[[nodiscard]] virtual EvalFlag evalFlag() const = 0;
|
||||
[[nodiscard]] virtual const ret_val_s &c_res() const = 0;
|
||||
};
|
||||
|
||||
template<std::invocable Func, typename ...Args>
|
||||
class test_definition_impl : public test_definition {
|
||||
public:
|
||||
using FuncType = Func;
|
||||
static constexpr std::size_t ARG_SIZE = sizeof...(Args);
|
||||
|
||||
constexpr test_definition_impl(const char *name, Func func, EvalFlag evalFlag, Args ...args)
|
||||
: _name(name), _func(func), _evalFlag(evalFlag), _args(std::make_tuple(std::forward(args)...)),
|
||||
_c_res(_name, ReturnCode::FAILED, "Could not be evaluated at compile time") {
|
||||
if consteval {
|
||||
if (evalFlag == EvalFlag::RUNTIME_CONSTEVAL || evalFlag == EvalFlag::CONSTEVAL) {
|
||||
_c_res = evaluate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr ret_val_s evaluate() const override {
|
||||
ret_val_s r = std::apply(_func, _args);
|
||||
r.test_name = _name;
|
||||
return r;
|
||||
}
|
||||
|
||||
[[nodiscard]] const char *name() const override { return _name; }
|
||||
[[nodiscard]] EvalFlag evalFlag() const override { return _evalFlag; }
|
||||
[[nodiscard]] const ret_val_s &c_res() const override{ return _c_res; }
|
||||
|
||||
private:
|
||||
const char *_name;
|
||||
EvalFlag _evalFlag;
|
||||
Func _func;
|
||||
std::tuple<Args...> _args;
|
||||
ret_val_s _c_res;
|
||||
};
|
||||
|
||||
template<typename ...TestDefs>
|
||||
requires (sizeof...(TestDefs) == 0 || (std::derived_from<TestDefs, test_definition> && ...))
|
||||
class test_suite {
|
||||
|
||||
public:
|
||||
static constexpr std::size_t TEST_NR = sizeof...(TestDefs);
|
||||
|
||||
constexpr test_suite(const char *name, std::tuple<TestDefs...> tests) : _name(name), _tests(tests) {}
|
||||
|
||||
int run() const {
|
||||
|
||||
auto test_arr = expand_test_tuple(_tests, std::make_index_sequence<TEST_NR>());
|
||||
int num_failed = 0;
|
||||
|
||||
std::array<std::array<ReturnCode, 2>, TEST_NR> ret_vals = { { ReturnCode::NOT_EVALUATED } };
|
||||
|
||||
for (auto [i, test_ref] : std::ranges::views::enumerate(test_arr)) {
|
||||
const auto& test = test_ref.get();
|
||||
|
||||
std::cout << "Running Test: \"" << test.name() << "\" "
|
||||
"(Test " << i+1 << "/" << test_arr.size() << ")\n";
|
||||
if (test.evalFlag() == EvalFlag::RUNTIME || test.evalFlag() == EvalFlag::RUNTIME_CONSTEVAL) {
|
||||
ret_val_s ret;
|
||||
std::string ret_exc_str;
|
||||
try {
|
||||
ret = test.evaluate();
|
||||
} catch (std::exception& e) {
|
||||
ret_exc_str = std::string("Test failed with Exception: \"") + e.what() + "\"";
|
||||
ret = ret_val_s(test.name(), ReturnCode::FAILED, ret_exc_str.c_str());
|
||||
}
|
||||
|
||||
std::cout << "Result of Runtime Evaluation of Test \"" << ret.test_name << "\": " << ret.val;
|
||||
if (ret.msg != nullptr) {
|
||||
std::cout << "\n\t" << ret.msg;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
ret_vals[i][0] = ret.val;
|
||||
}
|
||||
|
||||
if (test.evalFlag() == EvalFlag::CONSTEVAL || test.evalFlag() == EvalFlag::RUNTIME_CONSTEVAL) {
|
||||
const ret_val_s &ret = test.c_res();
|
||||
std::cout << "Result of Consteval Evaluation of Test \"" << ret.test_name << "\": " << ret.val;
|
||||
if (ret.msg != nullptr) {
|
||||
std::cout << "\n\t" << ret.msg;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
ret_vals[i][1] = ret.val;
|
||||
}
|
||||
|
||||
std::cout << "--------------\n";
|
||||
}
|
||||
|
||||
auto ret_vals_j = ret_vals | std::ranges::views::join;
|
||||
auto correct = std::ranges::count_if(ret_vals, [](auto&& e) {
|
||||
return std::ranges::none_of(e, [](auto&& c) { return c == ReturnCode::FAILED; })
|
||||
&& std::ranges::any_of(e, [](auto&& c) { return c == ReturnCode::PASSED; });
|
||||
});
|
||||
auto failed = std::ranges::count_if(ret_vals, [](auto&& e) {
|
||||
return std::ranges::any_of(e, [](auto&& c) { return c == ReturnCode::FAILED; }); });
|
||||
auto full_skipped = std::ranges::count_if(ret_vals, [](auto&& e) {
|
||||
return std::ranges::all_of(e, [](auto&& c) { return c == ReturnCode::SKIPPED || c == ReturnCode::NOT_EVALUATED; }); });
|
||||
auto part_skipped = std::ranges::count_if(ret_vals, [](auto&& e) {
|
||||
return std::ranges::any_of(e, [](auto&& c) { return c == ReturnCode::SKIPPED; }); });
|
||||
|
||||
std::size_t num_tests = ret_vals.size();
|
||||
|
||||
std::cout << "Final Result: " << "\n"
|
||||
<< correct << "/" << num_tests << " tests evaluated correctly" << "\n"
|
||||
<< failed << "/" << num_tests << " tests failed" << "\n"
|
||||
<< full_skipped << "/" << num_tests << " tests skipped" << "\n"
|
||||
<< part_skipped << "/" << num_tests << " tests have been partially skipped" << "\n";
|
||||
|
||||
return -failed;
|
||||
}
|
||||
|
||||
private:
|
||||
const char *_name;
|
||||
std::tuple<TestDefs...> _tests;
|
||||
|
||||
template<std::size_t ...Is>
|
||||
static constexpr auto expand_test_tuple(const auto &tests, std::index_sequence<Is...>) {
|
||||
return std::array {
|
||||
std::reference_wrapper(
|
||||
dynamic_cast<const test_definition&>(std::get<Is>(tests))
|
||||
)... };
|
||||
}
|
||||
|
||||
friend class quick_test_def<test_suite<TestDefs...>>;
|
||||
};
|
||||
|
||||
template<typename Suite>
|
||||
struct quick_test_def {
|
||||
Suite current;
|
||||
|
||||
template<std::invocable Func, typename ...Args>
|
||||
constexpr auto operator()(const char *name, Func func, Args... args) {
|
||||
return operator()(name, func, EvalFlag::RUNTIME, std::forward(args)...);
|
||||
}
|
||||
|
||||
template<std::invocable Func, typename ...Args>
|
||||
constexpr auto operator()(const char *name, Func func, EvalFlag evalFlag, Args... args) {
|
||||
auto test = test_definition_impl(name, func, evalFlag, args...);
|
||||
auto new_suite = test_suite(current._name, std::tuple_cat(current._tests, std::make_tuple(test)));
|
||||
return quick_test_def<decltype(new_suite)> { new_suite };
|
||||
}
|
||||
|
||||
constexpr operator Suite() {
|
||||
return current;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ...TestDefs>
|
||||
test_suite(quick_test_def<test_suite<TestDefs...>>) -> test_suite<TestDefs...>;
|
||||
|
||||
constexpr auto define_tests(const char *name) {
|
||||
return quick_test_def { test_suite<>{ name, std::make_tuple() } };
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, ReturnCode rc) {
|
||||
switch (rc) {
|
||||
case ReturnCode::FAILED:
|
||||
return os << "FAILED";
|
||||
case ReturnCode::PASSED:
|
||||
return os << "PASSED";
|
||||
case ReturnCode::SKIPPED:
|
||||
return os << "SKIPPED";
|
||||
case ReturnCode::NOT_EVALUATED:
|
||||
return os << "NOT EVALUATED";
|
||||
default:
|
||||
return os;
|
||||
}
|
||||
}
|
||||
|
||||
#endif //CONST_CONTAINER_TEST_HPP_
|
||||
|
|
@ -1,144 +0,0 @@
|
|||
//
|
||||
// Created by Patrick Maschek on 08/04/2024.
|
||||
//
|
||||
|
||||
#ifndef CONST_CONTAINER_TEST_DEFINE_TEST_HPP_
|
||||
#define CONST_CONTAINER_TEST_DEFINE_TEST_HPP_
|
||||
|
||||
#include <array>
|
||||
#include <concepts>
|
||||
#include <iostream>
|
||||
#include <ranges>
|
||||
#include <tuple>
|
||||
|
||||
#include "test_ret_val.h"
|
||||
|
||||
template<typename Suite>
|
||||
struct quick_test_def;
|
||||
|
||||
enum class EvalFlag { RUNTIME, CONSTEVAL, RUNTIME_CONSTEVAL };
|
||||
|
||||
struct test_def_base {};
|
||||
|
||||
template<std::invocable Func>
|
||||
struct test_def_func_base : public test_def_base {
|
||||
using FuncType = Func;
|
||||
|
||||
const char *name;
|
||||
Func func;
|
||||
EvalFlag evalFlag = EvalFlag::RUNTIME;
|
||||
|
||||
consteval test_def_func_base(const char * name, Func func) : name(name), func(func) {}
|
||||
consteval test_def_func_base(const char * name, Func func, EvalFlag evalFlag)
|
||||
: name(name), func(func), evalFlag(evalFlag) {}
|
||||
|
||||
virtual constexpr std::invoke_result_t<Func> operator()() const { return std::apply(func, std::make_tuple()); }
|
||||
|
||||
consteval auto run_consteval() const { return operator()(); }
|
||||
};
|
||||
|
||||
template<std::invocable Func, typename ...Args>
|
||||
struct test_definition : public test_def_func_base<Func> {
|
||||
using base = test_def_func_base<Func>;
|
||||
static constexpr std::size_t ARG_SIZE = sizeof...(Args);
|
||||
|
||||
std::tuple<Args...> args;
|
||||
|
||||
consteval test_definition(const char *name, Func func, Args ...args)
|
||||
: test_def_func_base<Func>(name, func), args(std::make_tuple(args...)) {}
|
||||
|
||||
consteval test_definition(const char *name, Func func, EvalFlag evalFlag, Args ...args)
|
||||
: test_def_func_base<Func>(name, func, evalFlag), args(std::make_tuple(args...)) {}
|
||||
|
||||
constexpr std::invoke_result_t<Func, Args...> operator()() const override { return std::apply(base::func, args); }
|
||||
};
|
||||
|
||||
|
||||
template<typename ...TestDefs>
|
||||
requires (sizeof...(TestDefs) == 0 || (std::derived_from<TestDefs, test_def_func_base<typename TestDefs::FuncType>> && ...))
|
||||
struct test_suite {
|
||||
|
||||
template<typename NewTest>
|
||||
using with_added_test_t = test_suite<TestDefs..., NewTest>;
|
||||
|
||||
static constexpr std::size_t TEST_NR = sizeof...(TestDefs);
|
||||
|
||||
const char *name;
|
||||
std::tuple<TestDefs...> tests;
|
||||
|
||||
consteval test_suite(const char *name, std::tuple<TestDefs...> tests) : name(name), tests(tests) {}
|
||||
|
||||
template<std::size_t ...Is>
|
||||
[[nodiscard]] constexpr auto get_tests() const {
|
||||
return get_tests_delegate(std::make_index_sequence<TEST_NR>());
|
||||
}
|
||||
|
||||
template<std::size_t ...Is>
|
||||
[[nodiscard]] constexpr auto get_tests_delegate(std::index_sequence<Is...>) const {
|
||||
return std::array { (std::reference_wrapper(std::get<Is>(tests)), ...) };
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Suite>
|
||||
struct quick_test_def {
|
||||
Suite current;
|
||||
|
||||
template<std::invocable Func, typename ...Args>
|
||||
consteval auto operator()(const char *name, Func func, EvalFlag evalFlag, Args... args) const {
|
||||
auto test = test_definition(name, func, evalFlag, args...);
|
||||
auto suite = test_suite(name, std::tuple_cat(current.tests, std::make_tuple(test)));
|
||||
return quick_test_def<decltype(suite)> { .current = suite };
|
||||
}
|
||||
|
||||
constexpr operator Suite() const {
|
||||
return current;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ...TestDefs>
|
||||
test_suite(quick_test_def<test_suite<TestDefs...>>) -> test_suite<TestDefs...>;
|
||||
|
||||
consteval auto define_tests(const char *name) {
|
||||
return quick_test_def { test_suite<>{ name, std::make_tuple() } };
|
||||
}
|
||||
|
||||
template<std::invocable Test>
|
||||
requires (std::derived_from<Test, test_def_func_base<typename Test::FuncType>>)
|
||||
static consteval ret_val_s run_consteval_test(const Test& test) {
|
||||
return test();
|
||||
}
|
||||
|
||||
template<typename ...TestDefs>
|
||||
void evaluate_tests(const test_suite<TestDefs...>& tests) {
|
||||
|
||||
for (auto [i, test_ref] : std::ranges::views::enumerate(tests.get_tests())) {
|
||||
auto test = test_ref.get();
|
||||
|
||||
std::cout << "Running Test: \"" << test.name << "\"\n";
|
||||
if (test.evalFlag == EvalFlag::RUNTIME || test.evalFlag == EvalFlag::RUNTIME_CONSTEVAL) {
|
||||
ret_val_s ret = test();
|
||||
|
||||
std::cout << "Result of Runtime Evaluation of Test \"" << ret.test_name << "\" (number: " << i
|
||||
<< "): "
|
||||
<< (ret.val == ReturnCode::PASSED ? "PASSED" : "FAILED") << "\n"
|
||||
<< "\t" << ret.msg << "\n";
|
||||
}
|
||||
|
||||
std::optional<ret_val_s> cret;
|
||||
|
||||
if (test.evalFlag == EvalFlag::CONSTEVAL || test.evalFlag == EvalFlag::RUNTIME_CONSTEVAL) {
|
||||
test.run_consteval();
|
||||
}
|
||||
|
||||
if (cret.has_value()) {
|
||||
auto ret = cret.value();
|
||||
std::cout << "Result of Consteval Evaluation of Test \"" << ret.test_name << "\" (number: " << i
|
||||
<< "): "
|
||||
<< (ret.val == ReturnCode::PASSED ? "PASSED" : "FAILED") << "\n"
|
||||
<< "\t" << ret.msg << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif //CONST_CONTAINER_TEST_DEFINE_TEST_HPP_
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
|
||||
#ifndef CONST_CONTAINER_TEST_RETURN_VAL_H_
|
||||
#define CONST_CONTAINER_TEST_RETURN_VAL_H_
|
||||
|
||||
#include <concepts>
|
||||
|
||||
#include <const_list.h>
|
||||
|
||||
#define TEST_FAIL(name, msg) ret_val_s { name, ReturnCode::FAILED, msg }
|
||||
#define TEST_PASS(name, msg) ret_val_s { name, ReturnCode::PASSED, msg }
|
||||
|
||||
enum ReturnCode { FAILED = -1, PASSED = 0 };
|
||||
|
||||
struct ret_val_s {
|
||||
const char *test_name = "";
|
||||
ReturnCode val = FAILED;
|
||||
const char *msg = "";
|
||||
};
|
||||
|
||||
template<std::size_t Nr>
|
||||
struct ret_val {
|
||||
const char * name;
|
||||
std::array<ret_val_s, Nr> vals;
|
||||
|
||||
[[nodiscard]] constexpr inline std::size_t size() const { return vals.size(); }
|
||||
|
||||
constexpr inline ret_val_s& operator[](std::size_t i) { return vals[i]; }
|
||||
constexpr inline const ret_val_s& operator[](std::size_t i) const { return vals[i]; }
|
||||
};
|
||||
|
||||
#endif //CONST_CONTAINER_TEST_RETURN_VAL_H_
|
||||
|
|
@ -1,53 +1,34 @@
|
|||
#include <const_vector.hpp>
|
||||
|
||||
#include "test_define_test.hpp"
|
||||
#include "test_util.hpp"
|
||||
#include "test_ret_val.h"
|
||||
#include "test.hpp"
|
||||
|
||||
constexpr test_suite tests = define_tests("Tests")
|
||||
("Test Runtime", [](int = 1) constexpr{
|
||||
|
||||
return TEST_PASS("Test Runtime", "PASS");
|
||||
return TEST_PASS();
|
||||
}, EvalFlag::RUNTIME)
|
||||
("Test Consteval 1", [](char = 2) constexpr {
|
||||
if (std::is_constant_evaluated()) {
|
||||
return TEST_PASS();
|
||||
} else {
|
||||
return TEST_FAIL("FAIL");
|
||||
}
|
||||
}, EvalFlag::CONSTEVAL)
|
||||
("Test Consteval", [](char = 2) constexpr {
|
||||
if (std::is_constant_evaluated()) {
|
||||
return TEST_PASS("Test Consteval", "PASS");
|
||||
return TEST_SKIP();
|
||||
} else {
|
||||
return TEST_FAIL("Test Consteval", "FAIL");
|
||||
return TEST_FAIL("FAIL");
|
||||
}
|
||||
}, EvalFlag::CONSTEVAL)
|
||||
("Test Runtime Consteval", [](short = 3) constexpr{
|
||||
if (std::is_constant_evaluated()) {
|
||||
return TEST_PASS("Test Consteval Runtime", "PASS Consteval");
|
||||
return TEST_SKIP();
|
||||
} else {
|
||||
return TEST_PASS("Test Consteval", "PASS Runtime");
|
||||
return TEST_PASS();
|
||||
}
|
||||
}, EvalFlag::RUNTIME_CONSTEVAL);
|
||||
|
||||
constexpr auto test_func(const char *name) {
|
||||
|
||||
auto ret_val = run_tests(name,
|
||||
[](){
|
||||
|
||||
return TEST_PASS("Test1", "PASS");
|
||||
});
|
||||
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
int main() {
|
||||
auto ret = test_func("Test 1");
|
||||
|
||||
auto cret = consteval_caller(test_func, "Consteval Test");
|
||||
|
||||
report(ret);
|
||||
report(cret);
|
||||
|
||||
evaluate_tests(tests);
|
||||
|
||||
//auto sret = tests.run();
|
||||
//report(sret);
|
||||
|
||||
return 0;
|
||||
return tests.run();
|
||||
}
|
||||
Loading…
Reference in New Issue