2 // Copyright (c) 2017 James E. King III
4 // Distributed under the Boost Software License, Version 1.0.
5 // (See accompanying file LICENSE_1_0.txt or copy at
6 // https://www.boost.org/LICENSE_1_0.txt)
8 // Mocks are used to test sad paths by forcing error responses
11 #include <boost/core/ignore_unused.hpp>
12 #include <boost/uuid/detail/random_provider_detect_platform.hpp>
14 #if defined(BOOST_UUID_TEST_RANDOM_MOCK)
16 #if defined(BOOST_UUID_RANDOM_PROVIDER_WINCRYPT) || defined(BOOST_UUID_RANDOM_PROVIDER_POSIX)
17 #define BOOST_UUID_TEST_RANDOM_MOCK_LINKAGE BOOST_SYMBOL_IMPORT
19 #define BOOST_UUID_TEST_RANDOM_MOCK_LINKAGE
22 //! \returns true if the provider can be mocked - if not then the test
23 //! should skip negative testing
24 BOOST_UUID_TEST_RANDOM_MOCK_LINKAGE bool expectations_capable();
26 //! Ensure all expectations for calls were consumed. This means the number
27 //! of expected calls was met.
28 //! \returns true if all expectations were met
29 BOOST_UUID_TEST_RANDOM_MOCK_LINKAGE bool expectations_met();
31 //! Set the response of the next mocked random/crypto call - builds up
32 //! a queue of responses. If the queue empties and another call is made,
33 //! the test will core.
34 //! \param[in] success true for success response, false for failure
35 BOOST_UUID_TEST_RANDOM_MOCK_LINKAGE void expect_next_call_success(bool success);
37 //! \returns true if the provider acquires a context
38 BOOST_UUID_TEST_RANDOM_MOCK_LINKAGE bool provider_acquires_context();
40 #if defined(BOOST_UUID_RANDOM_PROVIDER_ARC4RANDOM)
42 // arc4random cannot fail therefore it needs no mocking at all!
44 bool expectations_capable()
49 bool expectations_met()
51 throw std::logic_error("expectations not supported");
54 void expect_next_call_success(bool success)
56 boost::ignore_unused(success);
57 throw std::logic_error("expectations not supported");
60 bool provider_acquires_context()
62 throw std::logic_error("expectations not supported");
65 #elif defined(BOOST_UUID_RANDOM_PROVIDER_BCRYPT)
67 #include <boost/winapi/bcrypt.hpp>
69 std::deque<boost::winapi::NTSTATUS_> bcrypt_next_result;
71 bool expectations_capable()
76 bool expectations_met()
78 return bcrypt_next_result.empty();
81 void expect_next_call_success(bool success)
83 bcrypt_next_result.push_back(success ? 0 : 17);
86 bool provider_acquires_context()
91 boost::winapi::NTSTATUS_ BOOST_WINAPI_WINAPI_CC
92 BCryptOpenAlgorithmProvider(
93 boost::winapi::BCRYPT_ALG_HANDLE_ *phAlgorithm,
94 boost::winapi::LPCWSTR_ pszAlgId,
95 boost::winapi::LPCWSTR_ pszImplementation,
96 boost::winapi::DWORD_ dwFlags
99 boost::ignore_unused(phAlgorithm);
100 boost::ignore_unused(pszAlgId);
101 boost::ignore_unused(pszImplementation);
102 boost::ignore_unused(dwFlags);
104 boost::winapi::NTSTATUS_ result = bcrypt_next_result.front();
105 bcrypt_next_result.pop_front();
109 boost::winapi::NTSTATUS_ BOOST_WINAPI_WINAPI_CC
111 boost::winapi::BCRYPT_ALG_HANDLE_ hAlgorithm,
112 boost::winapi::PUCHAR_ pbBuffer,
113 boost::winapi::ULONG_ cbBuffer,
114 boost::winapi::ULONG_ dwFlags
117 boost::ignore_unused(hAlgorithm);
118 boost::ignore_unused(pbBuffer);
119 boost::ignore_unused(cbBuffer);
120 boost::ignore_unused(dwFlags);
122 boost::winapi::NTSTATUS_ result = bcrypt_next_result.front();
123 bcrypt_next_result.pop_front();
127 // the implementation ignores the result of close because it
128 // happens in a destructor
129 boost::winapi::NTSTATUS_ BOOST_WINAPI_WINAPI_CC
130 BCryptCloseAlgorithmProvider(
131 boost::winapi::BCRYPT_ALG_HANDLE_ hAlgorithm,
132 boost::winapi::ULONG_ dwFlags
135 boost::ignore_unused(hAlgorithm);
136 boost::ignore_unused(dwFlags);
140 #elif defined(BOOST_UUID_RANDOM_PROVIDER_GETRANDOM)
144 std::deque<bool> getrandom_next_result;
146 bool expectations_capable()
151 bool expectations_met()
153 return getrandom_next_result.empty();
156 void expect_next_call_success(bool success)
158 getrandom_next_result.push_back(success);
161 bool provider_acquires_context()
166 ssize_t mock_getrandom(void *buffer, size_t length, unsigned int flags)
168 boost::ignore_unused(buffer);
169 boost::ignore_unused(length);
170 boost::ignore_unused(flags);
172 bool success = getrandom_next_result.front();
173 getrandom_next_result.pop_front();
174 return success ? static_cast< ssize_t >(length) : static_cast< ssize_t >(-1);
177 #define BOOST_UUID_RANDOM_PROVIDER_GETRANDOM_IMPL_GETRANDOM ::mock_getrandom
179 #elif defined(BOOST_UUID_RANDOM_PROVIDER_GETENTROPY)
182 // This stubbing technique works on unix because of how the loader resolves
183 // functions. Locally defined functions resolve first.
188 std::deque<int> getentropy_next_result;
190 bool expectations_capable()
195 bool expectations_met()
197 return getentropy_next_result.empty();
200 void expect_next_call_success(bool success)
202 getentropy_next_result.push_back(success ? 0 : -1);
205 bool provider_acquires_context()
210 int getentropy(void *buffer, size_t length)
212 boost::ignore_unused(buffer);
213 boost::ignore_unused(length);
215 int result = getentropy_next_result.front();
216 getentropy_next_result.pop_front();
220 #elif defined(BOOST_UUID_RANDOM_PROVIDER_POSIX)
222 #include <boost/numeric/conversion/cast.hpp>
225 std::deque<bool> posix_next_result; // bool success
227 bool expectations_capable()
232 bool expectations_met()
234 return posix_next_result.empty();
237 void expect_next_call_success(bool success)
239 posix_next_result.push_back(success);
242 bool provider_acquires_context()
247 int mockopen(const char *fname, int flags)
249 boost::ignore_unused(fname);
250 boost::ignore_unused(flags);
252 bool success = posix_next_result.front();
253 posix_next_result.pop_front();
254 return success ? 17 : -1;
257 ssize_t mockread(int fd, void *buf, size_t siz)
259 boost::ignore_unused(fd);
260 boost::ignore_unused(buf);
262 // first call siz is 4, in a success case we return 1
263 // forcing a second loop to come through size 3
265 if (siz < 4) { return boost::numeric_cast<ssize_t>(siz); }
266 if (siz > 4) { throw std::logic_error("unexpected siz"); }
268 bool success = posix_next_result.front();
269 posix_next_result.pop_front();
270 return success ? 1 : -1;
273 #define BOOST_UUID_RANDOM_PROVIDER_POSIX_IMPL_OPEN mockopen
274 #define BOOST_UUID_RANDOM_PROVIDER_POSIX_IMPL_READ mockread
276 #elif defined(BOOST_UUID_RANDOM_PROVIDER_WINCRYPT)
278 // Nothing to declare, since the expectation methods were already
279 // defined as import, we will link against a mock library
283 #error support needed here for testing
287 #endif // BOOST_UUID_TEST_RANDOM_MOCK