From 43378e3827fd0d17325646c40c76bab9db1da19a Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 26 Oct 2016 15:01:54 +0200 Subject: Handle explicit test scopes --- build2/parser.cxx | 2 +- build2/test/script/parser.cxx | 66 ++++++++++++++++++++++++-- build2/test/script/script | 6 +++ unit-tests/test/script/parser/driver.cxx | 17 +++++-- unit-tests/test/script/parser/scope.test | 79 +++++++++++++++++++++++++++++++- 5 files changed, 160 insertions(+), 10 deletions(-) diff --git a/build2/parser.cxx b/build2/parser.cxx index 800d4e9..eb9f463 100644 --- a/build2/parser.cxx +++ b/build2/parser.cxx @@ -1747,7 +1747,7 @@ namespace build2 ns.insert (ns.end (), make_move_iterator (rhs.as ().begin ()), - make_move_iterator (rhs.as ().end ())); + make_move_iterator (rhs.as ().end ())); break; } diff --git a/build2/test/script/parser.cxx b/build2/test/script/parser.cxx index 25d3636..3043f05 100644 --- a/build2/test/script/parser.cxx +++ b/build2/test/script/parser.cxx @@ -114,10 +114,10 @@ namespace build2 // Push group. Use line number as the scope id. // + unique_ptr g (new group (to_string (ll.line), *group_)); + group* og (group_); - unique_ptr p ( - group_ = new group (to_string (ll.line), *og)); - og->scopes.push_back (move (p)); + group_ = g.get (); group_->start_loc_ = ll; token e (pre_parse_scope_body ()); @@ -127,6 +127,66 @@ namespace build2 // group_ = og; + // Drop empty scopes. + // + if (!g->empty ()) + { + // See if this turned out to be an explicit test scope. An + // explicit test scope contains a single test, only variable + // assignments in setup and nothing in teardown. Plus only the + // test or the scope (but not both) can have an explicit id. + // + // @@ TODO: explicit id. + // + auto& sc (g->scopes); + auto& su (g->setup_); + auto& td (g->tdown_); + + test* t; + if (sc.size () == 1 && + (t = dynamic_cast (sc.back ().get ())) != nullptr && + td.empty () && + find_if ( + su.begin (), su.end (), + [] (const line& l) + { + return l.type != line_type::variable; + }) == su.end ()) + { + // It would have been nice to reuse the test object and only + // throw aways the group. However, the merged scope should + // have id_path/wd_path of the group. So to keep things + // simple we are going to throw away both and create a new + // test object. + // + // @@ TODO: decide whose id to use. + // + unique_ptr m (new test (g->id_path.leaf ().string (), + *group_)); + + // Merge the lines of the group and the test. + // + if (su.empty ()) + m->tests_ = move (t->tests_); + else + { + m->tests_ = move (su); // Should come first. + m->tests_.insert (m->tests_.end (), + make_move_iterator (t->tests_.begin ()), + make_move_iterator (t->tests_.end ())); + } + + // Use start/end locations of the outer scope. + // + m->start_loc_ = g->start_loc_; + m->end_loc_ = g->end_loc_; + + group_->scopes.push_back (move (m)); + } + else + group_->scopes.push_back (move (g)); + } + if (e.type != type::rcbrace) fail (e) << "expected '}' at the end of the scope"; diff --git a/build2/test/script/script b/build2/test/script/script index 79ada8e..574760e 100644 --- a/build2/test/script/script +++ b/build2/test/script/script @@ -216,6 +216,12 @@ namespace build2 private: friend class parser; + bool + empty () const + { + return scopes.empty () && setup_.empty () && tdown_.empty (); + } + lines setup_; lines tdown_; }; diff --git a/unit-tests/test/script/parser/driver.cxx b/unit-tests/test/script/parser/driver.cxx index 6e3fed5..aad94f9 100644 --- a/unit-tests/test/script/parser/driver.cxx +++ b/unit-tests/test/script/parser/driver.cxx @@ -30,13 +30,16 @@ namespace build2 class print_runner: public runner { public: - print_runner (bool scope): scope_ (scope) {} + print_runner (bool scope, bool id): scope_ (scope), id_ (id) {} virtual void - enter (scope&, const location&) override + enter (scope& s, const location&) override { if (scope_) { + if (id_ && !s.id_path.empty ()) // Skip empty root scope id. + cout << ind_ << ": " << s.id_path.string () << endl; + cout << ind_ << "{" << endl; ind_ += " "; } @@ -60,10 +63,11 @@ namespace build2 private: bool scope_; + bool id_; string ind_; }; - // Usage: argv[0] [-s] [] + // Usage: argv[0] [-s] [-i] [] // int main (int argc, char* argv[]) @@ -74,6 +78,7 @@ namespace build2 reset (strings ()); // No command line variables. bool scope (false); + bool id (false); path name; for (int i (1); i != argc; ++i) @@ -82,6 +87,8 @@ namespace build2 if (a == "-s") scope = true; + else if (a == "-i") + id = true; else { name = path (move (a)); @@ -92,6 +99,8 @@ namespace build2 if (name.empty ()) name = path ("testscript"); + assert (!id || scope); // Id can only be printed with scope. + try { cin.exceptions (istream::failbit | istream::badbit); @@ -121,7 +130,7 @@ namespace build2 // Parse and run. // script s (tt, st, dir_path (work) /= "test-driver"); - print_runner r (scope); + print_runner r (scope, id); parser p; p.pre_parse (cin, name, s); diff --git a/unit-tests/test/script/parser/scope.test b/unit-tests/test/script/parser/scope.test index 593dbb2..a903959 100644 --- a/unit-tests/test/script/parser/scope.test +++ b/unit-tests/test/script/parser/scope.test @@ -17,8 +17,16 @@ $* -s <>EOO # group-empty } EOI { - { - } +} +EOO + +$* -s <>EOO # group-empty-empty +{ + { + } +} +EOI +{ } EOO @@ -40,6 +48,73 @@ EOI } EOO +# Test scope. +# + +$* -s -i <>EOO # test-scope +{ + cmd +} +EOI +{ + : 1 + { + cmd + } +} +EOO + +$* -s -i <>EOO # test-scope-nested +{ + { + cmd + } +} +EOI +{ + : 1 + { + cmd + } +} +EOO + +$* -s -i <>EOO # test-scope-var +{ + x = abc + cmd \$x +} +EOI +{ + : 1 + { + cmd abc + } +} +EOO + +$* -s -i <>EOO # test-scope-setup +{ + x = abc + +setup + cmd \$x +} +EOI +{ + : 1 + { + setup + : 1/4 + { + cmd abc + } + } +} +EOO + + +# +# $* <:"{x" 2>>EOE != 0 # expected-newline-lcbrace testscript:1:2: error: expected newline after '{' EOE -- cgit v1.1