GCC Code Coverage Report


Directory: ./
File: unittest/unittest_common.hpp
Date: 2025-05-13 10:30:51
Exec Total Coverage
Lines: 0 61 0.0%
Branches: 0 80 0.0%

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
26 #include "crocoddyl/core/utils/exception.hpp"
27 #include "random_generator.hpp"
28
29 namespace crocoddyl {
30 namespace unittest {
31
32 class CaptureIOStream {
33 public:
34 CaptureIOStream()
35 : m_oldStdOut(0), m_oldStdErr(0), m_capturing(false), m_init(false) {
36 m_pipe[READ] = 0;
37 m_pipe[WRITE] = 0;
38 if (pipe(m_pipe) == -1) {
39 throw_pretty("Cannot create pipe.");
40 }
41 m_oldStdOut = dup(fileno(stdout));
42 m_oldStdErr = dup(fileno(stderr));
43 if (m_oldStdOut == -1 || m_oldStdErr == -1) {
44 throw_pretty("Cannot redirect stdout or stderr.");
45 }
46
47 m_init = true;
48 }
49
50 ~CaptureIOStream() {
51 if (m_capturing) {
52 endCapture();
53 }
54 if (m_oldStdOut > 0) close(m_oldStdOut);
55 if (m_oldStdErr > 0) close(m_oldStdErr);
56 if (m_pipe[READ] > 0) close(m_pipe[READ]);
57 if (m_pipe[WRITE] > 0) close(m_pipe[WRITE]);
58 }
59
60 void beginCapture() {
61 if (!m_init) return;
62 if (m_capturing) endCapture();
63 fflush(stdout);
64 fflush(stderr);
65 dup2(m_pipe[WRITE], fileno(stdout));
66 dup2(m_pipe[WRITE], fileno(stderr));
67 m_capturing = true;
68 }
69
70 bool endCapture() {
71 usleep(2000);
72 if (!m_init || !m_capturing) {
73 return false;
74 }
75 fflush(stdout);
76 fflush(stderr);
77 dup2(m_oldStdOut, fileno(stdout));
78 dup2(m_oldStdErr, fileno(stderr));
79 m_captured.clear();
80
81 // read the pipe
82 ssize_t nb_read = 0;
83 // Set timeout to 0.2 seconds
84 struct timeval timeout;
85 timeout.tv_sec = 0;
86 timeout.tv_usec = 200000;
87 // Initialize file descriptor sets
88 fd_set read_fds, write_fds, except_fds;
89 FD_ZERO(&read_fds);
90 FD_ZERO(&write_fds);
91 FD_ZERO(&except_fds);
92 FD_SET(m_pipe[READ], &read_fds);
93 //
94 bool timed_out = false;
95
96 while (!timed_out) {
97 if (select(m_pipe[READ] + 1, &read_fds, &write_fds, &except_fds,
98 &timeout) == 1) {
99 // do the reading
100 char buff[1];
101 nb_read = read(m_pipe[READ], buff, sizeof(buff));
102 if (nb_read > 0) {
103 m_captured << *buff;
104 }
105 timed_out = false;
106 } else {
107 // timeout or error
108 timed_out = true;
109 }
110 }
111 return true;
112 }
113
114 std::string str() const { return m_captured.str(); }
115
116 private:
117 enum PIPES { READ, WRITE };
118 int m_pipe[2];
119 int m_oldStdOut;
120 int m_oldStdErr;
121 bool m_capturing;
122 bool m_init;
123 std::ostringstream m_captured;
124 };
125
126 std::string GetErrorMessages(boost::function<int(void)> function_with_errors) {
127 CaptureIOStream capture_ios;
128 capture_ios.beginCapture();
129 boost::execution_monitor monitor;
130 try {
131 monitor.execute(function_with_errors);
132 } catch (...) {
133 }
134 capture_ios.endCapture();
135 return capture_ios.str();
136 }
137
138 } // namespace unittest
139 } // namespace crocoddyl
140
141 #endif // CROCODDYL_UNITTEST_COMMON_HPP_
142