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/info.hpp>
11#include <boost/locale/localization_backend.hpp>
12#include <boost/core/ignore_unused.hpp>
13#include <ctime>
14#include <iomanip>
15#include <iostream>
16#include <utility>
17#ifndef BOOST_LOCALE_NO_WINAPI_BACKEND
18# ifndef NOMINMAX
19# define NOMINMAX
20# endif
21# include <windows.h>
22#endif
23#include "../src/boost/locale/win32/lcid.hpp"
24#include "boostLocale/test/tools.hpp"
25#include "boostLocale/test/unit_test.hpp"
26
27template<typename CharType>
28void test_by_char(const std::locale& l, std::string name, int lcid)
29{
30 typedef std::basic_stringstream<CharType> ss_type;
31
32 using namespace boost::locale;
33
34 {
35 std::cout << "--- Testing as::posix" << std::endl;
36 ss_type ss;
37 ss.imbue(l);
38
39 TEST(ss << 1045.45);
40 double n;
41 TEST(ss >> n);
42 TEST_EQ(n, 1045.45);
43 TEST_EQ(to_utf8(ss.str()), "1045.45");
44 }
45
46 {
47 std::cout << "--- Testing as::number" << std::endl;
48 ss_type ss;
49 ss.imbue(l);
50
51 ss << as::number;
52 TEST(ss << 1045.45);
53 double n;
54 TEST(ss >> n);
55 TEST_EQ(n, 1045.45);
56
57 if(name == "ru_RU.UTF-8") {
58 BOOST_LOCALE_START_CONST_CONDITION
59 if(sizeof(CharType) == 1) // Space
60 TEST_EQ(to_utf8(ss.str()), "1 045,45");
61 else // Non-breaking space
62 TEST_EQ(to_utf8(ss.str()),
63 "1\xC2\xA0"
64 "045,45");
65 BOOST_LOCALE_END_CONST_CONDITION
66 } else
67 TEST_EQ(to_utf8(ss.str()), "1,045.45");
68 }
69
70 {
71 std::cout << "--- Testing as::currency " << std::endl;
72
73 ss_type ss;
74 ss.imbue(l);
75
76 ss << as::currency;
77 TEST(ss << 1043.34);
78
79#ifndef BOOST_LOCALE_NO_WINAPI_BACKEND
80 wchar_t buf[256];
81 GetCurrencyFormatW(lcid, 0, L"1043.34", nullptr, buf, 256);
82 TEST_EQ(to_utf8(ss.str()), to_utf8<wchar_t>(buf));
83#else
84 boost::ignore_unused(lcid);
85#endif
86 }
87
88 {
89 std::cout << "--- Testing as::date/time" << std::endl;
90
91 const time_t a_date = 3600 * 24 * (31 + 4); // Feb 5th
92 const time_t a_time = 3600 * 15 + 60 * 33 + 13; // 15:33:13
93 const time_t a_datetime = a_date + a_time;
94
95 wchar_t time_buf[256]{};
96 wchar_t date_buf[256]{};
97#ifndef BOOST_LOCALE_NO_WINAPI_BACKEND
98 SYSTEMTIME st = {1970, 2, 5, 5, 15, 33, 13, 0};
99 GetTimeFormatW(lcid, 0, &st, nullptr, time_buf, 256);
100 GetDateFormatW(lcid, 0, &st, nullptr, date_buf, 256);
101#else
102 if(!time_buf[0])
103 return;
104#endif
105 const std::string expDate = to_utf8(utf_string: std::wstring(date_buf));
106 const std::string expTime = to_utf8(utf_string: std::wstring(time_buf));
107
108 ss_type ss;
109 ss.imbue(l);
110
111 ss << as::time_zone(id: "GMT");
112
113 empty_stream(ss) << as::date << a_datetime;
114 TEST_EQ(to_utf8(ss.str()), expDate);
115 empty_stream(ss) << as::time << a_datetime;
116 TEST_EQ(to_utf8(ss.str()), expTime);
117 empty_stream(ss) << as::datetime << a_datetime;
118 TEST_EQ(to_utf8(ss.str()), expDate + " " + expTime);
119 empty_stream(ss) << as::time_zone(id: "GMT+01:00") << as::ftime(ascii_to<CharType>("%H")) << a_datetime;
120 TEST_EQ(to_utf8(ss.str()), "16");
121 empty_stream(ss) << as::time_zone(id: "GMT+00:15") << as::ftime(ascii_to<CharType>("%M")) << a_datetime;
122 TEST_EQ(to_utf8(ss.str()), "48");
123 }
124}
125
126void test_date_time(const std::locale& l) // LCOV_EXCL_LINE
127{
128 std::ostringstream ss;
129 ss.imbue(loc: l);
130
131 ss << boost::locale::as::time_zone(id: "GMT");
132
133 time_t a_date = 3600 * 24 * (31 + 4); // Feb 5th
134 time_t a_time = 3600 * 15 + 60 * 33; // 15:33:13
135 time_t a_timesec = 13;
136 time_t a_datetime = a_date + a_time + a_timesec;
137
138 const std::pair<std::string, std::string> testCases[] = {
139 {"a", "Thu"}, {"A", "Thursday"}, {"b", "Feb"}, {"B", "February"}, {"d", "05"},
140 {"D", "02/05/70"}, {"e", "5"}, {"h", "Feb"}, {"H", "15"}, {"I", "03"},
141 {"m", "02"}, {"M", "33"}, {"n", "\n"}, {"p", "PM"}, {"r", "03:33:13 PM"},
142 {"R", "15:33"}, {"S", "13"}, {"t", "\t"}, {"y", "70"}, {"Y", "1970"},
143 {"%", "%"}};
144
145 for(const auto& patternAndResult : testCases) {
146 empty_stream(s&: ss) << boost::locale::as::ftime(format: "%" + patternAndResult.first) << a_datetime;
147 TEST_EQ(ss.str(), patternAndResult.second);
148 }
149} // LCOV_EXCL_LINE
150
151BOOST_LOCALE_DISABLE_UNREACHABLE_CODE_WARNING
152void test_main(int /*argc*/, char** /*argv*/)
153{
154#ifdef BOOST_LOCALE_NO_WINAPI_BACKEND
155 std::cout << "WinAPI Backend is not build... Skipping\n";
156 return;
157#endif
158 boost::locale::localization_backend_manager mgr = boost::locale::localization_backend_manager::global();
159 mgr.select(backend_name: "winapi");
160 boost::locale::localization_backend_manager::global(mgr);
161 boost::locale::generator gen;
162
163 for(const auto& name_lcid : {std::make_pair(x: "en_US.UTF-8", y: 0x0409),
164 std::make_pair(x: "he_IL.UTF-8", y: 0x040D),
165 std::make_pair(x: "ru_RU.UTF-8", y: 0x0419)})
166 {
167 const std::string name = name_lcid.first;
168 std::cout << "- " << name << " locale" << std::endl;
169 if(!has_win_locale(locale_name: name))
170 std::cout << "-- not supported, skipping" << std::endl; // LCOV_EXCL_LINE
171 else {
172 const std::locale l = gen(name);
173 std::cout << "-- UTF-8" << std::endl;
174 test_by_char<char>(l, name, lcid: name_lcid.second);
175 std::cout << "-- UTF-16" << std::endl;
176 test_by_char<wchar_t>(l, name, lcid: name_lcid.second);
177 }
178 }
179 std::cout << "- Testing strftime" << std::endl;
180 test_date_time(l: gen("en_US.UTF-8"));
181}
182
183// boostinspect:noascii
184

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