GCC Code Coverage Report


Directory: ./
File: unittest/unittest_common.hpp
Date: 2025-06-03 08:14:12
Exec Total Coverage
Lines: 0 65 0.0%
Functions: 0 6 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