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 {
check_ostream(error_code ec,const char * expected)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
divide(int dividend,int divisor,boost::system::error_code & ec=boost::throws ())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
test_throws_usage()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(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(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(10, 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
main(int,char **)106 int main( int, char ** )
107 {
108
109 std::cout << "Conversion use cases...\n";
110 error_condition x1( errc::file_exists );
111 //error_code x2( errc::file_exists ); // should fail to compile
112 make_error_code(errc::file_exists);
113 make_error_condition(errc::file_exists);
114
115 std::cout << "General tests...\n";
116 // unit tests:
117
118 BOOST_TEST( generic_category() == generic_category() );
119 BOOST_TEST( system_category() == system_category() );
120 BOOST_TEST( generic_category() != system_category() );
121 BOOST_TEST( system_category() != generic_category() );
122
123 BOOST_TEST_NE( generic_category() < system_category(), system_category() < generic_category() );
124
125 error_code ec;
126 error_condition econd;
127 BOOST_TEST( !ec );
128 BOOST_TEST( ec.value() == 0 );
129 econd = ec.default_error_condition();
130 BOOST_TEST( econd.value() == 0 );
131 BOOST_TEST( econd.category() == generic_category() );
132 BOOST_TEST( ec == errc::success );
133 BOOST_TEST( ec.category() == system_category() );
134 BOOST_TEST( std::strcmp( ec.category().name(), "system") == 0 );
135 BOOST_TEST( !(ec < error_code( 0, system_category() )) );
136 BOOST_TEST( !(error_code( 0, system_category() ) < ec) );
137 BOOST_TEST( ec < error_code( 1, system_category() ) );
138 BOOST_TEST( !(error_code( 1, system_category() ) < ec) );
139
140 error_code ec_0_system( 0, system_category() );
141 BOOST_TEST( !ec_0_system );
142 BOOST_TEST( ec_0_system.value() == 0 );
143 econd = ec_0_system.default_error_condition();
144 BOOST_TEST( econd.value() == 0 );
145 BOOST_TEST( econd.category() == generic_category() );
146 BOOST_TEST( ec_0_system == errc::success );
147 BOOST_TEST( ec_0_system.category() == system_category() );
148 BOOST_TEST( std::strcmp( ec_0_system.category().name(), "system") == 0 );
149 check_ostream( ec_0_system, "system:0" );
150
151 BOOST_TEST( ec_0_system == ec );
152
153 error_code ec_1_system( 1, system_category() );
154 BOOST_TEST( ec_1_system );
155 BOOST_TEST( ec_1_system.value() == 1 );
156 BOOST_TEST( ec_1_system.value() != 0 );
157 BOOST_TEST( ec != ec_1_system );
158 BOOST_TEST( ec_0_system != ec_1_system );
159 check_ostream( ec_1_system, "system:1" );
160
161 ec = error_code( BOOST_ACCESS_ERROR_MACRO, system_category() );
162 BOOST_TEST( ec );
163 BOOST_TEST( ec.value() == BOOST_ACCESS_ERROR_MACRO );
164 econd = ec.default_error_condition();
165 BOOST_TEST( econd.value() == static_cast<int>(errc::permission_denied) );
166 BOOST_TEST( econd.category() == generic_category() );
167 BOOST_TEST( econd == error_condition( errc::permission_denied, generic_category() ) );
168 BOOST_TEST( econd == errc::permission_denied );
169 BOOST_TEST( errc::permission_denied == econd );
170 BOOST_TEST( ec == errc::permission_denied );
171 BOOST_TEST( ec.category() == system_category() );
172 BOOST_TEST( std::strcmp( ec.category().name(), "system") == 0 );
173
174 // test the explicit make_error_code conversion for errc
175 ec = make_error_code( errc::bad_message );
176 BOOST_TEST( ec );
177 BOOST_TEST( ec == errc::bad_message );
178 BOOST_TEST( errc::bad_message == ec );
179 BOOST_TEST( ec != errc::permission_denied );
180 BOOST_TEST( errc::permission_denied != ec );
181 BOOST_TEST( ec.category() == generic_category() );
182
183 //// test the deprecated predefined error_category synonyms
184 //BOOST_TEST( &system_category() == &native_ecat );
185 //BOOST_TEST( &generic_category() == &errno_ecat );
186 //BOOST_TEST( system_category() == native_ecat );
187 //BOOST_TEST( generic_category() == errno_ecat );
188
189 // test error_code and error_condition message();
190 // see Boost.Filesystem operations_test for code specific message() tests
191 ec = error_code( -1, system_category() );
192 std::cout << "error_code message for -1 is \"" << ec.message() << "\"\n";
193 std::cout << "error_code message for 0 is \"" << ec_0_system.message() << "\"\n";
194 #if defined(BOOST_WINDOWS_API)
195 // Borland appends newline, so just check text
196 BOOST_TEST( ec.message().substr(0,13) == "Unknown error" );
197 // Fails when the language isn't US English
198 // BOOST_TEST( ec_0_system.message().substr(0,36) == "The operation completed successfully" );
199 #elif defined(linux) || defined(__linux) || defined(__linux__)
200 // Linux appends value to message as unsigned, so it varies with # of bits
201 BOOST_TEST( ec.message().substr(0,13) == "Unknown error" );
202 #elif defined(__hpux)
203 BOOST_TEST( ec.message() == "" );
204 #elif defined(__osf__)
205 BOOST_TEST( ec.message() == "Error -1 occurred." );
206 #elif defined(__vms)
207 BOOST_TEST( ec.message() == "error -1" );
208 #endif
209
210 ec = error_code( BOOST_ACCESS_ERROR_MACRO, system_category() );
211 BOOST_TEST( ec.message() != "" );
212 BOOST_TEST( ec.message().substr( 0, 13) != "Unknown error" );
213
214 econd = error_condition( -1, generic_category() );
215 error_condition econd_ok;
216 std::cout << "error_condition message for -1 is \"" << econd.message() << "\"\n";
217 std::cout << "error_condition message for 0 is \"" << econd_ok.message() << "\"\n";
218 #if defined(BOOST_WINDOWS_API)
219 // Borland appends newline, so just check text
220 BOOST_TEST( econd.message().substr(0,13) == "Unknown error" );
221 BOOST_TEST( econd_ok.message().substr(0,8) == "No error" );
222 #elif defined(linux) || defined(__linux) || defined(__linux__)
223 // Linux appends value to message as unsigned, so it varies with # of bits
224 BOOST_TEST( econd.message().substr(0,13) == "Unknown error" );
225 #elif defined(__hpux)
226 BOOST_TEST( econd.message() == "" );
227 #elif defined(__osf__)
228 BOOST_TEST( econd.message() == "Error -1 occurred." );
229 #elif defined(__vms)
230 BOOST_TEST( econd.message() == "error -1" );
231 #endif
232
233 econd = error_condition( BOOST_ACCESS_ERROR_MACRO, generic_category() );
234 BOOST_TEST( econd.message() != "" );
235 BOOST_TEST( econd.message().substr( 0, 13) != "Unknown error" );
236
237 test_throws_usage();
238
239 #ifdef BOOST_WINDOWS_API
240 std::cout << "Windows tests...\n";
241 // these tests probe the Windows errc decoder
242 // test the first entry in the decoder table:
243 ec = error_code( ERROR_ACCESS_DENIED, system_category() );
244 BOOST_TEST( ec.value() == ERROR_ACCESS_DENIED );
245 BOOST_TEST( ec == errc::permission_denied );
246 BOOST_TEST( ec.default_error_condition().value() == errc::permission_denied );
247 BOOST_TEST( ec.default_error_condition().category() == generic_category() );
248
249 // test the second entry in the decoder table:
250 ec = error_code( ERROR_ALREADY_EXISTS, system_category() );
251 BOOST_TEST( ec.value() == ERROR_ALREADY_EXISTS );
252 BOOST_TEST( ec == errc::file_exists );
253 BOOST_TEST( ec.default_error_condition().value() == errc::file_exists );
254 BOOST_TEST( ec.default_error_condition().category() == generic_category() );
255
256 // test the third entry in the decoder table:
257 ec = error_code( ERROR_BAD_UNIT, system_category() );
258 BOOST_TEST( ec.value() == ERROR_BAD_UNIT );
259 BOOST_TEST( ec == errc::no_such_device );
260 BOOST_TEST( ec.default_error_condition().value() == errc::no_such_device );
261 BOOST_TEST( ec.default_error_condition().category() == generic_category() );
262
263 // test the last non-Winsock entry in the decoder table:
264 ec = error_code( ERROR_WRITE_PROTECT, system_category() );
265 BOOST_TEST( ec.value() == ERROR_WRITE_PROTECT );
266 BOOST_TEST( ec == errc::permission_denied );
267 BOOST_TEST( ec.default_error_condition().value() == errc::permission_denied );
268 BOOST_TEST( ec.default_error_condition().category() == generic_category() );
269
270 // test the last Winsock entry in the decoder table:
271 ec = error_code( WSAEWOULDBLOCK, system_category() );
272 BOOST_TEST( ec.value() == WSAEWOULDBLOCK );
273 BOOST_TEST( ec == errc::operation_would_block );
274 BOOST_TEST( ec.default_error_condition().value() == errc::operation_would_block );
275 BOOST_TEST( ec.default_error_condition().category() == generic_category() );
276
277 // test not-in-table condition:
278 ec = error_code( 1234567890, system_category() );
279 BOOST_TEST( ec.value() == 1234567890 );
280 BOOST_TEST( ec.default_error_condition().value() == 1234567890 );
281 BOOST_TEST( ec.default_error_condition().category() == system_category() );
282
283 #else // POSIX
284
285 std::cout << "POSIX tests...\n";
286 ec = error_code( EACCES, system_category() );
287 BOOST_TEST( ec == error_code( errc::permission_denied, system_category() ) );
288 BOOST_TEST( error_code( errc::permission_denied, system_category() ) == ec );
289 BOOST_TEST( ec == errc::permission_denied );
290 BOOST_TEST( errc::permission_denied == ec );
291 BOOST_TEST( ec.default_error_condition().value() == errc::permission_denied );
292 BOOST_TEST( ec.default_error_condition().category() == generic_category() );
293
294 #endif
295
296 return ::boost::report_errors();
297 }
298