1 | // error_code_test.cpp -----------------------------------------------------// |
2 | |
3 | // Copyright Beman Dawes 2006 |
4 | |
5 | // Distributed under the Boost Software License, Version 1.0. (See accompanying |
6 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
7 | |
8 | // See library home page at http://www.boost.org/libs/system |
9 | |
10 | //----------------------------------------------------------------------------// |
11 | |
12 | #include <boost/config/warning_disable.hpp> |
13 | |
14 | #include <boost/system/error_code.hpp> |
15 | #include <boost/core/lightweight_test.hpp> |
16 | #include <iostream> |
17 | #include <sstream> |
18 | #include <string> |
19 | #include <cstring> |
20 | #include <functional> |
21 | #include <boost/cerrno.hpp> |
22 | |
23 | // Although using directives are not the best programming practice, testing |
24 | // with a boost::system using directive increases use scenario coverage. |
25 | using namespace boost::system; |
26 | |
27 | #if defined( BOOST_WINDOWS_API ) |
28 | // Neither MinGW or Cygwin versions of winerror.h work if used alone, so on |
29 | // either of those platforms include the full windows.h |
30 | # if defined(__MINGW32__) || defined(__CYGWIN__) |
31 | # include <windows.h> |
32 | # else |
33 | # include <winerror.h> |
34 | # endif |
35 | # define BOOST_ACCESS_ERROR_MACRO ERROR_ACCESS_DENIED |
36 | #elif defined( BOOST_POSIX_API ) |
37 | # define BOOST_ACCESS_ERROR_MACRO EACCES |
38 | #else |
39 | # error "Only supported for POSIX and Windows" |
40 | #endif |
41 | |
42 | namespace |
43 | { |
44 | void check_ostream( error_code ec, const char * expected ) |
45 | { |
46 | std::stringstream ss; |
47 | std::string s; |
48 | |
49 | ss << ec; |
50 | ss >> s; |
51 | BOOST_TEST( s == expected ); |
52 | } |
53 | |
54 | // throws_function_test ------------------------------------------------------------// |
55 | |
56 | // usage example |
57 | |
58 | int divide(int dividend, int divisor, boost::system::error_code& ec = boost::throws()) |
59 | { |
60 | if (divisor == 0) // is there an error? |
61 | { |
62 | if (&ec == &boost::throws()) // throw on error |
63 | throw "oops!" ; // whatever exception you prefer |
64 | ec = error_code(EDOM, generic_category()); // report error via error_code |
65 | return 0; |
66 | } |
67 | |
68 | if (&ec != &boost::throws()) // error reporting via error_code |
69 | ec.clear(); |
70 | return dividend / divisor; |
71 | } |
72 | |
73 | // test usage example |
74 | |
75 | void test_throws_usage() |
76 | { |
77 | std::cout << "Test throws() example and usage...\n" ; |
78 | error_code ec; |
79 | |
80 | // no error tests |
81 | BOOST_TEST_EQ((divide(10, 2)), 5); // no error, report via exception |
82 | ec = make_error_code(e: errc::argument_out_of_domain); |
83 | BOOST_TEST_EQ((divide(10, 5, ec)), 2); // no error, report via error_code |
84 | BOOST_TEST(!ec); |
85 | |
86 | ec = make_error_code(e: errc::argument_out_of_domain); |
87 | BOOST_TEST_EQ((divide(10, 0, ec)), 0); // error, report via error_code |
88 | BOOST_TEST(ec); |
89 | |
90 | bool exception_thrown = false; |
91 | try |
92 | { divide(dividend: 10, divisor: 0); } // error, report via exception |
93 | catch (...) |
94 | { exception_thrown = true; } |
95 | BOOST_TEST(exception_thrown); |
96 | |
97 | //error_code should_fail(boost::throws()); // should fail at runtime |
98 | //boost::throws() = ec; // should fail at runtime |
99 | } |
100 | } |
101 | |
102 | // main ------------------------------------------------------------------------------// |
103 | |
104 | // TODO: add hash_value tests |
105 | |
106 | int main( int, char ** ) |
107 | { |
108 | |
109 | std::cout << "Conversion use cases...\n" ; |
110 | error_condition x1( errc::file_exists ); |
111 | (void)x1; |
112 | //error_code x2( errc::file_exists ); // should fail to compile |
113 | make_error_code(e: errc::file_exists); |
114 | make_error_condition(e: errc::file_exists); |
115 | |
116 | std::cout << "General tests...\n" ; |
117 | // unit tests: |
118 | |
119 | BOOST_TEST( generic_category() == generic_category() ); |
120 | BOOST_TEST( system_category() == system_category() ); |
121 | BOOST_TEST( generic_category() != system_category() ); |
122 | BOOST_TEST( system_category() != generic_category() ); |
123 | |
124 | BOOST_TEST_NE( generic_category() < system_category(), system_category() < generic_category() ); |
125 | |
126 | error_code ec; |
127 | error_condition econd; |
128 | BOOST_TEST( !ec ); |
129 | BOOST_TEST( ec.value() == 0 ); |
130 | econd = ec.default_error_condition(); |
131 | BOOST_TEST( econd.value() == 0 ); |
132 | BOOST_TEST( econd.category() == generic_category() ); |
133 | BOOST_TEST( ec == errc::success ); |
134 | BOOST_TEST( ec.category() == system_category() ); |
135 | BOOST_TEST( std::strcmp( ec.category().name(), "system" ) == 0 ); |
136 | BOOST_TEST( !(ec < error_code( 0, system_category() )) ); |
137 | BOOST_TEST( !(error_code( 0, system_category() ) < ec) ); |
138 | BOOST_TEST( ec < error_code( 1, system_category() ) ); |
139 | BOOST_TEST( !(error_code( 1, system_category() ) < ec) ); |
140 | |
141 | error_code ec_0_system( 0, system_category() ); |
142 | BOOST_TEST( !ec_0_system ); |
143 | BOOST_TEST( ec_0_system.value() == 0 ); |
144 | econd = ec_0_system.default_error_condition(); |
145 | BOOST_TEST( econd.value() == 0 ); |
146 | BOOST_TEST( econd.category() == generic_category() ); |
147 | BOOST_TEST( ec_0_system == errc::success ); |
148 | BOOST_TEST( ec_0_system.category() == system_category() ); |
149 | BOOST_TEST( std::strcmp( ec_0_system.category().name(), "system" ) == 0 ); |
150 | check_ostream( ec: ec_0_system, expected: "system:0" ); |
151 | |
152 | BOOST_TEST( ec_0_system == ec ); |
153 | |
154 | error_code ec_1_system( 1, system_category() ); |
155 | BOOST_TEST( ec_1_system ); |
156 | BOOST_TEST( ec_1_system.value() == 1 ); |
157 | BOOST_TEST( ec_1_system.value() != 0 ); |
158 | BOOST_TEST( ec != ec_1_system ); |
159 | BOOST_TEST( ec_0_system != ec_1_system ); |
160 | check_ostream( ec: ec_1_system, expected: "system:1" ); |
161 | |
162 | ec = error_code( BOOST_ACCESS_ERROR_MACRO, system_category() ); |
163 | BOOST_TEST( ec ); |
164 | BOOST_TEST( ec.value() == BOOST_ACCESS_ERROR_MACRO ); |
165 | econd = ec.default_error_condition(); |
166 | BOOST_TEST( econd.value() == static_cast<int>(errc::permission_denied) ); |
167 | BOOST_TEST( econd.category() == generic_category() ); |
168 | BOOST_TEST( econd == error_condition( errc::permission_denied, generic_category() ) ); |
169 | BOOST_TEST( econd == errc::permission_denied ); |
170 | BOOST_TEST( errc::permission_denied == econd ); |
171 | BOOST_TEST( ec == errc::permission_denied ); |
172 | BOOST_TEST( ec.category() == system_category() ); |
173 | BOOST_TEST( std::strcmp( ec.category().name(), "system" ) == 0 ); |
174 | |
175 | // test the explicit make_error_code conversion for errc |
176 | ec = make_error_code( e: errc::bad_message ); |
177 | BOOST_TEST( ec ); |
178 | BOOST_TEST( ec == errc::bad_message ); |
179 | BOOST_TEST( errc::bad_message == ec ); |
180 | BOOST_TEST( ec != errc::permission_denied ); |
181 | BOOST_TEST( errc::permission_denied != ec ); |
182 | BOOST_TEST( ec.category() == generic_category() ); |
183 | |
184 | //// test the deprecated predefined error_category synonyms |
185 | //BOOST_TEST( &system_category() == &native_ecat ); |
186 | //BOOST_TEST( &generic_category() == &errno_ecat ); |
187 | //BOOST_TEST( system_category() == native_ecat ); |
188 | //BOOST_TEST( generic_category() == errno_ecat ); |
189 | |
190 | // test error_code and error_condition message(); |
191 | // see Boost.Filesystem operations_test for code specific message() tests |
192 | ec = error_code( -1, system_category() ); |
193 | std::cout << "error_code message for -1 is \"" << ec.message() << "\"\n" ; |
194 | std::cout << "error_code message for 0 is \"" << ec_0_system.message() << "\"\n" ; |
195 | #if defined(BOOST_WINDOWS_API) |
196 | // Borland appends newline, so just check text |
197 | BOOST_TEST( ec.message().substr(0,13) == "Unknown error" ); |
198 | // Fails when the language isn't US English |
199 | // BOOST_TEST( ec_0_system.message().substr(0,36) == "The operation completed successfully" ); |
200 | #elif defined(linux) || defined(__linux) || defined(__linux__) |
201 | // Linux appends value to message as unsigned, so it varies with # of bits |
202 | BOOST_TEST( ec.message().substr(0,13) == "Unknown error" ); |
203 | #elif defined(__hpux) |
204 | BOOST_TEST( ec.message() == "" ); |
205 | #elif defined(__osf__) |
206 | BOOST_TEST( ec.message() == "Error -1 occurred." ); |
207 | #elif defined(__vms) |
208 | BOOST_TEST( ec.message() == "error -1" ); |
209 | #endif |
210 | |
211 | ec = error_code( BOOST_ACCESS_ERROR_MACRO, system_category() ); |
212 | BOOST_TEST( ec.message() != "" ); |
213 | BOOST_TEST( ec.message().substr( 0, 13) != "Unknown error" ); |
214 | |
215 | econd = error_condition( -1, generic_category() ); |
216 | error_condition econd_ok; |
217 | std::cout << "error_condition message for -1 is \"" << econd.message() << "\"\n" ; |
218 | std::cout << "error_condition message for 0 is \"" << econd_ok.message() << "\"\n" ; |
219 | #if defined(BOOST_WINDOWS_API) |
220 | // Borland appends newline, so just check text |
221 | BOOST_TEST( econd.message().substr(0,13) == "Unknown error" ); |
222 | BOOST_TEST( econd_ok.message().substr(0,8) == "No error" ); |
223 | #elif defined(linux) || defined(__linux) || defined(__linux__) |
224 | // Linux appends value to message as unsigned, so it varies with # of bits |
225 | BOOST_TEST( econd.message().substr(0,13) == "Unknown error" ); |
226 | #elif defined(__hpux) |
227 | BOOST_TEST( econd.message() == "" ); |
228 | #elif defined(__osf__) |
229 | BOOST_TEST( econd.message() == "Error -1 occurred." ); |
230 | #elif defined(__vms) |
231 | BOOST_TEST( econd.message() == "error -1" ); |
232 | #endif |
233 | |
234 | econd = error_condition( BOOST_ACCESS_ERROR_MACRO, generic_category() ); |
235 | BOOST_TEST( econd.message() != "" ); |
236 | BOOST_TEST( econd.message().substr( 0, 13) != "Unknown error" ); |
237 | |
238 | test_throws_usage(); |
239 | |
240 | #ifdef BOOST_WINDOWS_API |
241 | std::cout << "Windows tests...\n" ; |
242 | // these tests probe the Windows errc decoder |
243 | // test the first entry in the decoder table: |
244 | ec = error_code( ERROR_ACCESS_DENIED, system_category() ); |
245 | BOOST_TEST( ec.value() == ERROR_ACCESS_DENIED ); |
246 | BOOST_TEST( ec == errc::permission_denied ); |
247 | BOOST_TEST( ec.default_error_condition().value() == errc::permission_denied ); |
248 | BOOST_TEST( ec.default_error_condition().category() == generic_category() ); |
249 | |
250 | // test the second entry in the decoder table: |
251 | ec = error_code( ERROR_ALREADY_EXISTS, system_category() ); |
252 | BOOST_TEST( ec.value() == ERROR_ALREADY_EXISTS ); |
253 | BOOST_TEST( ec == errc::file_exists ); |
254 | BOOST_TEST( ec.default_error_condition().value() == errc::file_exists ); |
255 | BOOST_TEST( ec.default_error_condition().category() == generic_category() ); |
256 | |
257 | // test the third entry in the decoder table: |
258 | ec = error_code( ERROR_BAD_UNIT, system_category() ); |
259 | BOOST_TEST( ec.value() == ERROR_BAD_UNIT ); |
260 | BOOST_TEST( ec == errc::no_such_device ); |
261 | BOOST_TEST( ec.default_error_condition().value() == errc::no_such_device ); |
262 | BOOST_TEST( ec.default_error_condition().category() == generic_category() ); |
263 | |
264 | // test the last non-Winsock entry in the decoder table: |
265 | ec = error_code( ERROR_WRITE_PROTECT, system_category() ); |
266 | BOOST_TEST( ec.value() == ERROR_WRITE_PROTECT ); |
267 | BOOST_TEST( ec == errc::permission_denied ); |
268 | BOOST_TEST( ec.default_error_condition().value() == errc::permission_denied ); |
269 | BOOST_TEST( ec.default_error_condition().category() == generic_category() ); |
270 | |
271 | // test the last Winsock entry in the decoder table: |
272 | ec = error_code( WSAEWOULDBLOCK, system_category() ); |
273 | BOOST_TEST( ec.value() == WSAEWOULDBLOCK ); |
274 | BOOST_TEST( ec == errc::operation_would_block ); |
275 | BOOST_TEST( ec.default_error_condition().value() == errc::operation_would_block ); |
276 | BOOST_TEST( ec.default_error_condition().category() == generic_category() ); |
277 | |
278 | // test not-in-table condition: |
279 | ec = error_code( 1234567890, system_category() ); |
280 | BOOST_TEST( ec.value() == 1234567890 ); |
281 | BOOST_TEST( ec.default_error_condition().value() == 1234567890 ); |
282 | BOOST_TEST( ec.default_error_condition().category() == system_category() ); |
283 | |
284 | #else // POSIX |
285 | |
286 | std::cout << "POSIX tests...\n" ; |
287 | ec = error_code( EACCES, system_category() ); |
288 | BOOST_TEST( ec == error_code( errc::permission_denied, system_category() ) ); |
289 | BOOST_TEST( error_code( errc::permission_denied, system_category() ) == ec ); |
290 | BOOST_TEST( ec == errc::permission_denied ); |
291 | BOOST_TEST( errc::permission_denied == ec ); |
292 | BOOST_TEST( ec.default_error_condition().value() == errc::permission_denied ); |
293 | BOOST_TEST( ec.default_error_condition().category() == generic_category() ); |
294 | |
295 | #endif |
296 | |
297 | return ::boost::report_errors(); |
298 | } |
299 | |