GCC Code Coverage Report


Directory: ./
File: unittest/unittest_common.hpp
Date: 2025-01-16 08:47:40
Exec Total Coverage
Lines: 52 63 82.5%
Branches: 31 80 38.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
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
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
2/4
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 16 times.
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
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 if (m_capturing) {
53 16 endCapture();
54 }
55
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 if (m_oldStdOut > 0) close(m_oldStdOut);
56
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 if (m_oldStdErr > 0) close(m_oldStdErr);
57
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 if (m_pipe[READ] > 0) close(m_pipe[READ]);
58
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 if (m_pipe[WRITE] > 0) close(m_pipe[WRITE]);
59 16 }
60
61 24 void beginCapture() {
62
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (!m_init) return;
63
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 16 times.
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
1/2
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
48 usleep(2000);
73
2/4
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 48 times.
48 if (!m_init || !m_capturing) {
74 return false;
75 }
76
1/2
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
48 fflush(stdout);
77
1/2
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
48 fflush(stderr);
78 48 dup2(m_oldStdOut, fileno(stdout));
79 48 dup2(m_oldStdErr, fileno(stderr));
80
1/2
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
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
2/2
✓ Branch 0 taken 768 times.
✓ Branch 1 taken 48 times.
816 FD_ZERO(&read_fds);
91
2/2
✓ Branch 0 taken 768 times.
✓ Branch 1 taken 48 times.
816 FD_ZERO(&write_fds);
92
2/2
✓ Branch 0 taken 768 times.
✓ Branch 1 taken 48 times.
816 FD_ZERO(&except_fds);
93 48 FD_SET(m_pipe[READ], &read_fds);
94 //
95 48 bool timed_out = false;
96
97
2/2
✓ Branch 0 taken 2064 times.
✓ Branch 1 taken 48 times.
2112 while (!timed_out) {
98
1/2
✓ Branch 1 taken 2064 times.
✗ Branch 2 not taken.
2064 if (select(m_pipe[READ] + 1, &read_fds, &write_fds, &except_fds,
99
2/2
✓ Branch 0 taken 2016 times.
✓ Branch 1 taken 48 times.
2064 &timeout) == 1) {
100 // do the reading
101 char buff[1];
102
1/2
✓ Branch 1 taken 2016 times.
✗ Branch 2 not taken.
2016 nb_read = read(m_pipe[READ], buff, sizeof(buff));
103
1/2
✓ Branch 0 taken 2016 times.
✗ Branch 1 not taken.
2016 if (nb_read > 0) {
104
1/2
✓ Branch 1 taken 2016 times.
✗ Branch 2 not taken.
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_
143