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