diff options
Diffstat (limited to 'libbuild2/test/init.cxx')
-rw-r--r-- | libbuild2/test/init.cxx | 138 |
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; |