Failed attempt of implementing constexpr evaluation of test

This commit is contained in:
cyborg1811m 2024-04-17 18:29:23 +02:00
parent d3bbb89e0f
commit bcc7cb68c6
3 changed files with 269 additions and 40 deletions

View File

@ -0,0 +1,161 @@
//
// 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;
constexpr test_def_func_base(const char * name, Func func) : name(name), func(func) {}
constexpr 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()() { return std::apply(func, std::make_tuple()); }
consteval auto run_consteval() { 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;
constexpr test_definition(const char *name, Func func, Args ...args)
: test_def_func_base<Func>(name, func), args(std::make_tuple(args...)) {}
constexpr 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()() override { return std::apply(base::func, args); }
};
struct test_suite_base {
const char *name;
};
template<typename ...TestDefs>
requires (sizeof...(TestDefs) == 0 || (std::derived_from<TestDefs, test_def_func_base<typename TestDefs::FuncType>> && ...))
class test_suite : public test_suite_base {
public:
static constexpr std::size_t TEST_NR = sizeof...(TestDefs);
constexpr test_suite(const char *name, std::tuple<TestDefs...> tests) : test_suite_base(name), tests(tests) {}
ret_val<TEST_NR> run() const {
constexpr auto is = std::make_index_sequence<TEST_NR>();
std::cout << "--------------\n";
constexpr auto test_arr = expand_tuple(tests, is);
constexpr auto const_test_arr = test_arr
| std::views::enumerate
| std::views::filter([](auto e) consteval { return noexcept(e.run_consteval()); });
for (auto [i, test_ref] : std::ranges::views::enumerate(test_arr)) {
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) {
//cret = run_consteval_test<>();
}
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";
}
}
ret_val<TEST_NR> ret = { name };
//std::ranges::move(v, ret.vals.begin());
return ret;
}
private:
static constexpr std::tuple<std::reference_wrapper<TestDefs>...> tests;
template<std::size_t ...Is>
static constexpr auto expand_tuple(const auto &tests, std::index_sequence<Is...>) {
return std::array { (std::reference_wrapper(std::get<Is>(tests)), ...) };
}
template<auto Test, typename Func>
requires (std::derived_from<decltype(Test), test_def_func_base<Func>>)
static consteval ret_val_s run_consteval_test() {
return Test();
}
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(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() } };
}
#endif //CONST_CONTAINER_TEST_DEFINE_TEST_HPP_

View File

@ -7,59 +7,75 @@
#include <array> #include <array>
#include <concepts> #include <concepts>
#include <iostream>
#include <ranges>
#include <tuple> #include <tuple>
#include "test_ret_val.h" #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> template<std::invocable Func>
struct test_def_base { struct test_def_func_base : public test_def_base {
using FuncType = Func; using FuncType = Func;
const char *name; const char *name;
Func func; Func func;
EvalFlag evalFlag = EvalFlag::RUNTIME;
constexpr test_def_base(const char * name, Func func) : name(name), func(func) {} 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()() { return std::apply(func, std::make_tuple()); } 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> template<std::invocable Func, typename ...Args>
struct test_definition : public test_def_base<Func> { struct test_definition : public test_def_func_base<Func> {
using base = test_def_base<Func>; using base = test_def_func_base<Func>;
static constexpr std::size_t ARG_SIZE = sizeof...(Args); static constexpr std::size_t ARG_SIZE = sizeof...(Args);
std::tuple<Args...> args; std::tuple<Args...> args;
constexpr test_definition(const char *name, Func func, Args ...args) consteval test_definition(const char *name, Func func, Args ...args)
: test_def_base<Func>(name, func), args(std::make_tuple(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()() override { return std::apply(base::func, args); } constexpr std::invoke_result_t<Func, Args...> operator()() const override { return std::apply(base::func, args); }
}; };
struct test_suite_base {
const char *name;
};
template<typename ...TestDefs> template<typename ...TestDefs>
requires (sizeof...(TestDefs) == 0 || (std::derived_from<TestDefs, test_def_base<typename TestDefs::FuncType>> && ...)) requires (sizeof...(TestDefs) == 0 || (std::derived_from<TestDefs, test_def_func_base<typename TestDefs::FuncType>> && ...))
struct test_suite : public test_suite_base { struct test_suite {
template<typename NewTest>
using with_added_test_t = test_suite<TestDefs..., NewTest>;
static constexpr std::size_t TEST_NR = sizeof...(TestDefs); static constexpr std::size_t TEST_NR = sizeof...(TestDefs);
const char *name;
std::tuple<TestDefs...> tests; std::tuple<TestDefs...> tests;
constexpr test_suite(const char *name, std::tuple<TestDefs...> tests) : test_suite_base(name), tests(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>());
}
constexpr ret_val<TEST_NR> run() { template<std::size_t ...Is>
[[nodiscard]] constexpr auto get_tests_delegate(std::index_sequence<Is...>) const {
std::vector<ret_val_s> v; return std::array { (std::reference_wrapper(std::get<Is>(tests)), ...) };
std::apply([&v](auto&& ...args) { ((v.push_back(args())), ...); }, tests);
ret_val<TEST_NR> ret = { name };
std::ranges::move(v, ret.vals.begin());
return ret;
} }
}; };
@ -68,13 +84,13 @@ struct quick_test_def {
Suite current; Suite current;
template<std::invocable Func, typename ...Args> template<std::invocable Func, typename ...Args>
constexpr auto operator()(const char *name, Func func, Args... args) { consteval auto operator()(const char *name, Func func, EvalFlag evalFlag, Args... args) const {
auto test = test_definition(name, func, args...); auto test = test_definition(name, func, evalFlag, args...);
auto new_suite = test_suite(current.name, std::tuple_cat(current.tests, std::make_tuple(test))); auto suite = test_suite(name, std::tuple_cat(current.tests, std::make_tuple(test)));
return quick_test_def<decltype(new_suite)> { new_suite }; return quick_test_def<decltype(suite)> { .current = suite };
} }
constexpr operator Suite() { constexpr operator Suite() const {
return current; return current;
} }
}; };
@ -82,8 +98,47 @@ struct quick_test_def {
template<typename ...TestDefs> template<typename ...TestDefs>
test_suite(quick_test_def<test_suite<TestDefs...>>) -> test_suite<TestDefs...>; test_suite(quick_test_def<test_suite<TestDefs...>>) -> test_suite<TestDefs...>;
constexpr auto define_tests(const char *name) { consteval auto define_tests(const char *name) {
return quick_test_def { test_suite<>{ name, std::make_tuple() } }; 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_ #endif //CONST_CONTAINER_TEST_DEFINE_TEST_HPP_

View File

@ -1,17 +1,28 @@
#include <any>
#include <iostream>
#include <const_vector.hpp> #include <const_vector.hpp>
#include "test_define_test.hpp" #include "test_define_test.hpp"
#include "test_util.hpp" #include "test_util.hpp"
#include "test_ret_val.h" #include "test_ret_val.h"
test_suite tests = define_tests("Tests") constexpr test_suite tests = define_tests("Tests")
("Test1", [](){ ("Test Runtime", [](int = 1) constexpr{
return TEST_PASS("Test1", "PASS"); return TEST_PASS("Test Runtime", "PASS");
}); }, EvalFlag::RUNTIME)
("Test Consteval", [](char = 2) constexpr {
if (std::is_constant_evaluated()) {
return TEST_PASS("Test Consteval", "PASS");
} else {
return TEST_FAIL("Test Consteval", "FAIL");
}
}, EvalFlag::CONSTEVAL)
("Test Runtime Consteval", [](short = 3) constexpr{
if (std::is_constant_evaluated()) {
return TEST_PASS("Test Consteval Runtime", "PASS Consteval");
} else {
return TEST_PASS("Test Consteval", "PASS Runtime");
}
}, EvalFlag::RUNTIME_CONSTEVAL);
constexpr auto test_func(const char *name) { constexpr auto test_func(const char *name) {
@ -33,8 +44,10 @@ int main() {
report(ret); report(ret);
report(cret); report(cret);
auto sret = tests.run(); evaluate_tests(tests);
report(sret);
//auto sret = tests.run();
//report(sret);
return 0; return 0;
} }