1 /*
2 * Copyright (C) 2012 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "third_party/blink/renderer/platform/text/locale_icu.h"
32
33 #include <unicode/uvernum.h>
34 #include <memory>
35 #include "testing/gtest/include/gtest/gtest.h"
36 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
37
38 namespace blink {
39
40 class LocaleICUTest : public testing::Test {
41 public:
42 // Labels class is used for printing results in EXPECT_EQ macro.
43 class Labels {
44 public:
Labels(const Vector<String> labels)45 Labels(const Vector<String> labels) : labels_(labels) {}
46
47 // FIXME: We should use Vector<T>::operator==() if it works.
operator ==(const Labels & other) const48 bool operator==(const Labels& other) const {
49 if (labels_.size() != other.labels_.size())
50 return false;
51 for (unsigned index = 0; index < labels_.size(); ++index) {
52 if (labels_[index] != other.labels_[index])
53 return false;
54 }
55 return true;
56 }
57
ToString() const58 String ToString() const {
59 StringBuilder builder;
60 builder.Append("labels(");
61 for (unsigned index = 0; index < labels_.size(); ++index) {
62 if (index)
63 builder.Append(", ");
64 builder.Append('"');
65 builder.Append(labels_[index]);
66 builder.Append('"');
67 }
68 builder.Append(')');
69 return builder.ToString();
70 }
71
72 private:
73 Vector<String> labels_;
74 };
75
76 protected:
LabelsFromTwoElements(const String & element1,const String & element2)77 Labels LabelsFromTwoElements(const String& element1, const String& element2) {
78 Vector<String> labels = Vector<String>();
79 labels.push_back(element1);
80 labels.push_back(element2);
81 return Labels(labels);
82 }
83
MonthFormat(const char * locale_string)84 String MonthFormat(const char* locale_string) {
85 auto locale = std::make_unique<LocaleICU>(locale_string);
86 return locale->MonthFormat();
87 }
88
LocalizedDateFormatText(const char * locale_string)89 String LocalizedDateFormatText(const char* locale_string) {
90 auto locale = std::make_unique<LocaleICU>(locale_string);
91 return locale->TimeFormat();
92 }
93
LocalizedShortDateFormatText(const char * locale_string)94 String LocalizedShortDateFormatText(const char* locale_string) {
95 auto locale = std::make_unique<LocaleICU>(locale_string);
96 return locale->ShortTimeFormat();
97 }
98
ShortMonthLabel(const char * locale_string,unsigned index)99 String ShortMonthLabel(const char* locale_string, unsigned index) {
100 auto locale = std::make_unique<LocaleICU>(locale_string);
101 return locale->ShortMonthLabels()[index];
102 }
103
ShortStandAloneMonthLabel(const char * locale_string,unsigned index)104 String ShortStandAloneMonthLabel(const char* locale_string, unsigned index) {
105 auto locale = std::make_unique<LocaleICU>(locale_string);
106 return locale->ShortStandAloneMonthLabels()[index];
107 }
108
StandAloneMonthLabel(const char * locale_string,unsigned index)109 String StandAloneMonthLabel(const char* locale_string, unsigned index) {
110 auto locale = std::make_unique<LocaleICU>(locale_string);
111 return locale->StandAloneMonthLabels()[index];
112 }
113
TimeAMPMLabels(const char * locale_string)114 Labels TimeAMPMLabels(const char* locale_string) {
115 auto locale = std::make_unique<LocaleICU>(locale_string);
116 return Labels(locale->TimeAMPMLabels());
117 }
118
IsRTL(const char * locale_string)119 bool IsRTL(const char* locale_string) {
120 auto locale = std::make_unique<LocaleICU>(locale_string);
121 return locale->IsRTL();
122 }
123 };
124
operator <<(std::ostream & os,const LocaleICUTest::Labels & labels)125 std::ostream& operator<<(std::ostream& os,
126 const LocaleICUTest::Labels& labels) {
127 return os << labels.ToString();
128 }
129
TEST_F(LocaleICUTest,isRTL)130 TEST_F(LocaleICUTest, isRTL) {
131 EXPECT_TRUE(IsRTL("ar-EG"));
132 EXPECT_FALSE(IsRTL("en-us"));
133 EXPECT_FALSE(IsRTL("ja-jp"));
134 EXPECT_FALSE(IsRTL("**invalid**"));
135 }
136
TEST_F(LocaleICUTest,monthFormat)137 TEST_F(LocaleICUTest, monthFormat) {
138 EXPECT_EQ("MMMM yyyy", MonthFormat("en_US"));
139 EXPECT_EQ("MMMM yyyy", MonthFormat("fr"));
140 EXPECT_EQ("yyyy\xE5\xB9\xB4M\xE6\x9C\x88", MonthFormat("ja").Utf8());
141 }
142
TEST_F(LocaleICUTest,localizedDateFormatText)143 TEST_F(LocaleICUTest, localizedDateFormatText) {
144 // Note: EXPECT_EQ(String, String) doesn't print result as string.
145 EXPECT_EQ("h:mm:ss a", LocalizedDateFormatText("en_US"));
146 EXPECT_EQ("HH:mm:ss", LocalizedDateFormatText("fr"));
147 EXPECT_EQ("H:mm:ss", LocalizedDateFormatText("ja"));
148 }
149
TEST_F(LocaleICUTest,localizedShortDateFormatText)150 TEST_F(LocaleICUTest, localizedShortDateFormatText) {
151 EXPECT_EQ("h:mm a", LocalizedShortDateFormatText("en_US"));
152 EXPECT_EQ("HH:mm", LocalizedShortDateFormatText("fr"));
153 EXPECT_EQ("H:mm", LocalizedShortDateFormatText("ja"));
154 }
155
TEST_F(LocaleICUTest,standAloneMonthLabels)156 TEST_F(LocaleICUTest, standAloneMonthLabels) {
157 EXPECT_EQ("January", StandAloneMonthLabel("en_US", 0));
158 EXPECT_EQ("June", StandAloneMonthLabel("en_US", 5));
159 EXPECT_EQ("December", StandAloneMonthLabel("en_US", 11));
160
161 #if U_ICU_VERSION_MAJOR_NUM >= 54
162 EXPECT_EQ("Janvier", StandAloneMonthLabel("fr_FR", 0));
163 EXPECT_EQ("Juin", StandAloneMonthLabel("fr_FR", 5));
164 EXPECT_EQ(
165 "D\xC3\xA9"
166 "cembre",
167 StandAloneMonthLabel("fr_FR", 11).Utf8());
168 #else
169 EXPECT_EQ("janvier", standAloneMonthLabel("fr_FR", 0));
170 EXPECT_EQ("juin", standAloneMonthLabel("fr_FR", 5));
171 EXPECT_EQ(
172 "d\xC3\xA9"
173 "cembre",
174 standAloneMonthLabel("fr_FR", 11));
175 #endif
176
177 EXPECT_EQ("1\xE6\x9C\x88", StandAloneMonthLabel("ja_JP", 0).Utf8());
178 EXPECT_EQ("6\xE6\x9C\x88", StandAloneMonthLabel("ja_JP", 5).Utf8());
179 EXPECT_EQ("12\xE6\x9C\x88", StandAloneMonthLabel("ja_JP", 11).Utf8());
180
181 EXPECT_EQ("\xD0\x9C\xD0\xB0\xD1\x80\xD1\x82",
182 StandAloneMonthLabel("ru_RU", 2).Utf8());
183 EXPECT_EQ("\xD0\x9C\xD0\xB0\xD0\xB9",
184 StandAloneMonthLabel("ru_RU", 4).Utf8());
185 }
186
TEST_F(LocaleICUTest,shortMonthLabels)187 TEST_F(LocaleICUTest, shortMonthLabels) {
188 EXPECT_EQ("Jan", ShortMonthLabel("en_US", 0));
189 EXPECT_EQ("Jan", ShortStandAloneMonthLabel("en_US", 0));
190 EXPECT_EQ("Dec", ShortMonthLabel("en_US", 11));
191 EXPECT_EQ("Dec", ShortStandAloneMonthLabel("en_US", 11));
192
193 #if U_ICU_VERSION_MAJOR_NUM >= 54
194 EXPECT_EQ("janv.", ShortMonthLabel("fr_FR", 0));
195 EXPECT_EQ("Janv.", ShortStandAloneMonthLabel("fr_FR", 0));
196 EXPECT_EQ(
197 "d\xC3\xA9"
198 "c.",
199 ShortMonthLabel("fr_FR", 11).Utf8());
200 EXPECT_EQ(
201 "D\xC3\xA9"
202 "c.",
203 ShortStandAloneMonthLabel("fr_FR", 11).Utf8());
204 #else
205 EXPECT_EQ("janv.", shortMonthLabel("fr_FR", 0));
206 EXPECT_EQ("janv.", shortStandAloneMonthLabel("fr_FR", 0));
207 EXPECT_EQ(
208 "d\xC3\xA9"
209 "c.",
210 shortMonthLabel("fr_FR", 11));
211 EXPECT_EQ(
212 "d\xC3\xA9"
213 "c.",
214 shortStandAloneMonthLabel("fr_FR", 11));
215 #endif
216
217 EXPECT_EQ("1\xE6\x9C\x88", ShortMonthLabel("ja_JP", 0).Utf8());
218 EXPECT_EQ("1\xE6\x9C\x88", ShortStandAloneMonthLabel("ja_JP", 0).Utf8());
219 EXPECT_EQ("12\xE6\x9C\x88", ShortMonthLabel("ja_JP", 11).Utf8());
220 EXPECT_EQ("12\xE6\x9C\x88", ShortStandAloneMonthLabel("ja_JP", 11).Utf8());
221
222 EXPECT_EQ("\xD0\xBC\xD0\xB0\xD1\x80.", ShortMonthLabel("ru_RU", 2).Utf8());
223 EXPECT_EQ("\xD0\x9C\xD0\xB0\xD1\x80\xD1\x82",
224 ShortStandAloneMonthLabel("ru_RU", 2).Utf8());
225 EXPECT_EQ("\xD0\xBC\xD0\xB0\xD1\x8F", ShortMonthLabel("ru_RU", 4).Utf8());
226 EXPECT_EQ("\xD0\x9C\xD0\xB0\xD0\xB9",
227 ShortStandAloneMonthLabel("ru_RU", 4).Utf8());
228 }
229
TEST_F(LocaleICUTest,timeAMPMLabels)230 TEST_F(LocaleICUTest, timeAMPMLabels) {
231 EXPECT_EQ(LabelsFromTwoElements("AM", "PM"), TimeAMPMLabels("en_US"));
232 EXPECT_EQ(LabelsFromTwoElements("AM", "PM"), TimeAMPMLabels("fr"));
233
234 UChar ja_am[3] = {0x5348, 0x524d, 0};
235 UChar ja_pm[3] = {0x5348, 0x5F8C, 0};
236 EXPECT_EQ(LabelsFromTwoElements(String(ja_am), String(ja_pm)),
237 TimeAMPMLabels("ja"));
238 }
239
TestDecimalSeparator(const AtomicString & locale_identifier)240 static String TestDecimalSeparator(const AtomicString& locale_identifier) {
241 std::unique_ptr<Locale> locale = Locale::Create(locale_identifier);
242 return locale->LocalizedDecimalSeparator();
243 }
244
TEST_F(LocaleICUTest,localizedDecimalSeparator)245 TEST_F(LocaleICUTest, localizedDecimalSeparator) {
246 EXPECT_EQ(String("."), TestDecimalSeparator("en_US"));
247 EXPECT_EQ(String(","), TestDecimalSeparator("fr"));
248 }
249
TestNumberIsReversible(const AtomicString & locale_identifier,const char * original,const char * should_have=nullptr)250 void TestNumberIsReversible(const AtomicString& locale_identifier,
251 const char* original,
252 const char* should_have = nullptr) {
253 std::unique_ptr<Locale> locale = Locale::Create(locale_identifier);
254 String localized = locale->ConvertToLocalizedNumber(original);
255 if (should_have)
256 EXPECT_TRUE(localized.Contains(should_have));
257 String converted = locale->ConvertFromLocalizedNumber(localized);
258 EXPECT_EQ(original, converted);
259 }
260
TestNumbers(const char * locale_string)261 void TestNumbers(const char* locale_string) {
262 TestNumberIsReversible(locale_string, "123456789012345678901234567890");
263 TestNumberIsReversible(locale_string, "-123.456");
264 TestNumberIsReversible(locale_string, ".456");
265 TestNumberIsReversible(locale_string, "-0.456");
266 }
267
TEST_F(LocaleICUTest,reversible)268 TEST_F(LocaleICUTest, reversible) {
269 TestNumberIsReversible("en_US", "123456789012345678901234567890");
270 TestNumberIsReversible("en_US", "-123.456", ".");
271 TestNumberIsReversible("en_US", ".456", ".");
272 TestNumberIsReversible("en_US", "-0.456", ".");
273
274 TestNumberIsReversible("fr", "123456789012345678901234567890");
275 TestNumberIsReversible("fr", "-123.456", ",");
276 TestNumberIsReversible("fr", ".456", ",");
277 TestNumberIsReversible("fr", "-0.456", ",");
278
279 // Persian locale has a negative prefix and a negative suffix.
280 TestNumbers("fa");
281
282 // Test some of major locales.
283 TestNumbers("ar");
284 TestNumbers("de_DE");
285 TestNumbers("es_ES");
286 TestNumbers("ja_JP");
287 TestNumbers("ko_KR");
288 TestNumbers("zh_CN");
289 TestNumbers("zh_HK");
290 TestNumbers("zh_TW");
291 }
292
293 } // namespace blink
294