aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/test/init.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'libbuild2/test/init.cxx')
-rw-r--r--libbuild2/test/init.cxx138
1 files changed, 117 insertions, 21 deletions
diff --git a/libbuild2/test/init.cxx b/libbuild2/test/init.cxx
index aaacdc6..32548f4 100644
--- a/libbuild2/test/init.cxx
+++ b/libbuild2/test/init.cxx
@@ -10,6 +10,8 @@
#include <libbuild2/config/utility.hxx>
+#include <libbuild2/script/timeout.hxx>
+
#include <libbuild2/test/module.hxx>
#include <libbuild2/test/target.hxx>
#include <libbuild2/test/operation.hxx>
@@ -21,6 +23,8 @@ namespace build2
{
namespace test
{
+ static const file_rule file_rule_ (true /* check_type */);
+
void
boot (scope& rs, const location&, module_boot_extra& extra)
{
@@ -28,15 +32,14 @@ namespace build2
l5 ([&]{trace << "for " << rs;});
- // Register our operations.
- //
- rs.insert_operation (test_id, op_test);
- rs.insert_operation (update_for_test_id, op_update_for_test);
-
// Enter module variables. Do it during boot in case they get assigned
// in bootstrap.build.
//
- auto& vp (rs.var_pool ());
+ // Most of the variables we enter are qualified so go straight for the
+ // public variable pool.
+ //
+ auto& vp (rs.var_pool (true /* public */));
+ auto& pvp (rs.var_pool ()); // For `test` and `for_test`.
common_data d {
@@ -44,8 +47,8 @@ namespace build2
//
// Specified as <target>@<path-id> pairs with both sides being
// optional. The variable is untyped (we want a list of name-pairs),
- // overridable, and with global visibiility. The target is relative
- // (in essence a prerequisite) which is resolved from the (root) scope
+ // overridable, and with global visibility. The target is relative (in
+ // essence a prerequisite) which is resolved from the (root) scope
// where the config.test value is defined.
//
vp.insert ("config.test"),
@@ -55,13 +58,28 @@ namespace build2
//
vp.insert<name_pair> ("config.test.output"),
+ // Test operation and individual test execution timeouts (see the
+ // manual for semantics).
+ //
+ vp.insert<string> ("config.test.timeout"),
+
+ // Test command runner path and options (see the manual for semantics).
+ //
+ vp.insert<strings> ("config.test.runner"),
+
// The test variable is a name which can be a path (with the
// true/false special values) or a target name.
//
- vp.insert<name> ("test", variable_visibility::target),
+ pvp.insert<name> ("test", variable_visibility::target),
vp.insert<strings> ("test.options"),
vp.insert<strings> ("test.arguments"),
+ // Test command runner path and options extracted from
+ // config.test.runner.
+ //
+ vp.insert<process_path> ("test.runner.path"),
+ vp.insert<strings> ("test.runner.options"),
+
// Prerequisite-specific.
//
// test.stdin and test.stdout can be used to mark a prerequisite as a
@@ -94,12 +112,12 @@ namespace build2
// This one is used by other modules/rules.
//
- vp.insert<bool> ("for_test", variable_visibility::prereq);
+ pvp.insert<bool> ("for_test", variable_visibility::prereq);
// These are only used in testscript.
//
- vp.insert<strings> ("test.redirects");
- vp.insert<strings> ("test.cleanups");
+ vp.insert<cmdline> ("test.redirects");
+ vp.insert<cmdline> ("test.cleanups");
// Unless already set, default test.target to build.host. Note that it
// can still be overriden by the user, e.g., in root.build.
@@ -108,9 +126,14 @@ namespace build2
value& v (rs.assign (d.test_target));
if (!v || v.empty ())
- v = cast<target_triplet> (rs.ctx.global_scope["build.host"]);
+ v = *rs.ctx.build_host;
}
+ // Register our operations.
+ //
+ rs.insert_operation (test_id, op_test, &d.var_test);
+ rs.insert_operation (update_for_test_id, op_update_for_test, &d.var_test);
+
extra.set_module (new module (move (d)));
}
@@ -189,11 +212,84 @@ namespace build2
else fail << "invalid config.test.output before value '" << b << "'";
}
+ // config.test.timeout
+ //
+ if (lookup l = lookup_config (rs, m.config_test_timeout))
+ {
+ const string& t (cast<string> (l));
+
+ const char* ot ("config.test.timeout test operation timeout value");
+ const char* tt ("config.test.timeout test timeout value");
+
+ size_t p (t.find ('/'));
+ if (p != string::npos)
+ {
+ // Note: either of the timeouts can be omitted but not both.
+ //
+ if (t.size () == 1)
+ fail << "invalid config.test.timeout value '" << t << "'";
+
+ if (p != 0)
+ m.operation_timeout = parse_timeout (string (t, 0, p), ot);
+
+ if (p != t.size () - 1)
+ m.test_timeout = parse_timeout (string (t, p + 1), tt);
+ }
+ else
+ m.operation_timeout = parse_timeout (t, ot);
+ }
+
+ // config.test.runner
+ //
+ {
+ value& pv (rs.assign (m.test_runner_path));
+ value& ov (rs.assign (m.test_runner_options));
+
+ if (lookup l = lookup_config (rs, m.config_test_runner))
+ {
+ const strings& args (cast<strings> (l));
+
+ // Extract the runner process path.
+ //
+ {
+ const string& s (args.empty () ? empty_string : args.front ());
+
+ path p;
+ try { p = path (s); } catch (const invalid_path&) {}
+
+ if (p.empty ())
+ fail << "invalid runner path '" << s << "' in "
+ << m.config_test_runner;
+
+ pv = run_search (p, false /* init */);
+ m.runner_path = &pv.as<process_path> ();
+ }
+
+ // Extract the runner options.
+ //
+ {
+ ov = strings (++args.begin (), args.end ());
+ m.runner_options = &ov.as<strings> ();
+ }
+ }
+ else
+ {
+ pv = nullptr;
+ ov = nullptr;
+ }
+ }
+
//@@ TODO: Need ability to specify extra diff options (e.g.,
// --strip-trailing-cr, now hardcoded).
//
//@@ TODO: Pring report.
+ // Environment.
+ //
+ // The only external program that we currently use is diff. None of the
+ // implementations we looked at (GNU diffutils, FreeBSD) use any
+ // environment variables.
+
// Register target types.
//
{
@@ -206,18 +302,18 @@ namespace build2
{
default_rule& dr (m);
- // Note: register for mtime_target to take priority over the fallback
- // rule below.
- //
- rs.insert_rule<target> (perform_test_id, "test", dr);
- rs.insert_rule<mtime_target> (perform_test_id, "test", dr);
- rs.insert_rule<alias> (perform_test_id, "test", dr);
+ rs.insert_rule<target> (perform_test_id, "test", dr);
+ rs.insert_rule<alias> (perform_test_id, "test", dr);
// Register the fallback file rule for the update-for-test operation,
// similar to update.
//
- rs.global_scope ().insert_rule<mtime_target> (
- perform_test_id, "test.file", file_rule::instance);
+ // Note: use target instead of anything more specific (such as
+ // mtime_target) in order not to take precedence over the "test" rule
+ // above.
+ //
+ rs.global_scope ().insert_rule<target> (
+ perform_test_id, "test.file", file_rule_);
}
return true;