• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (c) 2017 James E. King III
3 //
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)
7 //
8 // Mocks are used to test sad paths by forcing error responses
9 //
10 
11 #include <boost/core/ignore_unused.hpp>
12 #include <boost/uuid/detail/random_provider_detect_platform.hpp>
13 
14 #if defined(BOOST_UUID_TEST_RANDOM_MOCK)
15 
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
18 #else
19 #define BOOST_UUID_TEST_RANDOM_MOCK_LINKAGE
20 #endif
21 
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();
25 
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();
30 
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);
36 
37 //! \returns  true  if the provider acquires a context
38 BOOST_UUID_TEST_RANDOM_MOCK_LINKAGE bool provider_acquires_context();
39 
40 #if defined(BOOST_UUID_RANDOM_PROVIDER_ARC4RANDOM)
41 
42 // arc4random cannot fail therefore it needs no mocking at all!
43 
expectations_capable()44 bool expectations_capable()
45 {
46     return false;
47 }
48 
expectations_met()49 bool expectations_met()
50 {
51     throw std::logic_error("expectations not supported");
52 }
53 
expect_next_call_success(bool success)54 void expect_next_call_success(bool success)
55 {
56     boost::ignore_unused(success);
57     throw std::logic_error("expectations not supported");
58 }
59 
provider_acquires_context()60 bool provider_acquires_context()
61 {
62     throw std::logic_error("expectations not supported");
63 }
64 
65 #elif defined(BOOST_UUID_RANDOM_PROVIDER_BCRYPT)
66 
67 #include <boost/winapi/bcrypt.hpp>
68 #include <deque>
69 std::deque<boost::winapi::NTSTATUS_> bcrypt_next_result;
70 
expectations_capable()71 bool expectations_capable()
72 {
73     return true;
74 }
75 
expectations_met()76 bool expectations_met()
77 {
78     return bcrypt_next_result.empty();
79 }
80 
expect_next_call_success(bool success)81 void expect_next_call_success(bool success)
82 {
83     bcrypt_next_result.push_back(success ? 0 : 17);
84 }
85 
provider_acquires_context()86 bool provider_acquires_context()
87 {
88     return true;
89 }
90 
91 boost::winapi::NTSTATUS_ BOOST_WINAPI_WINAPI_CC
BCryptOpenAlgorithmProvider(boost::winapi::BCRYPT_ALG_HANDLE_ * phAlgorithm,boost::winapi::LPCWSTR_ pszAlgId,boost::winapi::LPCWSTR_ pszImplementation,boost::winapi::DWORD_ dwFlags)92 BCryptOpenAlgorithmProvider(
93     boost::winapi::BCRYPT_ALG_HANDLE_ *phAlgorithm,
94     boost::winapi::LPCWSTR_           pszAlgId,
95     boost::winapi::LPCWSTR_           pszImplementation,
96     boost::winapi::DWORD_             dwFlags
97 )
98 {
99     boost::ignore_unused(phAlgorithm);
100     boost::ignore_unused(pszAlgId);
101     boost::ignore_unused(pszImplementation);
102     boost::ignore_unused(dwFlags);
103 
104     boost::winapi::NTSTATUS_ result = bcrypt_next_result.front();
105     bcrypt_next_result.pop_front();
106     return result;
107 }
108 
109 boost::winapi::NTSTATUS_ BOOST_WINAPI_WINAPI_CC
BCryptGenRandom(boost::winapi::BCRYPT_ALG_HANDLE_ hAlgorithm,boost::winapi::PUCHAR_ pbBuffer,boost::winapi::ULONG_ cbBuffer,boost::winapi::ULONG_ dwFlags)110 BCryptGenRandom(
111     boost::winapi::BCRYPT_ALG_HANDLE_ hAlgorithm,
112     boost::winapi::PUCHAR_            pbBuffer,
113     boost::winapi::ULONG_             cbBuffer,
114     boost::winapi::ULONG_             dwFlags
115 )
116 {
117     boost::ignore_unused(hAlgorithm);
118     boost::ignore_unused(pbBuffer);
119     boost::ignore_unused(cbBuffer);
120     boost::ignore_unused(dwFlags);
121 
122     boost::winapi::NTSTATUS_ result = bcrypt_next_result.front();
123     bcrypt_next_result.pop_front();
124     return result;
125 }
126 
127 // the implementation ignores the result of close because it
128 // happens in a destructor
129 boost::winapi::NTSTATUS_ BOOST_WINAPI_WINAPI_CC
BCryptCloseAlgorithmProvider(boost::winapi::BCRYPT_ALG_HANDLE_ hAlgorithm,boost::winapi::ULONG_ dwFlags)130 BCryptCloseAlgorithmProvider(
131     boost::winapi::BCRYPT_ALG_HANDLE_ hAlgorithm,
132     boost::winapi::ULONG_             dwFlags
133 )
134 {
135     boost::ignore_unused(hAlgorithm);
136     boost::ignore_unused(dwFlags);
137     return 0;
138 }
139 
140 #elif defined(BOOST_UUID_RANDOM_PROVIDER_GETRANDOM)
141 
142 #include <deque>
143 #include <unistd.h>
144 std::deque<bool> getrandom_next_result;
145 
expectations_capable()146 bool expectations_capable()
147 {
148     return true;
149 }
150 
expectations_met()151 bool expectations_met()
152 {
153     return getrandom_next_result.empty();
154 }
155 
expect_next_call_success(bool success)156 void expect_next_call_success(bool success)
157 {
158     getrandom_next_result.push_back(success);
159 }
160 
provider_acquires_context()161 bool provider_acquires_context()
162 {
163     return false;
164 }
165 
mock_getrandom(void * buffer,size_t length,unsigned int flags)166 ssize_t mock_getrandom(void *buffer, size_t length, unsigned int flags)
167 {
168     boost::ignore_unused(buffer);
169     boost::ignore_unused(length);
170     boost::ignore_unused(flags);
171 
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);
175 }
176 
177 #define BOOST_UUID_RANDOM_PROVIDER_GETRANDOM_IMPL_GETRANDOM ::mock_getrandom
178 
179 #elif defined(BOOST_UUID_RANDOM_PROVIDER_GETENTROPY)
180 
181 //
182 // This stubbing technique works on unix because of how the loader resolves
183 // functions.  Locally defined functions resolve first.
184 //
185 
186 #include <deque>
187 #include <unistd.h>
188 std::deque<int> getentropy_next_result;
189 
expectations_capable()190 bool expectations_capable()
191 {
192     return true;
193 }
194 
expectations_met()195 bool expectations_met()
196 {
197     return getentropy_next_result.empty();
198 }
199 
expect_next_call_success(bool success)200 void expect_next_call_success(bool success)
201 {
202     getentropy_next_result.push_back(success ? 0 : -1);
203 }
204 
provider_acquires_context()205 bool provider_acquires_context()
206 {
207     return false;
208 }
209 
getentropy(void * buffer,size_t length)210 int getentropy(void *buffer, size_t length)
211 {
212     boost::ignore_unused(buffer);
213     boost::ignore_unused(length);
214 
215     int result = getentropy_next_result.front();
216     getentropy_next_result.pop_front();
217     return result;
218 }
219 
220 #elif defined(BOOST_UUID_RANDOM_PROVIDER_POSIX)
221 
222 #include <boost/numeric/conversion/cast.hpp>
223 #include <deque>
224 #include <stdexcept>
225 std::deque<bool> posix_next_result; // bool success
226 
expectations_capable()227 bool expectations_capable()
228 {
229     return true;
230 }
231 
expectations_met()232 bool expectations_met()
233 {
234     return posix_next_result.empty();
235 }
236 
expect_next_call_success(bool success)237 void expect_next_call_success(bool success)
238 {
239     posix_next_result.push_back(success);
240 }
241 
provider_acquires_context()242 bool provider_acquires_context()
243 {
244     return true;
245 }
246 
mockopen(const char * fname,int flags)247 int mockopen(const char *fname, int flags)
248 {
249     boost::ignore_unused(fname);
250     boost::ignore_unused(flags);
251 
252     bool success = posix_next_result.front();
253     posix_next_result.pop_front();
254     return success ? 17 : -1;
255 }
256 
mockread(int fd,void * buf,size_t siz)257 ssize_t mockread(int fd, void *buf, size_t siz)
258 {
259     boost::ignore_unused(fd);
260     boost::ignore_unused(buf);
261 
262     // first call siz is 4, in a success case we return 1
263     // forcing a second loop to come through size 3
264 
265     if (siz < 4) { return boost::numeric_cast<ssize_t>(siz); }
266     if (siz > 4) { throw std::logic_error("unexpected siz"); }
267 
268     bool success = posix_next_result.front();
269     posix_next_result.pop_front();
270     return success ? 1 : -1;
271 }
272 
273 #define BOOST_UUID_RANDOM_PROVIDER_POSIX_IMPL_OPEN mockopen
274 #define BOOST_UUID_RANDOM_PROVIDER_POSIX_IMPL_READ mockread
275 
276 #elif defined(BOOST_UUID_RANDOM_PROVIDER_WINCRYPT)
277 
278 // Nothing to declare, since the expectation methods were already
279 // defined as import, we will link against a mock library
280 
281 #else
282 
283 #error support needed here for testing
284 
285 #endif
286 
287 #endif // BOOST_UUID_TEST_RANDOM_MOCK
288