blob: a65a8b1688ea788823be3b9f38585038777e2367 [file] [log] [blame]
/*
* Copyright (C) 2012 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "third_party/blink/renderer/platform/text/locale_icu.h"
#include <unicode/uvernum.h>
#include <memory>
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
namespace blink {
class LocaleICUTest : public testing::Test {
public:
// Labels class is used for printing results in EXPECT_EQ macro.
class Labels {
public:
Labels(const Vector<String> labels) : labels_(labels) {}
// FIXME: We should use Vector<T>::operator==() if it works.
bool operator==(const Labels& other) const {
if (labels_.size() != other.labels_.size())
return false;
for (unsigned index = 0; index < labels_.size(); ++index) {
if (labels_[index] != other.labels_[index])
return false;
}
return true;
}
String ToString() const {
StringBuilder builder;
builder.Append("labels(");
for (unsigned index = 0; index < labels_.size(); ++index) {
if (index)
builder.Append(", ");
builder.Append('"');
builder.Append(labels_[index]);
builder.Append('"');
}
builder.Append(')');
return builder.ToString();
}
private:
Vector<String> labels_;
};
protected:
Labels LabelsFromTwoElements(const String& element1, const String& element2) {
Vector<String> labels = Vector<String>();
labels.push_back(element1);
labels.push_back(element2);
return Labels(labels);
}
String MonthFormat(const char* locale_string) {
auto locale = std::make_unique<LocaleICU>(locale_string);
return locale->MonthFormat();
}
String LocalizedDateFormatText(const char* locale_string) {
auto locale = std::make_unique<LocaleICU>(locale_string);
return locale->TimeFormat();
}
String LocalizedShortDateFormatText(const char* locale_string) {
auto locale = std::make_unique<LocaleICU>(locale_string);
return locale->ShortTimeFormat();
}
String ShortMonthLabel(const char* locale_string, unsigned index) {
auto locale = std::make_unique<LocaleICU>(locale_string);
return locale->ShortMonthLabels()[index];
}
String ShortStandAloneMonthLabel(const char* locale_string, unsigned index) {
auto locale = std::make_unique<LocaleICU>(locale_string);
return locale->ShortStandAloneMonthLabels()[index];
}
String StandAloneMonthLabel(const char* locale_string, unsigned index) {
auto locale = std::make_unique<LocaleICU>(locale_string);
return locale->StandAloneMonthLabels()[index];
}
Labels TimeAMPMLabels(const char* locale_string) {
auto locale = std::make_unique<LocaleICU>(locale_string);
return Labels(locale->TimeAMPMLabels());
}
bool IsRTL(const char* locale_string) {
auto locale = std::make_unique<LocaleICU>(locale_string);
return locale->IsRTL();
}
};
std::ostream& operator<<(std::ostream& os,
const LocaleICUTest::Labels& labels) {
return os << labels.ToString();
}
TEST_F(LocaleICUTest, isRTL) {
EXPECT_TRUE(IsRTL("ar-EG"));
EXPECT_FALSE(IsRTL("en-us"));
EXPECT_FALSE(IsRTL("ja-jp"));
EXPECT_FALSE(IsRTL("**invalid**"));
}
TEST_F(LocaleICUTest, monthFormat) {
EXPECT_EQ("MMMM yyyy", MonthFormat("en_US"));
EXPECT_EQ("MMMM yyyy", MonthFormat("fr"));
EXPECT_EQ("yyyy\xE5\xB9\xB4M\xE6\x9C\x88", MonthFormat("ja").Utf8());
}
TEST_F(LocaleICUTest, localizedDateFormatText) {
// Note: EXPECT_EQ(String, String) doesn't print result as string.
EXPECT_EQ("h:mm:ss a", LocalizedDateFormatText("en_US"));
EXPECT_EQ("HH:mm:ss", LocalizedDateFormatText("fr"));
EXPECT_EQ("H:mm:ss", LocalizedDateFormatText("ja"));
}
TEST_F(LocaleICUTest, localizedShortDateFormatText) {
EXPECT_EQ("h:mm a", LocalizedShortDateFormatText("en_US"));
EXPECT_EQ("HH:mm", LocalizedShortDateFormatText("fr"));
EXPECT_EQ("H:mm", LocalizedShortDateFormatText("ja"));
}
TEST_F(LocaleICUTest, standAloneMonthLabels) {
EXPECT_EQ("January", StandAloneMonthLabel("en_US", 0));
EXPECT_EQ("June", StandAloneMonthLabel("en_US", 5));
EXPECT_EQ("December", StandAloneMonthLabel("en_US", 11));
#if U_ICU_VERSION_MAJOR_NUM >= 54
EXPECT_EQ("Janvier", StandAloneMonthLabel("fr_FR", 0));
EXPECT_EQ("Juin", StandAloneMonthLabel("fr_FR", 5));
EXPECT_EQ(
"D\xC3\xA9"
"cembre",
StandAloneMonthLabel("fr_FR", 11).Utf8());
#else
EXPECT_EQ("janvier", standAloneMonthLabel("fr_FR", 0));
EXPECT_EQ("juin", standAloneMonthLabel("fr_FR", 5));
EXPECT_EQ(
"d\xC3\xA9"
"cembre",
standAloneMonthLabel("fr_FR", 11));
#endif
EXPECT_EQ("1\xE6\x9C\x88", StandAloneMonthLabel("ja_JP", 0).Utf8());
EXPECT_EQ("6\xE6\x9C\x88", StandAloneMonthLabel("ja_JP", 5).Utf8());
EXPECT_EQ("12\xE6\x9C\x88", StandAloneMonthLabel("ja_JP", 11).Utf8());
EXPECT_EQ("\xD0\x9C\xD0\xB0\xD1\x80\xD1\x82",
StandAloneMonthLabel("ru_RU", 2).Utf8());
EXPECT_EQ("\xD0\x9C\xD0\xB0\xD0\xB9",
StandAloneMonthLabel("ru_RU", 4).Utf8());
}
TEST_F(LocaleICUTest, shortMonthLabels) {
EXPECT_EQ("Jan", ShortMonthLabel("en_US", 0));
EXPECT_EQ("Jan", ShortStandAloneMonthLabel("en_US", 0));
EXPECT_EQ("Dec", ShortMonthLabel("en_US", 11));
EXPECT_EQ("Dec", ShortStandAloneMonthLabel("en_US", 11));
#if U_ICU_VERSION_MAJOR_NUM >= 54
EXPECT_EQ("janv.", ShortMonthLabel("fr_FR", 0));
EXPECT_EQ("Janv.", ShortStandAloneMonthLabel("fr_FR", 0));
EXPECT_EQ(
"d\xC3\xA9"
"c.",
ShortMonthLabel("fr_FR", 11).Utf8());
EXPECT_EQ(
"D\xC3\xA9"
"c.",
ShortStandAloneMonthLabel("fr_FR", 11).Utf8());
#else
EXPECT_EQ("janv.", shortMonthLabel("fr_FR", 0));
EXPECT_EQ("janv.", shortStandAloneMonthLabel("fr_FR", 0));
EXPECT_EQ(
"d\xC3\xA9"
"c.",
shortMonthLabel("fr_FR", 11));
EXPECT_EQ(
"d\xC3\xA9"
"c.",
shortStandAloneMonthLabel("fr_FR", 11));
#endif
EXPECT_EQ("1\xE6\x9C\x88", ShortMonthLabel("ja_JP", 0).Utf8());
EXPECT_EQ("1\xE6\x9C\x88", ShortStandAloneMonthLabel("ja_JP", 0).Utf8());
EXPECT_EQ("12\xE6\x9C\x88", ShortMonthLabel("ja_JP", 11).Utf8());
EXPECT_EQ("12\xE6\x9C\x88", ShortStandAloneMonthLabel("ja_JP", 11).Utf8());
EXPECT_EQ("\xD0\xBC\xD0\xB0\xD1\x80.", ShortMonthLabel("ru_RU", 2).Utf8());
EXPECT_EQ("\xD0\x9C\xD0\xB0\xD1\x80\xD1\x82",
ShortStandAloneMonthLabel("ru_RU", 2).Utf8());
EXPECT_EQ("\xD0\xBC\xD0\xB0\xD1\x8F", ShortMonthLabel("ru_RU", 4).Utf8());
EXPECT_EQ("\xD0\x9C\xD0\xB0\xD0\xB9",
ShortStandAloneMonthLabel("ru_RU", 4).Utf8());
}
TEST_F(LocaleICUTest, timeAMPMLabels) {
EXPECT_EQ(LabelsFromTwoElements("AM", "PM"), TimeAMPMLabels("en_US"));
EXPECT_EQ(LabelsFromTwoElements("AM", "PM"), TimeAMPMLabels("fr"));
UChar ja_am[3] = {0x5348, 0x524d, 0};
UChar ja_pm[3] = {0x5348, 0x5F8C, 0};
EXPECT_EQ(LabelsFromTwoElements(String(ja_am), String(ja_pm)),
TimeAMPMLabels("ja"));
}
static String TestDecimalSeparator(const AtomicString& locale_identifier) {
std::unique_ptr<Locale> locale = Locale::Create(locale_identifier);
return locale->LocalizedDecimalSeparator();
}
TEST_F(LocaleICUTest, localizedDecimalSeparator) {
EXPECT_EQ(String("."), TestDecimalSeparator("en_US"));
EXPECT_EQ(String(","), TestDecimalSeparator("fr"));
}
void TestNumberIsReversible(const AtomicString& locale_identifier,
const char* original,
const char* should_have = nullptr) {
std::unique_ptr<Locale> locale = Locale::Create(locale_identifier);
String localized = locale->ConvertToLocalizedNumber(original);
if (should_have)
EXPECT_TRUE(localized.Contains(should_have));
String converted = locale->ConvertFromLocalizedNumber(localized);
EXPECT_EQ(original, converted);
}
void TestNumbers(const char* locale_string) {
TestNumberIsReversible(locale_string, "123456789012345678901234567890");
TestNumberIsReversible(locale_string, "-123.456");
TestNumberIsReversible(locale_string, ".456");
TestNumberIsReversible(locale_string, "-0.456");
}
TEST_F(LocaleICUTest, reversible) {
TestNumberIsReversible("en_US", "123456789012345678901234567890");
TestNumberIsReversible("en_US", "-123.456", ".");
TestNumberIsReversible("en_US", ".456", ".");
TestNumberIsReversible("en_US", "-0.456", ".");
TestNumberIsReversible("fr", "123456789012345678901234567890");
TestNumberIsReversible("fr", "-123.456", ",");
TestNumberIsReversible("fr", ".456", ",");
TestNumberIsReversible("fr", "-0.456", ",");
// Persian locale has a negative prefix and a negative suffix.
TestNumbers("fa");
// Test some of major locales.
TestNumbers("ar");
TestNumbers("de_DE");
TestNumbers("es_ES");
TestNumbers("ja_JP");
TestNumbers("ko_KR");
TestNumbers("zh_CN");
TestNumbers("zh_HK");
TestNumbers("zh_TW");
}
} // namespace blink