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