1 | //===----------------------------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | // TODO(mordante) Investigate |
10 | // UNSUPPORTED: apple-clang |
11 | |
12 | // UNSUPPORTED: c++03, c++11, c++14, c++17 |
13 | // UNSUPPORTED: no-localization |
14 | // UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME |
15 | |
16 | // TODO FMT This test should not require std::to_chars(floating-point) |
17 | // XFAIL: availability-fp_to_chars-missing |
18 | |
19 | // REQUIRES: locale.fr_FR.UTF-8 |
20 | // REQUIRES: locale.ja_JP.UTF-8 |
21 | |
22 | // ADDITIONAL_COMPILE_FLAGS: -DFR_THOU_SEP=%{LOCALE_CONV_FR_FR_UTF_8_THOUSANDS_SEP} |
23 | // ADDITIONAL_COMPILE_FLAGS: -DFR_DEC_POINT=%{LOCALE_CONV_FR_FR_UTF_8_DECIMAL_POINT} |
24 | |
25 | // <chrono> |
26 | |
27 | // template<class Rep, class Period = ratio<1>> class duration; |
28 | |
29 | // template<class charT, class traits, class Rep, class Period> |
30 | // basic_ostream<charT, traits>& |
31 | // operator<<(basic_ostream<charT, traits>& os, |
32 | // const duration<Rep, Period>& d); |
33 | |
34 | #include <chrono> |
35 | |
36 | #include <cassert> |
37 | #include <concepts> |
38 | #include <ratio> |
39 | #include <sstream> |
40 | |
41 | #include "make_string.h" |
42 | #include "locale_helpers.h" |
43 | #include "platform_support.h" // locale name macros |
44 | #include "test_macros.h" |
45 | |
46 | #define SV(S) MAKE_STRING_VIEW(CharT, S) |
47 | |
48 | template <class CharT, class Rep, class Period> |
49 | static std::basic_string<CharT> stream_c_locale(std::chrono::duration<Rep, Period> duration) { |
50 | std::basic_stringstream<CharT> sstr; |
51 | sstr.precision(4); |
52 | sstr << std::fixed << duration; |
53 | return sstr.str(); |
54 | } |
55 | |
56 | template <class CharT, class Rep, class Period> |
57 | static std::basic_string<CharT> stream_fr_FR_locale(std::chrono::duration<Rep, Period> duration) { |
58 | std::basic_stringstream<CharT> sstr; |
59 | const std::locale locale(LOCALE_fr_FR_UTF_8); |
60 | sstr.imbue(locale); |
61 | sstr.precision(4); |
62 | sstr << std::fixed << duration; |
63 | return sstr.str(); |
64 | } |
65 | |
66 | template <class CharT, class Rep, class Period> |
67 | static std::basic_string<CharT> stream_ja_JP_locale(std::chrono::duration<Rep, Period> duration) { |
68 | std::basic_stringstream<CharT> sstr; |
69 | const std::locale locale(LOCALE_ja_JP_UTF_8); |
70 | sstr.imbue(locale); |
71 | sstr.precision(4); |
72 | sstr << std::fixed << duration; |
73 | return sstr.str(); |
74 | } |
75 | |
76 | template <class CharT> |
77 | static void test_values() { |
78 | using namespace std::literals::chrono_literals; |
79 | |
80 | assert(stream_c_locale<CharT>(-1'000'000s) == SV("-1000000s" )); |
81 | assert(stream_c_locale<CharT>(1'000'000s) == SV("1000000s" )); |
82 | assert(stream_c_locale<CharT>(-1'000.123456s) == SV("-1000.1235s" )); |
83 | assert(stream_c_locale<CharT>(1'000.123456s) == SV("1000.1235s" )); |
84 | |
85 | if constexpr (std::same_as<CharT, char>) { |
86 | #if defined(__APPLE__) |
87 | assert(stream_fr_FR_locale<CharT>(-1'000'000s) == SV("-1000000s" )); |
88 | assert(stream_fr_FR_locale<CharT>(1'000'000s) == SV("1000000s" )); |
89 | assert(stream_fr_FR_locale<CharT>(-1'000.123456s) == SV("-1000,1235s" )); |
90 | assert(stream_fr_FR_locale<CharT>(1'000.123456s) == SV("1000,1235s" )); |
91 | #else |
92 | assert(stream_fr_FR_locale<CharT>(-1'000'000s) == SV("-1 000 000s" )); |
93 | assert(stream_fr_FR_locale<CharT>(1'000'000s) == SV("1 000 000s" )); |
94 | assert(stream_fr_FR_locale<CharT>(-1'000.123456s) == SV("-1 000,1235s" )); |
95 | assert(stream_fr_FR_locale<CharT>(1'000.123456s) == SV("1 000,1235s" )); |
96 | #endif |
97 | } else { |
98 | #ifndef TEST_HAS_NO_WIDE_CHARACTERS |
99 | assert(stream_fr_FR_locale<CharT>(-1'000'000s) == L"-1" FR_THOU_SEP "000" FR_THOU_SEP "000s" ); |
100 | assert(stream_fr_FR_locale<CharT>(1'000'000s) == L"1" FR_THOU_SEP "000" FR_THOU_SEP "000s" ); |
101 | assert(stream_fr_FR_locale<CharT>(-1'000.123456s) == L"-1" FR_THOU_SEP "000" FR_DEC_POINT "1235s" ); |
102 | assert(stream_fr_FR_locale<CharT>(1'000.123456s) == L"1" FR_THOU_SEP "000" FR_DEC_POINT "1235s" ); |
103 | #endif |
104 | } |
105 | |
106 | assert(stream_ja_JP_locale<CharT>(-1'000'000s) == SV("-1,000,000s" )); |
107 | assert(stream_ja_JP_locale<CharT>(1'000'000s) == SV("1,000,000s" )); |
108 | assert(stream_ja_JP_locale<CharT>(-1'000.123456s) == SV("-1,000.1235s" )); |
109 | assert(stream_ja_JP_locale<CharT>(1'000.123456s) == SV("1,000.1235s" )); |
110 | } |
111 | |
112 | template <class CharT> |
113 | static void test_units() { |
114 | using namespace std::literals::chrono_literals; |
115 | |
116 | // C locale |
117 | assert(stream_c_locale<CharT>(std::chrono::duration<int, std::atto>(0)) == SV("0as" )); |
118 | assert(stream_c_locale<CharT>(std::chrono::duration<int, std::femto>(0)) == SV("0fs" )); |
119 | assert(stream_c_locale<CharT>(std::chrono::duration<int, std::pico>(0)) == SV("0ps" )); |
120 | assert(stream_c_locale<CharT>(0ns) == SV("0ns" )); |
121 | #ifndef TEST_HAS_NO_UNICODE |
122 | assert(stream_c_locale<CharT>(0us) == SV("0\u00b5s" )); |
123 | #else |
124 | assert(stream_c_locale<CharT>(0us) == SV("0us" )); |
125 | #endif |
126 | assert(stream_c_locale<CharT>(0ms) == SV("0ms" )); |
127 | assert(stream_c_locale<CharT>(std::chrono::duration<int, std::centi>(0)) == SV("0cs" )); |
128 | assert(stream_c_locale<CharT>(std::chrono::duration<int, std::deci>(0)) == SV("0ds" )); |
129 | |
130 | assert(stream_c_locale<CharT>(0s) == SV("0s" )); |
131 | |
132 | assert(stream_c_locale<CharT>(std::chrono::duration<int, std::deca>(0)) == SV("0das" )); |
133 | assert(stream_c_locale<CharT>(std::chrono::duration<int, std::hecto>(0)) == SV("0hs" )); |
134 | assert(stream_c_locale<CharT>(std::chrono::duration<int, std::kilo>(0)) == SV("0ks" )); |
135 | assert(stream_c_locale<CharT>(std::chrono::duration<int, std::mega>(0)) == SV("0Ms" )); |
136 | assert(stream_c_locale<CharT>(std::chrono::duration<int, std::giga>(0)) == SV("0Gs" )); |
137 | assert(stream_c_locale<CharT>(std::chrono::duration<int, std::tera>(0)) == SV("0Ts" )); |
138 | assert(stream_c_locale<CharT>(std::chrono::duration<int, std::peta>(0)) == SV("0Ps" )); |
139 | assert(stream_c_locale<CharT>(std::chrono::duration<int, std::exa>(0)) == SV("0Es" )); |
140 | |
141 | assert(stream_c_locale<CharT>(0min) == SV("0min" )); |
142 | assert(stream_c_locale<CharT>(0h) == SV("0h" )); |
143 | assert(stream_c_locale<CharT>(std::chrono::duration<int, std::ratio<86400>>(0)) == SV("0d" )); |
144 | |
145 | assert(stream_c_locale<CharT>(std::chrono::duration<int, std::ratio<42>>(0)) == SV("0[42]s" )); |
146 | assert(stream_c_locale<CharT>(std::chrono::duration<int, std::ratio<33, 3>>(0)) == SV("0[11]s" )); |
147 | assert(stream_c_locale<CharT>(std::chrono::duration<int, std::ratio<11, 9>>(0)) == SV("0[11/9]s" )); |
148 | |
149 | // fr_FR locale |
150 | assert(stream_fr_FR_locale<CharT>(std::chrono::duration<int, std::atto>(0)) == SV("0as" )); |
151 | assert(stream_fr_FR_locale<CharT>(std::chrono::duration<int, std::femto>(0)) == SV("0fs" )); |
152 | assert(stream_fr_FR_locale<CharT>(std::chrono::duration<int, std::pico>(0)) == SV("0ps" )); |
153 | assert(stream_fr_FR_locale<CharT>(0ns) == SV("0ns" )); |
154 | #ifndef TEST_HAS_NO_UNICODE |
155 | assert(stream_fr_FR_locale<CharT>(0us) == SV("0\u00b5s" )); |
156 | #else |
157 | assert(stream_fr_FR_locale<CharT>(0us) == SV("0us" )); |
158 | #endif |
159 | assert(stream_fr_FR_locale<CharT>(0ms) == SV("0ms" )); |
160 | assert(stream_fr_FR_locale<CharT>(std::chrono::duration<int, std::centi>(0)) == SV("0cs" )); |
161 | assert(stream_fr_FR_locale<CharT>(std::chrono::duration<int, std::deci>(0)) == SV("0ds" )); |
162 | |
163 | assert(stream_fr_FR_locale<CharT>(0s) == SV("0s" )); |
164 | |
165 | assert(stream_fr_FR_locale<CharT>(std::chrono::duration<int, std::deca>(0)) == SV("0das" )); |
166 | assert(stream_fr_FR_locale<CharT>(std::chrono::duration<int, std::hecto>(0)) == SV("0hs" )); |
167 | assert(stream_fr_FR_locale<CharT>(std::chrono::duration<int, std::kilo>(0)) == SV("0ks" )); |
168 | assert(stream_fr_FR_locale<CharT>(std::chrono::duration<int, std::mega>(0)) == SV("0Ms" )); |
169 | assert(stream_fr_FR_locale<CharT>(std::chrono::duration<int, std::giga>(0)) == SV("0Gs" )); |
170 | assert(stream_fr_FR_locale<CharT>(std::chrono::duration<int, std::tera>(0)) == SV("0Ts" )); |
171 | assert(stream_fr_FR_locale<CharT>(std::chrono::duration<int, std::peta>(0)) == SV("0Ps" )); |
172 | assert(stream_fr_FR_locale<CharT>(std::chrono::duration<int, std::exa>(0)) == SV("0Es" )); |
173 | |
174 | assert(stream_fr_FR_locale<CharT>(0min) == SV("0min" )); |
175 | assert(stream_fr_FR_locale<CharT>(0h) == SV("0h" )); |
176 | assert(stream_fr_FR_locale<CharT>(std::chrono::duration<int, std::ratio<86400>>(0)) == SV("0d" )); |
177 | |
178 | assert(stream_fr_FR_locale<CharT>(std::chrono::duration<int, std::ratio<42>>(0)) == SV("0[42]s" )); |
179 | assert(stream_fr_FR_locale<CharT>(std::chrono::duration<int, std::ratio<33, 3>>(0)) == SV("0[11]s" )); |
180 | assert(stream_fr_FR_locale<CharT>(std::chrono::duration<int, std::ratio<11, 9>>(0)) == SV("0[11/9]s" )); |
181 | |
182 | // ja_JP locale |
183 | assert(stream_ja_JP_locale<CharT>(std::chrono::duration<int, std::atto>(0)) == SV("0as" )); |
184 | assert(stream_ja_JP_locale<CharT>(std::chrono::duration<int, std::femto>(0)) == SV("0fs" )); |
185 | assert(stream_ja_JP_locale<CharT>(std::chrono::duration<int, std::pico>(0)) == SV("0ps" )); |
186 | assert(stream_ja_JP_locale<CharT>(0ns) == SV("0ns" )); |
187 | #ifndef TEST_HAS_NO_UNICODE |
188 | assert(stream_ja_JP_locale<CharT>(0us) == SV("0\u00b5s" )); |
189 | #else |
190 | assert(stream_ja_JP_locale<CharT>(0us) == SV("0us" )); |
191 | #endif |
192 | assert(stream_ja_JP_locale<CharT>(0ms) == SV("0ms" )); |
193 | assert(stream_ja_JP_locale<CharT>(std::chrono::duration<int, std::centi>(0)) == SV("0cs" )); |
194 | assert(stream_ja_JP_locale<CharT>(std::chrono::duration<int, std::deci>(0)) == SV("0ds" )); |
195 | |
196 | assert(stream_ja_JP_locale<CharT>(0s) == SV("0s" )); |
197 | |
198 | assert(stream_ja_JP_locale<CharT>(std::chrono::duration<int, std::deca>(0)) == SV("0das" )); |
199 | assert(stream_ja_JP_locale<CharT>(std::chrono::duration<int, std::hecto>(0)) == SV("0hs" )); |
200 | assert(stream_ja_JP_locale<CharT>(std::chrono::duration<int, std::kilo>(0)) == SV("0ks" )); |
201 | assert(stream_ja_JP_locale<CharT>(std::chrono::duration<int, std::mega>(0)) == SV("0Ms" )); |
202 | assert(stream_ja_JP_locale<CharT>(std::chrono::duration<int, std::giga>(0)) == SV("0Gs" )); |
203 | assert(stream_ja_JP_locale<CharT>(std::chrono::duration<int, std::tera>(0)) == SV("0Ts" )); |
204 | assert(stream_ja_JP_locale<CharT>(std::chrono::duration<int, std::peta>(0)) == SV("0Ps" )); |
205 | assert(stream_ja_JP_locale<CharT>(std::chrono::duration<int, std::exa>(0)) == SV("0Es" )); |
206 | |
207 | assert(stream_ja_JP_locale<CharT>(0min) == SV("0min" )); |
208 | assert(stream_ja_JP_locale<CharT>(0h) == SV("0h" )); |
209 | assert(stream_ja_JP_locale<CharT>(std::chrono::duration<int, std::ratio<86400>>(0)) == SV("0d" )); |
210 | |
211 | assert(stream_ja_JP_locale<CharT>(std::chrono::duration<int, std::ratio<42>>(0)) == SV("0[42]s" )); |
212 | assert(stream_ja_JP_locale<CharT>(std::chrono::duration<int, std::ratio<33, 3>>(0)) == SV("0[11]s" )); |
213 | assert(stream_ja_JP_locale<CharT>(std::chrono::duration<int, std::ratio<11, 9>>(0)) == SV("0[11/9]s" )); |
214 | } |
215 | |
216 | template <class CharT> |
217 | static void test_unsigned_types() { |
218 | // Reported in https://github.com/llvm/llvm-project/issues/96820 |
219 | using namespace std::literals::chrono_literals; |
220 | |
221 | // C locale |
222 | assert(stream_c_locale<CharT>(std::chrono::duration<unsigned short, std::atto>(0)) == SV("0as" )); |
223 | assert(stream_c_locale<CharT>(std::chrono::duration<unsigned, std::femto>(0)) == SV("0fs" )); |
224 | assert(stream_c_locale<CharT>(std::chrono::duration<unsigned long, std::pico>(0)) == SV("0ps" )); |
225 | assert(stream_c_locale<CharT>(std::chrono::duration<unsigned long long, std::nano>(0)) == SV("0ns" )); |
226 | |
227 | // fr_FR locale |
228 | assert(stream_fr_FR_locale<CharT>(std::chrono::duration<unsigned short, std::atto>(0)) == SV("0as" )); |
229 | assert(stream_fr_FR_locale<CharT>(std::chrono::duration<unsigned, std::femto>(0)) == SV("0fs" )); |
230 | assert(stream_fr_FR_locale<CharT>(std::chrono::duration<unsigned long, std::pico>(0)) == SV("0ps" )); |
231 | assert(stream_fr_FR_locale<CharT>(std::chrono::duration<unsigned long long, std::nano>(0)) == SV("0ns" )); |
232 | |
233 | // ja_JP locale |
234 | assert(stream_ja_JP_locale<CharT>(std::chrono::duration<unsigned short, std::atto>(0)) == SV("0as" )); |
235 | assert(stream_ja_JP_locale<CharT>(std::chrono::duration<unsigned, std::femto>(0)) == SV("0fs" )); |
236 | assert(stream_ja_JP_locale<CharT>(std::chrono::duration<unsigned long, std::pico>(0)) == SV("0ps" )); |
237 | assert(stream_ja_JP_locale<CharT>(std::chrono::duration<unsigned long long, std::nano>(0)) == SV("0ns" )); |
238 | } |
239 | |
240 | template <class CharT> |
241 | static void test() { |
242 | test_values<CharT>(); |
243 | test_units<CharT>(); |
244 | test_unsigned_types<CharT>(); |
245 | } |
246 | |
247 | int main(int, char**) { |
248 | test<char>(); |
249 | |
250 | #ifndef TEST_HAS_NO_WIDE_CHARACTERS |
251 | test<wchar_t>(); |
252 | #endif |
253 | |
254 | return 0; |
255 | } |
256 | |