diff options
Diffstat (limited to 'libbuild2/test/script')
-rw-r--r-- | libbuild2/test/script/parser.cxx | 40 | ||||
-rw-r--r-- | libbuild2/test/script/parser.test.cxx | 6 | ||||
-rw-r--r-- | libbuild2/test/script/runner.cxx | 6 | ||||
-rw-r--r-- | libbuild2/test/script/runner.hxx | 12 | ||||
-rw-r--r-- | libbuild2/test/script/script.cxx | 58 | ||||
-rw-r--r-- | libbuild2/test/script/script.hxx | 20 |
6 files changed, 133 insertions, 9 deletions
diff --git a/libbuild2/test/script/parser.cxx b/libbuild2/test/script/parser.cxx index 944e1c8..8179058 100644 --- a/libbuild2/test/script/parser.cxx +++ b/libbuild2/test/script/parser.cxx @@ -1280,7 +1280,45 @@ namespace build2 parse_here_documents (t, tt, p); assert (tt == type::newline); - return move (p.first); + command_expr r (move (p.first)); + + // If the test program runner is specified, then adjust the + // expressions to run test programs via this runner. + // + pair<const process_path*, const strings*> tr ( + runner_->test_runner ()); + + if (tr.first != nullptr) + { + for (expr_term& t: r) + { + for (command& c: t.pipe) + { + if (scope_->test_program (c.program.recall)) + { + // Append the runner options and the test program path to the + // the arguments list and rotate the list to the left, so that + // it starts from the runner options. This should probably be + // not less efficient than inserting the program path and then + // the runner options at the beginning of the list. + // + strings& args (c.arguments); + size_t n (args.size ()); + + args.insert (args.end (), + tr.second->begin (), tr.second->end ()); + + args.push_back (c.program.recall.string ()); + + rotate (args.begin (), args.begin () + n, args.end ()); + + c.program = process_path (*tr.first, false /* init */); + } + } + } + } + + return r; } // diff --git a/libbuild2/test/script/parser.test.cxx b/libbuild2/test/script/parser.test.cxx index 69583ae..dbdeb57 100644 --- a/libbuild2/test/script/parser.test.cxx +++ b/libbuild2/test/script/parser.test.cxx @@ -39,6 +39,12 @@ namespace build2 return true; } + virtual pair<const process_path*, const strings*> + test_runner () override + { + return make_pair (nullptr, nullptr); + } + virtual void enter (scope& s, const location&) override { diff --git a/libbuild2/test/script/runner.cxx b/libbuild2/test/script/runner.cxx index 03a1f0e..eb30e02 100644 --- a/libbuild2/test/script/runner.cxx +++ b/libbuild2/test/script/runner.cxx @@ -21,6 +21,12 @@ namespace build2 return common_.test (s.root.test_target, s.id_path); } + pair<const process_path*, const strings*> default_runner:: + test_runner () + { + return make_pair (common_.runner_path, common_.runner_options); + } + void default_runner:: enter (scope& sp, const location&) { diff --git a/libbuild2/test/script/runner.hxx b/libbuild2/test/script/runner.hxx index 22cae4e..b6a038d 100644 --- a/libbuild2/test/script/runner.hxx +++ b/libbuild2/test/script/runner.hxx @@ -29,6 +29,12 @@ namespace build2 virtual bool test (scope&) const = 0; + // Return the runner program path and options if the test commands + // must be run via the runner and the pair of NULLs otherwise. + // + virtual pair<const process_path*, const strings*> + test_runner () = 0; + // Location is the scope start location (for diagnostics, etc). // virtual void @@ -66,6 +72,12 @@ namespace build2 virtual bool test (scope& s) const override; + // Return the test.runner.{path,options} values, if config.test.runner + // is specified. + // + virtual pair<const process_path*, const strings*> + test_runner () override; + virtual void enter (scope&, const location&) override; diff --git a/libbuild2/test/script/script.cxx b/libbuild2/test/script/script.cxx index 3f615ee..cb367bc 100644 --- a/libbuild2/test/script/script.cxx +++ b/libbuild2/test/script/script.cxx @@ -94,12 +94,37 @@ namespace build2 const_cast<path&> (id_path) = path (move (s)); } - // Calculate the working directory path unless this is the root scope - // (handled in an ad hoc way). + // Calculate the working directory path and the test programs set + // unless this is the root scope (handled in an ad hoc way). // if (p != nullptr) + { const_cast<dir_path&> (*work_dir.path) = dir_path (*p->work_dir.path) /= id; + + // Note that we could probably keep the test programs sets fully + // independent across the scopes and check if the program is a test + // by traversing the scopes upwards recursively. Note though, that + // the parent scope's set cannot change during the nested scope + // lifetime and normally contains just a single entry. Thus, it + // seems more efficient to get rid of the recursion by copying the + // set from the parent now and potentially changing it later on the + // test variable assignment, etc. + // + test_programs_ = p->test_programs_; + } + } + + bool scope:: + test_program (const path& p) + { + assert (!test_programs_.empty ()); + + return find_if (test_programs_.begin (), test_programs_.end (), + [&p] (const path* tp) + { + return tp != nullptr ? *tp == p : false; + }) != test_programs_.end (); } void scope:: @@ -287,6 +312,12 @@ namespace build2 } } + // Reserve the entry for the test program specified via the test + // variable. Note that the value will be assigned by the below + // reset_special() call. + // + test_programs_.push_back (nullptr); + // Set the special $*, $N variables. // reset_special (); @@ -378,7 +409,8 @@ namespace build2 void scope:: reset_special () { - // First assemble the $* value. + // First assemble the $* value and save the test variable value into + // the test program set. // strings s; @@ -387,14 +419,24 @@ namespace build2 s.insert (s.end (), v.begin (), v.end ()); }; + // If the test variable can't be looked up for any reason (is NULL, + // etc), then keep $* empty. + // if (auto l = lookup (root.test_var)) - s.push_back (cast<path> (l).representation ()); + { + const path& p (cast<path> (l)); + s.push_back (p.representation ()); - if (auto l = lookup (root.options_var)) - append (cast<strings> (l)); + test_programs_[0] = &p; - if (auto l = lookup (root.arguments_var)) - append (cast<strings> (l)); + if (auto l = lookup (root.options_var)) + append (cast<strings> (l)); + + if (auto l = lookup (root.arguments_var)) + append (cast<strings> (l)); + } + else + test_programs_[0] = nullptr; // Keep redirects/cleanups out of $N. // diff --git a/libbuild2/test/script/script.hxx b/libbuild2/test/script/script.hxx index 2789cab..d387a11 100644 --- a/libbuild2/test/script/script.hxx +++ b/libbuild2/test/script/script.hxx @@ -28,6 +28,8 @@ namespace build2 using build2::script::redirect_type; using build2::script::line_type; using build2::script::command_expr; + using build2::script::expr_term; + using build2::script::command; using build2::script::deadline; using build2::script::timeout; @@ -105,6 +107,15 @@ namespace build2 virtual void create_temp_dir () override {assert (false);}; + // Return true if this is a test program path. + // + // Note that currently the test program is only specified via the test + // variable ($0 effectively). In the future we may invent some other + // means of marking a program as a test (builtin, etc). + // + bool + test_program (const path&); + // Variables. // public: @@ -163,6 +174,15 @@ namespace build2 location end_loc_; optional<line> if_cond_; + + // Test program paths. + // + // Currently always contains a single element (see test_program() for + // details). While in the future there can be more of them, the zero + // index will always refer to the test variable value and can + // potentially be NULL (see reset_special() for details). + // + small_vector<const path*, 1> test_programs_; }; // group |