Skip to content

Commit eabfb01

Browse files
authored
Add mock test for rcutils/strerror (#265)
* Add test using mimick vendored library * Add path to mimick_vendor * Link test to mimick library * Add multi-platform support * Reformat to separate different platform tests * Reformat to use strncpy to copy buffer * Change reset macro to take strerror_mock * Use mallock return type to reset function * Remove test_depend to mimick * Replace mock type * Change function strncpy to strncpy_s Signed-off-by: Jorge Perez <[email protected]>
1 parent 43a6eba commit eabfb01

File tree

3 files changed

+97
-3
lines changed

3 files changed

+97
-3
lines changed

CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,8 @@ if(BUILD_TESTING)
172172
"${CMAKE_CURRENT_BINARY_DIR}/include/rcutils/logging_macros.h")
173173
endif()
174174

175+
find_package(mimick_vendor REQUIRED)
176+
175177
find_package(osrf_testing_tools_cpp REQUIRED)
176178
get_target_property(memory_tools_test_env_vars
177179
osrf_testing_tools_cpp::memory_tools LIBRARY_PRELOAD_ENVIRONMENT_VARIABLE)
@@ -287,7 +289,7 @@ if(BUILD_TESTING)
287289
test/test_strerror.cpp
288290
)
289291
if(TARGET test_strerror)
290-
target_link_libraries(test_strerror ${PROJECT_NAME})
292+
target_link_libraries(test_strerror ${PROJECT_NAME} mimick)
291293
endif()
292294

293295
rcutils_custom_add_gtest(test_string_array

package.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
<test_depend>ament_cmake_pytest</test_depend>
1616
<test_depend>ament_lint_common</test_depend>
1717
<test_depend>ament_lint_auto</test_depend>
18+
<test_depend>mimick_vendor</test_depend>
1819
<test_depend>launch</test_depend>
1920
<test_depend>launch_testing</test_depend>
2021
<test_depend>launch_testing_ament_cmake</test_depend>

test/test_strerror.cpp

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,11 @@
2121
#include <dirent.h>
2222
#endif
2323

24-
#include <string>
25-
24+
#include "rcutils/macros.h"
2625
#include "rcutils/strerror.h"
2726

27+
#include "./mimick.h"
28+
2829
TEST(test_strerror, get_error) {
2930
// cleaning possible errors
3031
errno = 0;
@@ -54,3 +55,93 @@ TEST(test_strerror, get_error) {
5455
"' did not cause the expected error message.";
5556
#endif
5657
}
58+
59+
/*
60+
Define the blueprint of a mock identified by `strerror_r_proto`
61+
strerror_r possible signatures:
62+
63+
* int strerror_r(int errnum, char *buf, size_t buflen); (Case 1)
64+
* char *strerror_r(int errnum, char *buf, size_t buflen); (Case 2)
65+
* errno_t strerror_s( char *buf, rsize_t bufsz, errno_t errnum ); (Case 3)
66+
*/
67+
68+
#if defined(_WIN32)
69+
const char expected_error_msg[] = "Failed to get error";
70+
mmk_mock_define(strerror_s_mock, errno_t, char *, rsize_t, errno_t);
71+
72+
errno_t mocked_windows_strerror(char * buf, rsize_t bufsz, errno_t errnum)
73+
{
74+
(void) errnum;
75+
strncpy_s(buf, (size_t) bufsz, expected_error_msg, (size_t) bufsz);
76+
return errnum;
77+
}
78+
79+
// Mocking test example
80+
TEST(test_strerror, test_mock) {
81+
// Mock the strerror_s function in the current module using
82+
// the `strerror_s_mock` blueprint.
83+
strerror_s_mock mock = mmk_mock(RCUTILS_STRINGIFY(strerror_s) "@lib:rcutils", strerror_s_mock);
84+
// Tell the mock to call mocked_windows_strerror instead
85+
mmk_when(
86+
strerror_s(mmk_any(char *), mmk_any(rsize_t), mmk_any(errno_t)),
87+
.then_call = (mmk_fn) mocked_windows_strerror);
88+
89+
// Set the error (not used by the mock)
90+
errno = 2;
91+
char error_string[1024];
92+
rcutils_strerror(error_string, sizeof(error_string));
93+
ASSERT_STREQ(error_string, "Failed to get error");
94+
mmk_reset(mock);
95+
}
96+
97+
#elif defined(_GNU_SOURCE) && (!defined(ANDROID) || __ANDROID_API__ >= 23)
98+
const char expected_error_msg[] = "Failed to get error";
99+
mmk_mock_define(strerror_r_mock, char *, int, char *, size_t);
100+
101+
char * mocked_gnu_strerror(int errnum, char * buf, size_t buflen)
102+
{
103+
(void) errnum;
104+
strncpy(buf, expected_error_msg, buflen);
105+
return buf;
106+
}
107+
108+
// Mocking test example
109+
TEST(test_strerror, test_mock) {
110+
// Mock the strerror_r function in the current module using
111+
// the `strerror_r_mock` blueprint.
112+
mmk_mock(RCUTILS_STRINGIFY(strerror_r) "@lib:rcutils", strerror_r_mock);
113+
// Tell the mock to call mocked_gnu_strerror instead
114+
mmk_when(
115+
strerror_r(mmk_any(int), mmk_any(char *), mmk_any(size_t) ),
116+
.then_call = (mmk_fn) mocked_gnu_strerror);
117+
118+
// Set the error (not used by the mock)
119+
errno = 2;
120+
char error_string[1024];
121+
rcutils_strerror(error_string, sizeof(error_string));
122+
ASSERT_STREQ(error_string, "Failed to get error");
123+
mmk_reset(strerror_r);
124+
}
125+
126+
#else
127+
mmk_mock_define(strerror_r_mock, int, int, char *, size_t);
128+
129+
// Mocking test example
130+
TEST(test_strerror, test_mock) {
131+
// Mock the strerror_r function in the current module using
132+
// the `strerror_r_mock` blueprint.
133+
mmk_mock(RCUTILS_STRINGIFY(strerror_r) "@lib:rcutils", strerror_r_mock);
134+
// Tell the mock to return NULL and set errno to EINVAL
135+
// whatever the given parameter is.
136+
mmk_when(
137+
strerror_r(mmk_any(int), mmk_any(char *), mmk_any(size_t) ),
138+
.then_return = mmk_val(int, EINVAL));
139+
140+
// Set the error "No such file or directory" (not used by the mock)
141+
errno = 2;
142+
char error_string[1024];
143+
rcutils_strerror(error_string, sizeof(error_string));
144+
ASSERT_STREQ(error_string, "Failed to get error");
145+
mmk_reset(strerror_r);
146+
}
147+
#endif

0 commit comments

Comments
 (0)