Skip to content

Commit bcb394d

Browse files
committed
Complete rcutils API coverage.
Signed-off-by: Michel Hidalgo <[email protected]>
1 parent a6cfb76 commit bcb394d

File tree

9 files changed

+385
-13
lines changed

9 files changed

+385
-13
lines changed

CMakeLists.txt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ if(BUILD_TESTING)
177177
osrf_testing_tools_cpp::memory_tools LIBRARY_PRELOAD_ENVIRONMENT_IS_AVAILABLE)
178178

179179
ament_add_gtest(test_logging test/test_logging.cpp)
180-
target_link_libraries(test_logging ${PROJECT_NAME} osrf_testing_tools_cpp::memory_tools)
180+
target_link_libraries(test_logging ${PROJECT_NAME} mimick osrf_testing_tools_cpp::memory_tools)
181181

182182
add_executable(test_logging_long_messages test/test_logging_long_messages.cpp)
183183
target_link_libraries(test_logging_long_messages ${PROJECT_NAME})
@@ -230,7 +230,7 @@ if(BUILD_TESTING)
230230
test/test_char_array.cpp
231231
)
232232
if(TARGET test_char_array)
233-
target_link_libraries(test_char_array ${PROJECT_NAME})
233+
target_link_libraries(test_char_array ${PROJECT_NAME} mimick)
234234
endif()
235235

236236
# Can't use C++ with stdatomic_helper.h
@@ -271,7 +271,7 @@ if(BUILD_TESTING)
271271
test/test_split.cpp
272272
)
273273
if(TARGET test_split)
274-
target_link_libraries(test_split ${PROJECT_NAME})
274+
target_link_libraries(test_split ${PROJECT_NAME} mimick)
275275
endif()
276276

277277
rcutils_custom_add_gtest(test_find
@@ -318,7 +318,7 @@ if(BUILD_TESTING)
318318
)
319319
if(TARGET test_filesystem)
320320
ament_target_dependencies(test_filesystem "osrf_testing_tools_cpp")
321-
target_link_libraries(test_filesystem ${PROJECT_NAME})
321+
target_link_libraries(test_filesystem ${PROJECT_NAME} mimick)
322322
target_compile_definitions(test_filesystem PRIVATE BUILD_DIR="${CMAKE_CURRENT_BINARY_DIR}")
323323
endif()
324324

@@ -333,7 +333,7 @@ if(BUILD_TESTING)
333333
test/test_format_string.cpp
334334
)
335335
if(TARGET test_format_string)
336-
target_link_libraries(test_format_string ${PROJECT_NAME})
336+
target_link_libraries(test_format_string ${PROJECT_NAME} mimick)
337337
endif()
338338

339339
rcutils_custom_add_gtest(test_string_map
@@ -378,7 +378,7 @@ if(BUILD_TESTING)
378378
test/test_time.cpp
379379
ENV ${memory_tools_test_env_vars})
380380
if(TARGET test_time)
381-
target_link_libraries(test_time ${PROJECT_NAME} osrf_testing_tools_cpp::memory_tools)
381+
target_link_libraries(test_time ${PROJECT_NAME} mimick osrf_testing_tools_cpp::memory_tools)
382382
endif()
383383

384384
rcutils_custom_add_gtest(test_snprintf

src/char_array.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,14 +172,14 @@ rcutils_char_array_vsprintf(rcutils_char_array_t * char_array, const char * form
172172
if (new_size > char_array->buffer_capacity) {
173173
rcutils_ret_t ret = rcutils_char_array_expand_as_needed(char_array, new_size);
174174
if (ret != RCUTILS_RET_OK) {
175-
RCUTILS_SET_ERROR_MSG("char array failed to expand");
176175
return ret;
177176
}
178177

179178
if (_rcutils_char_array_vsprintf(char_array, format, args) != size) {
180179
if (rcutils_char_array_fini(char_array) == RCUTILS_RET_OK) {
181180
RCUTILS_SET_ERROR_MSG("vsprintf on resized char array failed");
182181
} else {
182+
rcutils_reset_error();
183183
RCUTILS_SET_ERROR_MSG("vsprintf on resized char array failed; clean up failed too");
184184
}
185185
return RCUTILS_RET_ERROR;
@@ -196,7 +196,6 @@ rcutils_char_array_memcpy(rcutils_char_array_t * char_array, const char * src, s
196196
{
197197
rcutils_ret_t ret = rcutils_char_array_expand_as_needed(char_array, n);
198198
if (ret != RCUTILS_RET_OK) {
199-
RCUTILS_SET_ERROR_MSG("char array failed to expand");
200199
return ret;
201200
}
202201
memcpy(char_array->buffer, src, n);
@@ -217,7 +216,6 @@ rcutils_char_array_strncat(rcutils_char_array_t * char_array, const char * src,
217216
size_t new_length = current_strlen + n + 1;
218217
rcutils_ret_t ret = rcutils_char_array_expand_as_needed(char_array, new_length);
219218
if (ret != RCUTILS_RET_OK) {
220-
RCUTILS_SET_ERROR_MSG("char array failed to expand");
221219
return ret;
222220
}
223221
#ifndef _WIN32

test/mocking_utils.h

Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
// Copyright 2020 Open Source Robotics Foundation, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#ifndef MOCKING_UTILS_H_
16+
#define MOCKING_UTILS_H_
17+
18+
#include <cstring>
19+
20+
#include "rcutils/macros.h"
21+
#include "rcutils/get_env.h"
22+
23+
#include "mimick.h"
24+
25+
template<typename T>
26+
class state_chain {
27+
public:
28+
state_chain() {
29+
prev_state_ = this_state;
30+
this_state = &state_;
31+
}
32+
~state_chain() {
33+
this_state = prev_state_;
34+
}
35+
36+
static T * this_state;
37+
protected:
38+
T * prev_state_;
39+
T state_;
40+
};
41+
42+
template <typename T>
43+
T * state_chain<T>::this_state{nullptr};
44+
45+
#if !defined(_WIN32)
46+
#if defined(__MACH__)
47+
48+
#include <mach/clock.h>
49+
#include <mach/mach.h>
50+
51+
class stopped_clock_mock : private state_chain<mach_timespec_t> {
52+
public:
53+
stopped_clock_mock() {
54+
m_ = mmk_mock(RCUTILS_STRINGIFY(clock_get_time) "@lib:rcutils", clock_get_time_mock_t);
55+
mmk_when(clock_get_time(mmk_any(clock_serv_t), mmk_any(mach_timespec_t *)),
56+
.then_call = reinterpret_cast<mmk_fn>(return_timespec));
57+
}
58+
59+
~stopped_clock_mock() {
60+
mmk_reset(m);
61+
}
62+
63+
mach_timespec_t & time() {
64+
return state_;
65+
}
66+
67+
bool called(int times = 1) const {
68+
return mmk_verify(
69+
clock_get_time(
70+
mmk_any(clock_serv_t),
71+
mmk_any(mach_timespec_t *)),
72+
.times = times);
73+
}
74+
private:
75+
mmk_mock_define(clock_get_time_mock_t, kern_return_t, clock_serv_t, mach_timespec_t *);
76+
77+
static kern_return_t this_implementation(clock_serv_t, mach_timespec_t * ts) {
78+
*ts = *this_implementation;
79+
return 0;
80+
}
81+
82+
clock_get_time_mock_t m_;
83+
};
84+
85+
#else // defined(__MACH__)
86+
87+
#include <time.h>
88+
89+
class stopped_clock_mock : private state_chain<struct timespec> {
90+
public:
91+
stopped_clock_mock() {
92+
m_ = mmk_mock(RCUTILS_STRINGIFY(clock_gettime) "@lib:rcutils", clock_gettime_mock_t);
93+
mmk_when(clock_gettime(mmk_any(clockid_t), mmk_any(struct timespec *)),
94+
.then_call = reinterpret_cast<mmk_fn>(this_implementation));
95+
}
96+
97+
~stopped_clock_mock() {
98+
mmk_reset(m_);
99+
}
100+
101+
struct timespec & time() {
102+
return state_;
103+
}
104+
105+
bool called(int times = 1) const {
106+
return mmk_verify(
107+
clock_gettime(
108+
mmk_any(clockid_t),
109+
mmk_any(struct timespec *)),
110+
.times = times);
111+
}
112+
private:
113+
mmk_mock_define(clock_gettime_mock_t, int, clockid_t, struct timespec *);
114+
115+
static int this_implementation(clockid_t, struct timespec * ts) {
116+
*ts = *this_state;
117+
return 0;
118+
}
119+
120+
clock_gettime_mock_t m_;
121+
};
122+
123+
#endif // defined(__MACH__)
124+
125+
class vsnprintf_fails_formatting_mock : private state_chain<size_t> {
126+
public:
127+
vsnprintf_fails_formatting_mock() {
128+
m_ = mmk_mock(RCUTILS_STRINGIFY(vsnprintf) "@lib:rcutils", vsnprintf_mock_t);
129+
mmk_when(vsnprintf(mmk_any(char *),
130+
mmk_any(size_t),
131+
mmk_any(const char *),
132+
mmk_any(va_list)),
133+
.then_call = reinterpret_cast<mmk_fn>(this_implementation));
134+
state_ = 1u;
135+
}
136+
137+
void requires_size(size_t n) {
138+
state_ = n;
139+
}
140+
141+
~vsnprintf_fails_formatting_mock() {
142+
mmk_reset(m_);
143+
}
144+
145+
private:
146+
mmk_mock_define(vsnprintf_mock_t, int, char *, size_t, const char *, va_list);
147+
148+
static int this_implementation(char * buffer, size_t buffer_size, const char *, va_list) {
149+
if (NULL == buffer || buffer_size < *this_state) {
150+
return *this_state;
151+
}
152+
errno = EINVAL;
153+
return -1;
154+
}
155+
156+
vsnprintf_mock_t m_;
157+
};
158+
159+
#include <sys/types.h>
160+
#include <dirent.h>
161+
162+
class failing_file_api_mock {
163+
public:
164+
failing_file_api_mock() {
165+
m_ = mmk_mock(RCUTILS_STRINGIFY(opendir) "@lib:rcutils", opendir_mock_t);
166+
mmk_when(opendir(mmk_any(const char *)),
167+
.then_call = reinterpret_cast<mmk_fn>(this_implementation));
168+
}
169+
170+
~failing_file_api_mock() {
171+
mmk_reset(m_);
172+
}
173+
private:
174+
mmk_mock_define(opendir_mock_t, DIR *, const char *);
175+
176+
static DIR * this_implementation(const char *) {
177+
errno = ENFILE;
178+
return NULL;
179+
}
180+
181+
opendir_mock_t m_;
182+
};
183+
184+
#else // !defined(_WIN32)
185+
186+
class vsnprintf_fails_formatting_mock : private state_chain<size_t> {
187+
public:
188+
vsnprintf_fails_formatting_mock() {
189+
m_ = mmk_mock(RCUTILS_STRINGIFY(_vsnprintf_s) "@lib:rcutils", _vsnprintf_s_mock_t);
190+
mmk_when(_vsnprintf_s(mmk_any(char *),
191+
mmk_any(size_t),
192+
mmk_any(size_t),
193+
mmk_any(const char *),
194+
mmk_any(va_list)),
195+
.then_call = reinterpret_cast<mmk_fn>(this_implementation));
196+
state_ = 1u;
197+
}
198+
199+
void requires_size(size_t n) {
200+
state_ = n;
201+
}
202+
203+
~vsnprintf_fails_formatting_mock() {
204+
mmk_reset(m_);
205+
}
206+
private:
207+
mmk_mock_define(_vsnprintf_s_mock_t, int, char *, size_t, size_t, const char *, va_list);
208+
209+
static
210+
int this_implementation(char * buffer, size_t buffer_size, size_t, const char *, va_list) {
211+
if (NULL == buffer || buffer_size < *this_state) {
212+
return *this_state;
213+
}
214+
errno = EINVAL;
215+
return -1;
216+
}
217+
218+
_vsnprintf_s_mock_t m_;
219+
};
220+
221+
#endif // !defined(_WIN32)
222+
223+
class rcutils_get_env_mock : private state_chain<std::set<std::string>> {
224+
public:
225+
rcutils_get_env_mock() {
226+
m_ = mmk_mock("rcutils_get_env@lib:rcutils", rcutils_get_env_mock_t);
227+
mmk_when(rcutils_get_env(mmk_any(const char *), mmk_any(const char **)),
228+
.then_call = reinterpret_cast<mmk_fn>(this_implementation));
229+
}
230+
231+
void fails_to_get(std::string name) {
232+
state_.insert(std::move(name));
233+
}
234+
235+
~rcutils_get_env_mock() {
236+
mmk_reset(m_);
237+
}
238+
private:
239+
mmk_mock_define(rcutils_get_env_mock_t, const char *, const char *, const char **);
240+
241+
static const char * this_implementation(const char * name, const char ** value)
242+
{
243+
if (this_state->count(name) > 0) {
244+
return "ERROR";
245+
}
246+
*value = "";
247+
return NULL;
248+
}
249+
250+
rcutils_get_env_mock_t m_;
251+
};
252+
253+
#endif // MOCKING_UTILS_H_

test/test_char_array.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <string.h>
1717

1818
#include "./allocator_testing_utils.h"
19+
#include "./mocking_utils.h"
1920
#include "rcutils/allocator.h"
2021
#include "rcutils/error_handling.h"
2122
#include "rcutils/types/char_array.h"
@@ -121,11 +122,21 @@ TEST_F(ArrayCharTest, vsprintf_fail) {
121122
ASSERT_EQ(RCUTILS_RET_OK, ret);
122123

123124
char_array.allocator = failing_allocator;
124-
ret = example_logger(&char_array, "Long string for the case %d", 2);
125+
ret = example_logger(&char_array, "Long string for given %s", "array");
125126
EXPECT_EQ(RCUTILS_RET_BAD_ALLOC, ret);
126127
rcutils_reset_error();
127-
128128
char_array.allocator = allocator;
129+
130+
vsnprintf_fails_formatting_mock mock;
131+
ret = example_logger(&char_array, "Long string for given %s", "array");
132+
EXPECT_EQ(RCUTILS_RET_ERROR, ret);
133+
rcutils_reset_error();
134+
135+
mock.requires_size(20);
136+
ret = example_logger(&char_array, "Long string for the case %d", "array");
137+
EXPECT_EQ(RCUTILS_RET_ERROR, ret);
138+
rcutils_reset_error();
139+
129140
EXPECT_EQ(RCUTILS_RET_OK, rcutils_char_array_fini(&char_array));
130141
}
131142

test/test_filesystem.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
#include <gtest/gtest.h>
1616
#include <string>
1717

18+
#include "./mocking_utils.h"
19+
1820
#include "rcutils/filesystem.h"
1921

2022
#include "osrf_testing_tools_cpp/scope_exit.hpp"
@@ -346,6 +348,10 @@ TEST_F(TestFilesystemFixture, calculate_directory_size) {
346348
{
347349
g_allocator.deallocate(non_existing_path, g_allocator.state);
348350
});
351+
352+
failing_file_api_mock mock;
353+
size = rcutils_calculate_directory_size(path, g_allocator);
354+
EXPECT_EQ(0u, size);
349355
}
350356

351357
TEST_F(TestFilesystemFixture, calculate_file_size) {

0 commit comments

Comments
 (0)