1//
2// Copyright (c) 2009-2011 Artyom Beilis (Tonkikh)
3//
4// Distributed under the Boost Software License, Version 1.0.
5// https://www.boost.org/LICENSE_1_0.txt
6
7#include <boost/locale/encoding.hpp>
8#include <boost/locale/formatting.hpp>
9#include <boost/locale/generator.hpp>
10#include <boost/locale/localization_backend.hpp>
11#include <ctime>
12#include <iomanip>
13#include <iostream>
14
15#include "boostLocale/test/tools.hpp"
16#include "boostLocale/test/unit_test.hpp"
17
18template<typename CharType, typename RefCharType>
19void test_by_char(const std::locale& l, const std::locale& lreal)
20{
21 typedef std::basic_stringstream<CharType> ss_type;
22 typedef std::basic_stringstream<RefCharType> ss_ref_type;
23
24 using namespace boost::locale;
25
26 {
27 std::cout << "- Testing as::posix" << std::endl;
28 ss_type ss;
29 ss.imbue(l);
30
31 TEST(ss << 1045.45);
32 double n;
33 TEST(ss >> n);
34 TEST_EQ(n, 1045.45);
35 TEST_EQ(ss.str(), ascii_to<CharType>("1045.45"));
36 ss_ref_type ss_ref;
37 ss_ref.imbue(std::locale::classic());
38 empty_stream(ss) << std::setw(8) << 1 << CharType(':') << 2 << CharType(':') << 1234 << CharType(':')
39 << std::setw(8) << std::setfill(CharType('0')) << std::hex << 1234;
40 ss_ref << std::setw(8) << 1 << RefCharType(':') << 2 << RefCharType(':') << 1234 << RefCharType(':')
41 << std::setw(8) << std::setfill(RefCharType('0')) << std::hex << 1234;
42 TEST_EQ(to_utf8(ss.str()), to_utf8(ss_ref.str()));
43 }
44
45 {
46 std::cout << "- Testing as::number" << std::endl;
47 ss_type ss;
48 ss.imbue(l);
49
50 TEST(ss << as::number);
51 TEST(ss << 1045.45);
52 double n;
53 TEST(ss >> n);
54 TEST_EQ(n, 1045.45);
55
56 ss_ref_type ss_ref;
57 ss_ref.imbue(lreal);
58
59 TEST(ss_ref << 1045.45);
60
61 TEST_EQ(to_utf8(ss.str()), to_utf8(ss_ref.str()));
62 }
63
64 {
65 std::cout << "- Testing as::currency national " << std::endl;
66
67 bool bad_parsing = false;
68 ss_ref_type ss_ref;
69 ss_ref.imbue(lreal);
70 ss_ref << std::showbase;
71 std::use_facet<std::money_put<RefCharType>>(lreal).put(ss_ref, false, ss_ref, RefCharType(' '), 104334);
72 { // workaround MSVC library issues
73 std::ios_base::iostate err = std::ios_base::iostate();
74 typename std::money_get<RefCharType>::iter_type end;
75 long double tmp;
76 std::use_facet<std::money_get<RefCharType>>(lreal).get(ss_ref, end, false, ss_ref, err, tmp);
77 if(err & std::ios_base::failbit) {
78 std::cout << "-- Looks like standard library does not support parsing well" << std::endl;
79 bad_parsing = true;
80 }
81 }
82
83 ss_type ss;
84 ss.imbue(l);
85
86 TEST(ss << as::currency);
87 TEST(ss << 1043.34);
88 if(!bad_parsing) {
89 double v1;
90 TEST(ss >> v1);
91 TEST_EQ(v1, 1043.34);
92 }
93
94 TEST_EQ(to_utf8(ss.str()), to_utf8(ss_ref.str()));
95 }
96
97 {
98 std::cout << "- Testing as::currency iso" << std::endl;
99 ss_type ss;
100 ss.imbue(l);
101
102 ss << as::currency << as::currency_iso;
103 TEST(ss << 1043.34);
104 double v1;
105 TEST(ss >> v1);
106 TEST_EQ(v1, 1043.34);
107
108 ss_ref_type ss_ref;
109 ss_ref.imbue(lreal);
110 ss_ref << std::showbase;
111 std::use_facet<std::money_put<RefCharType>>(lreal).put(ss_ref, true, ss_ref, RefCharType(' '), 104334);
112
113 TEST_EQ(to_utf8(ss.str()), to_utf8(ss_ref.str()));
114 }
115
116 {
117 std::cout << "- Testing as::date/time" << std::endl;
118
119 const time_t a_date = 3600 * 24 * (31 + 4); // Feb 5th
120 const time_t a_time = 3600 * 15 + 60 * 33 + 13; // 15:33:13
121 const time_t a_datetime = a_date + a_time;
122
123 const std::tm tm = *gmtime_wrap(time: &a_datetime);
124 ss_ref_type ss_ref;
125 ss_ref.imbue(lreal);
126 empty_stream(ss_ref) << std::put_time(&tm, ascii_to<RefCharType>("%x").c_str());
127 const std::string expDate = to_utf8(ss_ref.str());
128 empty_stream(ss_ref) << std::put_time(&tm, ascii_to<RefCharType>("%X").c_str());
129 const std::string expTime = to_utf8(ss_ref.str());
130 empty_stream(ss_ref) << std::put_time(&tm, ascii_to<RefCharType>("%c").c_str());
131 const std::string expDateTime = to_utf8(ss_ref.str());
132
133 if(expDateTime == "%c") {
134 std::cout << "-- Standard library failed to format the datetime value" << std::endl; // LCOV_EXCL_LINE
135 } else {
136 ss_type ss;
137 ss.imbue(l);
138 ss << as::time_zone(id: "GMT");
139
140 empty_stream(ss) << as::date << a_datetime;
141 TEST_EQ(to_utf8(ss.str()), expDate);
142 empty_stream(ss) << as::time << a_datetime;
143 TEST_EQ(to_utf8(ss.str()), expTime);
144 empty_stream(ss) << as::datetime << a_datetime;
145 TEST_EQ(to_utf8(ss.str()), expDateTime);
146 empty_stream(ss) << as::time_zone(id: "GMT+01:00") << as::ftime(ascii_to<CharType>("%H")) << a_datetime;
147 TEST_EQ(to_utf8(ss.str()), "16");
148 empty_stream(ss) << as::time_zone(id: "GMT+00:15") << as::ftime(ascii_to<CharType>("%M")) << a_datetime;
149 TEST_EQ(to_utf8(ss.str()), "48");
150 }
151 }
152}
153
154BOOST_LOCALE_DISABLE_UNREACHABLE_CODE_WARNING
155void test_main(int /*argc*/, char** /*argv*/)
156{
157#ifdef BOOST_LOCALE_NO_STD_BACKEND
158 std::cout << "STD Backend is not build... Skipping\n";
159 return;
160#endif
161
162 boost::locale::localization_backend_manager mgr = boost::locale::localization_backend_manager::global();
163 mgr.select(backend_name: "std");
164 boost::locale::localization_backend_manager::global(mgr);
165 boost::locale::generator gen;
166 for(const std::string lName : {"en_US.UTF-8", "en_US.ISO8859-1", "he_IL.UTF-8", "he_IL.ISO8859-8"}) {
167 std::cout << lName << " locale" << std::endl;
168 std::string real_name;
169 std::string name = get_std_name(name: lName, real_name: &real_name);
170 if(name.empty())
171 std::cout << lName << " not supported" << std::endl; // LCOV_EXCL_LINE
172 else {
173 std::cout << "\tstd name: " << name << std::endl;
174 std::locale l1 = gen(name);
175 std::cout << "\treal name: " << real_name << std::endl;
176 std::locale l2(real_name);
177 if(lName.find(s: ".UTF-8") != std::string::npos) {
178 std::cout << "\tUTF-8" << std::endl;
179 if(name == real_name)
180 test_by_char<char, char>(l: l1, lreal: l2);
181 else
182 test_by_char<char, wchar_t>(l: l1, lreal: l2); // LCOV_EXCL_LINE
183 } else {
184 std::cout << "\tchar" << std::endl;
185 test_by_char<char, char>(l: l1, lreal: l2);
186 }
187
188 std::cout << "\tWide UTF-" << sizeof(wchar_t) * 8 << std::endl;
189 test_by_char<wchar_t, wchar_t>(l: l1, lreal: l2);
190
191#ifdef BOOST_LOCALE_ENABLE_CHAR16_T
192 std::cout << "\tchar16_t" << std::endl;
193 test_by_char<char16_t, char16_t>(l1, l2);
194#endif
195#ifdef BOOST_LOCALE_ENABLE_CHAR32_T
196 std::cout << "\tchar32_t" << std::endl;
197 test_by_char<char32_t, char32_t>(l1, l2);
198#endif
199 }
200 }
201 {
202 std::cout << "Testing UTF-8 punct workaround" << std::endl;
203 std::string real_name;
204 std::string name = get_std_name(name: "ru_RU.UTF-8", real_name: &real_name);
205 if(name.empty())
206 std::cout << "- No Russian locale" << std::endl; // LCOV_EXCL_LINE
207 else if(name != real_name)
208 std::cout << "- No Russian UTF-8 locale, no need for workaround" << std::endl; // LCOV_EXCL_LINE
209 else {
210 std::locale l1 = gen(name), l2(real_name);
211 bool fails = false;
212 try {
213 std::ostringstream ss;
214 ss.imbue(loc: l2);
215 ss << 12345.45;
216 boost::locale::conv::from_utf<char>(text: ss.str(), charset: "windows-1251", how: boost::locale::conv::stop);
217 fails = false;
218 } catch(...) {
219 fails = true;
220 }
221
222 if(!fails)
223 std::cout << "- No invalid UTF. No need to check" << std::endl;
224 else {
225 std::ostringstream ss;
226 ss.imbue(loc: l1);
227 ss << std::setprecision(10);
228 ss << boost::locale::as::number << 12345.45;
229 TEST(ss.str() == "12 345,45" || ss.str() == "12345,45");
230 }
231 }
232 }
233}
234
235// boostinspect:noascii
236

source code of boost/libs/locale/test/test_std_formatting.cpp