Skip to content

Commit

Permalink
auto-registering of @test functions
Browse files Browse the repository at this point in the history
  • Loading branch information
DyXel committed Jan 27, 2024
1 parent fa0134a commit 81d85f8
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 13 deletions.
44 changes: 44 additions & 0 deletions include/cpp2testing.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#ifndef CPP2_TESTING_H
#define CPP2_TESTING_H

namespace cpp2::testing {

using test_function = void(void);

class session {
public:
session() {
std::cout << "Creating test session!\n";
}

static inline session& the() {
static session instance;
return instance;
}

void register_test(test_function* tf) {
tests_.push_back(tf);
}

void run(int const argc, char** argv) {
std::cout << "Running test session!\n";
int test_count = 0;
for(auto test : tests_) {
std::cout << "Running test " << test_count++ << "!\n";
test();
}
}
private:
std::vector<test_function*> tests_;
};

struct auto_reg {
auto_reg(test_function* tf) {
std::cout << "Registering test func: " << tf << '\n';
session::the().register_test(tf);
}
};

}

#endif
2 changes: 2 additions & 0 deletions include/cpp2util.h
Original file line number Diff line number Diff line change
Expand Up @@ -2043,6 +2043,8 @@ inline constexpr auto as_() -> decltype(auto)

using cpp2::cpp2_new;

#include "cpp2testing.h"


// Stabilize line numbers for "compatibility" static assertions that we know
// will fire for some compilers, to keep regression test outputs cleaner
Expand Down
39 changes: 37 additions & 2 deletions source/parse.h
Original file line number Diff line number Diff line change
Expand Up @@ -8064,6 +8064,21 @@ class parser
auto apply_type_metafunctions( declaration_node& decl )
-> bool;

auto apply_function_metafunctions( declaration_node& decl )
-> bool;

private:
std::vector<std::string> tests;
public:
auto add_test(std::string_view test_name) -> void {
tests.emplace_back(test_name);
std::cout << "\nexperiment: adding test to registry '" << test_name << "'\n";
}

auto test_names() const -> std::vector<std::string> const& {
return tests;
}


//G unnamed-declaration:
//G ':' meta-functions? template-parameters? function-type requires-clause? '=' statement
Expand Down Expand Up @@ -8272,10 +8287,19 @@ class parser
n->type = std::move(t);
assert (n->is_function());

if (!n->metafunctions.empty()) {
bool bad_meta = n->metafunctions.size() > 1;

if(!bad_meta && !n->metafunctions.empty()) {
// from reflect.h2:1402
auto name = n->metafunctions[0]->to_string();
name = name.substr(0, name.find('<'));
bad_meta = name != "test";
}

if (bad_meta) {
errors.emplace_back(
n->metafunctions.front()->position(),
"(temporary alpha limitation) metafunctions are currently not supported on functions, only on types"
"(temporary alpha limitation) metafunctions are currently not supported on functions (except @test), only on types"
);
return {};
}
Expand Down Expand Up @@ -8611,6 +8635,17 @@ class parser
}
}

// If this is a function with a metafunction, apply those
if (n->is_function()) {
if (!apply_function_metafunctions(*n)) {
error(
"error encountered while applying function metafunctions",
false, {}, true
);
return {};
}
}

// If this is a function, record its extents
if (n->is_function()) {
function_body_extents.emplace_back(
Expand Down
32 changes: 32 additions & 0 deletions source/sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,38 @@ auto parser::apply_type_metafunctions( declaration_node& n )
);
}

auto parser::apply_function_metafunctions( declaration_node& n )
-> bool
{
assert(n.is_function());
if(n.metafunctions.empty())
return true;
assert(n.metafunctions.size() == 1);
{ // Require that the metafunction name is 'test'
// from reflect.h2:1402
auto name = n.metafunctions[0]->to_string();
name = name.substr(0, name.find('<'));
assert(name == "test");
}
if(n.metafunctions[0]->template_arguments().size() > 0)
{
error("(experiment limitation) A test can't have template params", false);
return false;
}
if(n.parameter_count() > 0)
{
error("(experiment limitation) A test can't have parameters", false);
return false;
}
if(n.has_declared_return_type())
{
error("(experiment limitation) A test can't have a declared return type", false);
return false;
}
this->add_test(*n.name());
return true;
}


//-----------------------------------------------------------------------
//
Expand Down
61 changes: 50 additions & 11 deletions source/to_cpp1.h
Original file line number Diff line number Diff line change
Expand Up @@ -1589,6 +1589,28 @@ class cppfront
}
}

if(parser.test_names().size() > 0) {
if(cpp1_filename.back() == 'h') {
errors.emplace_back(
source_position{},
"tests should never be on headers, move them to a cpp2 file."
);
}
printer.print_extra( "\n//=== Cpp2 test registry for this TU =====================================\n\n" );
printer.print_extra("namespace {\n");
auto& tests = parser.test_names();
int test_count = 0;
for(auto test : tests) {
std::string test_decl = "cpp2::testing::auto_reg t";
test_decl += std::to_string(test_count++);
test_decl += "(&";
test_decl += test;
test_decl += ");\n";
printer.print_extra(test_decl);
}
printer.print_extra("}");
}

if (cpp1_filename.back() == 'h') {
printer.print_extra( "\n#endif" );
}
Expand Down Expand Up @@ -4694,18 +4716,35 @@ class cppfront
return;
}

if (
is_main
&& n.parameters->parameters.size() > 0
)
if (is_main)
{
printer.print_cpp2(
"(int const argc_, char** argv_)",
n.parameters->position()
);
current_functions.back().prolog.statements.push_back(
"auto const args = cpp2::make_args(argc_, argv_); "
);
// Should probably be "are tests enabled?", to be able to run tests
// from different TUs.
bool const has_tests = parser.test_names().size() > 0;
if(n.parameters->parameters.size() > 0) {
printer.print_cpp2(
"(int const argc_, char** argv_)",
n.parameters->position()
);
if(has_tests) {
current_functions.back().prolog.statements.push_back(
"cpp2::testing::session::the().run(argc_, argv_); "
);
}
current_functions.back().prolog.statements.push_back(
"auto const args = cpp2::make_args(argc_, argv_); "
);
}else {
printer.print_cpp2(
"()",
n.parameters->position()
);
if(has_tests) {
current_functions.back().prolog.statements.push_back(
"cpp2::testing::session::the().run(0, nullptr); "
);
}
}
}
else {
emit(*n.parameters, false, false, generating_postfix_inc_dec);
Expand Down

0 comments on commit 81d85f8

Please sign in to comment.