]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Unit test for boost::lexical_cast. |
2 | // | |
3 | // See http://www.boost.org for most recent version, including documentation. | |
4 | // | |
5 | // Copyright Terje Sletteb and Kevlin Henney, 2005. | |
6 | // Copyright Alexander Nasonov, 2006. | |
7 | // Copyright Antony Polukhin, 2011-2012. | |
8 | // | |
9 | // Distributed under the Boost | |
10 | // Software License, Version 1.0. (See accompanying file | |
11 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). | |
12 | // | |
13 | // Note: The unit test no longer compile on MSVC 6, but lexical_cast itself works for it. | |
14 | ||
15 | // | |
16 | // We need this #define before any #includes: otherwise msvc will emit warnings | |
17 | // deep within std::string, resulting from our (perfectly legal) use of basic_string | |
18 | // with a custom traits class: | |
19 | // | |
20 | #define _SCL_SECURE_NO_WARNINGS | |
21 | ||
22 | #include <boost/config.hpp> | |
23 | ||
24 | #if defined(__INTEL_COMPILER) | |
25 | #pragma warning(disable: 193 383 488 981 1418 1419) | |
26 | #elif defined(BOOST_MSVC) | |
27 | #pragma warning(disable: 4097 4100 4121 4127 4146 4244 4245 4511 4512 4701 4800) | |
28 | #endif | |
29 | ||
30 | #include <boost/lexical_cast.hpp> | |
31 | ||
32 | #include <boost/cstdint.hpp> | |
33 | #include <boost/test/unit_test.hpp> | |
34 | #include <boost/test/floating_point_comparison.hpp> | |
35 | ||
36 | #include <boost/type_traits/integral_promotion.hpp> | |
37 | #include <boost/type_traits/make_unsigned.hpp> | |
38 | #include <string> | |
39 | #include <vector> | |
40 | #include <memory> | |
41 | ||
42 | #if (defined(BOOST_HAS_LONG_LONG) || defined(BOOST_HAS_MS_INT64)) \ | |
43 | && !(defined(BOOST_MSVC) && BOOST_MSVC < 1300) | |
44 | #define LCAST_TEST_LONGLONG | |
45 | #endif | |
46 | ||
47 | #if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_WSTRING) | |
48 | #define BOOST_LCAST_NO_WCHAR_T | |
49 | #endif | |
50 | ||
51 | // Test all 65536 values if true: | |
52 | bool const lcast_test_small_integral_types_completely = false; | |
53 | ||
54 | // lcast_integral_test_counter: use when testing all values of an integral | |
55 | // types is not possible. Max. portable value is 32767. | |
56 | int const lcast_integral_test_counter=500; | |
57 | ||
58 | using namespace boost; | |
59 | ||
60 | ||
61 | ||
62 | void test_conversion_from_to_short(); | |
63 | void test_conversion_from_to_ushort(); | |
64 | void test_conversion_from_to_int(); | |
65 | void test_conversion_from_to_uint(); | |
66 | void test_conversion_from_to_long(); | |
67 | void test_conversion_from_to_ulong(); | |
68 | void test_conversion_from_to_intmax_t(); | |
69 | void test_conversion_from_to_uintmax_t(); | |
70 | #ifdef LCAST_TEST_LONGLONG | |
71 | void test_conversion_from_to_longlong(); | |
72 | void test_conversion_from_to_ulonglong(); | |
73 | #endif | |
74 | #ifdef BOOST_HAS_INT128 | |
75 | void test_conversion_from_to_int128(); | |
76 | void test_conversion_from_to_uint128(); | |
77 | #endif | |
78 | void test_integral_conversions_on_min_max(); | |
79 | ||
80 | ||
81 | unit_test::test_suite *init_unit_test_suite(int, char *[]) | |
82 | { | |
83 | unit_test::test_suite *suite = | |
84 | BOOST_TEST_SUITE("lexical_cast unit test on integral types"); | |
85 | ||
86 | suite->add(BOOST_TEST_CASE(&test_conversion_from_to_short)); | |
87 | suite->add(BOOST_TEST_CASE(&test_conversion_from_to_ushort)); | |
88 | suite->add(BOOST_TEST_CASE(&test_conversion_from_to_int)); | |
89 | suite->add(BOOST_TEST_CASE(&test_conversion_from_to_uint)); | |
90 | suite->add(BOOST_TEST_CASE(&test_conversion_from_to_long)); | |
91 | suite->add(BOOST_TEST_CASE(&test_conversion_from_to_ulong)); | |
92 | suite->add(BOOST_TEST_CASE(&test_conversion_from_to_intmax_t)); | |
93 | suite->add(BOOST_TEST_CASE(&test_conversion_from_to_uintmax_t)); | |
94 | #ifdef LCAST_TEST_LONGLONG | |
95 | suite->add(BOOST_TEST_CASE(&test_conversion_from_to_longlong)); | |
96 | suite->add(BOOST_TEST_CASE(&test_conversion_from_to_ulonglong)); | |
97 | #endif | |
98 | #ifdef BOOST_HAS_INT128 | |
99 | suite->add(BOOST_TEST_CASE(&test_conversion_from_to_int128)); | |
100 | suite->add(BOOST_TEST_CASE(&test_conversion_from_to_uint128)); | |
101 | #endif | |
102 | suite->add(BOOST_TEST_CASE(&test_integral_conversions_on_min_max)); | |
103 | ||
104 | return suite; | |
105 | } | |
106 | ||
107 | template<class T, class CharT> | |
108 | void test_conversion_from_integral_to_char(CharT zero) | |
109 | { | |
110 | BOOST_CHECK(lexical_cast<CharT>(static_cast<T>(0)) == zero + 0); | |
111 | BOOST_CHECK(lexical_cast<CharT>(static_cast<T>(1)) == zero + 1); | |
112 | BOOST_CHECK(lexical_cast<CharT>(static_cast<T>(2)) == zero + 2); | |
113 | BOOST_CHECK(lexical_cast<CharT>(static_cast<T>(3)) == zero + 3); | |
114 | BOOST_CHECK(lexical_cast<CharT>(static_cast<T>(4)) == zero + 4); | |
115 | BOOST_CHECK(lexical_cast<CharT>(static_cast<T>(5)) == zero + 5); | |
116 | BOOST_CHECK(lexical_cast<CharT>(static_cast<T>(6)) == zero + 6); | |
117 | BOOST_CHECK(lexical_cast<CharT>(static_cast<T>(7)) == zero + 7); | |
118 | BOOST_CHECK(lexical_cast<CharT>(static_cast<T>(8)) == zero + 8); | |
119 | BOOST_CHECK(lexical_cast<CharT>(static_cast<T>(9)) == zero + 9); | |
120 | ||
121 | BOOST_CHECK_THROW(lexical_cast<CharT>(static_cast<T>(10)), bad_lexical_cast); | |
122 | ||
123 | T t = (std::numeric_limits<T>::max)(); | |
124 | BOOST_CHECK_THROW(lexical_cast<CharT>(t), bad_lexical_cast); | |
125 | } | |
126 | ||
127 | template<class T, class CharT> | |
128 | void test_conversion_from_char_to_integral(CharT zero) | |
129 | { | |
130 | BOOST_CHECK(lexical_cast<T>( static_cast<CharT>(zero + 0)) == static_cast<T>(0) ); | |
131 | BOOST_CHECK(lexical_cast<T>( static_cast<CharT>(zero + 1)) == static_cast<T>(1) ); | |
132 | BOOST_CHECK(lexical_cast<T>( static_cast<CharT>(zero + 2)) == static_cast<T>(2) ); | |
133 | BOOST_CHECK(lexical_cast<T>( static_cast<CharT>(zero + 3)) == static_cast<T>(3) ); | |
134 | BOOST_CHECK(lexical_cast<T>( static_cast<CharT>(zero + 4)) == static_cast<T>(4) ); | |
135 | BOOST_CHECK(lexical_cast<T>( static_cast<CharT>(zero + 5)) == static_cast<T>(5) ); | |
136 | BOOST_CHECK(lexical_cast<T>( static_cast<CharT>(zero + 6)) == static_cast<T>(6) ); | |
137 | BOOST_CHECK(lexical_cast<T>( static_cast<CharT>(zero + 7)) == static_cast<T>(7) ); | |
138 | BOOST_CHECK(lexical_cast<T>( static_cast<CharT>(zero + 8)) == static_cast<T>(8) ); | |
139 | BOOST_CHECK(lexical_cast<T>( static_cast<CharT>(zero + 9)) == static_cast<T>(9) ); | |
140 | ||
141 | BOOST_CHECK_THROW(lexical_cast<T>( static_cast<CharT>(zero + 10)), bad_lexical_cast); | |
142 | BOOST_CHECK_THROW(lexical_cast<T>( static_cast<CharT>(zero - 1)), bad_lexical_cast); | |
143 | } | |
144 | ||
145 | template<class T> | |
146 | void test_conversion_from_integral_to_integral() | |
147 | { | |
148 | T t = 0; | |
149 | BOOST_CHECK(lexical_cast<T>(t) == t); | |
150 | ||
151 | // Next two variables are used to suppress warnings. | |
152 | int st = 32767; unsigned int ut = st; | |
153 | t = st; | |
154 | BOOST_CHECK(lexical_cast<short>(t) == st); | |
155 | BOOST_CHECK(lexical_cast<unsigned short>(t) == ut); | |
156 | BOOST_CHECK(lexical_cast<int>(t) == st); | |
157 | BOOST_CHECK(lexical_cast<unsigned int>(t) == ut); | |
158 | BOOST_CHECK(lexical_cast<long>(t) == st); | |
159 | BOOST_CHECK(lexical_cast<unsigned long>(t) == ut); | |
160 | ||
161 | t = (std::numeric_limits<T>::max)(); | |
162 | BOOST_CHECK(lexical_cast<T>(t) == t); | |
163 | ||
164 | t = (std::numeric_limits<T>::min)(); | |
165 | BOOST_CHECK(lexical_cast<T>(t) == t); | |
166 | } | |
167 | ||
168 | ||
169 | ||
170 | ||
171 | // Replace "-,999" with "-999". | |
172 | template<class CharT> | |
173 | std::basic_string<CharT> to_str_gcc_workaround(std::basic_string<CharT> str) | |
174 | { | |
175 | std::locale loc; | |
176 | std::numpunct<CharT> const& np = BOOST_USE_FACET(std::numpunct<CharT>, loc); | |
177 | std::ctype<CharT> const& ct = BOOST_USE_FACET(std::ctype<CharT>, loc); | |
178 | ||
179 | if(np.grouping().empty()) | |
180 | return str; | |
181 | ||
182 | CharT prefix[3] = { ct.widen('-'), np.thousands_sep(), CharT() }; | |
183 | ||
184 | if(str.find(prefix) != 0) | |
185 | return str; | |
186 | ||
187 | prefix[1] = CharT(); | |
188 | str.replace(0, 2, prefix); | |
189 | return str; | |
190 | } | |
191 | ||
192 | template<class CharT, class T> | |
193 | std::basic_string<CharT> to_str(T t) | |
194 | { | |
195 | std::basic_ostringstream<CharT> o; | |
196 | o << t; | |
197 | return to_str_gcc_workaround(o.str()); | |
198 | } | |
199 | ||
200 | ||
201 | template<class T, class CharT> | |
202 | void test_conversion_from_integral_to_string(CharT) | |
203 | { | |
204 | typedef std::numeric_limits<T> limits; | |
205 | typedef std::basic_string<CharT> string_type; | |
206 | ||
207 | T t; | |
208 | ||
209 | t = (limits::min)(); | |
210 | BOOST_CHECK(lexical_cast<string_type>(t) == to_str<CharT>(t)); | |
211 | ||
212 | t = (limits::max)(); | |
213 | BOOST_CHECK(lexical_cast<string_type>(t) == to_str<CharT>(t)); | |
214 | ||
215 | if(limits::digits <= 16 && lcast_test_small_integral_types_completely) | |
216 | // min and max have already been tested. | |
217 | for(t = 1 + (limits::min)(); t != (limits::max)(); ++t) | |
218 | BOOST_CHECK(lexical_cast<string_type>(t) == to_str<CharT>(t)); | |
219 | else | |
220 | { | |
221 | T const min_val = (limits::min)(); | |
222 | T const max_val = (limits::max)(); | |
223 | T const half_max_val = max_val / 2; | |
224 | T const cnt = lcast_integral_test_counter; // to suppress warnings | |
225 | unsigned int const counter = cnt < half_max_val ? cnt : half_max_val; | |
226 | ||
227 | unsigned int i; | |
228 | ||
229 | // Test values around min: | |
230 | t = min_val; | |
231 | for(i = 0; i < counter; ++i, ++t) | |
232 | BOOST_CHECK(lexical_cast<string_type>(t) == to_str<CharT>(t)); | |
233 | ||
234 | // Test values around max: | |
235 | t = max_val; | |
236 | for(i = 0; i < counter; ++i, --t) | |
237 | BOOST_CHECK(lexical_cast<string_type>(t) == to_str<CharT>(t)); | |
238 | ||
239 | // Test values around zero: | |
240 | if(limits::is_signed) | |
241 | for(t = static_cast<T>(-counter); t < static_cast<T>(counter); ++t) | |
242 | BOOST_CHECK(lexical_cast<string_type>(t) == to_str<CharT>(t)); | |
243 | ||
244 | // Test values around 100, 1000, 10000, ... | |
245 | T ten_power = 100; | |
246 | for(int e = 2; e < limits::digits10; ++e, ten_power *= 10) | |
247 | { | |
248 | // ten_power + 100 probably never overflows | |
249 | for(t = ten_power - 100; t != ten_power + 100; ++t) | |
250 | BOOST_CHECK(lexical_cast<string_type>(t) == to_str<CharT>(t)); | |
251 | } | |
252 | } | |
253 | } | |
254 | ||
255 | template<class T, class CharT> | |
256 | void test_conversion_from_string_to_integral(CharT) | |
257 | { | |
258 | typedef std::numeric_limits<T> limits; | |
259 | typedef std::basic_string<CharT> string_type; | |
260 | ||
261 | string_type s; | |
262 | string_type const zero = to_str<CharT>(0); | |
263 | string_type const nine = to_str<CharT>(9); | |
264 | T const min_val = (limits::min)(); | |
265 | T const max_val = (limits::max)(); | |
266 | ||
267 | s = to_str<CharT>(min_val); | |
268 | BOOST_CHECK_EQUAL(lexical_cast<T>(s), min_val); | |
269 | if(limits::is_signed) | |
270 | { | |
271 | BOOST_CHECK_THROW(lexical_cast<T>(s + zero), bad_lexical_cast); | |
272 | BOOST_CHECK_THROW(lexical_cast<T>(s + nine), bad_lexical_cast); | |
273 | } | |
274 | ||
275 | s = to_str<CharT>(max_val); | |
276 | BOOST_CHECK_EQUAL(lexical_cast<T>(s), max_val); | |
277 | { | |
278 | BOOST_CHECK_THROW(lexical_cast<T>(s + zero), bad_lexical_cast); | |
279 | BOOST_CHECK_THROW(lexical_cast<T>(s + nine), bad_lexical_cast); | |
280 | ||
281 | s = to_str<CharT>(max_val); | |
282 | for (int i =1; i <=10; ++i) { | |
283 | s[s.size()-1] += 1; | |
284 | BOOST_CHECK_THROW(lexical_cast<T>( s ), bad_lexical_cast); | |
285 | } | |
286 | ||
287 | s = to_str<CharT>(max_val); | |
288 | std::locale loc; | |
289 | typedef std::numpunct<char> numpunct; | |
290 | if ( BOOST_USE_FACET(numpunct, loc).grouping().empty() ) { | |
291 | // Following tests work well for locale C | |
292 | BOOST_CHECK_EQUAL(lexical_cast<T>(to_str<CharT>(0)+s), max_val); | |
293 | BOOST_CHECK_EQUAL(lexical_cast<T>(to_str<CharT>(0)+to_str<CharT>(0)+s), max_val); | |
294 | BOOST_CHECK_EQUAL(lexical_cast<T>(to_str<CharT>(0)+to_str<CharT>(0)+to_str<CharT>(0)+s), max_val); | |
295 | } | |
296 | ||
297 | for (int i =1; i <=256; ++i) { | |
298 | BOOST_CHECK_THROW(lexical_cast<T>( to_str<CharT>(i)+s ), bad_lexical_cast); | |
299 | } | |
300 | ||
301 | typedef BOOST_DEDUCED_TYPENAME boost::integral_promotion<T>::type promoted; | |
302 | if ( !(boost::is_same<T, promoted>::value) ) | |
303 | { | |
304 | promoted prom = max_val; | |
305 | s = to_str<CharT>(max_val); | |
306 | for (int i =1; i <=256; ++i) { | |
307 | BOOST_CHECK_THROW(lexical_cast<T>( to_str<CharT>(prom+i) ), bad_lexical_cast); | |
308 | BOOST_CHECK_THROW(lexical_cast<T>( to_str<CharT>(i)+s ), bad_lexical_cast); | |
309 | } | |
310 | } | |
311 | } | |
312 | ||
313 | if(limits::digits <= 16 && lcast_test_small_integral_types_completely) | |
314 | // min and max have already been tested. | |
315 | for(T t = 1 + min_val; t != max_val; ++t) | |
316 | BOOST_CHECK(lexical_cast<T>(to_str<CharT>(t)) == t); | |
317 | else | |
318 | { | |
319 | T const half_max_val = max_val / 2; | |
320 | T const cnt = lcast_integral_test_counter; // to suppress warnings | |
321 | unsigned int const counter = cnt < half_max_val ? cnt : half_max_val; | |
322 | ||
323 | T t; | |
324 | unsigned int i; | |
325 | ||
326 | // Test values around min: | |
327 | t = min_val; | |
328 | for(i = 0; i < counter; ++i, ++t) | |
329 | BOOST_CHECK(lexical_cast<T>(to_str<CharT>(t)) == t); | |
330 | ||
331 | // Test values around max: | |
332 | t = max_val; | |
333 | for(i = 0; i < counter; ++i, --t) | |
334 | BOOST_CHECK(lexical_cast<T>(to_str<CharT>(t)) == t); | |
335 | ||
336 | // Test values around zero: | |
337 | if(limits::is_signed) | |
338 | for(t = static_cast<T>(-counter); t < static_cast<T>(counter); ++t) | |
339 | BOOST_CHECK(lexical_cast<T>(to_str<CharT>(t)) == t); | |
340 | ||
341 | // Test values around 100, 1000, 10000, ... | |
342 | T ten_power = 100; | |
343 | for(int e = 2; e < limits::digits10; ++e, ten_power *= 10) | |
344 | { | |
345 | // ten_power + 100 probably never overflows | |
346 | for(t = ten_power - 100; t != ten_power + 100; ++t) | |
347 | BOOST_CHECK(lexical_cast<T>(to_str<CharT>(t)) == t); | |
348 | } | |
349 | } | |
350 | } | |
351 | ||
352 | template<class T> | |
353 | void test_conversion_from_to_integral_for_locale() | |
354 | { | |
355 | std::locale current_locale; | |
356 | typedef std::numpunct<char> numpunct; | |
357 | numpunct const& np = BOOST_USE_FACET(numpunct, current_locale); | |
358 | if ( !np.grouping().empty() ) | |
359 | { | |
360 | BOOST_CHECK_THROW( | |
361 | lexical_cast<T>( std::string("100") + np.thousands_sep() + np.thousands_sep() + "0" ) | |
362 | , bad_lexical_cast); | |
363 | BOOST_CHECK_THROW(lexical_cast<T>( std::string("100") + np.thousands_sep() ), bad_lexical_cast); | |
364 | BOOST_CHECK_THROW(lexical_cast<T>( np.thousands_sep() + std::string("100") ), bad_lexical_cast); | |
365 | ||
366 | // Exception must not be thrown, when we are using no separators at all | |
367 | BOOST_CHECK( lexical_cast<T>("30000") == static_cast<T>(30000) ); | |
368 | } | |
369 | ||
370 | ||
371 | test_conversion_from_integral_to_integral<T>(); | |
372 | ||
373 | // This is a part of test_conversion_from_integral_to_string<T>('0') method, | |
374 | // but with BOOST_CHECK_EQUAL instead of BOOST_CHECK. It is required to see | |
375 | // what is produced by the to_str<char>(t) method in situations when result | |
376 | // is different. BOOST_CHECK does not work with wchar_t. | |
377 | typedef std::numeric_limits<T> limits; | |
378 | T t = (limits::min)(); | |
379 | BOOST_CHECK_EQUAL(lexical_cast<std::string>(t), to_str<char>(t)); | |
380 | ||
381 | test_conversion_from_integral_to_string<T>('0'); | |
382 | test_conversion_from_string_to_integral<T>('0'); | |
383 | #if !defined(BOOST_LCAST_NO_WCHAR_T) | |
384 | if (lexical_cast<std::wstring>(t) != to_str<wchar_t>(t)) { | |
385 | // Something went wrong, and now we are attempting to find and print the | |
386 | // difference. | |
387 | std::wstring wstr = to_str<wchar_t>(t); | |
388 | std::string lcast_str = lexical_cast<std::string>(t); | |
389 | std::string str; | |
390 | str.reserve(wstr.size()); | |
391 | for (std::size_t i = 0; i < wstr.size(); ++i) { | |
392 | str.push_back(static_cast<char>(wstr[i])); | |
393 | } | |
394 | ||
395 | BOOST_CHECK_EQUAL(lcast_str.length(), lexical_cast<std::wstring>(t).length()); | |
396 | BOOST_CHECK_EQUAL(to_str<char>(t), str); | |
397 | BOOST_CHECK_EQUAL(lcast_str, str); | |
398 | } | |
399 | ||
400 | test_conversion_from_integral_to_string<T>(L'0'); | |
401 | test_conversion_from_string_to_integral<T>(L'0'); | |
402 | #endif | |
403 | } | |
404 | ||
405 | struct restore_oldloc | |
406 | { | |
407 | std::locale oldloc; | |
408 | ~restore_oldloc() { std::locale::global(oldloc); } | |
409 | }; | |
410 | ||
411 | template<class T> | |
412 | void test_conversion_from_to_integral_minimal() | |
413 | { | |
414 | char const zero = '0'; | |
415 | signed char const szero = '0'; | |
416 | unsigned char const uzero = '0'; | |
417 | test_conversion_from_integral_to_char<T>(zero); | |
418 | test_conversion_from_char_to_integral<T>(zero); | |
419 | test_conversion_from_integral_to_char<T>(szero); | |
420 | test_conversion_from_char_to_integral<T>(szero); | |
421 | test_conversion_from_integral_to_char<T>(uzero); | |
422 | test_conversion_from_char_to_integral<T>(uzero); | |
423 | #if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) | |
424 | wchar_t const wzero = L'0'; | |
425 | test_conversion_from_integral_to_char<T>(wzero); | |
426 | test_conversion_from_char_to_integral<T>(wzero); | |
427 | #endif | |
b32b8144 | 428 | #if !defined(BOOST_NO_CXX11_CHAR16_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) && !defined(_LIBCPP_VERSION) && !defined(BOOST_MSVC) |
7c673cae FG |
429 | char16_t const u16zero = u'0'; |
430 | test_conversion_from_integral_to_char<T>(u16zero); | |
431 | test_conversion_from_char_to_integral<T>(u16zero); | |
432 | #endif | |
b32b8144 | 433 | #if !defined(BOOST_NO_CXX11_CHAR32_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) && !defined(_LIBCPP_VERSION) && !defined(BOOST_MSVC) |
7c673cae FG |
434 | char32_t const u32zero = u'0'; |
435 | test_conversion_from_integral_to_char<T>(u32zero); | |
436 | test_conversion_from_char_to_integral<T>(u32zero); | |
437 | #endif | |
438 | ||
439 | BOOST_CHECK(lexical_cast<T>("-1") == static_cast<T>(-1)); | |
440 | BOOST_CHECK(lexical_cast<T>("-9") == static_cast<T>(-9)); | |
441 | BOOST_CHECK(lexical_cast<T>(-1) == static_cast<T>(-1)); | |
442 | BOOST_CHECK(lexical_cast<T>(-9) == static_cast<T>(-9)); | |
443 | ||
444 | BOOST_CHECK_THROW(lexical_cast<T>("-1.0"), bad_lexical_cast); | |
445 | BOOST_CHECK_THROW(lexical_cast<T>("-9.0"), bad_lexical_cast); | |
446 | BOOST_CHECK(lexical_cast<T>(-1.0) == static_cast<T>(-1)); | |
447 | BOOST_CHECK(lexical_cast<T>(-9.0) == static_cast<T>(-9)); | |
448 | ||
449 | BOOST_CHECK(lexical_cast<T>(static_cast<T>(1)) == static_cast<T>(1)); | |
450 | BOOST_CHECK(lexical_cast<T>(static_cast<T>(9)) == static_cast<T>(9)); | |
451 | BOOST_CHECK_THROW(lexical_cast<T>(1.1f), bad_lexical_cast); | |
452 | BOOST_CHECK_THROW(lexical_cast<T>(1.1), bad_lexical_cast); | |
453 | BOOST_CHECK_THROW(lexical_cast<T>(1.1L), bad_lexical_cast); | |
454 | BOOST_CHECK_THROW(lexical_cast<T>(1.0001f), bad_lexical_cast); | |
455 | BOOST_CHECK_THROW(lexical_cast<T>(1.0001), bad_lexical_cast); | |
456 | BOOST_CHECK_THROW(lexical_cast<T>(1.0001L), bad_lexical_cast); | |
457 | ||
458 | BOOST_CHECK(lexical_cast<T>("+1") == static_cast<T>(1) ); | |
459 | BOOST_CHECK(lexical_cast<T>("+9") == static_cast<T>(9) ); | |
460 | BOOST_CHECK(lexical_cast<T>("+10") == static_cast<T>(10) ); | |
461 | BOOST_CHECK(lexical_cast<T>("+90") == static_cast<T>(90) ); | |
462 | BOOST_CHECK_THROW(lexical_cast<T>("++1"), bad_lexical_cast); | |
463 | BOOST_CHECK_THROW(lexical_cast<T>("-+9"), bad_lexical_cast); | |
464 | BOOST_CHECK_THROW(lexical_cast<T>("--1"), bad_lexical_cast); | |
465 | BOOST_CHECK_THROW(lexical_cast<T>("+-9"), bad_lexical_cast); | |
466 | // test_conversion_from_to_integral_for_locale | |
467 | ||
468 | // Overflow test case from David W. Birdsall | |
469 | std::string must_owerflow_str = (sizeof(T) < 16 ? "160000000000000000000" : "1600000000000000000000000000000000000000"); | |
470 | std::string must_owerflow_negative_str = (sizeof(T) < 16 ? "-160000000000000000000" : "-1600000000000000000000000000000000000000"); | |
471 | for (int i = 0; i < 15; ++i) { | |
472 | BOOST_CHECK_THROW(lexical_cast<T>(must_owerflow_str), bad_lexical_cast); | |
473 | BOOST_CHECK_THROW(lexical_cast<T>(must_owerflow_negative_str), bad_lexical_cast); | |
474 | ||
475 | must_owerflow_str += '0'; | |
476 | must_owerflow_negative_str += '0'; | |
477 | } | |
478 | } | |
479 | ||
480 | template<class T> | |
481 | void test_conversion_from_to_integral() | |
482 | { | |
483 | test_conversion_from_to_integral_minimal<T>(); | |
484 | typedef std::numpunct<char> numpunct; | |
485 | ||
486 | restore_oldloc guard; | |
487 | std::locale const& oldloc = guard.oldloc; | |
488 | ||
489 | std::string grouping1 = BOOST_USE_FACET(numpunct, oldloc).grouping(); | |
490 | std::string grouping2(grouping1); | |
491 | ||
492 | test_conversion_from_to_integral_for_locale<T>(); | |
493 | ||
494 | try | |
495 | { | |
496 | std::locale newloc(""); | |
497 | std::locale::global(newloc); | |
498 | ||
499 | grouping2 = BOOST_USE_FACET(numpunct, newloc).grouping(); | |
500 | } | |
501 | catch(std::exception const& ex) | |
502 | { | |
503 | std::string msg("Failed to set system locale: "); | |
504 | msg += ex.what(); | |
505 | BOOST_TEST_MESSAGE(msg); | |
506 | } | |
507 | ||
508 | if(grouping1 != grouping2) | |
509 | test_conversion_from_to_integral_for_locale<T>(); | |
510 | ||
511 | if(grouping1.empty() && grouping2.empty()) | |
512 | BOOST_TEST_MESSAGE("Formatting with thousands_sep has not been tested"); | |
513 | } | |
514 | ||
515 | void test_conversion_from_to_short() | |
516 | { | |
517 | test_conversion_from_to_integral<short>(); | |
518 | } | |
519 | ||
520 | void test_conversion_from_to_ushort() | |
521 | { | |
522 | test_conversion_from_to_integral<unsigned short>(); | |
523 | } | |
524 | ||
525 | void test_conversion_from_to_int() | |
526 | { | |
527 | test_conversion_from_to_integral<int>(); | |
528 | } | |
529 | ||
530 | void test_conversion_from_to_uint() | |
531 | { | |
532 | test_conversion_from_to_integral<unsigned int>(); | |
533 | } | |
534 | ||
535 | void test_conversion_from_to_long() | |
536 | { | |
537 | test_conversion_from_to_integral<long>(); | |
538 | } | |
539 | ||
540 | void test_conversion_from_to_ulong() | |
541 | { | |
542 | test_conversion_from_to_integral<unsigned long>(); | |
543 | } | |
544 | ||
545 | void test_conversion_from_to_intmax_t() | |
546 | { | |
547 | test_conversion_from_to_integral<boost::intmax_t>(); | |
548 | } | |
549 | ||
550 | void test_conversion_from_to_uintmax_t() | |
551 | { | |
552 | test_conversion_from_to_integral<boost::uintmax_t>(); | |
553 | } | |
554 | ||
555 | #if defined(BOOST_HAS_LONG_LONG) | |
556 | ||
557 | void test_conversion_from_to_longlong() | |
558 | { | |
559 | test_conversion_from_to_integral<boost::long_long_type>(); | |
560 | } | |
561 | ||
562 | void test_conversion_from_to_ulonglong() | |
563 | { | |
564 | test_conversion_from_to_integral<boost::ulong_long_type>(); | |
565 | } | |
566 | ||
567 | #elif defined(BOOST_HAS_MS_INT64) | |
568 | ||
569 | void test_conversion_from_to_longlong() | |
570 | { | |
571 | test_conversion_from_to_integral<__int64>(); | |
572 | } | |
573 | ||
574 | void test_conversion_from_to_ulonglong() | |
575 | { | |
576 | test_conversion_from_to_integral<unsigned __int64>(); | |
577 | } | |
578 | ||
579 | #endif | |
580 | ||
581 | ||
582 | #ifdef BOOST_HAS_INT128 | |
583 | ||
584 | template <bool Specialized, class T> | |
585 | struct test_if_specialized { | |
586 | static void test() {} | |
587 | }; | |
588 | ||
589 | template <class T> | |
590 | struct test_if_specialized<true, T> { | |
591 | static void test() { | |
592 | test_conversion_from_to_integral_minimal<T>(); | |
593 | } | |
594 | }; | |
595 | ||
596 | void test_conversion_from_to_int128() | |
597 | { | |
598 | test_if_specialized< | |
599 | std::numeric_limits<boost::int128_type>::is_specialized, | |
600 | boost::int128_type | |
601 | >::test(); | |
602 | } | |
603 | ||
604 | void test_conversion_from_to_uint128() | |
605 | { | |
606 | test_if_specialized< | |
607 | std::numeric_limits<boost::int128_type>::is_specialized, | |
608 | boost::uint128_type | |
609 | >::test(); | |
610 | } | |
611 | #endif | |
612 | ||
613 | template <typename SignedT> | |
614 | void test_integral_conversions_on_min_max_impl() | |
615 | { | |
616 | typedef SignedT signed_t; | |
617 | typedef BOOST_DEDUCED_TYPENAME boost::make_unsigned<signed_t>::type unsigned_t; | |
618 | ||
619 | typedef std::numeric_limits<signed_t> s_limits; | |
620 | typedef std::numeric_limits<unsigned_t> uns_limits; | |
621 | ||
622 | BOOST_CHECK_EQUAL(lexical_cast<unsigned_t>((uns_limits::max)()), (uns_limits::max)()); | |
623 | BOOST_CHECK_EQUAL(lexical_cast<unsigned_t>((uns_limits::min)()), (uns_limits::min)()); | |
624 | ||
625 | BOOST_CHECK_EQUAL(lexical_cast<signed_t>((s_limits::max)()), (s_limits::max)()); | |
626 | BOOST_CHECK_EQUAL(lexical_cast<signed_t>((uns_limits::min)()), static_cast<signed_t>((uns_limits::min)())); | |
627 | ||
628 | BOOST_CHECK_EQUAL(lexical_cast<unsigned_t>((s_limits::max)()), static_cast<unsigned_t>((s_limits::max)())); | |
629 | BOOST_CHECK_EQUAL(lexical_cast<unsigned_t>((s_limits::min)()), static_cast<unsigned_t>((s_limits::min)())); | |
630 | } | |
631 | ||
632 | void test_integral_conversions_on_min_max() | |
633 | { | |
634 | test_integral_conversions_on_min_max_impl<int>(); | |
635 | test_integral_conversions_on_min_max_impl<short>(); | |
636 | ||
637 | #ifdef _MSC_VER | |
638 | test_integral_conversions_on_min_max_impl<long int>(); | |
639 | ||
640 | #if defined(BOOST_HAS_LONG_LONG) | |
641 | test_integral_conversions_on_min_max_impl<boost::long_long_type>(); | |
642 | #elif defined(BOOST_HAS_MS_INT64) | |
643 | test_integral_conversions_on_min_max_impl<__int64>(); | |
644 | #endif | |
645 | ||
646 | #ifdef BOOST_HAS_INT128 | |
647 | test_integral_conversions_on_min_max_impl<boost::int128_type>(); | |
648 | #endif | |
649 | #endif | |
650 | ||
651 | } | |
652 | ||
653 |