1// Boost.Convert test and usage example
2// Copyright (c) 2009-2020 Vladimir Batov.
3// Use, modification and distribution are subject to the Boost Software License,
4// Version 1.0. See http://www.boost.org/LICENSE_1_0.txt.
5
6#include "./test.hpp"
7
8#if !defined(BOOST_CONVERT_CXX14)
9int main(int, char const* []) { return 0; }
10#else
11
12#include <boost/convert.hpp>
13#include <boost/convert/stream.hpp>
14#include <boost/test/tools/floating_point_comparison.hpp>
15#include <cstdio>
16#include <cstdlib>
17#include <stdlib.h>
18
19//[stream_using
20using std::string;
21using std::wstring;
22using boost::convert;
23//]
24//[stream_cnv_namespace_shortcut
25namespace cnv = boost::cnv;
26namespace arg = boost::cnv::parameter;
27//]
28
29static
30void
31test_dbl_to_str()
32{
33 boost::cnv::cstream cnv;
34
35 cnv(std::fixed);
36
37 BOOST_TEST(convert<string>( 99.999, cnv(arg::precision = 2)).value_or("bad") == "100.00");
38 BOOST_TEST(convert<string>( 99.949, cnv(arg::precision = 2)).value_or("bad") == "99.95");
39 BOOST_TEST(convert<string>(-99.949, cnv(arg::precision = 2)).value_or("bad") == "-99.95");
40 BOOST_TEST(convert<string>( 99.949, cnv(arg::precision = 1)).value_or("bad") == "99.9");
41 BOOST_TEST(convert<string>( 0.999, cnv(arg::precision = 2)).value_or("bad") == "1.00");
42 BOOST_TEST(convert<string>( -0.999, cnv(arg::precision = 2)).value_or("bad") == "-1.00");
43 BOOST_TEST(convert<string>( 0.949, cnv(arg::precision = 2)).value_or("bad") == "0.95");
44 BOOST_TEST(convert<string>( -0.949, cnv(arg::precision = 2)).value_or("bad") == "-0.95");
45 BOOST_TEST(convert<string>( 1.949, cnv(arg::precision = 1)).value_or("bad") == "1.9");
46 BOOST_TEST(convert<string>( -1.949, cnv(arg::precision = 1)).value_or("bad") == "-1.9");
47}
48
49static
50void
51test_numbase()
52{
53 //[stream_numbase_example1
54 /*`The following example demonstrates the deployment of `std::dec`, `std::oct` `std::hex`
55 manipulators:
56 */
57 boost::cnv::cstream ccnv;
58
59 BOOST_TEST(convert<int>( "11", ccnv(std::hex)).value_or(0) == 17); // 11(16) = 17(10)
60 BOOST_TEST(convert<int>( "11", ccnv(std::oct)).value_or(0) == 9); // 11(8) = 9(10)
61 BOOST_TEST(convert<int>( "11", ccnv(std::dec)).value_or(0) == 11);
62
63 BOOST_TEST(convert<string>( 18, ccnv(std::hex)).value_or("bad") == "12"); // 18(10) = 12(16)
64 BOOST_TEST(convert<string>( 10, ccnv(std::oct)).value_or("bad") == "12"); // 10(10) = 12(8)
65 BOOST_TEST(convert<string>( 12, ccnv(std::dec)).value_or("bad") == "12");
66 BOOST_TEST(convert<string>(255, ccnv(arg::base = boost::cnv::base::oct)).value_or("bad") == "377");
67 BOOST_TEST(convert<string>(255, ccnv(arg::base = boost::cnv::base::hex)).value_or("bad") == "ff");
68 BOOST_TEST(convert<string>(255, ccnv(arg::base = boost::cnv::base::dec)).value_or("bad") == "255");
69
70 ccnv(std::showbase);
71
72 BOOST_TEST(convert<string>(18, ccnv(std::hex)).value_or("bad") == "0x12");
73 BOOST_TEST(convert<string>(10, ccnv(std::oct)).value_or("bad") == "012");
74
75 ccnv(std::uppercase);
76
77 BOOST_TEST(convert<string>(18, ccnv(std::hex)).value_or("bad") == "0X12");
78 //]
79 //[stream_numbase_example2
80 BOOST_TEST(convert<int>("11", ccnv(arg::base = cnv::base::hex)).value_or(0) == 17);
81 BOOST_TEST(convert<int>("11", ccnv(arg::base = cnv::base::oct)).value_or(0) == 9);
82 BOOST_TEST(convert<int>("11", ccnv(arg::base = cnv::base::dec)).value_or(0) == 11);
83 //]
84 //[wide_stream_numeric_base
85 boost::cnv::wstream wcnv;
86
87 BOOST_TEST(convert<int>(L"11", wcnv(std::hex)).value_or(0) == 17); // 11(16) = 17(10)
88 BOOST_TEST(convert<int>(L"11", wcnv(std::oct)).value_or(0) == 9); // 11(8) = 9(10)
89 BOOST_TEST(convert<int>(L"11", wcnv(std::dec)).value_or(0) == 11);
90
91 BOOST_TEST(convert<wstring>(254, wcnv(arg::base = cnv::base::dec)).value_or(L"bad") == L"254");
92 BOOST_TEST(convert<wstring>(254, wcnv(arg::base = cnv::base::hex)).value_or(L"bad") == L"fe");
93 BOOST_TEST(convert<wstring>(254, wcnv(arg::base = cnv::base::oct)).value_or(L"bad") == L"376");
94 //]
95}
96
97static
98void
99test_boolalpha()
100{
101 boost::cnv::cstream cnv;
102 //[stream_boolalpha_example
103 BOOST_TEST(convert<string>( true, cnv(std::boolalpha)).value_or("bad") == "true");
104 BOOST_TEST(convert<string>(false, cnv(std::boolalpha)).value_or("bad") == "false");
105
106 BOOST_TEST(convert<bool>( "true", cnv(std::boolalpha)).value_or(false) == true);
107 BOOST_TEST(convert<bool>("false", cnv(std::boolalpha)).value_or( true) == false);
108
109 BOOST_TEST(convert<string>( true, cnv(std::noboolalpha)).value_or("bad") == "1");
110 BOOST_TEST(convert<string>(false, cnv(std::noboolalpha)).value_or("bad") == "0");
111
112 BOOST_TEST(convert<bool>("1", cnv(std::noboolalpha)).value_or(false) == true);
113 BOOST_TEST(convert<bool>("0", cnv(std::noboolalpha)).value_or( true) == false);
114 //]
115}
116
117static
118void
119test_skipws_char()
120{
121 //[stream_skipws_example
122 boost::cnv::cstream ccnv;
123 char const* const cstr_good = " 123";
124 char const* const cstr_bad = " 123 "; // std::skipws only affects leading spaces.
125
126 ccnv(std::skipws); // Ignore leading whitespaces
127// ccnv(arg::skipws = true); // Ignore leading whitespaces. Alternative interface
128
129 BOOST_TEST(convert<int>(cstr_good, ccnv).value_or(0) == 123);
130 BOOST_TEST(convert<string>(" 123", ccnv).value_or("bad") == "123");
131
132 BOOST_TEST(!convert<int>(cstr_bad, ccnv));
133
134 ccnv(std::noskipws); // Do not ignore leading whitespaces
135// ccnv(arg::skipws = false); // Do not ignore leading whitespaces. Alternative interface
136
137 // All conversions fail.
138 BOOST_TEST(!convert<int>(cstr_good, ccnv));
139 BOOST_TEST(!convert<int>( cstr_bad, ccnv));
140 //]
141}
142
143static
144void
145test_skipws_wchar()
146{
147 //[wide_stream_skipws
148 boost::cnv::wstream wcnv;
149
150 wcnv(std::noskipws); // Do not ignore leading whitespaces
151
152 BOOST_TEST( convert<int>( L"123", wcnv).value_or(0) == 123);
153 BOOST_TEST(!convert<int>( L" 123", wcnv));
154 BOOST_TEST(!convert<int>(L" 123 ", wcnv));
155
156 wcnv(std::skipws); // Ignore leading whitespaces
157// wcnv(arg::skipws = true); // Ignore leading whitespaces. Alternative interface
158
159 BOOST_TEST( convert<int>( L" 123", wcnv).value_or(0) == 123);
160 BOOST_TEST(!convert<int>(L" 123 ", wcnv));
161 //]
162}
163
164static
165void
166test_width()
167{
168 //[stream_width_example
169 boost::cnv::cstream cnv;
170
171 boost::optional<string> s01 = convert<string>(12, cnv(std::setw(4)));
172 boost::optional<string> s02 = convert<string>(12, cnv(std::setw(5))(std::setfill('*')));
173 boost::optional<string> s03 = convert<string>(12, cnv(std::setw(5))(std::setfill('*'))(std::left));
174
175 BOOST_TEST(s01 && s01.value() == " 12"); // Field width = 4.
176 BOOST_TEST(s02 && s02.value() == "***12"); // Field width = 5, filler = '*'.
177 BOOST_TEST(s03 && s03.value() == "12***"); // Field width = 5, filler = '*', left adjustment
178
179 /*`It needs to be remembered that `boost::cnv::stream` converter uses `std::stream` as its underlying
180 conversion engine. Consequently, formatting-related behavior are driven by the `std::stream`. Namely,
181 after every operation is performed, the ['default field width is restored]. The values of
182 the fill character and the adjustment remain unchanged until they are modified explicitly.
183 */
184
185 // The fill and adjustment remain '*' and 'left'.
186 boost::optional<string> s11 = convert<string>(12, cnv(arg::width = 4));
187 boost::optional<string> s12 = convert<string>(12, cnv(arg::width = 5)
188 (arg::fill = ' ')
189 (arg::adjust = cnv::adjust::right));
190
191 BOOST_TEST(s11 && s11.value() == "12**"); // Field width was set to 4.
192 BOOST_TEST(s12 && s12.value() == " 12"); // Field width was set to 5 with the ' ' filler.
193 //]
194}
195
196static
197void
198test_manipulators()
199{
200 auto ccnv = boost::cnv::cstream();
201 auto wcnv = boost::cnv::wstream();
202
203 int const hex_v01 = boost::convert<int>("FF", ccnv(std::hex)).value_or(0);
204 int const hex_v02 = boost::convert<int>(L"F", wcnv(std::hex)).value_or(0);
205 int const hex_v03 = boost::convert<int>("FF", ccnv(std::dec)).value_or(-5);
206 int const hex_v04 = boost::convert<int>(L"F", wcnv(std::dec)).value_or(-6);
207
208 BOOST_TEST(hex_v01 == 255); // "FF"
209 BOOST_TEST(hex_v02 == 15); // L"F"
210 BOOST_TEST(hex_v03 == -5); // Failed conversion
211 BOOST_TEST(hex_v04 == -6); // Failed conversion
212
213 ccnv(std::noshowbase)(std::nouppercase)(std::oct);
214
215 BOOST_TEST(boost::convert<string>(255, ccnv).value_or("bad") == "377");
216 BOOST_TEST(boost::convert<string>( 15, ccnv).value_or("bad") == "17");
217
218 ccnv(std::showbase);
219
220 BOOST_TEST(boost::convert<string>(255, ccnv).value_or("bad") == "0377");
221 BOOST_TEST(boost::convert<string>( 15, ccnv).value_or("bad") == "017");
222
223 ccnv(std::uppercase)(std::hex);
224
225 BOOST_TEST(boost::convert<string>(255, ccnv).value_or("bad") == "0XFF");
226 BOOST_TEST(boost::convert<string>( 15, ccnv).value_or("bad") == "0XF");
227
228 ccnv(std::noshowbase)(std::nouppercase)(std::oct);
229
230 BOOST_TEST(boost::convert<string>(255, ccnv).value_or("bad") == "377");
231 BOOST_TEST(boost::convert<string>( 15, ccnv).value_or("bad") == "17");
232
233 ccnv(std::showbase)(arg::uppercase = true)(arg::base = cnv::base::hex);
234
235 BOOST_TEST(boost::convert<string>(255, ccnv).value_or("bad") == "0XFF");
236 BOOST_TEST(boost::convert<string>( 15, ccnv).value_or("bad") == "0XF");
237}
238
239void
240test_locale_example()
241{
242 //[stream_locale_example1
243 boost::cnv::cstream cnv;
244 std::locale rus_locale;
245 std::locale eng_locale;
246
247 char const* eng_locale_name = test::cnv::is_msc ? "English_United States.1251" : "en_US.UTF-8";
248 char const* rus_locale_name = test::cnv::is_msc ? "Russian_Russia.1251" : "ru_RU.UTF-8";
249 char const* rus_expected = test::cnv::is_msc ? "1,235e-002" : "1,235e-02";
250 char const* eng_expected = test::cnv::is_msc ? "1.235e-002" : "1.235e-02";
251 char const* dbl_expected = test::cnv::is_msc ? "1.2345E-002" : "1.2345E-02";
252
253// cnv(std::setprecision(4))(std::uppercase)(std::scientific);
254 cnv(arg::precision = 4)
255 (arg::uppercase = true)
256 (arg::notation = cnv::notation::scientific);
257
258 double double_v01 = convert<double>(dbl_expected, cnv).value_or(0);
259 string double_s02 = convert<string>(double_v01, cnv).value_or("bad");
260
261 BOOST_TEST(dbl_expected == double_s02);
262
263 try { rus_locale = std::locale(rus_locale_name); }
264 catch (...) { printf("Bad locale %s.\n", rus_locale_name); exit(1); }
265
266 try { eng_locale = std::locale(eng_locale_name); }
267 catch (...) { printf("Bad locale %s.\n", eng_locale_name); exit(1); }
268
269// cnv(std::setprecision(3))(std::nouppercase);
270 cnv(arg::precision = 3)(arg::uppercase = false);
271
272 string double_rus = convert<string>(double_v01, cnv(rus_locale)).value_or("bad double_rus");
273 string double_eng = convert<string>(double_v01, cnv(eng_locale)).value_or("bad double_eng");
274
275 BOOST_TEST(double_rus == rus_expected);
276 BOOST_TEST(double_eng == eng_expected);
277 //]
278}
279
280void
281test_locale(double v, boost::cnv::cstream const& cnv, char const* expected)
282{
283 boost::optional<string> res = convert<string>(v, cnv);
284 std::string str = res ? *res : "conversion failed";
285
286 BOOST_TEST(res);
287 BOOST_TEST(str == expected);
288
289 if (str != expected)
290 printf("%s [%d]: result=<%s>, expected=<%s>\n", __FILE__, __LINE__, str.c_str(), expected);
291}
292
293static
294void
295test_locale()
296{
297 boost::cnv::cstream cnv;
298 std::locale rus_locale;
299 std::locale eng_locale;
300 bool eng_ignore = false;
301 bool rus_ignore = false;
302 char const* eng_locale_name = test::cnv::is_msc ? "English_United States.1251" : "en_US.UTF-8";
303 char const* rus_locale_name = test::cnv::is_msc ? "Russian_Russia.1251" : "ru_RU.UTF-8";
304 char const* eng_expected = test::cnv::is_old_msc ? "1.235e-002" : "1.235e-02";
305 char const* rus_expected = test::cnv::is_old_msc ? "1,235e-002" : "1,235e-02";
306 char const* dbl_expected = test::cnv::is_old_msc ? "1.2345E-002" : "1.2345E-02";
307
308 cnv(arg::precision = 4)
309 (arg::uppercase = true)
310 (arg::notation = cnv::notation::scientific);
311
312 double const double_v01 = convert<double>(dbl_expected, cnv).value_or(0);
313 string const double_s02 = convert<string>(double_v01, cnv).value_or("bad");
314
315 BOOST_TEST(double_v01 != 0);
316 BOOST_TEST(dbl_expected == double_s02);
317
318 if (dbl_expected != double_s02)
319 printf("%s [%d]: <%s> != <%s>\n", __FILE__, __LINE__, dbl_expected, double_s02.c_str());
320
321 try { eng_locale = std::locale(eng_locale_name); }
322 catch (...) { printf("Bad locale %s. Ignored.\n", eng_locale_name); eng_ignore = true; }
323
324 try { rus_locale = std::locale(rus_locale_name); }
325 catch (...) { printf("Bad locale %s. Ignored.\n", rus_locale_name); rus_ignore = true; }
326
327// cnv(std::setprecision(3))(std::nouppercase);
328 cnv(arg::precision = 3)(arg::uppercase = false);
329
330 if (!eng_ignore) test_locale(double_v01, cnv(eng_locale), eng_expected);
331 if (!rus_ignore) test_locale(double_v01, cnv(rus_locale), rus_expected);
332}
333
334static
335void
336test_user_str()
337{
338 //[stream_my_string
339 boost::cnv::cstream cnv;
340 my_string my_str("123");
341
342 cnv(std::setprecision(2))(std::fixed);
343
344 BOOST_TEST(convert<int>(my_str, cnv).value_or(0) == 123);
345
346 BOOST_TEST(convert<my_string>( 99.999, cnv).value_or("bad") == "100.00");
347 BOOST_TEST(convert<my_string>( 99.949, cnv).value_or("bad") == "99.95");
348 BOOST_TEST(convert<my_string>(-99.949, cnv).value_or("bad") == "-99.95");
349 //]
350}
351
352static
353void
354test_notation()
355{
356 //[stream_notation
357 boost::cnv::cstream cnv;
358
359 BOOST_TEST( "-3.14159" == convert<string>(-3.14159, cnv(arg::notation = cnv::notation::fixed)(arg::precision = 5)).value());
360 BOOST_TEST("-3.142e+00" == convert<string>(-3.14159, cnv(arg::notation = cnv::notation::scientific)(arg::precision = 3)).value());
361
362 // precision doesn't affect hexfloat
363 BOOST_TEST("-0x1.921f9f01b866ep+1" == convert<string>(-3.14159, cnv(arg::notation = cnv::notation::hex)).value());
364
365 const auto close = boost::math::fpc::close_at_tolerance<double>(1);
366
367 BOOST_TEST_WITH(-3.14159, convert<double>("-3.14159", cnv(arg::notation = cnv::notation::fixed)).value(), close);
368 BOOST_TEST_WITH(-3.14159, convert<double>("-3.142e+00", cnv(arg::notation = cnv::notation::scientific)).value(), close);
369 // not supported due to https://gcc.gnu.org/bugzilla//show_bug.cgi?id=81122
370 // BOOST_TEST_WITH(-3.14159, convert<double>("-0x1.921f9f01b866ep+1", cnv(arg::notation = cnv::notation::hex)).value(), close);
371 //]
372}
373
374int
375main(int, char const* [])
376{
377 try
378 {
379 // QNX fails to handle std::skipws for wchat_t.
380 // Excluding from tests so that I do not have to stare on the yellow box (regression failure)
381 /*********************/ test_skipws_char();
382 if (!test::cnv::is_qnx) test_skipws_wchar();
383
384 test_numbase();
385 test_boolalpha();
386 test_width();
387 test_manipulators();
388 test_locale();
389 test_dbl_to_str();
390 test_user_str();
391 test_notation();
392 }
393 catch(boost::bad_optional_access const&)
394 {
395 BOOST_TEST(!"Caught boost::bad_optional_access exception");
396 }
397 catch(...)
398 {
399 BOOST_TEST(!"Caught an unknown exception");
400 }
401 return boost::report_errors();
402}
403
404#endif
405

source code of boost/libs/convert/test/stream_converter.cpp