aboutsummaryrefslogtreecommitdiff
path: root/build2/test/script/runner.cxx
blob: c4778bfcc431079e3a1709749b3086d6ab24afa6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// file      : build2/test/script/runner.cxx -*- C++ -*-
// copyright : Copyright (c) 2014-2016 Code Synthesis Ltd
// license   : MIT; see accompanying LICENSE file

#include <build2/test/script/runner>

using namespace std;

namespace build2
{
  namespace test
  {
    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

        // @@ 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);
      }
    }
  }
}