1 | // Unit test for boost::lexical_cast. |
2 | // |
3 | // See http://www.boost.org for most recent version, including documentation. |
4 | // |
5 | // Copyright Antony Polukhin, 2011-2024. |
6 | // |
7 | // Distributed under the Boost |
8 | // Software License, Version 1.0. (See accompanying file |
9 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). |
10 | |
11 | #ifndef BOOST_LEXICAL_CAST_DETAIL_TEST_ON_OLD |
12 | #include <boost/lexical_cast.hpp> |
13 | #else |
14 | // Make sure that tests work the same way on non-optimized version |
15 | #include "lexical_cast_old.hpp" |
16 | #endif |
17 | |
18 | #include <boost/cstdint.hpp> |
19 | #include <boost/core/lightweight_test.hpp> |
20 | #include <boost/type_traits/is_same.hpp> |
21 | #include <boost/type_traits/is_signed.hpp> |
22 | |
23 | #ifndef BOOST_TEST_CLOSE_FRACTION |
24 | // Naiive, but works for most tests in this file |
25 | #define BOOST_TEST_CLOSE_FRACTION(x, y, eps) \ |
26 | BOOST_TEST(x - y + eps <= eps * 2); \ |
27 | BOOST_TEST(y - x + eps <= eps * 2); |
28 | #endif |
29 | |
30 | #if (defined(__CYGWIN__) || defined(__FreeBSD__) || defined(__NetBSD__) \ |
31 | || (defined(__hppa) && !defined(__OpenBSD__)) || (defined(__NO_LONG_DOUBLE_MATH) && (DBL_MANT_DIG != LDBL_MANT_DIG))) \ |
32 | || defined(__MINGW64__) |
33 | # define BOOST_LEXICAL_CAST_NO_LONG_DOUBLE_MATH_FUNCTIONS |
34 | #endif |
35 | |
36 | using namespace boost; |
37 | |
38 | |
39 | // Replace "-,999" with "-999". |
40 | template<class CharT> |
41 | std::basic_string<CharT> to_str_gcc_workaround(std::basic_string<CharT> str) |
42 | { |
43 | std::locale loc; |
44 | std::numpunct<CharT> const& np = BOOST_USE_FACET(std::numpunct<CharT>, loc); |
45 | std::ctype<CharT> const& ct = BOOST_USE_FACET(std::ctype<CharT>, loc); |
46 | |
47 | if(np.grouping().empty()) |
48 | return str; |
49 | |
50 | CharT prefix[3] = { ct.widen('-'), np.thousands_sep(), CharT() }; |
51 | |
52 | if(str.find(prefix) != 0) |
53 | return str; |
54 | |
55 | prefix[1] = CharT(); |
56 | str.replace(0, 2, prefix); |
57 | return str; |
58 | } |
59 | |
60 | template<class CharT, class T> |
61 | std::basic_string<CharT> to_str(T t) |
62 | { |
63 | std::basic_ostringstream<CharT> o; |
64 | o << t; |
65 | return to_str_gcc_workaround(o.str()); |
66 | } |
67 | |
68 | |
69 | template<class T> |
70 | void test_conversion_from_to_float_for_locale() |
71 | { |
72 | std::locale current_locale; |
73 | typedef std::numpunct<char> numpunct; |
74 | numpunct const& np = BOOST_USE_FACET(numpunct, current_locale); |
75 | if ( !np.grouping().empty() ) |
76 | { |
77 | BOOST_TEST_THROWS( |
78 | lexical_cast<T>( std::string("100" ) + np.thousands_sep() + np.thousands_sep() + "0" ) |
79 | , bad_lexical_cast); |
80 | BOOST_TEST_THROWS(lexical_cast<T>( std::string("100" ) + np.thousands_sep() ), bad_lexical_cast); |
81 | BOOST_TEST_THROWS(lexical_cast<T>( np.thousands_sep() + std::string("100" ) ), bad_lexical_cast); |
82 | BOOST_TEST_THROWS(lexical_cast<T>( std::string("1" ) + np.thousands_sep() + np.decimal_point() + "e10" ), bad_lexical_cast); |
83 | BOOST_TEST_THROWS(lexical_cast<T>( std::string("1e10" ) + np.thousands_sep() ), bad_lexical_cast); |
84 | BOOST_TEST_THROWS(lexical_cast<T>( std::string("1" ) + np.thousands_sep() + "e10" ), bad_lexical_cast); |
85 | |
86 | BOOST_TEST_CLOSE_FRACTION(lexical_cast<T>( to_str< char >(100000) ), 100000, (std::numeric_limits<T>::epsilon()) ); |
87 | BOOST_TEST_CLOSE_FRACTION(lexical_cast<T>( to_str< char >(10000000u) ), 10000000u, (std::numeric_limits<T>::epsilon()) ); |
88 | BOOST_TEST_CLOSE_FRACTION(lexical_cast<T>( to_str< char >(100) ), 100, (std::numeric_limits<T>::epsilon()) ); |
89 | #if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) |
90 | BOOST_TEST_CLOSE_FRACTION(lexical_cast<T>( to_str< wchar_t >(100000) ), 100000, (std::numeric_limits<T>::epsilon()) ); |
91 | BOOST_TEST_CLOSE_FRACTION(lexical_cast<T>( to_str< wchar_t >(10000000u) ), 10000000u, (std::numeric_limits<T>::epsilon()) ); |
92 | BOOST_TEST_CLOSE_FRACTION(lexical_cast<T>( to_str< wchar_t >(100) ), 100, (std::numeric_limits<T>::epsilon()) ); |
93 | #endif |
94 | // Exception must not be thrown, when we are using no separators at all |
95 | BOOST_TEST_CLOSE_FRACTION( lexical_cast<T>("30000" ), static_cast<T>(30000), (std::numeric_limits<T>::epsilon()) ); |
96 | } |
97 | } |
98 | |
99 | |
100 | |
101 | |
102 | /* |
103 | * Converts char* [and wchar_t*] to float number type and checks, that generated |
104 | * number does not exceeds allowed epsilon. |
105 | */ |
106 | #ifndef BOOST_LCAST_NO_WCHAR_T |
107 | #define CHECK_CLOSE_ABS_DIFF(VAL,PREFIX) \ |
108 | converted_val = lexical_cast<test_t>(#VAL); \ |
109 | BOOST_TEST_CLOSE_FRACTION( (static_cast<bool>(VAL ## L)? VAL ## L : std::numeric_limits<test_t>::epsilon()), \ |
110 | (converted_val ? converted_val : std::numeric_limits<test_t>::epsilon()), \ |
111 | std::numeric_limits<test_t>::epsilon() \ |
112 | ); \ |
113 | BOOST_TEST_EQ(converted_val, lexical_cast<test_t>(L## #VAL) ); |
114 | |
115 | #else |
116 | #define CHECK_CLOSE_ABS_DIFF(VAL,TYPE) \ |
117 | converted_val = lexical_cast<test_t>(#VAL); \ |
118 | BOOST_TEST_CLOSE_FRACTION( (static_cast<bool>(VAL ## L)? VAL ## L : std::numeric_limits<test_t>::epsilon()), \ |
119 | (converted_val ? converted_val : std::numeric_limits<test_t>::epsilon()), \ |
120 | std::numeric_limits<test_t>::epsilon() \ |
121 | ); |
122 | #endif |
123 | |
124 | template <class TestType> |
125 | void test_converion_to_float_types() |
126 | { |
127 | typedef TestType test_t; |
128 | test_t converted_val; |
129 | |
130 | BOOST_TEST_CLOSE_FRACTION(1.0, lexical_cast<test_t>('1'), (std::numeric_limits<test_t>::epsilon())); |
131 | BOOST_TEST_EQ(0.0, lexical_cast<test_t>('0')); |
132 | |
133 | unsigned char const uc_one = '1'; |
134 | unsigned char const uc_zero ='0'; |
135 | BOOST_TEST_CLOSE_FRACTION(1.0, lexical_cast<test_t>(uc_one), (std::numeric_limits<test_t>::epsilon())); |
136 | BOOST_TEST_EQ(0.0, lexical_cast<test_t>(uc_zero)); |
137 | |
138 | signed char const sc_one = '1'; |
139 | signed char const sc_zero ='0'; |
140 | BOOST_TEST_CLOSE_FRACTION(1.0, lexical_cast<test_t>(sc_one), (std::numeric_limits<test_t>::epsilon())); |
141 | BOOST_TEST_EQ(0.0, lexical_cast<test_t>(sc_zero)); |
142 | |
143 | BOOST_TEST_CLOSE_FRACTION(1e34L, lexical_cast<test_t>( "10000000000000000000000000000000000" ), (std::numeric_limits<test_t>::epsilon() * 1e34L) ); |
144 | |
145 | // VC failes the next test |
146 | // BOOST_TEST_CLOSE_FRACTION(1e-35L, lexical_cast<test_t>("0.00000000000000000000000000000000001"), (std::numeric_limits<test_t>::epsilon()) ); |
147 | BOOST_TEST_CLOSE_FRACTION( |
148 | 0.1111111111111111111111111111111111111111111111111111111111111111111111111L |
149 | , lexical_cast<test_t>("0.1111111111111111111111111111111111111111111111111111111111111111111111111" ) |
150 | , (std::numeric_limits<test_t>::epsilon()) ); |
151 | |
152 | CHECK_CLOSE_ABS_DIFF(1,test_t); |
153 | BOOST_TEST_EQ(0,lexical_cast<test_t>("0" )); |
154 | CHECK_CLOSE_ABS_DIFF(-1,test_t); |
155 | |
156 | CHECK_CLOSE_ABS_DIFF(1.0, test_t); |
157 | CHECK_CLOSE_ABS_DIFF(0.0, test_t); |
158 | CHECK_CLOSE_ABS_DIFF(-1.0,test_t); |
159 | |
160 | CHECK_CLOSE_ABS_DIFF(1e1, test_t); |
161 | CHECK_CLOSE_ABS_DIFF(0e1, test_t); |
162 | CHECK_CLOSE_ABS_DIFF(-1e1,test_t); |
163 | |
164 | CHECK_CLOSE_ABS_DIFF(1.0e1, test_t); |
165 | CHECK_CLOSE_ABS_DIFF(0.0e1, test_t); |
166 | CHECK_CLOSE_ABS_DIFF(-1.0e1,test_t); |
167 | |
168 | CHECK_CLOSE_ABS_DIFF(1e-1, test_t); |
169 | CHECK_CLOSE_ABS_DIFF(0e-1, test_t); |
170 | CHECK_CLOSE_ABS_DIFF(-1e-1,test_t); |
171 | |
172 | CHECK_CLOSE_ABS_DIFF(1.0e-1, test_t); |
173 | CHECK_CLOSE_ABS_DIFF(0.0e-1, test_t); |
174 | CHECK_CLOSE_ABS_DIFF(-1.0e-1,test_t); |
175 | |
176 | CHECK_CLOSE_ABS_DIFF(1E1, test_t); |
177 | CHECK_CLOSE_ABS_DIFF(0E1, test_t); |
178 | CHECK_CLOSE_ABS_DIFF(-1E1,test_t); |
179 | |
180 | CHECK_CLOSE_ABS_DIFF(1.0E1, test_t); |
181 | CHECK_CLOSE_ABS_DIFF(0.0E1, test_t); |
182 | CHECK_CLOSE_ABS_DIFF(-1.0E1,test_t); |
183 | |
184 | CHECK_CLOSE_ABS_DIFF(1E-1, test_t); |
185 | CHECK_CLOSE_ABS_DIFF(0E-1, test_t); |
186 | CHECK_CLOSE_ABS_DIFF(-1E-1,test_t); |
187 | |
188 | CHECK_CLOSE_ABS_DIFF(1.0E-1, test_t); |
189 | CHECK_CLOSE_ABS_DIFF(0.0E-1, test_t); |
190 | CHECK_CLOSE_ABS_DIFF(-1.0E-1, test_t); |
191 | |
192 | CHECK_CLOSE_ABS_DIFF(.0E-1, test_t); |
193 | CHECK_CLOSE_ABS_DIFF(.0E-1, test_t); |
194 | CHECK_CLOSE_ABS_DIFF(-.0E-1, test_t); |
195 | |
196 | CHECK_CLOSE_ABS_DIFF(10.0, test_t); |
197 | CHECK_CLOSE_ABS_DIFF(00.0, test_t); |
198 | CHECK_CLOSE_ABS_DIFF(-10.0,test_t); |
199 | |
200 | CHECK_CLOSE_ABS_DIFF(10e1, test_t); |
201 | CHECK_CLOSE_ABS_DIFF(00e1, test_t); |
202 | CHECK_CLOSE_ABS_DIFF(-10e1,test_t); |
203 | |
204 | CHECK_CLOSE_ABS_DIFF(10.0e1, test_t); |
205 | CHECK_CLOSE_ABS_DIFF(00.0e1, test_t); |
206 | CHECK_CLOSE_ABS_DIFF(-10.0e1,test_t); |
207 | |
208 | CHECK_CLOSE_ABS_DIFF(10e-1, test_t); |
209 | CHECK_CLOSE_ABS_DIFF(00e-1, test_t); |
210 | CHECK_CLOSE_ABS_DIFF(-10e-1,test_t); |
211 | |
212 | CHECK_CLOSE_ABS_DIFF(10.0e-1, test_t); |
213 | CHECK_CLOSE_ABS_DIFF(00.0e-1, test_t); |
214 | CHECK_CLOSE_ABS_DIFF(-10.0e-1,test_t); |
215 | |
216 | CHECK_CLOSE_ABS_DIFF(10E1, test_t); |
217 | CHECK_CLOSE_ABS_DIFF(00E1, test_t); |
218 | CHECK_CLOSE_ABS_DIFF(-10E1,test_t); |
219 | |
220 | CHECK_CLOSE_ABS_DIFF(10.0E1, test_t); |
221 | CHECK_CLOSE_ABS_DIFF(00.0E1, test_t); |
222 | CHECK_CLOSE_ABS_DIFF(-10.0E1,test_t); |
223 | |
224 | CHECK_CLOSE_ABS_DIFF(10E-1, test_t); |
225 | CHECK_CLOSE_ABS_DIFF(00E-1, test_t); |
226 | CHECK_CLOSE_ABS_DIFF(-10E-1,test_t); |
227 | |
228 | CHECK_CLOSE_ABS_DIFF(10.0E-1, test_t); |
229 | CHECK_CLOSE_ABS_DIFF(00.0E-1, test_t); |
230 | CHECK_CLOSE_ABS_DIFF(-10.0E-1, test_t); |
231 | |
232 | CHECK_CLOSE_ABS_DIFF(-10101.0E-011, test_t); |
233 | CHECK_CLOSE_ABS_DIFF(-10101093, test_t); |
234 | CHECK_CLOSE_ABS_DIFF(10101093, test_t); |
235 | |
236 | CHECK_CLOSE_ABS_DIFF(-.34, test_t); |
237 | CHECK_CLOSE_ABS_DIFF(.34, test_t); |
238 | CHECK_CLOSE_ABS_DIFF(.34e10, test_t); |
239 | |
240 | BOOST_TEST_THROWS(lexical_cast<test_t>("-1.e" ), bad_lexical_cast); |
241 | BOOST_TEST_THROWS(lexical_cast<test_t>("-1.E" ), bad_lexical_cast); |
242 | BOOST_TEST_THROWS(lexical_cast<test_t>("1.e" ), bad_lexical_cast); |
243 | BOOST_TEST_THROWS(lexical_cast<test_t>("1.E" ), bad_lexical_cast); |
244 | |
245 | BOOST_TEST_THROWS(lexical_cast<test_t>("1.0e" ), bad_lexical_cast); |
246 | BOOST_TEST_THROWS(lexical_cast<test_t>("1.0E" ), bad_lexical_cast); |
247 | BOOST_TEST_THROWS(lexical_cast<test_t>("10E" ), bad_lexical_cast); |
248 | BOOST_TEST_THROWS(lexical_cast<test_t>("10e" ), bad_lexical_cast); |
249 | BOOST_TEST_THROWS(lexical_cast<test_t>("1.0e-" ), bad_lexical_cast); |
250 | BOOST_TEST_THROWS(lexical_cast<test_t>("1.0E-" ), bad_lexical_cast); |
251 | BOOST_TEST_THROWS(lexical_cast<test_t>("10E-" ), bad_lexical_cast); |
252 | BOOST_TEST_THROWS(lexical_cast<test_t>("10e-" ), bad_lexical_cast); |
253 | BOOST_TEST_THROWS(lexical_cast<test_t>("e1" ), bad_lexical_cast); |
254 | BOOST_TEST_THROWS(lexical_cast<test_t>("e-1" ), bad_lexical_cast); |
255 | BOOST_TEST_THROWS(lexical_cast<test_t>("e-" ), bad_lexical_cast); |
256 | BOOST_TEST_THROWS(lexical_cast<test_t>(".e" ), bad_lexical_cast); |
257 | BOOST_TEST_THROWS(lexical_cast<test_t>(".11111111111111111111111111111111111111111111111111111111111111111111ee" ), bad_lexical_cast); |
258 | BOOST_TEST_THROWS(lexical_cast<test_t>(".11111111111111111111111111111111111111111111111111111111111111111111e-" ), bad_lexical_cast); |
259 | BOOST_TEST_THROWS(lexical_cast<test_t>("." ), bad_lexical_cast); |
260 | |
261 | BOOST_TEST_THROWS(lexical_cast<test_t>("-B" ), bad_lexical_cast); |
262 | |
263 | // Following two tests are not valid for C++11 compilers |
264 | //BOOST_TEST_THROWS(lexical_cast<test_t>("0xB"), bad_lexical_cast); |
265 | //BOOST_TEST_THROWS(lexical_cast<test_t>("0x0"), bad_lexical_cast); |
266 | |
267 | BOOST_TEST_THROWS(lexical_cast<test_t>("--1.0" ), bad_lexical_cast); |
268 | BOOST_TEST_THROWS(lexical_cast<test_t>("1.0e--1" ), bad_lexical_cast); |
269 | BOOST_TEST_THROWS(lexical_cast<test_t>("1.0.0" ), bad_lexical_cast); |
270 | BOOST_TEST_THROWS(lexical_cast<test_t>("1e1e1" ), bad_lexical_cast); |
271 | BOOST_TEST_THROWS(lexical_cast<test_t>("1.0e-1e-1" ), bad_lexical_cast); |
272 | BOOST_TEST_THROWS(lexical_cast<test_t>(" 1.0" ), bad_lexical_cast); |
273 | BOOST_TEST_THROWS(lexical_cast<test_t>("1.0 " ), bad_lexical_cast); |
274 | BOOST_TEST_THROWS(lexical_cast<test_t>("" ), bad_lexical_cast); |
275 | BOOST_TEST_THROWS(lexical_cast<test_t>("-" ), bad_lexical_cast); |
276 | BOOST_TEST_THROWS(lexical_cast<test_t>('\0'), bad_lexical_cast); |
277 | BOOST_TEST_THROWS(lexical_cast<test_t>('-'), bad_lexical_cast); |
278 | BOOST_TEST_THROWS(lexical_cast<test_t>('.'), bad_lexical_cast); |
279 | } |
280 | |
281 | template <class T> |
282 | void test_float_typess_for_overflows() |
283 | { |
284 | typedef T test_t; |
285 | test_t minvalue = (std::numeric_limits<test_t>::min)(); |
286 | std::string s_min_value = lexical_cast<std::string>(minvalue); |
287 | BOOST_TEST_CLOSE_FRACTION(minvalue, lexical_cast<test_t>(minvalue), (std::numeric_limits<test_t>::epsilon())); |
288 | BOOST_TEST_CLOSE_FRACTION(minvalue, lexical_cast<test_t>(s_min_value), (std::numeric_limits<test_t>::epsilon() * 2)); |
289 | |
290 | test_t maxvalue = (std::numeric_limits<test_t>::max)(); |
291 | std::string s_max_value = lexical_cast<std::string>(maxvalue); |
292 | BOOST_TEST_CLOSE_FRACTION(maxvalue, lexical_cast<test_t>(maxvalue), (std::numeric_limits<test_t>::epsilon())); |
293 | BOOST_TEST_CLOSE_FRACTION(maxvalue, lexical_cast<test_t>(s_max_value), (std::numeric_limits<test_t>::epsilon())); |
294 | |
295 | #ifndef _LIBCPP_VERSION |
296 | // libc++ had a bug in implementation of stream conversions for values that must be represented as infinity. |
297 | // http://llvm.org/bugs/show_bug.cgi?id=15723#c4 |
298 | BOOST_TEST_THROWS(lexical_cast<test_t>(s_max_value+"1" ), bad_lexical_cast); |
299 | BOOST_TEST_THROWS(lexical_cast<test_t>(s_max_value+"9" ), bad_lexical_cast); |
300 | |
301 | // VC9 can fail the following tests on floats and doubles when using stingstream... |
302 | BOOST_TEST_THROWS(lexical_cast<test_t>("1" +s_max_value), bad_lexical_cast); |
303 | BOOST_TEST_THROWS(lexical_cast<test_t>("9" +s_max_value), bad_lexical_cast); |
304 | #endif |
305 | |
306 | if ( is_same<test_t,float>::value ) |
307 | { |
308 | BOOST_TEST_THROWS(lexical_cast<test_t>( (std::numeric_limits<double>::max)() ), bad_lexical_cast); |
309 | BOOST_TEST( |
310 | (std::numeric_limits<double>::min)() - std::numeric_limits<test_t>::epsilon() |
311 | <= lexical_cast<test_t>( (std::numeric_limits<double>::min)() ) |
312 | && lexical_cast<test_t>( (std::numeric_limits<double>::min)() ) |
313 | <= (std::numeric_limits<double>::min)() + std::numeric_limits<test_t>::epsilon() |
314 | ); |
315 | |
316 | BOOST_TEST( |
317 | (std::numeric_limits<double>::min)() / 2 - std::numeric_limits<test_t>::epsilon() |
318 | <= lexical_cast<test_t>( (std::numeric_limits<double>::min)() / 2 ) |
319 | && lexical_cast<test_t>( (std::numeric_limits<double>::min)() / 2 ) |
320 | <= (std::numeric_limits<double>::min)() / 2 + std::numeric_limits<test_t>::epsilon() |
321 | ); |
322 | } |
323 | |
324 | if ( sizeof(test_t) < sizeof(long double) ) |
325 | { |
326 | BOOST_TEST_THROWS(lexical_cast<test_t>( (std::numeric_limits<long double>::max)() ), bad_lexical_cast); |
327 | BOOST_TEST( |
328 | (std::numeric_limits<long double>::min)() - std::numeric_limits<test_t>::epsilon() |
329 | <= lexical_cast<test_t>( (std::numeric_limits<long double>::min)() ) |
330 | && lexical_cast<test_t>( (std::numeric_limits<long double>::min)() ) |
331 | <= (std::numeric_limits<long double>::min)() + std::numeric_limits<test_t>::epsilon() |
332 | ); |
333 | |
334 | BOOST_TEST( |
335 | (std::numeric_limits<long double>::min)() / 2 - std::numeric_limits<test_t>::epsilon() |
336 | <= lexical_cast<test_t>( (std::numeric_limits<long double>::min)() / 2 ) |
337 | && lexical_cast<test_t>( (std::numeric_limits<long double>::min)() / 2 ) |
338 | <= (std::numeric_limits<long double>::min)() / 2 + std::numeric_limits<test_t>::epsilon() |
339 | ); |
340 | } |
341 | } |
342 | |
343 | #undef CHECK_CLOSE_ABS_DIFF |
344 | |
345 | // Epsilon is multiplied by 2 because of two lexical conversions |
346 | #define TEST_TO_FROM_CAST_AROUND_TYPED(VAL,STRING_TYPE) \ |
347 | test_value = VAL + std::numeric_limits<test_t>::epsilon() * i ; \ |
348 | converted_val = lexical_cast<test_t>( lexical_cast<STRING_TYPE>(test_value) ); \ |
349 | BOOST_TEST_CLOSE_FRACTION( \ |
350 | test_value, \ |
351 | converted_val, \ |
352 | std::numeric_limits<test_t>::epsilon() * 2 \ |
353 | ); |
354 | |
355 | /* |
356 | * For interval [ from_mult*epsilon+VAL, to_mult*epsilon+VAL ], converts float type |
357 | * numbers to string[wstring] and then back to float type, then compares initial |
358 | * values and generated. |
359 | * Step is epsilon |
360 | */ |
361 | #ifndef BOOST_LCAST_NO_WCHAR_T |
362 | # define TEST_TO_FROM_CAST_AROUND(VAL) \ |
363 | for(i=from_mult; i<=to_mult; ++i) { \ |
364 | TEST_TO_FROM_CAST_AROUND_TYPED(VAL, std::string) \ |
365 | TEST_TO_FROM_CAST_AROUND_TYPED(VAL, std::wstring) \ |
366 | } |
367 | #else |
368 | # define TEST_TO_FROM_CAST_AROUND(VAL) \ |
369 | for(i=from_mult; i<=to_mult; ++i) { \ |
370 | TEST_TO_FROM_CAST_AROUND_TYPED(VAL, std::string) \ |
371 | } |
372 | #endif |
373 | |
374 | template <class TestType> |
375 | void test_converion_from_to_float_types() |
376 | { |
377 | typedef TestType test_t; |
378 | test_t test_value; |
379 | test_t converted_val; |
380 | |
381 | int i; |
382 | int from_mult = -50; |
383 | int to_mult = 50; |
384 | |
385 | TEST_TO_FROM_CAST_AROUND( 0.0 ); |
386 | |
387 | long double val1; |
388 | for(val1 = 1.0e-10L; val1 < 1e11; val1*=10 ) |
389 | TEST_TO_FROM_CAST_AROUND( val1 ); |
390 | |
391 | long double val2; |
392 | for(val2 = -1.0e-10L; val2 > -1e11; val2*=10 ) |
393 | TEST_TO_FROM_CAST_AROUND( val2 ); |
394 | |
395 | from_mult = -100; |
396 | to_mult = 0; |
397 | TEST_TO_FROM_CAST_AROUND( (std::numeric_limits<test_t>::max)() ); |
398 | |
399 | from_mult = 0; |
400 | to_mult = 100; |
401 | TEST_TO_FROM_CAST_AROUND( (std::numeric_limits<test_t>::min)() ); |
402 | } |
403 | |
404 | #undef TEST_TO_FROM_CAST_AROUND |
405 | #undef TEST_TO_FROM_CAST_AROUND_TYPED |
406 | |
407 | |
408 | template<class T, class CharT> |
409 | void test_conversion_from_float_to_char(CharT zero) |
410 | { |
411 | BOOST_TEST(lexical_cast<CharT>(static_cast<T>(0)) == zero + 0); |
412 | BOOST_TEST(lexical_cast<CharT>(static_cast<T>(1)) == zero + 1); |
413 | BOOST_TEST(lexical_cast<CharT>(static_cast<T>(2)) == zero + 2); |
414 | BOOST_TEST(lexical_cast<CharT>(static_cast<T>(3)) == zero + 3); |
415 | BOOST_TEST(lexical_cast<CharT>(static_cast<T>(4)) == zero + 4); |
416 | BOOST_TEST(lexical_cast<CharT>(static_cast<T>(5)) == zero + 5); |
417 | BOOST_TEST(lexical_cast<CharT>(static_cast<T>(6)) == zero + 6); |
418 | BOOST_TEST(lexical_cast<CharT>(static_cast<T>(7)) == zero + 7); |
419 | BOOST_TEST(lexical_cast<CharT>(static_cast<T>(8)) == zero + 8); |
420 | BOOST_TEST(lexical_cast<CharT>(static_cast<T>(9)) == zero + 9); |
421 | |
422 | BOOST_TEST_THROWS(lexical_cast<CharT>(static_cast<T>(10)), bad_lexical_cast); |
423 | |
424 | T t = (std::numeric_limits<T>::max)(); |
425 | BOOST_TEST_THROWS(lexical_cast<CharT>(t), bad_lexical_cast); |
426 | } |
427 | |
428 | template<class T, class CharT> |
429 | void test_conversion_from_char_to_float(CharT zero) |
430 | { |
431 | BOOST_TEST_CLOSE_FRACTION(lexical_cast<T>( static_cast<CharT>(zero + 0)), static_cast<T>(0), (std::numeric_limits<T>::epsilon()) ); |
432 | BOOST_TEST_CLOSE_FRACTION(lexical_cast<T>( static_cast<CharT>(zero + 1)), static_cast<T>(1), (std::numeric_limits<T>::epsilon()) ); |
433 | BOOST_TEST_CLOSE_FRACTION(lexical_cast<T>( static_cast<CharT>(zero + 2)), static_cast<T>(2), (std::numeric_limits<T>::epsilon()) ); |
434 | BOOST_TEST_CLOSE_FRACTION(lexical_cast<T>( static_cast<CharT>(zero + 3)), static_cast<T>(3), (std::numeric_limits<T>::epsilon()) ); |
435 | BOOST_TEST_CLOSE_FRACTION(lexical_cast<T>( static_cast<CharT>(zero + 4)), static_cast<T>(4), (std::numeric_limits<T>::epsilon()) ); |
436 | BOOST_TEST_CLOSE_FRACTION(lexical_cast<T>( static_cast<CharT>(zero + 5)), static_cast<T>(5), (std::numeric_limits<T>::epsilon()) ); |
437 | BOOST_TEST_CLOSE_FRACTION(lexical_cast<T>( static_cast<CharT>(zero + 6)), static_cast<T>(6), (std::numeric_limits<T>::epsilon()) ); |
438 | BOOST_TEST_CLOSE_FRACTION(lexical_cast<T>( static_cast<CharT>(zero + 7)), static_cast<T>(7), (std::numeric_limits<T>::epsilon()) ); |
439 | BOOST_TEST_CLOSE_FRACTION(lexical_cast<T>( static_cast<CharT>(zero + 8)), static_cast<T>(8), (std::numeric_limits<T>::epsilon()) ); |
440 | BOOST_TEST_CLOSE_FRACTION(lexical_cast<T>( static_cast<CharT>(zero + 9)), static_cast<T>(9), (std::numeric_limits<T>::epsilon()) ); |
441 | |
442 | BOOST_TEST_THROWS(lexical_cast<T>( static_cast<CharT>(zero + 10)), bad_lexical_cast); |
443 | BOOST_TEST_THROWS(lexical_cast<T>( static_cast<CharT>(zero - 1)), bad_lexical_cast); |
444 | } |
445 | |
446 | struct restore_oldloc |
447 | { |
448 | std::locale oldloc; |
449 | ~restore_oldloc() { std::locale::global(loc: oldloc); } |
450 | }; |
451 | |
452 | template<class T> |
453 | void test_conversion_from_to_float() |
454 | { char const zero = '0'; |
455 | signed char const szero = '0'; |
456 | unsigned char const uzero = '0'; |
457 | test_conversion_from_float_to_char<T>(zero); |
458 | test_conversion_from_char_to_float<T>(zero); |
459 | test_conversion_from_float_to_char<T>(szero); |
460 | test_conversion_from_char_to_float<T>(szero); |
461 | test_conversion_from_float_to_char<T>(uzero); |
462 | test_conversion_from_char_to_float<T>(uzero); |
463 | #if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) |
464 | wchar_t const wzero = L'0'; |
465 | test_conversion_from_float_to_char<T>(wzero); |
466 | test_conversion_from_char_to_float<T>(wzero); |
467 | #endif |
468 | |
469 | BOOST_TEST_CLOSE_FRACTION(lexical_cast<T>("+1" ), 1, std::numeric_limits<T>::epsilon()); |
470 | BOOST_TEST_CLOSE_FRACTION(lexical_cast<T>("+9" ), 9, std::numeric_limits<T>::epsilon()); |
471 | |
472 | BOOST_TEST_THROWS(lexical_cast<T>("++1" ), bad_lexical_cast); |
473 | BOOST_TEST_THROWS(lexical_cast<T>("-+9" ), bad_lexical_cast); |
474 | BOOST_TEST_THROWS(lexical_cast<T>("--1" ), bad_lexical_cast); |
475 | BOOST_TEST_THROWS(lexical_cast<T>("+-9" ), bad_lexical_cast); |
476 | |
477 | test_converion_to_float_types<T>(); |
478 | test_float_typess_for_overflows<T>(); |
479 | test_converion_from_to_float_types<T>(); |
480 | |
481 | |
482 | typedef std::numpunct<char> numpunct; |
483 | |
484 | restore_oldloc guard; |
485 | std::locale const& oldloc = guard.oldloc; |
486 | |
487 | std::string grouping1 = BOOST_USE_FACET(numpunct, oldloc).grouping(); |
488 | std::string grouping2(grouping1); |
489 | |
490 | test_conversion_from_to_float_for_locale<T>(); |
491 | |
492 | try |
493 | { |
494 | std::locale newloc("" ); |
495 | std::locale::global(loc: newloc); |
496 | |
497 | grouping2 = BOOST_USE_FACET(numpunct, newloc).grouping(); |
498 | } |
499 | catch(std::exception const& ex) |
500 | { |
501 | std::string msg("Failed to set system locale: " ); |
502 | msg += ex.what(); |
503 | std::cerr << msg; |
504 | } |
505 | |
506 | if(grouping1 != grouping2) |
507 | test_conversion_from_to_float_for_locale<T>(); |
508 | |
509 | if(grouping1.empty() && grouping2.empty()) |
510 | std::cerr << "Formatting with thousands_sep has not been tested" ; |
511 | } |
512 | |
513 | |
514 | |
515 | void test_conversion_from_to_float() |
516 | { |
517 | test_conversion_from_to_float<float>(); |
518 | } |
519 | void test_conversion_from_to_double() |
520 | { |
521 | test_conversion_from_to_float<double>(); |
522 | } |
523 | void test_conversion_from_to_long_double() |
524 | { |
525 | // We do not run tests on compilers and Standard Libraries with poor support of long double |
526 | #if !defined(BOOST_LEXICAL_CAST_NO_LONG_DOUBLE_MATH_FUNCTIONS) |
527 | test_conversion_from_to_float<long double>(); |
528 | #endif |
529 | BOOST_TEST(true); |
530 | } |
531 | |
532 | template <class Integral, class Float> |
533 | void test_conversion_integral_float() |
534 | { |
535 | BOOST_TEST_CLOSE_FRACTION(lexical_cast<Float>(static_cast<Float>(1)), static_cast<Float>(1), std::numeric_limits<Float>::epsilon()); |
536 | BOOST_TEST_CLOSE_FRACTION(lexical_cast<Float>(static_cast<Float>(1.1234)), static_cast<Float>(1.1234), std::numeric_limits<Float>::epsilon()); |
537 | BOOST_TEST_CLOSE_FRACTION(lexical_cast<Float>(static_cast<Float>(-1.1234)), static_cast<Float>(-1.1234), std::numeric_limits<Float>::epsilon()); |
538 | |
539 | BOOST_TEST_CLOSE_FRACTION(lexical_cast<Float>(static_cast<Integral>(0)), static_cast<Float>(0), std::numeric_limits<Float>::epsilon()); |
540 | BOOST_TEST_CLOSE_FRACTION(lexical_cast<Float>(static_cast<Integral>(1)), static_cast<Float>(1), std::numeric_limits<Float>::epsilon()); |
541 | |
542 | #ifndef __CYGWIN__ |
543 | BOOST_TEST_CLOSE_FRACTION(lexical_cast<Float>((std::numeric_limits<Integral>::max)()), static_cast<Float>((std::numeric_limits<Integral>::max)()), std::numeric_limits<Float>::epsilon()); |
544 | BOOST_TEST_CLOSE_FRACTION(lexical_cast<Float>((std::numeric_limits<Integral>::min)()), static_cast<Float>((std::numeric_limits<Integral>::min)()), std::numeric_limits<Float>::epsilon()); |
545 | #endif |
546 | |
547 | BOOST_TEST_EQ(lexical_cast<Integral>(static_cast<Float>(0.0)), 0); |
548 | BOOST_TEST_EQ(lexical_cast<Integral>(static_cast<Float>(1.0)), 1); |
549 | BOOST_TEST_EQ(lexical_cast<Integral>(static_cast<Float>(8.0)), 8); |
550 | BOOST_TEST_EQ(lexical_cast<Integral>(static_cast<Float>(16.0)), 16); |
551 | |
552 | if (boost::is_signed<Integral>::value) { |
553 | BOOST_TEST_EQ(lexical_cast<Integral>(static_cast<Float>(-1.0)), -1); |
554 | BOOST_TEST_EQ(lexical_cast<Integral>(static_cast<Float>(-8.0)), -8); |
555 | BOOST_TEST_EQ(lexical_cast<Integral>(static_cast<Float>(-16.0)), -16); |
556 | } else { |
557 | BOOST_TEST_EQ(lexical_cast<Integral>(static_cast<Float>(-1.0)), (std::numeric_limits<Integral>::max)()); |
558 | BOOST_TEST_EQ(lexical_cast<Integral>(static_cast<Float>(-8.0)), (std::numeric_limits<Integral>::max)() - 7); |
559 | BOOST_TEST_EQ(lexical_cast<Integral>(static_cast<Float>(-16.0)), (std::numeric_limits<Integral>::max)() - 15); |
560 | } |
561 | |
562 | BOOST_TEST_THROWS(lexical_cast<Integral>(static_cast<Float>(0.5)), bad_lexical_cast); |
563 | BOOST_TEST_THROWS(lexical_cast<Integral>(static_cast<Float>(-0.5)), bad_lexical_cast); |
564 | BOOST_TEST_THROWS(lexical_cast<Integral>(static_cast<Float>(1.5)), bad_lexical_cast); |
565 | BOOST_TEST_THROWS(lexical_cast<Integral>(static_cast<Float>(-1.5)), bad_lexical_cast); |
566 | |
567 | BOOST_TEST_THROWS(lexical_cast<Integral>((std::numeric_limits<Float>::min)()), bad_lexical_cast); |
568 | BOOST_TEST_THROWS(lexical_cast<Integral>((std::numeric_limits<Float>::max)()), bad_lexical_cast); |
569 | BOOST_TEST_THROWS(lexical_cast<Integral>((std::numeric_limits<Float>::epsilon)()), bad_lexical_cast); |
570 | BOOST_TEST_THROWS(lexical_cast<Integral>((std::numeric_limits<Float>::lowest)()), bad_lexical_cast); |
571 | } |
572 | |
573 | |
574 | int main() |
575 | { |
576 | test_conversion_from_to_float(); |
577 | test_conversion_from_to_double(); |
578 | test_conversion_from_to_long_double(); |
579 | |
580 | test_conversion_integral_float<int, float>(); |
581 | test_conversion_integral_float<int, double>(); |
582 | test_conversion_integral_float<unsigned short, float>(); |
583 | test_conversion_integral_float<unsigned short, double>(); |
584 | test_conversion_integral_float<short, float>(); |
585 | test_conversion_integral_float<short, double>(); |
586 | test_conversion_integral_float<long int, float>(); |
587 | test_conversion_integral_float<long int, double>(); |
588 | test_conversion_integral_float<long long, float>(); |
589 | test_conversion_integral_float<long long, double>(); |
590 | test_conversion_integral_float<unsigned long long, float>(); |
591 | test_conversion_integral_float<unsigned long long, double>(); |
592 | |
593 | return boost::report_errors(); |
594 | } |
595 | |