Skip to content

Commit 81d85f8

Browse files
committed
auto-registering of @test functions
1 parent fa0134a commit 81d85f8

File tree

5 files changed

+165
-13
lines changed

5 files changed

+165
-13
lines changed

include/cpp2testing.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#ifndef CPP2_TESTING_H
2+
#define CPP2_TESTING_H
3+
4+
namespace cpp2::testing {
5+
6+
using test_function = void(void);
7+
8+
class session {
9+
public:
10+
session() {
11+
std::cout << "Creating test session!\n";
12+
}
13+
14+
static inline session& the() {
15+
static session instance;
16+
return instance;
17+
}
18+
19+
void register_test(test_function* tf) {
20+
tests_.push_back(tf);
21+
}
22+
23+
void run(int const argc, char** argv) {
24+
std::cout << "Running test session!\n";
25+
int test_count = 0;
26+
for(auto test : tests_) {
27+
std::cout << "Running test " << test_count++ << "!\n";
28+
test();
29+
}
30+
}
31+
private:
32+
std::vector<test_function*> tests_;
33+
};
34+
35+
struct auto_reg {
36+
auto_reg(test_function* tf) {
37+
std::cout << "Registering test func: " << tf << '\n';
38+
session::the().register_test(tf);
39+
}
40+
};
41+
42+
}
43+
44+
#endif

include/cpp2util.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2043,6 +2043,8 @@ inline constexpr auto as_() -> decltype(auto)
20432043

20442044
using cpp2::cpp2_new;
20452045

2046+
#include "cpp2testing.h"
2047+
20462048

20472049
// Stabilize line numbers for "compatibility" static assertions that we know
20482050
// will fire for some compilers, to keep regression test outputs cleaner

source/parse.h

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8064,6 +8064,21 @@ class parser
80648064
auto apply_type_metafunctions( declaration_node& decl )
80658065
-> bool;
80668066

8067+
auto apply_function_metafunctions( declaration_node& decl )
8068+
-> bool;
8069+
8070+
private:
8071+
std::vector<std::string> tests;
8072+
public:
8073+
auto add_test(std::string_view test_name) -> void {
8074+
tests.emplace_back(test_name);
8075+
std::cout << "\nexperiment: adding test to registry '" << test_name << "'\n";
8076+
}
8077+
8078+
auto test_names() const -> std::vector<std::string> const& {
8079+
return tests;
8080+
}
8081+
80678082

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

8275-
if (!n->metafunctions.empty()) {
8290+
bool bad_meta = n->metafunctions.size() > 1;
8291+
8292+
if(!bad_meta && !n->metafunctions.empty()) {
8293+
// from reflect.h2:1402
8294+
auto name = n->metafunctions[0]->to_string();
8295+
name = name.substr(0, name.find('<'));
8296+
bad_meta = name != "test";
8297+
}
8298+
8299+
if (bad_meta) {
82768300
errors.emplace_back(
82778301
n->metafunctions.front()->position(),
8278-
"(temporary alpha limitation) metafunctions are currently not supported on functions, only on types"
8302+
"(temporary alpha limitation) metafunctions are currently not supported on functions (except @test), only on types"
82798303
);
82808304
return {};
82818305
}
@@ -8611,6 +8635,17 @@ class parser
86118635
}
86128636
}
86138637

8638+
// If this is a function with a metafunction, apply those
8639+
if (n->is_function()) {
8640+
if (!apply_function_metafunctions(*n)) {
8641+
error(
8642+
"error encountered while applying function metafunctions",
8643+
false, {}, true
8644+
);
8645+
return {};
8646+
}
8647+
}
8648+
86148649
// If this is a function, record its extents
86158650
if (n->is_function()) {
86168651
function_body_extents.emplace_back(

source/sema.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,38 @@ auto parser::apply_type_metafunctions( declaration_node& n )
3939
);
4040
}
4141

42+
auto parser::apply_function_metafunctions( declaration_node& n )
43+
-> bool
44+
{
45+
assert(n.is_function());
46+
if(n.metafunctions.empty())
47+
return true;
48+
assert(n.metafunctions.size() == 1);
49+
{ // Require that the metafunction name is 'test'
50+
// from reflect.h2:1402
51+
auto name = n.metafunctions[0]->to_string();
52+
name = name.substr(0, name.find('<'));
53+
assert(name == "test");
54+
}
55+
if(n.metafunctions[0]->template_arguments().size() > 0)
56+
{
57+
error("(experiment limitation) A test can't have template params", false);
58+
return false;
59+
}
60+
if(n.parameter_count() > 0)
61+
{
62+
error("(experiment limitation) A test can't have parameters", false);
63+
return false;
64+
}
65+
if(n.has_declared_return_type())
66+
{
67+
error("(experiment limitation) A test can't have a declared return type", false);
68+
return false;
69+
}
70+
this->add_test(*n.name());
71+
return true;
72+
}
73+
4274

4375
//-----------------------------------------------------------------------
4476
//

source/to_cpp1.h

Lines changed: 50 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1589,6 +1589,28 @@ class cppfront
15891589
}
15901590
}
15911591

1592+
if(parser.test_names().size() > 0) {
1593+
if(cpp1_filename.back() == 'h') {
1594+
errors.emplace_back(
1595+
source_position{},
1596+
"tests should never be on headers, move them to a cpp2 file."
1597+
);
1598+
}
1599+
printer.print_extra( "\n//=== Cpp2 test registry for this TU =====================================\n\n" );
1600+
printer.print_extra("namespace {\n");
1601+
auto& tests = parser.test_names();
1602+
int test_count = 0;
1603+
for(auto test : tests) {
1604+
std::string test_decl = "cpp2::testing::auto_reg t";
1605+
test_decl += std::to_string(test_count++);
1606+
test_decl += "(&";
1607+
test_decl += test;
1608+
test_decl += ");\n";
1609+
printer.print_extra(test_decl);
1610+
}
1611+
printer.print_extra("}");
1612+
}
1613+
15921614
if (cpp1_filename.back() == 'h') {
15931615
printer.print_extra( "\n#endif" );
15941616
}
@@ -4694,18 +4716,35 @@ class cppfront
46944716
return;
46954717
}
46964718

4697-
if (
4698-
is_main
4699-
&& n.parameters->parameters.size() > 0
4700-
)
4719+
if (is_main)
47014720
{
4702-
printer.print_cpp2(
4703-
"(int const argc_, char** argv_)",
4704-
n.parameters->position()
4705-
);
4706-
current_functions.back().prolog.statements.push_back(
4707-
"auto const args = cpp2::make_args(argc_, argv_); "
4708-
);
4721+
// Should probably be "are tests enabled?", to be able to run tests
4722+
// from different TUs.
4723+
bool const has_tests = parser.test_names().size() > 0;
4724+
if(n.parameters->parameters.size() > 0) {
4725+
printer.print_cpp2(
4726+
"(int const argc_, char** argv_)",
4727+
n.parameters->position()
4728+
);
4729+
if(has_tests) {
4730+
current_functions.back().prolog.statements.push_back(
4731+
"cpp2::testing::session::the().run(argc_, argv_); "
4732+
);
4733+
}
4734+
current_functions.back().prolog.statements.push_back(
4735+
"auto const args = cpp2::make_args(argc_, argv_); "
4736+
);
4737+
}else {
4738+
printer.print_cpp2(
4739+
"()",
4740+
n.parameters->position()
4741+
);
4742+
if(has_tests) {
4743+
current_functions.back().prolog.statements.push_back(
4744+
"cpp2::testing::session::the().run(0, nullptr); "
4745+
);
4746+
}
4747+
}
47094748
}
47104749
else {
47114750
emit(*n.parameters, false, false, generating_postfix_inc_dec);

0 commit comments

Comments
 (0)