-
Notifications
You must be signed in to change notification settings - Fork 112
Add mock test for rcutils/strerror #265
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 10 commits
ae91f73
18b53d1
56782e7
2927385
7a7ec42
d3407d6
8338f9e
2135205
4e8b05d
dcf80fa
85d4d1a
fe73174
5b8ce8f
1b3ad34
fd8d93b
f00a0dc
0ffe78b
200b5e0
a870d60
ee41b34
a6cfb76
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,10 +21,11 @@ | |
| #include <dirent.h> | ||
| #endif | ||
|
|
||
| #include <string> | ||
|
|
||
| #include "rcutils/macros.h" | ||
| #include "rcutils/strerror.h" | ||
|
|
||
| #include "./mimick.h" | ||
|
|
||
| TEST(test_strerror, get_error) { | ||
| // cleaning possible errors | ||
| errno = 0; | ||
|
|
@@ -54,3 +55,92 @@ TEST(test_strerror, get_error) { | |
| "' did not cause the expected error message."; | ||
| #endif | ||
| } | ||
|
|
||
| const char expected_error_msg[] = "Failed to get error"; | ||
| /* | ||
| Define the blueprint of a mock identified by `strerror_r_proto` | ||
| strerror_r possible signatures: | ||
|
|
||
| * int strerror_r(int errnum, char *buf, size_t buflen); (Case 1) | ||
| * char *strerror_r(int errnum, char *buf, size_t buflen); (Case 2) | ||
| * errno_t strerror_s( char *buf, rsize_t bufsz, errno_t errnum ); (Case 3) | ||
| */ | ||
|
|
||
| #if defined(_WIN32) | ||
| mmk_mock_define(strerror_s_mock, errno_t, char *, rsize_t, errno_t); | ||
|
|
||
| errno_t mocked_windows_strerror(char * buf, rsize_t bufsz, errno_t errnum) | ||
| { | ||
| (void) errnum; | ||
| strncpy(buf, expected_error_msg, (size_t) bufsz); | ||
| return errnum; | ||
| } | ||
|
|
||
| /* Mocking test example */ | ||
| TEST(test_strerror, test_mock) { | ||
| /* Mock the strerror_s function in the current module using | ||
| the `strerror_s_mock` blueprint. */ | ||
| mmk_mock(RCUTILS_STRINGIFY(strerror_s) "@lib:rcutils", strerror_s_mock); | ||
| /* Tell the mock to call mocked_windows_strerror instead*/ | ||
| mmk_when( | ||
| strerror_s(mmk_any(errno_t), mmk_any(char *), mmk_any(rsize_t), mmk_any(errno_t)), | ||
| .then_call = (mmk_fn) mocked_windows_strerror); | ||
|
|
||
| // Set the error (not used by the mock) | ||
| errno = 2; | ||
| char error_string[1024]; | ||
| rcutils_strerror(error_string, sizeof(error_string)); | ||
| ASSERT_STREQ(error_string, "Failed to get error"); | ||
| mmk_reset(strerror_s); | ||
| } | ||
|
|
||
| #elif defined(_GNU_SOURCE) && (!defined(ANDROID) || __ANDROID_API__ >= 23) | ||
| mmk_mock_define(strerror_r_mock, char *, int, char *, size_t); | ||
|
|
||
| char * mocked_gnu_strerror(int errnum, char * buf, size_t buflen) | ||
| { | ||
| (void) errnum; | ||
| strncpy(buf, expected_error_msg, buflen); | ||
| return buf; | ||
| } | ||
|
|
||
| /* Mocking test example */ | ||
| TEST(test_strerror, test_mock) { | ||
Blast545 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| /* Mock the strerror_r function in the current module using | ||
| the `strerror_r_mock` blueprint. */ | ||
| mmk_mock(RCUTILS_STRINGIFY(strerror_r) "@lib:rcutils", strerror_r_mock); | ||
| /* Tell the mock to call mocked_gnu_strerror instead */ | ||
| mmk_when( | ||
| strerror_r(mmk_any(int), mmk_any(char *), mmk_any(size_t) ), | ||
| .then_call = (mmk_fn) mocked_gnu_strerror); | ||
|
|
||
| // Set the error (not used by the mock) | ||
| errno = 2; | ||
| char error_string[1024]; | ||
| rcutils_strerror(error_string, sizeof(error_string)); | ||
| ASSERT_STREQ(error_string, "Failed to get error"); | ||
| mmk_reset(strerror_r); | ||
| } | ||
|
|
||
| #else | ||
| mmk_mock_define(strerror_r_mock, int, int, char *, size_t); | ||
| /* Mocking test example */ | ||
| TEST(test_strerror, test_mock) { | ||
| /* Mock the strerror_r function in the current module using | ||
| the `strerror_r_mock` blueprint. */ | ||
| mmk_mock(RCUTILS_STRINGIFY(strerror_r) "@lib:rcutils", strerror_r_mock); | ||
| /* Tell the mock to return NULL and set errno to EINVAL | ||
| whatever the given parameter is. */ | ||
Blast545 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| mmk_when( | ||
| strerror_r(mmk_any(int), mmk_any(char *), mmk_any(size_t) ), | ||
|
||
| .then_return = mmk_val(int, EINVAL)); | ||
|
|
||
| // Set the error "No such file or directory" (not used by the mock) | ||
| errno = 2; | ||
| char error_string[1024]; | ||
| rcutils_strerror(error_string, sizeof(error_string)); | ||
| ASSERT_STREQ(error_string, "Failed to get error"); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm sure this is a case-by-case matter, but what risks are there for maintainers adding calls to the mocked function that sits between the unit test and the targeted invocation? It seems like unit tests that call high-level functions, but mock low-level functions would be pretty brittle, and you would need to mock functions whose number of uses in the code under test is unlikely to change.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see a fundamental risk, besides the maintenance burden that comes from white-box testing and the coupling between test and implementation it entails. It's important to bear in mind that mocking is not a tool for fault injection in a running system, but a way to unit test the interactions between the entity under test and its direct dependencies. In an |
||
| mmk_reset(strerror_r); | ||
| } | ||
|
|
||
| #endif | ||
Uh oh!
There was an error while loading. Please reload this page.