diff options
-rw-r--r-- | build2/test/script/parser.cxx | 23 | ||||
-rw-r--r-- | build2/test/script/runner.cxx | 102 | ||||
-rw-r--r-- | build2/test/script/script | 4 | ||||
-rw-r--r-- | unit-tests/test/script/lexer/script-line.test | 2 |
4 files changed, 118 insertions, 13 deletions
diff --git a/build2/test/script/parser.cxx b/build2/test/script/parser.cxx index 626bc38..b670956 100644 --- a/build2/test/script/parser.cxx +++ b/build2/test/script/parser.cxx @@ -172,8 +172,7 @@ namespace build2 pending p (pending::program); // Ordered sequence of here-document redirects that we can expect to - // see after the command line. We temporarily store the end marker - // as the redirect's value. + // see after the command line. // vector<reference_wrapper<redirect>> hd; @@ -182,6 +181,12 @@ namespace build2 // auto add_word = [&ts, &p, &hd, this] (string&& w, const location& l) { + auto add_heredoc = [&w, &hd] (redirect& r) + { + hd.push_back (r); + r.end_marker = move (w); + }; + switch (p) { case pending::none: ts.arguments.push_back (move (w)); break; @@ -200,13 +205,11 @@ namespace build2 } break; } - case pending::in_document: hd.push_back (ts.in); // Fall through. - case pending::in_string: ts.in.value = move (w); break; - - case pending::out_document: hd.push_back (ts.out); // Fall through. + case pending::in_document: add_heredoc (ts.in); break; + case pending::in_string: ts.in.value = move (w); break; + case pending::out_document: add_heredoc (ts.out); break; case pending::out_string: ts.out.value = move (w); break; - - case pending::err_document: hd.push_back (ts.err); // Fall through. + case pending::err_document: add_heredoc (ts.err); break; case pending::err_string: ts.err.value = move (w); break; } @@ -541,9 +544,7 @@ namespace build2 mode (lexer_mode::here_line); next (t, tt); - // The end marker is temporarily stored as the redirect's value. - // - r.value = parse_here_document (t, tt, r.value); + r.value = parse_here_document (t, tt, r.end_marker); expire_mode (); } diff --git a/build2/test/script/runner.cxx b/build2/test/script/runner.cxx index a17b9bf..c4778bf 100644 --- a/build2/test/script/runner.cxx +++ b/build2/test/script/runner.cxx @@ -12,11 +12,111 @@ namespace build2 { namespace script { + static ostream& + operator<< (ostream& o, const test& t) + { + auto print_string = [&o] (const string& s) + { + // Quote if empty or contains spaces. + // + if (s.empty () || s.find (' ') != string::npos) + o << '"' << s << '"'; + else + o << s; + }; + + auto print_redirect = [&o, &print_string] (const redirect& r, + const char* prefix) + { + o << ' ' << prefix; + + size_t n (string::traits_type::length (prefix)); + assert (n > 0); + + switch (r.type) + { + case redirect_type::null: o << '!'; break; + case redirect_type::here_string: print_string (r.value); break; + case redirect_type::here_document: + { + o << prefix[n - 1]; // Add another '>' or '<'. + print_string (r.end_marker); + break; + } + default: assert (false); + } + }; + + auto print_heredoc = [&o] (const redirect& r) + { + // Here-document value always ends with a newline. + // + o << endl << r.value << r.end_marker; + }; + + print_string (t.program.string ()); + + for (const auto& a: t.arguments) + { + o << ' '; + print_string (a); + } + + if (t.in.type != redirect_type::none) + print_redirect (t.in, "<"); + + if (t.out.type != redirect_type::none) + print_redirect (t.out, ">"); + + if (t.err.type != redirect_type::none) + print_redirect (t.err, "2>"); + + if (t.exit.comparison != exit_comparison::eq || t.exit.status != 0) + o << (t.exit.comparison == exit_comparison::eq ? " == " : " != ") + << (int)t.exit.status; + + if (t.in.type == redirect_type::here_document) + print_heredoc (t.in); + + if (t.out.type == redirect_type::here_document) + print_heredoc (t.out); + + if (t.err.type == redirect_type::here_document) + print_heredoc (t.err); + + return o; + } + + static void + print_test (diag_record& r, const test& t) + { + // @@ No indentation performed for here-documents. If to fix then + // probably need to do on diag_record level in a way similar to + // butl::pager approach. + // + r << t; + } + + static void + print_test (const test& t) + { + diag_record r (text); + print_test (r, t); + } + void concurrent_runner:: run (const test& t) { // @@ TODO - text << "run " << t.program.string (); + + // @@ When running multiple threads will need to synchronize printing + // the diagnostics so it don't overlap for concurrent tests. + // Alternatively we can not bother with that and expect a user to + // re-run test operation in the single-thread mode. + // + + if (verb >= 3) + print_test (t); } } } diff --git a/build2/test/script/script b/build2/test/script/script index 9fb2a28..8f918fc 100644 --- a/build2/test/script/script +++ b/build2/test/script/script @@ -32,6 +32,10 @@ namespace build2 { redirect_type type = redirect_type::none; string value; + + // Meaningul for here-documents only. Used for diagnostics. + // + string end_marker; }; struct command diff --git a/unit-tests/test/script/lexer/script-line.test b/unit-tests/test/script/lexer/script-line.test index ff67801..692161b 100644 --- a/unit-tests/test/script/lexer/script-line.test +++ b/unit-tests/test/script/lexer/script-line.test @@ -1,6 +1,6 @@ foo != 0 a=aaa -foo bar <"bbb $a ccc" >ddd 2>>EOE +foo bar <"bbb $a ccc" >ddd 2>>EOE == 2 eee EOE foo |