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