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