aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2016-10-19 16:41:43 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2016-11-04 09:26:33 +0200
commita17e517e079c33bcb4d6dea94f6c441a5eb2e33a (patch)
tree52a529d7b54513aa88417e1f7a49e24a5893ecef
parent43124ef418bd7fe909027b977bf5effc305b4740 (diff)
Generalize and move test printing code to script
-rw-r--r--build2/test/script/parser.cxx3
-rw-r--r--build2/test/script/runner.cxx75
-rw-r--r--build2/test/script/script18
-rw-r--r--build2/test/script/script.cxx97
-rw-r--r--build2/test/script/script.ixx39
5 files changed, 157 insertions, 75 deletions
diff --git a/build2/test/script/parser.cxx b/build2/test/script/parser.cxx
index 9655778..a9a179b 100644
--- a/build2/test/script/parser.cxx
+++ b/build2/test/script/parser.cxx
@@ -514,6 +514,9 @@ namespace build2
// interesting characters (operators plus quotes/escapes),
// then no need to re-lex.
//
+ // NOTE: updated quoting (script.cxx:to_stream_q()) if adding
+ // any new characters.
+ //
if (q || s.find_first_of ("|&<>\'\"\\") == string::npos)
add_word (move (s), l);
else
diff --git a/build2/test/script/runner.cxx b/build2/test/script/runner.cxx
index 25383cf..3a5eb76 100644
--- a/build2/test/script/runner.cxx
+++ b/build2/test/script/runner.cxx
@@ -12,81 +12,6 @@ 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.here_end);
- break;
- }
- default: assert (false);
- }
- };
-
- auto print_heredoc = [&o] (const redirect& r)
- {
- // Here-document value always ends with a newline.
- //
- o << endl << r.value << r.here_end;
- };
-
- 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)
{
diff --git a/build2/test/script/script b/build2/test/script/script
index e3afbca..04b964f 100644
--- a/build2/test/script/script
+++ b/build2/test/script/script
@@ -59,6 +59,19 @@ namespace build2
redirect err;
};
+ enum class command_to_stream: uint16_t
+ {
+ header = 0x01,
+ here_doc = 0x02, // Note: printed on a new line.
+ all = header | here_doc
+ };
+
+ void
+ to_stream (ostream&, const command&, command_to_stream);
+
+ ostream&
+ operator<< (ostream&, const command&);
+
enum class exit_comparison {eq, ne};
struct command_exit
@@ -91,6 +104,9 @@ namespace build2
command_exit exit;
};
+ ostream&
+ operator<< (ostream&, const test&);
+
class scope
{
public:
@@ -162,4 +178,6 @@ namespace build2
}
}
+#include <build2/test/script/script.ixx>
+
#endif // BUILD2_TEST_SCRIPT_SCRIPT
diff --git a/build2/test/script/script.cxx b/build2/test/script/script.cxx
index 2be023d..1fb100d 100644
--- a/build2/test/script/script.cxx
+++ b/build2/test/script/script.cxx
@@ -14,6 +14,103 @@ namespace build2
{
namespace script
{
+ // Quote if empty or contains spaces or any of the special characters.
+ //
+ // @@ What if it contains quotes, escapes?
+ //
+ static void
+ to_stream_q (ostream& o, const string& s)
+ {
+ if (s.empty () || s.find_first_of (" |&<>=") != string::npos)
+ o << '"' << s << '"';
+ else
+ o << s;
+ };
+
+ void
+ to_stream (ostream& o, const command& c, command_to_stream m)
+ {
+ auto print_redirect = [&o] (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::none: assert (false); break;
+ case redirect_type::null: o << '!'; break;
+ case redirect_type::here_string: to_stream_q (o, r.value); break;
+ case redirect_type::here_document:
+ {
+ // Add another '>' or '<'. Note that here end marker never
+ // needs to be quoted.
+ //
+ o << prefix[n - 1] << r.here_end;
+ break;
+ }
+ }
+ };
+
+ auto print_doc = [&o] (const redirect& r)
+ {
+ // Here-document value always ends with a newline.
+ //
+ o << endl << r.value << r.here_end;
+ };
+
+ if ((m & command_to_stream::header) == command_to_stream::header)
+ {
+ // Program.
+ //
+ to_stream_q (o, c.program.string ());
+
+ // Arguments.
+ //
+ for (const string& a: c.arguments)
+ {
+ o << ' ';
+ to_stream_q (o, a);
+ }
+
+ // Redirects.
+ //
+ if (c.in.type != redirect_type::none) print_redirect (c.in, "<");
+ if (c.out.type != redirect_type::none) print_redirect (c.out, ">");
+ if (c.err.type != redirect_type::none) print_redirect (c.err, "2>");
+ }
+
+ if ((m & command_to_stream::here_doc) == command_to_stream::here_doc)
+ {
+ // Here-documents.
+ //
+ if (c.in.type == redirect_type::here_document) print_doc (c.in);
+ if (c.out.type == redirect_type::here_document) print_doc (c.out);
+ if (c.err.type == redirect_type::here_document) print_doc (c.err);
+ }
+ }
+
+ ostream&
+ operator<< (ostream& o, const test& t)
+ {
+ to_stream (o, t, command_to_stream::header);
+
+ if (t.exit.comparison != exit_comparison::eq || t.exit.status != 0)
+ {
+ switch (t.exit.comparison)
+ {
+ case exit_comparison::eq: o << " == "; break;
+ case exit_comparison::ne: o << " != "; break;
+ }
+
+ o << static_cast<uint16_t> (t.exit.status);
+ }
+
+ to_stream (o, t, command_to_stream::here_doc);
+ return o;
+ }
+
script::
script (target& tt, testscript& st)
: test_target (tt), script_target (st),
diff --git a/build2/test/script/script.ixx b/build2/test/script/script.ixx
new file mode 100644
index 0000000..2e215da
--- /dev/null
+++ b/build2/test/script/script.ixx
@@ -0,0 +1,39 @@
+// file : build2/test/script/script.ixx -*- C++ -*-
+// copyright : Copyright (c) 2014-2016 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+namespace build2
+{
+ namespace test
+ {
+ namespace script
+ {
+ inline command_to_stream
+ operator&= (command_to_stream& x, command_to_stream y)
+ {
+ return x = static_cast<command_to_stream> (
+ static_cast<uint16_t> (x) & static_cast<uint16_t> (y));
+ }
+
+ inline command_to_stream
+ operator|= (command_to_stream& x, command_to_stream y)
+ {
+ return x = static_cast<command_to_stream> (
+ static_cast<uint16_t> (x) | static_cast<uint16_t> (y));
+ }
+
+ inline command_to_stream
+ operator& (command_to_stream x, command_to_stream y) {return x &= y;}
+
+ inline command_to_stream
+ operator| (command_to_stream x, command_to_stream y) {return x |= y;}
+
+ inline ostream&
+ operator<< (ostream& o, const command& c)
+ {
+ to_stream (o, c, command_to_stream::all);
+ return o;
+ }
+ }
+ }
+}