aboutsummaryrefslogtreecommitdiff
path: root/tests/progress/driver.cxx
blob: 0ff68f028704a5e80e574f698885c816ff58b361 (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
124
125
126
127
// file      : tests/progress/driver.cxx -*- C++ -*-
// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
// license   : MIT; see accompanying LICENSE file

#ifndef _WIN32
#  include <unistd.h> // write()

#  include <thread> // this_thread::sleep_for()
#else
#  include <libbutl/win32-utility.hxx>

#  include <io.h> //_write()
#endif

#include <cstddef>  // size_t
#include <iostream>

#include <libbutl/process.hxx>
#include <libbutl/fdstream.hxx>    // fdnull(), stderr_fd()
#include <libbutl/diagnostics.hxx>

using namespace std;
using namespace butl;

// Usage:
//
// argv[0] [-n] [-c]
//
// -n
//    Do not run child process. By default the program runs itself with -c
//    option (see below).
//
// -c
//    Run as a child process that just prints lines with a small but varying
//    delay.
//
int
main (int argc, const char* argv[])
{
  bool child (false);
  bool no_child (false);

  assert (argc > 0);

  for (int i (1); i != argc; ++i)
  {
    string v (argv[i]);

    if (v == "-c")
      child = true;
    else if (v == "-n")
      no_child = true;
    else
      assert (false);
  }

  auto sleep = [] (size_t ms = 100)
  {
    // MINGW GCC 4.9 doesn't implement this_thread so use Win32 Sleep().
    //
#ifndef _WIN32
    this_thread::sleep_for (chrono::milliseconds (ms));
#else
    Sleep (static_cast<DWORD> (ms));
#endif
  };

  if (child)
  {
    auto print = [] (const string& s)
    {
#ifndef _WIN32
      ssize_t r (write (stderr_fd(), s.c_str (), s.size ()));
#else
      int r (_write (stderr_fd(),
                     s.c_str (),
                     static_cast<unsigned int> (s.size ())));
#endif

      assert (r != -1);
    };

    for (size_t i (50); i != 0; --i)
    {
      print ("Child line " + to_string (i) + '\n');
      sleep (200 - i);
    }

    return 0;
  }

  process pr (!no_child
              ? process_start (fdnull (), fdnull (), 2, argv[0], "-c")
              : process (process_exit (0))); // Exited normally.

  for (size_t i (100); i != 0; --i)
  {
    if (i % 10 == 0)
      diag_stream_lock () << "Line " << i / 10 << endl;

    {
      diag_progress_lock l;
      diag_progress = "  " + to_string (i) + "%";
    }

    sleep ();
  }

  sleep (1000);

  // Test that the progress line is restored by the diag_stream_lock.
  //
  diag_stream_lock () << "Printed to diag_stream" << endl;

  sleep (1000);

  // Test that the progress line is restored after printing to cerr.
  //
  {
    cerr << "Printed to std::cerr" << endl;
    diag_progress_lock ();
  }

  sleep (1000);

  assert (pr.wait ());
}