GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: unittest/unittest_common.hpp Lines: 52 63 82.5 %
Date: 2024-02-13 11:12:33 Branches: 25 74 33.8 %

Line Branch Exec Source
1
///////////////////////////////////////////////////////////////////////////////
2
// BSD 3-Clause License
3
//
4
// Copyright (C) 2019-2023, LAAS-CNRS, University of Edinburgh
5
// Copyright note valid unless otherwise stated in individual files.
6
// All rights reserved.
7
///////////////////////////////////////////////////////////////////////////////
8
9
/**
10
 * To be included last in the test_XXX.cpp,
11
 * otherwise it interferes with pinocchio boost::variant.
12
 */
13
14
#ifndef CROCODDYL_UNITTEST_COMMON_HPP_
15
#define CROCODDYL_UNITTEST_COMMON_HPP_
16
17
#include <fcntl.h>
18
#include <stdio.h>
19
#include <unistd.h>
20
21
#include <boost/function.hpp>
22
#include <boost/test/execution_monitor.hpp>  // for execution_exception
23
#include <boost/test/included/unit_test.hpp>
24
#include <iterator>
25
#include <string>
26
27
#include "crocoddyl/core/utils/exception.hpp"
28
#include "random_generator.hpp"
29
30
namespace crocoddyl {
31
namespace unittest {
32
33
class CaptureIOStream {
34
 public:
35
16
  CaptureIOStream()
36
16
      : m_oldStdOut(0), m_oldStdErr(0), m_capturing(false), m_init(false) {
37
16
    m_pipe[READ] = 0;
38
16
    m_pipe[WRITE] = 0;
39
16
    if (pipe(m_pipe) == -1) {
40
      throw_pretty("Cannot create pipe.");
41
    }
42
16
    m_oldStdOut = dup(fileno(stdout));
43
16
    m_oldStdErr = dup(fileno(stderr));
44

16
    if (m_oldStdOut == -1 || m_oldStdErr == -1) {
45
      throw_pretty("Cannot redirect stdout or stderr.");
46
    }
47
48
16
    m_init = true;
49
16
  }
50
51
16
  ~CaptureIOStream() {
52
16
    if (m_capturing) {
53
16
      endCapture();
54
    }
55
16
    if (m_oldStdOut > 0) close(m_oldStdOut);
56
16
    if (m_oldStdErr > 0) close(m_oldStdErr);
57
16
    if (m_pipe[READ] > 0) close(m_pipe[READ]);
58
16
    if (m_pipe[WRITE] > 0) close(m_pipe[WRITE]);
59
16
  }
60
61
24
  void beginCapture() {
62
24
    if (!m_init) return;
63
24
    if (m_capturing) endCapture();
64
24
    fflush(stdout);
65
24
    fflush(stderr);
66
24
    dup2(m_pipe[WRITE], fileno(stdout));
67
24
    dup2(m_pipe[WRITE], fileno(stderr));
68
24
    m_capturing = true;
69
  }
70
71
48
  bool endCapture() {
72
48
    usleep(2000);
73

48
    if (!m_init || !m_capturing) {
74
      return false;
75
    }
76
48
    fflush(stdout);
77
48
    fflush(stderr);
78
48
    dup2(m_oldStdOut, fileno(stdout));
79
48
    dup2(m_oldStdErr, fileno(stderr));
80
48
    m_captured.clear();
81
82
    // read the pipe
83
48
    ssize_t nb_read = 0;
84
    // Set timeout to 0.2 seconds
85
    struct timeval timeout;
86
48
    timeout.tv_sec = 0;
87
48
    timeout.tv_usec = 200000;
88
    // Initialize file descriptor sets
89
    fd_set read_fds, write_fds, except_fds;
90
48
    FD_ZERO(&read_fds);
91
48
    FD_ZERO(&write_fds);
92
48
    FD_ZERO(&except_fds);
93
48
    FD_SET(m_pipe[READ], &read_fds);
94
    //
95
48
    bool timed_out = false;
96
97
2112
    while (!timed_out) {
98
2064
      if (select(m_pipe[READ] + 1, &read_fds, &write_fds, &except_fds,
99
2064
                 &timeout) == 1) {
100
        // do the reading
101
        char buff[1];
102
2016
        nb_read = read(m_pipe[READ], buff, sizeof(buff));
103
2016
        if (nb_read > 0) {
104
2016
          m_captured << *buff;
105
        }
106
2016
        timed_out = false;
107
      } else {
108
        // timeout or error
109
48
        timed_out = true;
110
      }
111
    }
112
48
    return true;
113
  }
114
115
24
  std::string str() const { return m_captured.str(); }
116
117
 private:
118
  enum PIPES { READ, WRITE };
119
  int m_pipe[2];
120
  int m_oldStdOut;
121
  int m_oldStdErr;
122
  bool m_capturing;
123
  bool m_init;
124
  std::ostringstream m_captured;
125
};
126
127
std::string GetErrorMessages(boost::function<int(void)> function_with_errors) {
128
  CaptureIOStream capture_ios;
129
  capture_ios.beginCapture();
130
  boost::execution_monitor monitor;
131
  try {
132
    monitor.execute(function_with_errors);
133
  } catch (...) {
134
  }
135
  capture_ios.endCapture();
136
  return capture_ios.str();
137
}
138
139
}  // namespace unittest
140
}  // namespace crocoddyl
141
142
#endif  // CROCODDYL_UNITTEST_COMMON_HPP_