diff options
Diffstat (limited to '')
25 files changed, 8320 insertions, 0 deletions
diff --git a/intl/locale/tests/gtest/TestCollation.cpp b/intl/locale/tests/gtest/TestCollation.cpp new file mode 100644 index 0000000000..4085f6433f --- /dev/null +++ b/intl/locale/tests/gtest/TestCollation.cpp @@ -0,0 +1,157 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "gtest/gtest.h" +#include "nsCollationCID.h" +#include "nsComponentManagerUtils.h" +#include "nsCOMPtr.h" +#include "nsICollation.h" +#include "nsString.h" +#include "nsTArray.h" + +TEST(Collation, AllocateRowSortKey) +{ + nsCOMPtr<nsICollationFactory> colFactory = + do_CreateInstance(NS_COLLATIONFACTORY_CONTRACTID); + ASSERT_TRUE(colFactory); + + // Don't throw error even if locale name is invalid + nsCOMPtr<nsICollation> collator; + nsresult rv = colFactory->CreateCollationForLocale("$languageName"_ns, + getter_AddRefs(collator)); + ASSERT_TRUE(NS_SUCCEEDED(rv)); + + nsTArray<uint8_t> sortKey1; + // Don't throw error even if locale name is invalid + rv = collator->AllocateRawSortKey(nsICollation::kCollationStrengthDefault, + u"ABC"_ns, sortKey1); + ASSERT_TRUE(NS_SUCCEEDED(rv)); + + nsTArray<uint8_t> sortKey2; + // Don't throw error even if locale name is invalid + rv = collator->AllocateRawSortKey(nsICollation::kCollationStrengthDefault, + u"DEF"_ns, sortKey2); + ASSERT_TRUE(NS_SUCCEEDED(rv)); + + int32_t result; + rv = collator->CompareRawSortKey(sortKey1, sortKey2, &result); + ASSERT_TRUE(NS_SUCCEEDED(rv)); + + ASSERT_TRUE(result < 0); +} + +class CollationComparator final { + public: + explicit CollationComparator(nsICollation* aCollation) + : mCollation(aCollation) {} + + bool Equals(const nsString& a, const nsString& b) const { + int32_t result = 0; + mCollation->CompareString(nsICollation::kCollationStrengthDefault, a, b, + &result); + return result == 0; + } + + bool LessThan(const nsString& a, const nsString& b) const { + int32_t result = 0; + mCollation->CompareString(nsICollation::kCollationStrengthDefault, a, b, + &result); + return result < 0; + } + + private: + nsCOMPtr<nsICollation> mCollation; +}; + +TEST(Collation, CompareString) +{ + nsTArray<nsString> input; + input.AppendElement(u"Argentina"_ns); + input.AppendElement(u"Oerlikon"_ns); + input.AppendElement(u"Offenbach"_ns); + input.AppendElement(u"Sverige"_ns); + input.AppendElement(u"Vaticano"_ns); + input.AppendElement(u"Zimbabwe"_ns); + input.AppendElement(u"la France"_ns); + input.AppendElement(u"\u00a1viva Espa\u00f1a!"_ns); + input.AppendElement(u"\u00d6sterreich"_ns); + input.AppendElement(u"\u4e2d\u56fd"_ns); + input.AppendElement(u"\u65e5\u672c"_ns); + input.AppendElement(u"\ud55c\uad6d"_ns); + + nsCOMPtr<nsICollationFactory> colFactory = + do_CreateInstance(NS_COLLATIONFACTORY_CONTRACTID); + ASSERT_TRUE(colFactory); + + // Locale en-US; default options. + nsCOMPtr<nsICollation> collation; + colFactory->CreateCollationForLocale("en-US"_ns, getter_AddRefs(collation)); + ASSERT_TRUE(collation); + + { + CollationComparator comparator(collation); + input.Sort(comparator); + + ASSERT_TRUE(input[0].Equals(u"\u00a1viva Espa\u00f1a!"_ns)); + ASSERT_TRUE(input[1].Equals(u"Argentina"_ns)); + ASSERT_TRUE(input[2].Equals(u"la France"_ns)); + ASSERT_TRUE(input[3].Equals(u"Oerlikon"_ns)); + ASSERT_TRUE(input[4].Equals(u"Offenbach"_ns)); + ASSERT_TRUE(input[5].Equals(u"\u00d6sterreich"_ns)); + ASSERT_TRUE(input[6].Equals(u"Sverige"_ns)); + ASSERT_TRUE(input[7].Equals(u"Vaticano"_ns)); + ASSERT_TRUE(input[8].Equals(u"Zimbabwe"_ns)); + ASSERT_TRUE(input[9].Equals(u"\ud55c\uad6d"_ns)); + ASSERT_TRUE(input[10].Equals(u"\u4e2d\u56fd"_ns)); + ASSERT_TRUE(input[11].Equals(u"\u65e5\u672c"_ns)); + } + + // Locale sv-SE; default options. + // Swedish treats "Ö" as a separate character, which sorts after "Z". + colFactory->CreateCollationForLocale("sv-SE"_ns, getter_AddRefs(collation)); + ASSERT_TRUE(collation); + + { + CollationComparator comparator(collation); + input.Sort(comparator); + + ASSERT_TRUE(input[0].Equals(u"\u00a1viva Espa\u00f1a!"_ns)); + ASSERT_TRUE(input[1].Equals(u"Argentina"_ns)); + ASSERT_TRUE(input[2].Equals(u"la France"_ns)); + ASSERT_TRUE(input[3].Equals(u"Oerlikon"_ns)); + ASSERT_TRUE(input[4].Equals(u"Offenbach"_ns)); + ASSERT_TRUE(input[5].Equals(u"Sverige"_ns)); + ASSERT_TRUE(input[6].Equals(u"Vaticano"_ns)); + ASSERT_TRUE(input[7].Equals(u"Zimbabwe"_ns)); + ASSERT_TRUE(input[8].Equals(u"\u00d6sterreich"_ns)); + ASSERT_TRUE(input[9].Equals(u"\ud55c\uad6d"_ns)); + ASSERT_TRUE(input[10].Equals(u"\u4e2d\u56fd"_ns)); + ASSERT_TRUE(input[11].Equals(u"\u65e5\u672c"_ns)); + } + + // Locale de-DE; default options. + // In German standard sorting, umlauted characters are treated as variants + // of their base characters: ä ≅ a, ö ≅ o, ü ≅ u. + colFactory->CreateCollationForLocale("de-DE"_ns, getter_AddRefs(collation)); + ASSERT_TRUE(collation); + + { + CollationComparator comparator(collation); + input.Sort(comparator); + + ASSERT_TRUE(input[0].Equals(u"\u00a1viva Espa\u00f1a!"_ns)); + ASSERT_TRUE(input[1].Equals(u"Argentina"_ns)); + ASSERT_TRUE(input[2].Equals(u"la France"_ns)); + ASSERT_TRUE(input[3].Equals(u"Oerlikon"_ns)); + ASSERT_TRUE(input[4].Equals(u"Offenbach"_ns)); + ASSERT_TRUE(input[5].Equals(u"\u00d6sterreich"_ns)); + ASSERT_TRUE(input[6].Equals(u"Sverige"_ns)); + ASSERT_TRUE(input[7].Equals(u"Vaticano"_ns)); + ASSERT_TRUE(input[8].Equals(u"Zimbabwe"_ns)); + ASSERT_TRUE(input[9].Equals(u"\ud55c\uad6d"_ns)); + ASSERT_TRUE(input[10].Equals(u"\u4e2d\u56fd"_ns)); + ASSERT_TRUE(input[11].Equals(u"\u65e5\u672c"_ns)); + } +} diff --git a/intl/locale/tests/gtest/TestDateTimeFormat.cpp b/intl/locale/tests/gtest/TestDateTimeFormat.cpp new file mode 100644 index 0000000000..e2e56014cf --- /dev/null +++ b/intl/locale/tests/gtest/TestDateTimeFormat.cpp @@ -0,0 +1,240 @@ +#include "gtest/gtest.h" +#include "DateTimeFormat.h" + +namespace mozilla { + +TEST(DateTimeFormat, FormatPRExplodedTime) +{ + PRTime prTime = 0; + PRExplodedTime prExplodedTime; + PR_ExplodeTime(prTime, PR_GMTParameters, &prExplodedTime); + + mozilla::DateTimeFormat::mLocale = new nsCString("en-US"); + mozilla::DateTimeFormat::DeleteCache(); + + nsAutoString formattedTime; + nsresult rv = mozilla::DateTimeFormat::FormatPRExplodedTime( + kDateFormatLong, kTimeFormatLong, &prExplodedTime, formattedTime); + ASSERT_TRUE(NS_SUCCEEDED(rv)); + ASSERT_TRUE(formattedTime.Find("January") != kNotFound); + ASSERT_TRUE(formattedTime.Find("1970") != kNotFound); + ASSERT_TRUE(formattedTime.Find("12:00:00 AM") != kNotFound || + formattedTime.Find("00:00:00") != kNotFound); + + prExplodedTime = {0, 0, 19, 0, 1, 0, 1970, 4, 0, {(19 * 60), 0}}; + rv = mozilla::DateTimeFormat::FormatPRExplodedTime( + kDateFormatLong, kTimeFormatLong, &prExplodedTime, formattedTime); + ASSERT_TRUE(NS_SUCCEEDED(rv)); + ASSERT_TRUE(formattedTime.Find("January") != kNotFound); + ASSERT_TRUE(formattedTime.Find("1970") != kNotFound); + ASSERT_TRUE(formattedTime.Find("12:19:00 AM") != kNotFound || + formattedTime.Find("00:19:00") != kNotFound); + + prExplodedTime = {0, 0, 0, 7, 1, + 0, 1970, 4, 0, {(6 * 60 * 60), (1 * 60 * 60)}}; + rv = mozilla::DateTimeFormat::FormatPRExplodedTime( + kDateFormatLong, kTimeFormatLong, &prExplodedTime, formattedTime); + ASSERT_TRUE(NS_SUCCEEDED(rv)); + ASSERT_TRUE(formattedTime.Find("January") != kNotFound); + ASSERT_TRUE(formattedTime.Find("1970") != kNotFound); + ASSERT_TRUE(formattedTime.Find("7:00:00 AM") != kNotFound || + formattedTime.Find("07:00:00") != kNotFound); + + prExplodedTime = { + 0, 0, 29, 11, 1, + 0, 1970, 4, 0, {(10 * 60 * 60) + (29 * 60), (1 * 60 * 60)}}; + rv = mozilla::DateTimeFormat::FormatPRExplodedTime( + kDateFormatLong, kTimeFormatLong, &prExplodedTime, formattedTime); + ASSERT_TRUE(NS_SUCCEEDED(rv)); + ASSERT_TRUE(formattedTime.Find("January") != kNotFound); + ASSERT_TRUE(formattedTime.Find("1970") != kNotFound); + ASSERT_TRUE(formattedTime.Find("11:29:00 AM") != kNotFound || + formattedTime.Find("11:29:00") != kNotFound); + + prExplodedTime = {0, 0, 37, 23, 31, 11, 1969, 3, 364, {-(23 * 60), 0}}; + rv = mozilla::DateTimeFormat::FormatPRExplodedTime( + kDateFormatLong, kTimeFormatLong, &prExplodedTime, formattedTime); + ASSERT_TRUE(NS_SUCCEEDED(rv)); + ASSERT_TRUE(formattedTime.Find("December") != kNotFound); + ASSERT_TRUE(formattedTime.Find("31") != kNotFound); + ASSERT_TRUE(formattedTime.Find("1969") != kNotFound); + ASSERT_TRUE(formattedTime.Find("11:37:00 PM") != kNotFound || + formattedTime.Find("23:37:00") != kNotFound); + + prExplodedTime = {0, 0, 0, 17, 31, 11, 1969, 3, 364, {-(7 * 60 * 60), 0}}; + rv = mozilla::DateTimeFormat::FormatPRExplodedTime( + kDateFormatLong, kTimeFormatLong, &prExplodedTime, formattedTime); + ASSERT_TRUE(NS_SUCCEEDED(rv)); + ASSERT_TRUE(formattedTime.Find("December") != kNotFound); + ASSERT_TRUE(formattedTime.Find("31") != kNotFound); + ASSERT_TRUE(formattedTime.Find("1969") != kNotFound); + ASSERT_TRUE(formattedTime.Find("5:00:00 PM") != kNotFound || + formattedTime.Find("17:00:00") != kNotFound); + + prExplodedTime = { + 0, 0, 47, 14, 31, + 11, 1969, 3, 364, {-((10 * 60 * 60) + (13 * 60)), (1 * 60 * 60)}}; + rv = mozilla::DateTimeFormat::FormatPRExplodedTime( + kDateFormatLong, kTimeFormatLong, &prExplodedTime, formattedTime); + ASSERT_TRUE(NS_SUCCEEDED(rv)); + ASSERT_TRUE(formattedTime.Find("December") != kNotFound); + ASSERT_TRUE(formattedTime.Find("31") != kNotFound); + ASSERT_TRUE(formattedTime.Find("1969") != kNotFound); + ASSERT_TRUE(formattedTime.Find("2:47:00 PM") != kNotFound || + formattedTime.Find("14:47:00") != kNotFound); +} + +TEST(DateTimeFormat, DateFormatSelectors) +{ + PRTime prTime = 0; + PRExplodedTime prExplodedTime; + PR_ExplodeTime(prTime, PR_GMTParameters, &prExplodedTime); + + mozilla::DateTimeFormat::mLocale = new nsCString("en-US"); + mozilla::DateTimeFormat::DeleteCache(); + + nsAutoString formattedTime; + nsresult rv = mozilla::DateTimeFormat::FormatDateTime( + &prExplodedTime, DateTimeFormat::Skeleton::yyyyMM, formattedTime); + ASSERT_TRUE(NS_SUCCEEDED(rv)); + ASSERT_STREQ("01/1970", NS_ConvertUTF16toUTF8(formattedTime).get()); + + rv = mozilla::DateTimeFormat::FormatDateTime( + &prExplodedTime, DateTimeFormat::Skeleton::yyyyMMMM, formattedTime); + ASSERT_TRUE(NS_SUCCEEDED(rv)); + ASSERT_STREQ("January 1970", NS_ConvertUTF16toUTF8(formattedTime).get()); + + rv = mozilla::DateTimeFormat::GetCalendarSymbol( + mozilla::DateTimeFormat::Field::Month, + mozilla::DateTimeFormat::Style::Wide, &prExplodedTime, formattedTime); + ASSERT_TRUE(NS_SUCCEEDED(rv)); + ASSERT_STREQ("January", NS_ConvertUTF16toUTF8(formattedTime).get()); + + rv = mozilla::DateTimeFormat::GetCalendarSymbol( + mozilla::DateTimeFormat::Field::Weekday, + mozilla::DateTimeFormat::Style::Abbreviated, &prExplodedTime, + formattedTime); + ASSERT_TRUE(NS_SUCCEEDED(rv)); + ASSERT_STREQ("Thu", NS_ConvertUTF16toUTF8(formattedTime).get()); +} + +TEST(DateTimeFormat, FormatPRExplodedTimeForeign) +{ + PRTime prTime = 0; + PRExplodedTime prExplodedTime; + PR_ExplodeTime(prTime, PR_GMTParameters, &prExplodedTime); + + mozilla::DateTimeFormat::mLocale = new nsCString("de-DE"); + mozilla::DateTimeFormat::DeleteCache(); + + nsAutoString formattedTime; + nsresult rv = mozilla::DateTimeFormat::FormatPRExplodedTime( + kDateFormatLong, kTimeFormatLong, &prExplodedTime, formattedTime); + ASSERT_TRUE(NS_SUCCEEDED(rv)); + ASSERT_TRUE(formattedTime.Find("1.") != kNotFound); + ASSERT_TRUE(formattedTime.Find("Januar") != kNotFound); + ASSERT_TRUE(formattedTime.Find("1970") != kNotFound); + ASSERT_TRUE(formattedTime.Find("12:00:00 AM") != kNotFound || + formattedTime.Find("00:00:00") != kNotFound); + + prExplodedTime = {0, 0, 19, 0, 1, 0, 1970, 4, 0, {(19 * 60), 0}}; + rv = mozilla::DateTimeFormat::FormatPRExplodedTime( + kDateFormatLong, kTimeFormatLong, &prExplodedTime, formattedTime); + ASSERT_TRUE(NS_SUCCEEDED(rv)); + ASSERT_TRUE(formattedTime.Find("1.") != kNotFound); + ASSERT_TRUE(formattedTime.Find("Januar") != kNotFound); + ASSERT_TRUE(formattedTime.Find("1970") != kNotFound); + ASSERT_TRUE(formattedTime.Find("12:19:00 AM") != kNotFound || + formattedTime.Find("00:19:00") != kNotFound); + + prExplodedTime = {0, 0, 0, 7, 1, + 0, 1970, 4, 0, {(6 * 60 * 60), (1 * 60 * 60)}}; + rv = mozilla::DateTimeFormat::FormatPRExplodedTime( + kDateFormatLong, kTimeFormatLong, &prExplodedTime, formattedTime); + ASSERT_TRUE(NS_SUCCEEDED(rv)); + ASSERT_TRUE(formattedTime.Find("1.") != kNotFound); + ASSERT_TRUE(formattedTime.Find("Januar") != kNotFound); + ASSERT_TRUE(formattedTime.Find("1970") != kNotFound); + ASSERT_TRUE(formattedTime.Find("7:00:00 AM") != kNotFound || + formattedTime.Find("07:00:00") != kNotFound); + + prExplodedTime = { + 0, 0, 29, 11, 1, + 0, 1970, 4, 0, {(10 * 60 * 60) + (29 * 60), (1 * 60 * 60)}}; + rv = mozilla::DateTimeFormat::FormatPRExplodedTime( + kDateFormatLong, kTimeFormatLong, &prExplodedTime, formattedTime); + ASSERT_TRUE(NS_SUCCEEDED(rv)); + ASSERT_TRUE(formattedTime.Find("1.") != kNotFound); + ASSERT_TRUE(formattedTime.Find("Januar") != kNotFound); + ASSERT_TRUE(formattedTime.Find("1970") != kNotFound); + ASSERT_TRUE(formattedTime.Find("11:29:00 AM") != kNotFound || + formattedTime.Find("11:29:00") != kNotFound); + + prExplodedTime = {0, 0, 37, 23, 31, 11, 1969, 3, 364, {-(23 * 60), 0}}; + rv = mozilla::DateTimeFormat::FormatPRExplodedTime( + kDateFormatLong, kTimeFormatLong, &prExplodedTime, formattedTime); + ASSERT_TRUE(NS_SUCCEEDED(rv)); + ASSERT_TRUE(formattedTime.Find("31.") != kNotFound); + ASSERT_TRUE(formattedTime.Find("Dezember") != kNotFound); + ASSERT_TRUE(formattedTime.Find("1969") != kNotFound); + ASSERT_TRUE(formattedTime.Find("11:37:00 PM") != kNotFound || + formattedTime.Find("23:37:00") != kNotFound); + + prExplodedTime = {0, 0, 0, 17, 31, 11, 1969, 3, 364, {-(7 * 60 * 60), 0}}; + rv = mozilla::DateTimeFormat::FormatPRExplodedTime( + kDateFormatLong, kTimeFormatLong, &prExplodedTime, formattedTime); + ASSERT_TRUE(NS_SUCCEEDED(rv)); + ASSERT_TRUE(formattedTime.Find("31.") != kNotFound); + ASSERT_TRUE(formattedTime.Find("Dezember") != kNotFound); + ASSERT_TRUE(formattedTime.Find("1969") != kNotFound); + ASSERT_TRUE(formattedTime.Find("5:00:00 PM") != kNotFound || + formattedTime.Find("17:00:00") != kNotFound); + + prExplodedTime = { + 0, 0, 47, 14, 31, + 11, 1969, 3, 364, {-((10 * 60 * 60) + (13 * 60)), (1 * 60 * 60)}}; + rv = mozilla::DateTimeFormat::FormatPRExplodedTime( + kDateFormatLong, kTimeFormatLong, &prExplodedTime, formattedTime); + ASSERT_TRUE(NS_SUCCEEDED(rv)); + ASSERT_TRUE(formattedTime.Find("31.") != kNotFound); + ASSERT_TRUE(formattedTime.Find("Dezember") != kNotFound); + ASSERT_TRUE(formattedTime.Find("1969") != kNotFound); + ASSERT_TRUE(formattedTime.Find("2:47:00 PM") != kNotFound || + formattedTime.Find("14:47:00") != kNotFound); +} + +TEST(DateTimeFormat, DateFormatSelectorsForeign) +{ + PRTime prTime = 0; + PRExplodedTime prExplodedTime; + PR_ExplodeTime(prTime, PR_GMTParameters, &prExplodedTime); + + mozilla::DateTimeFormat::mLocale = new nsCString("de-DE"); + mozilla::DateTimeFormat::DeleteCache(); + + nsAutoString formattedTime; + nsresult rv = mozilla::DateTimeFormat::FormatDateTime( + &prExplodedTime, DateTimeFormat::Skeleton::yyyyMM, formattedTime); + ASSERT_TRUE(NS_SUCCEEDED(rv)); + ASSERT_STREQ("01.1970", NS_ConvertUTF16toUTF8(formattedTime).get()); + + rv = mozilla::DateTimeFormat::FormatDateTime( + &prExplodedTime, DateTimeFormat::Skeleton::yyyyMMMM, formattedTime); + ASSERT_TRUE(NS_SUCCEEDED(rv)); + ASSERT_STREQ("Januar 1970", NS_ConvertUTF16toUTF8(formattedTime).get()); + + rv = mozilla::DateTimeFormat::GetCalendarSymbol( + mozilla::DateTimeFormat::Field::Month, + mozilla::DateTimeFormat::Style::Wide, &prExplodedTime, formattedTime); + ASSERT_TRUE(NS_SUCCEEDED(rv)); + ASSERT_STREQ("Januar", NS_ConvertUTF16toUTF8(formattedTime).get()); + + rv = mozilla::DateTimeFormat::GetCalendarSymbol( + mozilla::DateTimeFormat::Field::Weekday, + mozilla::DateTimeFormat::Style::Abbreviated, &prExplodedTime, + formattedTime); + ASSERT_TRUE(NS_SUCCEEDED(rv)); + ASSERT_STREQ("Do", NS_ConvertUTF16toUTF8(formattedTime).get()); +} + +} // namespace mozilla diff --git a/intl/locale/tests/gtest/TestLocaleService.cpp b/intl/locale/tests/gtest/TestLocaleService.cpp new file mode 100644 index 0000000000..32bdff61d6 --- /dev/null +++ b/intl/locale/tests/gtest/TestLocaleService.cpp @@ -0,0 +1,154 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "gtest/gtest.h" +#include "mozilla/Preferences.h" +#include "mozilla/intl/LocaleService.h" +#include "mozilla/intl/MozLocale.h" + +using namespace mozilla::intl; + +TEST(Intl_Locale_LocaleService, CanonicalizeLanguageId) +{ + nsCString locale("en-US.POSIX"); + ASSERT_TRUE(LocaleService::CanonicalizeLanguageId(locale)); + ASSERT_TRUE(locale.EqualsLiteral("en-US")); + + locale.AssignLiteral("en-US_POSIX"); + ASSERT_TRUE(LocaleService::CanonicalizeLanguageId(locale)); + ASSERT_TRUE(locale.EqualsLiteral("en-US-posix")); + + locale.AssignLiteral("en-US-POSIX"); + ASSERT_TRUE(LocaleService::CanonicalizeLanguageId(locale)); + ASSERT_TRUE(locale.EqualsLiteral("en-US-posix")); + + locale.AssignLiteral("C"); + ASSERT_FALSE(LocaleService::CanonicalizeLanguageId(locale)); + ASSERT_TRUE(locale.EqualsLiteral("und")); + + locale.AssignLiteral(""); + ASSERT_FALSE(LocaleService::CanonicalizeLanguageId(locale)); + ASSERT_TRUE(locale.EqualsLiteral("und")); +} + +TEST(Intl_Locale_LocaleService, GetAppLocalesAsBCP47) +{ + nsTArray<nsCString> appLocales; + LocaleService::GetInstance()->GetAppLocalesAsBCP47(appLocales); + + ASSERT_FALSE(appLocales.IsEmpty()); +} + +TEST(Intl_Locale_LocaleService, GetAppLocalesAsLangTags) +{ + nsTArray<nsCString> appLocales; + LocaleService::GetInstance()->GetAppLocalesAsLangTags(appLocales); + + ASSERT_FALSE(appLocales.IsEmpty()); +} + +TEST(Intl_Locale_LocaleService, GetAppLocalesAsLangTags_lastIsPresent) +{ + nsAutoCString lastFallbackLocale; + LocaleService::GetInstance()->GetLastFallbackLocale(lastFallbackLocale); + + nsTArray<nsCString> appLocales; + LocaleService::GetInstance()->GetAppLocalesAsLangTags(appLocales); + + ASSERT_TRUE(appLocales.Contains(lastFallbackLocale)); +} + +TEST(Intl_Locale_LocaleService, GetAppLocaleAsLangTag) +{ + nsTArray<nsCString> appLocales; + LocaleService::GetInstance()->GetAppLocalesAsLangTags(appLocales); + + nsAutoCString locale; + LocaleService::GetInstance()->GetAppLocaleAsLangTag(locale); + + ASSERT_TRUE(appLocales[0] == locale); +} + +TEST(Intl_Locale_LocaleService, GetRegionalPrefsLocales) +{ + nsTArray<nsCString> rpLocales; + LocaleService::GetInstance()->GetRegionalPrefsLocales(rpLocales); + + int32_t len = rpLocales.Length(); + ASSERT_TRUE(len > 0); +} + +TEST(Intl_Locale_LocaleService, GetWebExposedLocales) +{ + const nsTArray<nsCString> spoofLocale{"de"_ns}; + LocaleService::GetInstance()->SetAvailableLocales(spoofLocale); + LocaleService::GetInstance()->SetRequestedLocales(spoofLocale); + + nsTArray<nsCString> pvLocales; + + mozilla::Preferences::SetInt("privacy.spoof_english", 0); + LocaleService::GetInstance()->GetWebExposedLocales(pvLocales); + ASSERT_TRUE(pvLocales.Length() > 0); + ASSERT_TRUE(pvLocales[0].Equals("de"_ns)); + + mozilla::Preferences::SetCString("intl.locale.privacy.web_exposed", "zh-TW"); + LocaleService::GetInstance()->GetWebExposedLocales(pvLocales); + ASSERT_TRUE(pvLocales.Length() > 0); + ASSERT_TRUE(pvLocales[0].Equals("zh-TW"_ns)); + + mozilla::Preferences::SetInt("privacy.spoof_english", 2); + LocaleService::GetInstance()->GetWebExposedLocales(pvLocales); + ASSERT_EQ(1u, pvLocales.Length()); + ASSERT_TRUE(pvLocales[0].Equals("en-US"_ns)); +} + +TEST(Intl_Locale_LocaleService, GetRequestedLocales) +{ + nsTArray<nsCString> reqLocales; + LocaleService::GetInstance()->GetRequestedLocales(reqLocales); + + int32_t len = reqLocales.Length(); + ASSERT_TRUE(len > 0); +} + +TEST(Intl_Locale_LocaleService, GetAvailableLocales) +{ + nsTArray<nsCString> availableLocales; + LocaleService::GetInstance()->GetAvailableLocales(availableLocales); + + int32_t len = availableLocales.Length(); + ASSERT_TRUE(len > 0); +} + +TEST(Intl_Locale_LocaleService, GetPackagedLocales) +{ + nsTArray<nsCString> packagedLocales; + LocaleService::GetInstance()->GetPackagedLocales(packagedLocales); + + int32_t len = packagedLocales.Length(); + ASSERT_TRUE(len > 0); +} + +TEST(Intl_Locale_LocaleService, GetDefaultLocale) +{ + nsAutoCString locStr; + LocaleService::GetInstance()->GetDefaultLocale(locStr); + + ASSERT_FALSE(locStr.IsEmpty()); + ASSERT_TRUE(Locale(locStr).IsWellFormed()); +} + +TEST(Intl_Locale_LocaleService, IsAppLocaleRTL) +{ + mozilla::Preferences::SetCString("intl.l10n.pseudo", "bidi"); + ASSERT_TRUE(LocaleService::GetInstance()->IsAppLocaleRTL()); + mozilla::Preferences::ClearUser("intl.l10n.pseudo"); + + mozilla::Preferences::SetInt("intl.uidirection", 0); + ASSERT_FALSE(LocaleService::GetInstance()->IsAppLocaleRTL()); + mozilla::Preferences::SetInt("intl.uidirection", 1); + ASSERT_TRUE(LocaleService::GetInstance()->IsAppLocaleRTL()); + mozilla::Preferences::SetInt("intl.uidirection", -1); +} diff --git a/intl/locale/tests/gtest/TestLocaleServiceNegotiate.cpp b/intl/locale/tests/gtest/TestLocaleServiceNegotiate.cpp new file mode 100644 index 0000000000..c428e81c8d --- /dev/null +++ b/intl/locale/tests/gtest/TestLocaleServiceNegotiate.cpp @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "gtest/gtest.h" +#include "mozilla/intl/LocaleService.h" + +using namespace mozilla::intl; + +TEST(Intl_Locale_LocaleService, Negotiate) +{ + nsTArray<nsCString> requestedLocales; + nsTArray<nsCString> availableLocales; + nsTArray<nsCString> supportedLocales; + nsAutoCString defaultLocale("en-US"); + int32_t strategy = LocaleService::kLangNegStrategyFiltering; + + requestedLocales.AppendElement("sr"_ns); + + availableLocales.AppendElement("sr-Cyrl"_ns); + availableLocales.AppendElement("sr-Latn"_ns); + + LocaleService::GetInstance()->NegotiateLanguages( + requestedLocales, availableLocales, defaultLocale, strategy, + supportedLocales); + + ASSERT_TRUE(supportedLocales.Length() == 2); + ASSERT_TRUE(supportedLocales[0].EqualsLiteral("sr-Cyrl")); + ASSERT_TRUE(supportedLocales[1].EqualsLiteral("en-US")); +} + +TEST(Intl_Locale_LocaleService, UseLSDefaultLocale) +{ + nsTArray<nsCString> requestedLocales; + nsTArray<nsCString> availableLocales; + nsTArray<nsCString> supportedLocales; + nsAutoCString defaultLocale("en-US"); + int32_t strategy = LocaleService::kLangNegStrategyLookup; + + requestedLocales.AppendElement("sr"_ns); + + availableLocales.AppendElement("de"_ns); + + LocaleService::GetInstance()->NegotiateLanguages( + requestedLocales, availableLocales, defaultLocale, strategy, + supportedLocales); + + nsAutoCString lsDefaultLocale; + LocaleService::GetInstance()->GetDefaultLocale(lsDefaultLocale); + ASSERT_TRUE(supportedLocales.Length() == 1); + ASSERT_TRUE(supportedLocales[0].Equals(lsDefaultLocale)); +} diff --git a/intl/locale/tests/gtest/TestMozLocale.cpp b/intl/locale/tests/gtest/TestMozLocale.cpp new file mode 100644 index 0000000000..c56bc14eb3 --- /dev/null +++ b/intl/locale/tests/gtest/TestMozLocale.cpp @@ -0,0 +1,123 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "gtest/gtest.h" +#include "mozilla/intl/MozLocale.h" + +using namespace mozilla::intl; + +TEST(Intl_Locale_Locale, Locale) +{ + Locale loc = Locale("en-US"); + + ASSERT_TRUE(loc.GetLanguage().Equals("en")); + ASSERT_TRUE(loc.GetRegion().Equals("US")); +} + +TEST(Intl_Locale_Locale, AsString) +{ + Locale loc = Locale("ja-jp-windows"); + + ASSERT_TRUE(loc.AsString().Equals("ja-JP-windows")); +} + +TEST(Intl_Locale_Locale, GetSubTags) +{ + Locale loc = Locale("en-latn-us-macos"); + + ASSERT_TRUE(loc.GetLanguage().Equals("en")); + ASSERT_TRUE(loc.GetScript().Equals("Latn")); + ASSERT_TRUE(loc.GetRegion().Equals("US")); + + nsTArray<nsCString> variants; + loc.GetVariants(variants); + ASSERT_TRUE(variants.Length() == 1); + ASSERT_TRUE(variants[0].Equals("macos")); +} + +TEST(Intl_Locale_Locale, Matches) +{ + Locale loc = Locale("en-US"); + + Locale loc2 = Locale("en-GB"); + ASSERT_FALSE(loc == loc2); + + Locale loc3 = Locale("en-US"); + ASSERT_TRUE(loc == loc3); + + Locale loc4 = Locale("En_us"); + ASSERT_TRUE(loc == loc4); +} + +TEST(Intl_Locale_Locale, MatchesRange) +{ + Locale loc = Locale("en-US"); + + Locale loc2 = Locale("en-Latn-US"); + ASSERT_FALSE(loc == loc2); + ASSERT_TRUE(loc.Matches(loc2, true, false)); + ASSERT_FALSE(loc.Matches(loc2, false, true)); + ASSERT_FALSE(loc.Matches(loc2, false, false)); + ASSERT_TRUE(loc.Matches(loc2, true, true)); + + Locale loc3 = Locale("en"); + ASSERT_FALSE(loc == loc3); + ASSERT_TRUE(loc.Matches(loc3, false, true)); + ASSERT_FALSE(loc.Matches(loc3, true, false)); + ASSERT_FALSE(loc.Matches(loc3, false, false)); + ASSERT_TRUE(loc.Matches(loc3, true, true)); +} + +TEST(Intl_Locale_Locale, Variants) +{ + Locale loc = Locale("en-US-UniFon-BasicEng"); + + // Make sure that we canonicalize and sort variant tags + ASSERT_TRUE(loc.AsString().Equals("en-US-basiceng-unifon")); +} + +TEST(Intl_Locale_Locale, InvalidLocale) +{ + Locale loc = Locale("en-verylongsubtag"); + ASSERT_FALSE(loc.IsWellFormed()); + + Locale loc2 = Locale("p-te"); + ASSERT_FALSE(loc2.IsWellFormed()); +} + +TEST(Intl_Locale_Locale, ClearRegion) +{ + Locale loc = Locale("en-US"); + loc.ClearRegion(); + ASSERT_TRUE(loc.AsString().Equals("en")); +} + +TEST(Intl_Locale_Locale, ClearVariants) +{ + Locale loc = Locale("en-US-windows"); + loc.ClearVariants(); + ASSERT_TRUE(loc.AsString().Equals("en-US")); +} + +TEST(Intl_Locale_Locale, jaJPmac) +{ + Locale loc = Locale("ja-JP-mac"); + ASSERT_TRUE(loc.AsString().Equals("ja-JP-macos")); +} + +TEST(Intl_Locale_Locale, Maximize) +{ + Locale loc = Locale("en"); + + ASSERT_TRUE(loc.GetLanguage().Equals("en")); + ASSERT_TRUE(loc.GetScript().IsEmpty()); + ASSERT_TRUE(loc.GetRegion().IsEmpty()); + + ASSERT_TRUE(loc.Maximize()); + + ASSERT_TRUE(loc.GetLanguage().Equals("en")); + ASSERT_TRUE(loc.GetScript().Equals("Latn")); + ASSERT_TRUE(loc.GetRegion().Equals("US")); +} diff --git a/intl/locale/tests/gtest/TestOSPreferences.cpp b/intl/locale/tests/gtest/TestOSPreferences.cpp new file mode 100644 index 0000000000..605b301c09 --- /dev/null +++ b/intl/locale/tests/gtest/TestOSPreferences.cpp @@ -0,0 +1,203 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "gtest/gtest.h" +#include "mozilla/ArrayUtils.h" +#include "mozilla/Preferences.h" +#include "mozilla/intl/OSPreferences.h" + +using namespace mozilla::intl; + +/** + * We test that on all platforms we test against (irrelevant of the tier), + * we will be able to retrieve at least a single locale out of the system. + * + * In theory, that may not be true, but if we encounter such platform we should + * decide how to handle this and special case and this test should make + * it not happen without us noticing. + */ +TEST(Intl_Locale_OSPreferences, GetSystemLocales) +{ + nsTArray<nsCString> systemLocales; + ASSERT_TRUE(NS_SUCCEEDED( + OSPreferences::GetInstance()->GetSystemLocales(systemLocales))); + + ASSERT_FALSE(systemLocales.IsEmpty()); +} + +/** + * We test that on all platforms we test against (irrelevant of the tier), + * we will be able to retrieve at least a single locale out of the system. + * + * In theory, that may not be true, but if we encounter such platform we should + * decide how to handle this and special case and this test should make + * it not happen without us noticing. + */ +TEST(Intl_Locale_OSPreferences, GetRegionalPrefsLocales) +{ + nsTArray<nsCString> rgLocales; + ASSERT_TRUE(NS_SUCCEEDED( + OSPreferences::GetInstance()->GetRegionalPrefsLocales(rgLocales))); + + ASSERT_FALSE(rgLocales.IsEmpty()); +} + +/** + * We test that on all platforms we test against, + * we will be able to retrieve a date and time pattern. + * + * This may come back empty on platforms where we don't have platforms + * bindings for, so effectively, we're testing for crashes. We should + * never crash. + */ +TEST(Intl_Locale_OSPreferences, GetDateTimePattern) +{ + nsAutoCString pattern; + OSPreferences* osprefs = OSPreferences::GetInstance(); + + struct Test { + int dateStyle; + int timeStyle; + const char* locale; + }; + Test tests[] = {{0, 0, ""}, {1, 0, "pl"}, {2, 0, "de-DE"}, {3, 0, "fr"}, + {4, 0, "ar"}, + + {0, 1, ""}, {0, 2, "it"}, {0, 3, ""}, {0, 4, "ru"}, + + {4, 1, ""}, {3, 2, "cs"}, {2, 3, ""}, {1, 4, "ja"}}; + + for (unsigned i = 0; i < mozilla::ArrayLength(tests); i++) { + const Test& t = tests[i]; + if (NS_SUCCEEDED(osprefs->GetDateTimePattern( + t.dateStyle, t.timeStyle, nsDependentCString(t.locale), pattern))) { + ASSERT_TRUE((t.dateStyle == 0 && t.timeStyle == 0) || !pattern.IsEmpty()); + } + } + + // If the locale is not specified, we should get the pattern corresponding to + // the first regional prefs locale. + AutoTArray<nsCString, 10> rpLocales; + LocaleService::GetInstance()->GetRegionalPrefsLocales(rpLocales); + ASSERT_TRUE(rpLocales.Length() > 0); + + nsAutoCString rpLocalePattern; + ASSERT_TRUE(NS_SUCCEEDED( + osprefs->GetDateTimePattern(mozIOSPreferences::dateTimeFormatStyleLong, + mozIOSPreferences::dateTimeFormatStyleLong, + rpLocales[0], rpLocalePattern))); + ASSERT_TRUE(NS_SUCCEEDED( + osprefs->GetDateTimePattern(mozIOSPreferences::dateTimeFormatStyleLong, + mozIOSPreferences::dateTimeFormatStyleLong, + nsDependentCString(""), pattern))); + ASSERT_EQ(rpLocalePattern, pattern); +} + +/** + * Test that is possible to override the OS defaults through a pref. + */ +TEST(Intl_Locale_OSPreferences, GetDateTimePatternPrefOverrides) +{ + nsresult nr; + nsAutoCString default_pattern, pattern; + OSPreferences* osprefs = OSPreferences::GetInstance(); + + struct { + const char* DatePref; + const char* TimePref; + int32_t DateTimeFormatStyle; + } configs[] = {{"intl.date_time.pattern_override.date_short", + "intl.date_time.pattern_override.time_short", + mozIOSPreferences::dateTimeFormatStyleShort}, + {"intl.date_time.pattern_override.date_medium", + "intl.date_time.pattern_override.time_medium", + mozIOSPreferences::dateTimeFormatStyleMedium}, + {"intl.date_time.pattern_override.date_long", + "intl.date_time.pattern_override.time_long", + mozIOSPreferences::dateTimeFormatStyleLong}, + {"intl.date_time.pattern_override.date_full", + "intl.date_time.pattern_override.time_full", + mozIOSPreferences::dateTimeFormatStyleFull}}; + + for (const auto& config : configs) { + // Get default value for the OS + nr = osprefs->GetDateTimePattern(config.DateTimeFormatStyle, + mozIOSPreferences::dateTimeFormatStyleNone, + nsDependentCString(""), default_pattern); + ASSERT_TRUE(NS_SUCCEEDED(nr)); + + // Override date format + mozilla::Preferences::SetCString(config.DatePref, "yy-MM"); + nr = osprefs->GetDateTimePattern(config.DateTimeFormatStyle, + mozIOSPreferences::dateTimeFormatStyleNone, + nsDependentCString(""), pattern); + ASSERT_TRUE(NS_SUCCEEDED(nr)); + ASSERT_TRUE(pattern.EqualsASCII("yy-MM")); + + // Override time format + mozilla::Preferences::SetCString(config.TimePref, "HH:mm"); + nr = osprefs->GetDateTimePattern(mozIOSPreferences::dateTimeFormatStyleNone, + config.DateTimeFormatStyle, + nsDependentCString(""), pattern); + ASSERT_TRUE(NS_SUCCEEDED(nr)); + ASSERT_TRUE(pattern.EqualsASCII("HH:mm")); + + // Override both + nr = osprefs->GetDateTimePattern(config.DateTimeFormatStyle, + config.DateTimeFormatStyle, + nsDependentCString(""), pattern); + ASSERT_TRUE(NS_SUCCEEDED(nr)); + ASSERT_TRUE(pattern.Find("yy-MM") != kNotFound); + ASSERT_TRUE(pattern.Find("HH:mm") != kNotFound); + + // Clear overrides, we should get the default value back. + mozilla::Preferences::ClearUser(config.DatePref); + mozilla::Preferences::ClearUser(config.TimePref); + nr = osprefs->GetDateTimePattern(config.DateTimeFormatStyle, + mozIOSPreferences::dateTimeFormatStyleNone, + nsDependentCString(""), pattern); + ASSERT_TRUE(NS_SUCCEEDED(nr)); + ASSERT_EQ(default_pattern, pattern); + } + + // Test overriding connector + nr = osprefs->GetDateTimePattern(mozIOSPreferences::dateTimeFormatStyleShort, + mozIOSPreferences::dateTimeFormatStyleShort, + nsDependentCString(""), default_pattern); + + mozilla::Preferences::SetCString("intl.date_time.pattern_override.date_short", + "yyyy-MM-dd"); + mozilla::Preferences::SetCString("intl.date_time.pattern_override.time_short", + "HH:mm:ss"); + mozilla::Preferences::SetCString( + "intl.date_time.pattern_override.date_time_short", "{1} {0}"); + nr = osprefs->GetDateTimePattern(mozIOSPreferences::dateTimeFormatStyleShort, + mozIOSPreferences::dateTimeFormatStyleShort, + nsDependentCString(""), pattern); + ASSERT_TRUE(NS_SUCCEEDED(nr)); + ASSERT_TRUE(pattern.EqualsASCII("yyyy-MM-dd HH:mm:ss")); + + // Reset to date and time to defaults + mozilla::Preferences::ClearUser("intl.date_time.pattern_override.date_short"); + mozilla::Preferences::ClearUser("intl.date_time.pattern_override.time_short"); + + // Invalid patterns are ignored + mozilla::Preferences::SetCString( + "intl.date_time.pattern_override.date_time_short", "hello, world!"); + nr = osprefs->GetDateTimePattern(mozIOSPreferences::dateTimeFormatStyleShort, + mozIOSPreferences::dateTimeFormatStyleShort, + nsDependentCString(""), pattern); + ASSERT_TRUE(NS_SUCCEEDED(nr)); + ASSERT_EQ(default_pattern, pattern); + + // Clearing the override results in getting the default pattern back. + mozilla::Preferences::ClearUser( + "intl.date_time.pattern_override.date_time_short"); + nr = osprefs->GetDateTimePattern(mozIOSPreferences::dateTimeFormatStyleShort, + mozIOSPreferences::dateTimeFormatStyleShort, + nsDependentCString(""), pattern); + ASSERT_TRUE(NS_SUCCEEDED(nr)); + ASSERT_EQ(default_pattern, pattern); +} diff --git a/intl/locale/tests/gtest/moz.build b/intl/locale/tests/gtest/moz.build new file mode 100644 index 0000000000..e23c828f26 --- /dev/null +++ b/intl/locale/tests/gtest/moz.build @@ -0,0 +1,16 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +UNIFIED_SOURCES += [ + "TestCollation.cpp", + "TestDateTimeFormat.cpp", + "TestLocaleService.cpp", + "TestLocaleServiceNegotiate.cpp", + "TestMozLocale.cpp", + "TestOSPreferences.cpp", +] + +FINAL_LIBRARY = "xul-gtest" diff --git a/intl/locale/tests/sort/us-ascii_base.txt b/intl/locale/tests/sort/us-ascii_base.txt new file mode 100644 index 0000000000..3bc7fbc7be --- /dev/null +++ b/intl/locale/tests/sort/us-ascii_base.txt @@ -0,0 +1,95 @@ + +! +" +# +$ +% +& +' +( +) +* ++ +, +- +. +/ +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +: +; +< += +> +? +@ +A +B +C +D +E +F +G +H +I +J +K +L +M +N +O +P +Q +R +S +T +U +V +W +X +Y +Z +[ +\ +] +^ +_ +` +a +b +c +d +e +f +g +h +i +j +k +l +m +n +o +p +q +r +s +t +u +v +w +x +y +z +{ +| +} +~ diff --git a/intl/locale/tests/sort/us-ascii_base_case_res.txt b/intl/locale/tests/sort/us-ascii_base_case_res.txt new file mode 100644 index 0000000000..3e526d226b --- /dev/null +++ b/intl/locale/tests/sort/us-ascii_base_case_res.txt @@ -0,0 +1,96 @@ +' +- + +! +" +# +$ +% +& +( +) +* +, +. +/ +: +; +? +@ +[ +\ +] +^ +_ +` +{ +| +} +~ ++ +< += +> +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +A +b +B +c +C +d +D +e +E +f +F +g +G +h +H +i +I +j +J +k +K +l +L +m +M +n +N +o +O +p +P +q +Q +r +R +s +S +t +T +u +U +v +V +w +W +x +X +y +Y +z +Z + diff --git a/intl/locale/tests/sort/us-ascii_base_nocase_res.txt b/intl/locale/tests/sort/us-ascii_base_nocase_res.txt new file mode 100644 index 0000000000..2d18096db5 --- /dev/null +++ b/intl/locale/tests/sort/us-ascii_base_nocase_res.txt @@ -0,0 +1,96 @@ +' +- + +! +" +# +$ +% +& +( +) +* +, +. +/ +: +; +? +@ +[ +\ +] +^ +_ +` +{ +| +} +~ ++ +< += +> +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +a +B +b +C +c +d +D +e +E +f +F +g +G +h +H +i +I +j +J +k +K +L +l +m +M +n +N +O +o +p +P +q +Q +r +R +s +S +t +T +u +U +v +V +w +W +X +x +Y +y +Z +z + diff --git a/intl/locale/tests/sort/us-ascii_sort.txt b/intl/locale/tests/sort/us-ascii_sort.txt new file mode 100644 index 0000000000..b6962f8de8 --- /dev/null +++ b/intl/locale/tests/sort/us-ascii_sort.txt @@ -0,0 +1,78 @@ +ludwig van beethoven +Ludwig van Beethoven +Ludwig van beethoven +Jane +jane +JANE +jAne +jaNe +janE +JAne +JaNe +JanE +JANe +JaNE +JAnE +jANE +Umberto Eco +Umberto eco +umberto eco +umberto Eco +UMBERTO ECO +ace +bash +*ace +!ace +%ace +~ace +#ace +cork +denizen +[denizen] +(denizen) +{denizen} +/denizen/ +#denizen# +$denizen$ +@denizen +elf +full +gnome +gnomic investigation of typological factors in the grammaticalization process of Malayo-Polynesian substaratum in the protoAltaic vocabulary core in the proto-layers of pre-historic Japanese +gnomic investigation of typological factors in the grammaticalization process of Malayo-Polynesian substaratum in the protoAltaic vocabulary core in the proto-layers of pre-historic Javanese +hint +Internationalization +Zinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalization +Zinternationalization internationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizatio +n +Zinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalization internationalizationinternationalizationinternationalizationinternationalizationinternationalization +ZinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizaTioninternationalizationinternationalizationinternationalizationinternationalization +ZinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizaTion +jostle +kin +Laymen +lumens +Lumens +motleycrew +motley crew +niven's creative talents +nivens creative talents +opie +posh restaurants in surbanized and still urban incorporated subsection of this beautifl city in the Rockies +posh restaurants in surbanized and still urban incorporated subsection of this beautifl city in the Rokkies +posh restaurants in surbanized and still urban incorporated subsection of this beautifl city in the rockies +quilt's +quilts +quilt +Rondo +street +tamale oxidization and iodization in rapid progress +tamale oxidization and iodization in rapid Progress +until +vera +Wobble +Xanadu's legenary imaginary floccinaucinihilipilification in localization of theoretical portions of glottochronological understanding of the phoneme +Xanadu's legenary imaginary floccinaucinihilipilification in localization of theoretical portions of glottochronological understanding of the phoname +yearn +zodiac + diff --git a/intl/locale/tests/sort/us-ascii_sort_case_res.txt b/intl/locale/tests/sort/us-ascii_sort_case_res.txt new file mode 100644 index 0000000000..2720a83426 --- /dev/null +++ b/intl/locale/tests/sort/us-ascii_sort_case_res.txt @@ -0,0 +1,79 @@ +!ace +#ace +#denizen# +$denizen$ +%ace +(denizen) +*ace +/denizen/ +@denizen +[denizen] +{denizen} +~ace +ace +bash +cork +denizen +elf +full +gnome +gnomic investigation of typological factors in the grammaticalization process of Malayo-Polynesian substaratum in the protoAltaic vocabulary core in the proto-layers of pre-historic Japanese +gnomic investigation of typological factors in the grammaticalization process of Malayo-Polynesian substaratum in the protoAltaic vocabulary core in the proto-layers of pre-historic Javanese +hint +Internationalization +jane +janE +jaNe +jAne +jANE +Jane +JanE +JaNe +JaNE +JAne +JAnE +JANe +JANE +jostle +kin +Laymen +ludwig van beethoven +Ludwig van beethoven +Ludwig van Beethoven +lumens +Lumens +motley crew +motleycrew +nivens creative talents +niven's creative talents +opie +posh restaurants in surbanized and still urban incorporated subsection of this beautifl city in the rockies +posh restaurants in surbanized and still urban incorporated subsection of this beautifl city in the Rockies +posh restaurants in surbanized and still urban incorporated subsection of this beautifl city in the Rokkies +quilt +quilts +quilt's +Rondo +street +tamale oxidization and iodization in rapid progress +tamale oxidization and iodization in rapid Progress +umberto eco +umberto Eco +Umberto eco +Umberto Eco +UMBERTO ECO +until +veda +Veda +vera +Vera +Wobble +Xanadu's legenary imaginary floccinaucinihilipilification in localization of theoretical portions of glottochronological understanding of the phoname +Xanadu's legenary imaginary floccinaucinihilipilification in localization of theoretical portions of glottochronological understanding of the phoneme +yearn +Zinternationalization internationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalization +Zinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalization internationalizationinternationalizationinternationalizationinternationalizationinternationalization +Zinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalization +ZinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizaTion +ZinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizaTioninternationalizationinternationalizationinternationalizationinternationalization +zodiac diff --git a/intl/locale/tests/sort/us-ascii_sort_nocase_res.txt b/intl/locale/tests/sort/us-ascii_sort_nocase_res.txt new file mode 100644 index 0000000000..fa3426d4e9 --- /dev/null +++ b/intl/locale/tests/sort/us-ascii_sort_nocase_res.txt @@ -0,0 +1,79 @@ +!ace +#ace +#denizen# +$denizen$ +%ace +(denizen) +*ace +/denizen/ +@denizen +[denizen] +{denizen} +~ace +ace +bash +cork +denizen +elf +full +gnome +gnomic investigation of typological factors in the grammaticalization process of Malayo-Polynesian substaratum in the protoAltaic vocabulary core in the proto-layers of pre-historic Japanese +gnomic investigation of typological factors in the grammaticalization process of Malayo-Polynesian substaratum in the protoAltaic vocabulary core in the proto-layers of pre-historic Javanese +hint +Internationalization +JANe +jANE +JAnE +JaNE +Jane +JanE +JaNe +JAne +janE +jaNe +jAne +JANE +jane +jostle +kin +Laymen +Ludwig van beethoven +Ludwig van Beethoven +ludwig van beethoven +Lumens +lumens +motley crew +motleycrew +nivens creative talents +niven's creative talents +opie +posh restaurants in surbanized and still urban incorporated subsection of this beautifl city in the rockies +posh restaurants in surbanized and still urban incorporated subsection of this beautifl city in the Rockies +posh restaurants in surbanized and still urban incorporated subsection of this beautifl city in the Rokkies +quilt +quilts +quilt's +Rondo +street +tamale oxidization and iodization in rapid Progress +tamale oxidization and iodization in rapid progress +Umberto eco +Umberto Eco +umberto eco +UMBERTO ECO +umberto Eco +until +Veda +veda +Vera +vera +Wobble +Xanadu's legenary imaginary floccinaucinihilipilification in localization of theoretical portions of glottochronological understanding of the phoname +Xanadu's legenary imaginary floccinaucinihilipilification in localization of theoretical portions of glottochronological understanding of the phoneme +yearn +Zinternationalization internationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalization +Zinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalization internationalizationinternationalizationinternationalizationinternationalizationinternationalization +ZinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizaTioninternationalizationinternationalizationinternationalizationinternationalization +ZinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizaTion +Zinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalization +zodiac diff --git a/intl/locale/tests/unit/data/chrome.manifest b/intl/locale/tests/unit/data/chrome.manifest new file mode 100644 index 0000000000..a8678deef3 --- /dev/null +++ b/intl/locale/tests/unit/data/chrome.manifest @@ -0,0 +1 @@ +content locale ./ diff --git a/intl/locale/tests/unit/data/intl_on_workers_worker.js b/intl/locale/tests/unit/data/intl_on_workers_worker.js new file mode 100644 index 0000000000..fe03359002 --- /dev/null +++ b/intl/locale/tests/unit/data/intl_on_workers_worker.js @@ -0,0 +1,4 @@ +self.onmessage = function(data) { + let myLocale = Intl.NumberFormat().resolvedOptions().locale; + self.postMessage(myLocale); +}; diff --git a/intl/locale/tests/unit/test_bug1086527.js b/intl/locale/tests/unit/test_bug1086527.js new file mode 100644 index 0000000000..a344688698 --- /dev/null +++ b/intl/locale/tests/unit/test_bug1086527.js @@ -0,0 +1,22 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * This unit test makes sure that PluralForm.get can be called from strict mode + */ + +const { PluralForm } = ChromeUtils.import( + "resource://gre/modules/PluralForm.jsm" +); + +delete PluralForm.numForms; +delete PluralForm.get; +[PluralForm.get, PluralForm.numForms] = PluralForm.makeGetter(9); + +function run_test() { + "use strict"; + + Assert.equal(3, PluralForm.numForms()); + Assert.equal("one", PluralForm.get(5, "one;many")); +} diff --git a/intl/locale/tests/unit/test_bug22310.js b/intl/locale/tests/unit/test_bug22310.js new file mode 100644 index 0000000000..bc312398db --- /dev/null +++ b/intl/locale/tests/unit/test_bug22310.js @@ -0,0 +1,65 @@ +String.prototype.has = function(s) { + return this.includes(s); +}; + +function dt(locale) { + var date = new Date("2008-06-30T13:56:34"); + const dtOptions = { + year: "numeric", + month: "long", + day: "numeric", + hour: "numeric", + minute: "numeric", + second: "numeric", + }; + return date.toLocaleString(locale, dtOptions); +} + +var all_passed = true; +const tests = [ + [dt("en-US").has("June"), "month name in en-US"], + [dt("en-US").has("2008"), "year in en-US"], + [dt("da").has("jun"), "month name in da"], + [dt("da-DK") == dt("da"), "da same as da-DK"], + [ + dt("en-GB").has("30") && + dt("en-GB").has("June") && + dt("en-GB").indexOf("30") < dt("en-GB").indexOf("June"), + "day before month in en-GB", + ], + [ + dt("en-US").has("30") && + dt("en-US").has("June") && + dt("en-US").indexOf("30") > dt("en-US").indexOf("June"), + "month before day in en-US", + ], + [dt("ja-JP").has("\u5E746\u670830\u65E5"), "year month and day in ja-JP"], + // The Firefox locale code ja-JP-mac will be resolved to a BCP47-compliant + // tag ja-JP-x-lvariant-mac by uloc_toLanguageTag + [ + dt("ja-JP") == dt("ja-JP-x-lvariant-mac"), + "ja-JP-x-lvariant-mac same as ja-JP", + ], + [dt("nn-NO").has("juni"), "month name in nn-NO"], + [dt("nb-NO").has("juni"), "month name in nb-NO"], + // Bug 1261775 - failures on win10 + //[dt("no-NO").has("30. juni"), "month name in no-NO"], + [dt("sv-SE").has("30 jun"), "month name in sv-SE"], + [dt("kok").has("\u091C\u0942\u0928"), "month name in kok"], + [dt("ta-IN").has("\u0B9C\u0BC2\u0BA9\u0BCD"), "month name in ta-IN"], + [!!dt("ab-CD").length, "fallback for ab-CD"], +]; + +function one_test(testcase, msg) { + if (!testcase) { + all_passed = false; + dump("Unexpected date format: " + msg + "\n"); + } +} + +function run_test() { + for (var i = 0; i < tests.length; ++i) { + one_test(tests[i][0], tests[i][1]); + } + Assert.ok(all_passed); +} diff --git a/intl/locale/tests/unit/test_intl_on_workers.js b/intl/locale/tests/unit/test_intl_on_workers.js new file mode 100644 index 0000000000..4de22cf1c3 --- /dev/null +++ b/intl/locale/tests/unit/test_intl_on_workers.js @@ -0,0 +1,29 @@ +function run_test() { + do_load_manifest("data/chrome.manifest"); + + if (typeof Intl !== "object") { + dump("Intl not enabled, skipping test\n"); + equal(true, true); + return; + } + + let mainThreadLocale = Intl.NumberFormat().resolvedOptions().locale; + let testWorker = new Worker( + "chrome://locale/content/intl_on_workers_worker.js" + ); + testWorker.onmessage = function(e) { + try { + let workerLocale = e.data; + equal( + mainThreadLocale, + workerLocale, + "Worker should inherit Intl locale from main thread." + ); + } finally { + do_test_finished(); + } + }; + + do_test_pending(); + testWorker.postMessage("go!"); +} diff --git a/intl/locale/tests/unit/test_localeService.js b/intl/locale/tests/unit/test_localeService.js new file mode 100644 index 0000000000..2ad0f82a34 --- /dev/null +++ b/intl/locale/tests/unit/test_localeService.js @@ -0,0 +1,241 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); +const osPrefs = Cc["@mozilla.org/intl/ospreferences;1"].getService( + Ci.mozIOSPreferences +); + +const localeService = Services.locale; + +/** + * Make sure the locale service can be instantiated. + */ + +add_test(function test_defaultLocale() { + const defaultLocale = localeService.defaultLocale; + Assert.ok(defaultLocale.length !== 0, "Default locale is not empty"); + run_next_test(); +}); + +add_test(function test_lastFallbackLocale() { + const lastFallbackLocale = localeService.lastFallbackLocale; + Assert.ok(lastFallbackLocale === "en-US", "Last fallback locale is en-US"); + run_next_test(); +}); + +add_test(function test_appLocalesAsLangTags() { + const appLocale = localeService.appLocaleAsLangTag; + Assert.ok(appLocale != "", "appLocale is non-empty"); + + const appLocales = localeService.appLocalesAsLangTags; + Assert.ok(Array.isArray(appLocales), "appLocales returns an array"); + + Assert.ok( + appLocale == appLocales[0], + "appLocale matches first entry in appLocales" + ); + + const enUSLocales = appLocales.filter(loc => loc === "en-US"); + Assert.ok(enUSLocales.length == 1, "en-US is present exactly one time"); + + run_next_test(); +}); + +const PREF_REQUESTED_LOCALES = "intl.locale.requested"; +const REQ_LOC_CHANGE_EVENT = "intl:requested-locales-changed"; + +add_test(function test_requestedLocales() { + const requestedLocales = localeService.requestedLocales; + Assert.ok( + Array.isArray(requestedLocales), + "requestedLocales returns an array" + ); + + run_next_test(); +}); + +/** + * In this test we verify that after we set an observer on the LocaleService + * event for requested locales change, it will be fired when the + * pref for matchOS is set to true. + * + * Then, we test that when the matchOS is set to true, we will retrieve + * OS locale from requestedLocales. + */ +add_test(function test_requestedLocales_matchOS() { + do_test_pending(); + + Services.prefs.setCharPref(PREF_REQUESTED_LOCALES, "ar-IR"); + + const observer = { + observe(aSubject, aTopic, aData) { + switch (aTopic) { + case REQ_LOC_CHANGE_EVENT: + const reqLocs = localeService.requestedLocales; + Assert.ok(reqLocs[0] === osPrefs.systemLocale); + Services.obs.removeObserver(observer, REQ_LOC_CHANGE_EVENT); + do_test_finished(); + } + }, + }; + + Services.obs.addObserver(observer, REQ_LOC_CHANGE_EVENT); + Services.prefs.setCharPref(PREF_REQUESTED_LOCALES, ""); + + run_next_test(); +}); + +/** + * In this test we verify that after we set an observer on the LocaleService + * event for requested locales change, it will be fired when the + * pref for browser UI locale changes. + */ +add_test(function test_requestedLocales_onChange() { + do_test_pending(); + + Services.prefs.setCharPref(PREF_REQUESTED_LOCALES, "ar-IR"); + + const observer = { + observe(aSubject, aTopic, aData) { + switch (aTopic) { + case REQ_LOC_CHANGE_EVENT: + const reqLocs = localeService.requestedLocales; + Assert.ok(reqLocs[0] === "sr-RU"); + Services.obs.removeObserver(observer, REQ_LOC_CHANGE_EVENT); + do_test_finished(); + } + }, + }; + + Services.obs.addObserver(observer, REQ_LOC_CHANGE_EVENT); + Services.prefs.setCharPref(PREF_REQUESTED_LOCALES, "sr-RU"); + + run_next_test(); +}); + +add_test(function test_requestedLocale() { + Services.prefs.setCharPref(PREF_REQUESTED_LOCALES, "tlh"); + + let requestedLocale = localeService.requestedLocale; + Assert.ok( + requestedLocale === "tlh", + "requestedLocale returns the right value" + ); + + Services.prefs.clearUserPref(PREF_REQUESTED_LOCALES); + + run_next_test(); +}); + +add_test(function test_requestedLocales() { + localeService.requestedLocales = ["de-AT", "de-DE", "de-CH"]; + + let locales = localeService.requestedLocales; + Assert.ok(locales[0] === "de-AT"); + Assert.ok(locales[1] === "de-DE"); + Assert.ok(locales[2] === "de-CH"); + + run_next_test(); +}); + +add_test(function test_isAppLocaleRTL() { + Assert.ok(typeof localeService.isAppLocaleRTL === "boolean"); + + run_next_test(); +}); + +add_test(function test_isAppLocaleRTL_pseudo() { + let avLocales = localeService.availableLocales; + let reqLocales = localeService.requestedLocales; + + localeService.availableLocales = ["en-US"]; + localeService.requestedLocales = ["en-US"]; + Services.prefs.setCharPref("intl.l10n.pseudo", ""); + + Assert.ok(localeService.isAppLocaleRTL === false); + + Services.prefs.setCharPref("intl.l10n.pseudo", "bidi"); + Assert.ok(localeService.isAppLocaleRTL === true); + + Services.prefs.setCharPref("intl.l10n.pseudo", "accented"); + Assert.ok(localeService.isAppLocaleRTL === false); + + // Clean up + localeService.availableLocales = avLocales; + localeService.requestedLocales = reqLocales; + Services.prefs.clearUserPref("intl.l10n.pseudo"); + + run_next_test(); +}); + +add_test(function test_packagedLocales() { + const locales = localeService.packagedLocales; + Assert.ok(locales.length !== 0, "Packaged locales are empty"); + run_next_test(); +}); + +add_test(function test_availableLocales() { + const avLocales = localeService.availableLocales; + localeService.availableLocales = ["und", "ar-IR"]; + + let locales = localeService.availableLocales; + Assert.ok(locales.length == 2); + Assert.ok(locales[0] === "und"); + Assert.ok(locales[1] === "ar-IR"); + + localeService.availableLocales = avLocales; + + run_next_test(); +}); + +/** + * This test verifies that all values coming from the pref are sanitized. + */ +add_test(function test_requestedLocales_sanitize() { + Services.prefs.setStringPref( + PREF_REQUESTED_LOCALES, + "de,2,#$@#,pl,ąó,!a2,DE-at,,;" + ); + + let locales = localeService.requestedLocales; + Assert.equal(locales[0], "de"); + Assert.equal(locales[1], "pl"); + Assert.equal(locales[2], "de-AT"); + Assert.equal(locales.length, 3); + + Services.prefs.clearUserPref(PREF_REQUESTED_LOCALES); + + run_next_test(); +}); + +add_test(function test_handle_ja_JP_mac() { + const bkpAvLocales = localeService.availableLocales; + + localeService.availableLocales = ["ja-JP-mac", "en-US"]; + + localeService.requestedLocales = ["ja-JP-mac"]; + + let reqLocales = localeService.requestedLocales; + Assert.equal(reqLocales[0], "ja-JP-macos"); + + let avLocales = localeService.availableLocales; + Assert.equal(avLocales[0], "ja-JP-macos"); + + let appLocales = localeService.appLocalesAsBCP47; + Assert.equal(appLocales[0], "ja-JP-macos"); + + let appLocalesAsLT = localeService.appLocalesAsLangTags; + Assert.equal(appLocalesAsLT[0], "ja-JP-mac"); + + Assert.equal(localeService.appLocaleAsLangTag, "ja-JP-mac"); + + localeService.availableLocales = bkpAvLocales; + + run_next_test(); +}); + +registerCleanupFunction(() => { + Services.prefs.clearUserPref(PREF_REQUESTED_LOCALES); +}); diff --git a/intl/locale/tests/unit/test_localeService_negotiateLanguages.js b/intl/locale/tests/unit/test_localeService_negotiateLanguages.js new file mode 100644 index 0000000000..392a2dd7d9 --- /dev/null +++ b/intl/locale/tests/unit/test_localeService_negotiateLanguages.js @@ -0,0 +1,205 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); +const localeService = Services.locale; + +const data = { + filtering: { + "exact match": [ + [["en"], ["en"], ["en"]], + [["en-US"], ["en-US"], ["en-US"]], + [["en-Latn-US"], ["en-Latn-US"], ["en-Latn-US"]], + [["en-Latn-US-windows"], ["en-Latn-US-windows"], ["en-Latn-US-windows"]], + [["fr-FR"], ["de", "it", "fr-FR"], ["fr-FR"]], + [ + ["fr", "pl", "de-DE"], + ["pl", "en-US", "de-DE"], + ["pl", "de-DE"], + ], + ], + "available as range": [ + [["en-US"], ["en"], ["en"]], + [["en-Latn-US"], ["en-US"], ["en-US"]], + [["en-US-windows"], ["en-US"], ["en-US"]], + [ + ["fr-CA", "de-DE"], + ["fr", "it", "de"], + ["fr", "de"], + ], + [["ja-JP-windows"], ["ja"], ["ja"]], + [ + ["en-Latn-GB", "en-Latn-IN"], + ["en-IN", "en-GB"], + ["en-GB", "en-IN"], + ], + ], + "should match on likely subtag": [ + [["en"], ["en-GB", "de", "en-US"], ["en-US", "en-GB"]], + [ + ["en"], + ["en-Latn-GB", "de", "en-Latn-US"], + ["en-Latn-US", "en-Latn-GB"], + ], + [["fr"], ["fr-CA", "fr-FR"], ["fr-FR", "fr-CA"]], + [["az-IR"], ["az-Latn", "az-Arab"], ["az-Arab"]], + [["sr-RU"], ["sr-Cyrl", "sr-Latn"], ["sr-Latn"]], + [["sr"], ["sr-Latn", "sr-Cyrl"], ["sr-Cyrl"]], + [["zh-GB"], ["zh-Hans", "zh-Hant"], ["zh-Hant"]], + [["sr", "ru"], ["sr-Latn", "ru"], ["ru"]], + [["sr-RU"], ["sr-Latn-RO", "sr-Cyrl"], ["sr-Latn-RO"]], + ], + "should match likelySubtag region over other regions": [ + [["en-CA"], ["en-ZA", "en-GB", "en-US"], ["en-US", "en-ZA", "en-GB"]], + ], + "should match cross-region": [ + [["en"], ["en-US"], ["en-US"]], + [["en-US"], ["en-GB"], ["en-GB"]], + [["en-Latn-US"], ["en-Latn-GB"], ["en-Latn-GB"]], + ], + "should match cross-variant": [ + [["en-US-linux"], ["en-US-windows"], ["en-US-windows"]], + ], + "should prioritize properly": [ + // exact match first + [ + ["en-US"], + ["en-US-windows", "en", "en-US"], + ["en-US", "en", "en-US-windows"], + ], + // available as range second + [["en-Latn-US"], ["en-GB", "en-US"], ["en-US", "en-GB"]], + // likely subtags third + [["en"], ["en-Cyrl-US", "en-Latn-US"], ["en-Latn-US"]], + // variant range fourth + [ + ["en-US-macos"], + ["en-US-windows", "en-GB-macos"], + ["en-US-windows", "en-GB-macos"], + ], + // regional range fifth + [["en-US-macos"], ["en-GB-windows"], ["en-GB-windows"]], + [["en-US"], ["en-GB", "en"], ["en", "en-GB"]], + [ + ["fr-CA-macos", "de-DE"], + ["de-DE", "fr-FR-windows"], + ["fr-FR-windows", "de-DE"], + ], + ], + "should handle default locale properly": [ + [["fr"], ["de", "it"], []], + [["fr"], ["de", "it"], "en-US", ["en-US"]], + [["fr"], ["de", "en-US"], "en-US", ["en-US"]], + [ + ["fr", "de-DE"], + ["de-DE", "fr-CA"], + "en-US", + ["fr-CA", "de-DE", "en-US"], + ], + ], + "should handle all matches on the 1st higher than any on the 2nd": [ + [ + ["fr-CA-macos", "de-DE"], + ["de-DE", "fr-FR-windows"], + ["fr-FR-windows", "de-DE"], + ], + ], + "should handle cases and underscores, returning the form given in the 'available' list": [ + [["fr_FR"], ["fr-FR"], ["fr-FR"]], + [["fr_fr"], ["fr-FR"], ["fr-FR"]], + [["fr_Fr"], ["fr-fR"], ["fr-fR"]], + [["fr_lAtN_fr"], ["fr-Latn-FR"], ["fr-Latn-FR"]], + [["fr_FR"], ["fr_FR"], ["fr_FR"]], + [["fr-FR"], ["fr_FR"], ["fr_FR"]], + [["fr_Cyrl_FR_macos"], ["fr_Cyrl_fr-macos"], ["fr_Cyrl_fr-macos"]], + ], + "should handle mozilla specific 3-letter variants": [ + [ + ["ja-JP-mac", "de-DE"], + ["ja-JP-mac", "de-DE"], + ["ja-JP-mac", "de-DE"], + ], + ], + "should not crash on invalid input": [ + [["fą-FŻ"], ["ór_Fń"], []], + [["2"], ["ąóżł"], []], + [[[""]], ["fr-FR"], []], + ], + "should not match on invalid input": [[["en"], ["ťŮ"], []]], + }, + matching: { + "should match only one per requested": [ + [ + ["fr", "en"], + ["en-US", "fr-FR", "en", "fr"], + null, + localeService.langNegStrategyMatching, + ["fr", "en"], + ], + ], + }, + lookup: { + "should match only one": [ + [ + ["fr-FR", "en"], + ["en-US", "fr-FR", "en", "fr"], + "en-US", + localeService.langNegStrategyLookup, + ["fr-FR"], + ], + ], + }, +}; + +function run_test() { + const nl = localeService.negotiateLanguages; + + const json = JSON.stringify; + for (const strategy in data) { + for (const groupName in data[strategy]) { + const group = data[strategy][groupName]; + for (const test of group) { + const requested = test[0]; + const available = test[1]; + const defaultLocale = test.length > 3 ? test[2] : undefined; + const strategyInner = test.length > 4 ? test[3] : undefined; + const supported = test[test.length - 1]; + + const result = nl(test[0], test[1], defaultLocale, strategyInner); + deepEqual( + result, + supported, + `\nExpected ${json(requested)} * ${json(available)} = ${json( + supported + )}.\n` + ); + } + } + } + + // Verify that we error out when requested or available is not an array. + for (const [req, avail] in [ + [null, ["fr-FR"]], + [undefined, ["fr-FR"]], + [2, ["fr-FR"]], + ["fr-FR", ["fr-FR"]], + [["fr-FR"], null], + [["fr-FR"], undefined], + [["fr-FR"], 2], + [["fr-FR"], "fr-FR"], + [[null], []], + [[undefined], []], + [[undefined], [null]], + [[undefined], [undefined]], + [[null], [null]], + [[[]], [[2]]], + ]) { + Assert.throws( + () => { + nl(req, avail); + }, + err => err.result == Cr.NS_ERROR_XPC_CANT_CONVERT_PRIMITIVE_TO_ARRAY + ); + } +} diff --git a/intl/locale/tests/unit/test_osPreferences.js b/intl/locale/tests/unit/test_osPreferences.js new file mode 100644 index 0000000000..6d1bb637ff --- /dev/null +++ b/intl/locale/tests/unit/test_osPreferences.js @@ -0,0 +1,44 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +function run_test() { + const osprefs = Cc["@mozilla.org/intl/ospreferences;1"].getService( + Ci.mozIOSPreferences + ); + + const systemLocale = osprefs.systemLocale; + Assert.ok(systemLocale != "", "systemLocale is non-empty"); + + const systemLocales = osprefs.systemLocales; + Assert.ok(Array.isArray(systemLocales), "systemLocales returns an array"); + + Assert.ok( + systemLocale == systemLocales[0], + "systemLocale matches first entry in systemLocales" + ); + + const rgLocales = osprefs.regionalPrefsLocales; + Assert.ok(Array.isArray(rgLocales), "regionalPrefsLocales returns an array"); + + const getDateTimePatternTests = [ + [osprefs.dateTimeFormatStyleNone, osprefs.dateTimeFormatStyleNone, ""], + [osprefs.dateTimeFormatStyleShort, osprefs.dateTimeFormatStyleNone, ""], + [osprefs.dateTimeFormatStyleNone, osprefs.dateTimeFormatStyleLong, "ar"], + [osprefs.dateTimeFormatStyleFull, osprefs.dateTimeFormatStyleMedium, "ru"], + ]; + + for (let i = 0; i < getDateTimePatternTests.length; i++) { + const test = getDateTimePatternTests[i]; + + const pattern = osprefs.getDateTimePattern(...test); + if ( + test[0] !== osprefs.dateTimeFormatStyleNone && + test[1] !== osprefs.dateTImeFormatStyleNone + ) { + Assert.greater(pattern.length, 0, "pattern is not empty."); + } + } + + Assert.ok(1, "osprefs didn't crash"); +} diff --git a/intl/locale/tests/unit/test_pluralForm.js b/intl/locale/tests/unit/test_pluralForm.js new file mode 100644 index 0000000000..a5c486327c --- /dev/null +++ b/intl/locale/tests/unit/test_pluralForm.js @@ -0,0 +1,6150 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * Make sure each of the plural forms have the correct number of forms and + * match up in functionality. + */ + +const { PluralForm } = ChromeUtils.import( + "resource://gre/modules/PluralForm.jsm" +); + +function run_test() { + let allExpect = [ + [ + // 0: Chinese 0-9, 10-19, ..., 90-99 + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + // 100-109, 110-119, ..., 190-199 + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + // 200-209, 210-219, ..., 290-299 + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + ], + [ + // 1: English 0-9, 10-19, ..., 90-99 + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + // 100-109, 110-119, ..., 190-199 + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + // 200-209, 210-219, ..., 290-299 + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + ], + [ + // 2: French 0-9, 10-19, ..., 90-99 + 1, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + // 100-109, 110-119, ..., 190-199 + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + // 200-209, 210-219, ..., 290-299 + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + ], + [ + // 3: Latvian 0-9, 10-19, ..., 90-99 + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + // 100-109, 110-119, ..., 190-199 + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + // 200-209, 210-219, ..., 290-299 + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + ], + [ + // 4: Scottish Gaelic 0-9, 10-19, ..., 90-99 + 4, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + // 100-109, 110-119, ..., 190-199 + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + // 200-209, 210-219, ..., 290-299 + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + ], + [ + // 5: Romanian 0-9, 10-19, ..., 90-99 + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + // 100-109, 110-119, ..., 190-199 + 3, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + // 200-209, 210-219, ..., 290-299 + 3, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + ], + [ + // 6: Lithuanian 0-9, 10-19, ..., 90-99 + 2, + 1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + // 100-109, 110-119, ..., 190-199 + 2, + 1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + // 200-209, 210-219, ..., 290-299 + 2, + 1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + ], + [ + // 7: Russian 0-9, 10-19, ..., 90-99 + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + // 100-109, 110-119, ..., 190-199 + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + // 200-209, 210-219, ..., 290-299 + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + ], + [ + // 8: Slovak 0-9, 10-19, ..., 90-99 + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + // 100-109, 110-119, ..., 190-199 + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + // 200-209, 210-219, ..., 290-299 + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + ], + [ + // 9: Polish 0-9, 10-19, ..., 90-99 + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + // 100-109, 110-119, ..., 190-199 + 3, + 3, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + // 200-209, 210-219, ..., 290-299 + 3, + 3, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + ], + [ + // 10: Slovenian 0-9, 10-19, ..., 90-99 + 4, + 1, + 2, + 3, + 3, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + // 100-109, 110-119, ..., 190-199 + 4, + 1, + 2, + 3, + 3, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + // 200-209, 210-219, ..., 290-299 + 4, + 1, + 2, + 3, + 3, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + ], + [ + // 11: Irish Gaeilge 0-9, 10-19, ..., 90-99 + 5, + 1, + 2, + 3, + 3, + 3, + 3, + 4, + 4, + 4, + 4, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + // 100-109, 110-119, ..., 190-199 + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + // 200-209, 210-219, ..., 290-299 + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + ], + [ + // 12: Arabic 0-9, 10-19, ..., 90-99 + 6, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + // 100-109, 110-119, ..., 190-199 + 5, + 5, + 5, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + // 200-209, 210-219, ..., 290-299 + 5, + 5, + 5, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + ], + [ + // 13: Maltese 0-9, 10-19, ..., 90-99 + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + // 100-109, 110-119, ..., 190-199 + 4, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + // 200-209, 210-219, ..., 290-299 + 4, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + ], + [ + // 14: Unused 0-9, 10-19, ..., 90-99 + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + // 100-109, 110-119, ..., 190-199 + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + // 200-209, 210-219, ..., 290-299 + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + ], + [ + // 15: Icelandic, Macedonian 0-9, 10-19, ..., 90-99 + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + // 100-109, 110-119, ..., 190-199 + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + // 200-209, 210-219, ..., 290-299 + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + ], + [ + // 16: Breton 0-9, 10-19, ..., 90-99 + 5, + 1, + 2, + 3, + 3, + 5, + 5, + 5, + 5, + 3, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 1, + 2, + 3, + 3, + 5, + 5, + 5, + 5, + 3, + 5, + 1, + 2, + 3, + 3, + 5, + 5, + 5, + 5, + 3, + 5, + 1, + 2, + 3, + 3, + 5, + 5, + 5, + 5, + 3, + 5, + 1, + 2, + 3, + 3, + 5, + 5, + 5, + 5, + 3, + 5, + 1, + 2, + 3, + 3, + 5, + 5, + 5, + 5, + 3, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 1, + 2, + 3, + 3, + 5, + 5, + 5, + 5, + 3, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + // 100-109, 110-119, ..., 190-199 + 5, + 1, + 2, + 3, + 3, + 5, + 5, + 5, + 5, + 3, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 1, + 2, + 3, + 3, + 5, + 5, + 5, + 5, + 3, + 5, + 1, + 2, + 3, + 3, + 5, + 5, + 5, + 5, + 3, + 5, + 1, + 2, + 3, + 3, + 5, + 5, + 5, + 5, + 3, + 5, + 1, + 2, + 3, + 3, + 5, + 5, + 5, + 5, + 3, + 5, + 1, + 2, + 3, + 3, + 5, + 5, + 5, + 5, + 3, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 1, + 2, + 3, + 3, + 5, + 5, + 5, + 5, + 3, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + // 200-209, 210-219, ..., 290-299 + 5, + 1, + 2, + 3, + 3, + 5, + 5, + 5, + 5, + 3, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 1, + 2, + 3, + 3, + 5, + 5, + 5, + 5, + 3, + 5, + 1, + 2, + 3, + 3, + 5, + 5, + 5, + 5, + 3, + 5, + 1, + 2, + 3, + 3, + 5, + 5, + 5, + 5, + 3, + 5, + 1, + 2, + 3, + 3, + 5, + 5, + 5, + 5, + 3, + 5, + 1, + 2, + 3, + 3, + 5, + 5, + 5, + 5, + 3, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 1, + 2, + 3, + 3, + 5, + 5, + 5, + 5, + 3, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + 5, + ], + [ + // 17: Shuar 0-9, 10-19, ..., 90-99 + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + // 100-109, 110-119, ..., 190-199 + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + // 200-209, 210-219, ..., 290-299 + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + ], + [ + // 18: Welsh 0-9, 10-19, ..., 90-99 + 1, + 2, + 3, + 4, + 6, + 6, + 5, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + // 100-109, 110-119, ..., 190-199 + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + // 200-209, 210-219, ..., 290-299 + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + 6, + ], + [ + // 19: Slavic languages (bs, hr, sr) 0-9, 10-19, ..., 90-99 + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + // 100-109, 110-119, ..., 190-199 + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + // 200-209, 210-219, ..., 290-299 + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + ], + ]; + + for (let [rule, expect] of allExpect.entries()) { + print("\nTesting rule #" + rule); + + let [get, numForms] = PluralForm.makeGetter(rule); + + // Make sure the largest value expected matches the number of plural forms + let maxExpect = Math.max.apply(this, expect); + Assert.equal(maxExpect, numForms()); + + // Make a string of numbers, e.g., 1;2;3;4;5 + let words = []; + for (let i = 1; i <= maxExpect; i++) { + words.push(i); + } + words = words.join(";"); + + // Make sure we get the expected number + for (let [index, number] of expect.entries()) { + print( + [ + "Plural form of ", + index, + " should be ", + number, + " (", + words, + ")", + ].join("") + ); + Assert.equal(get(index, words), number); + } + } +} diff --git a/intl/locale/tests/unit/test_pluralForm_english.js b/intl/locale/tests/unit/test_pluralForm_english.js new file mode 100644 index 0000000000..1e4cbf12ab --- /dev/null +++ b/intl/locale/tests/unit/test_pluralForm_english.js @@ -0,0 +1,31 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * This unit test makes sure the plural form for the default language (by + * development), English, is working for the PluralForm javascript module. + */ + +const { PluralForm } = ChromeUtils.import( + "resource://gre/modules/PluralForm.jsm" +); + +function run_test() { + // English has 2 plural forms + Assert.equal(2, PluralForm.numForms()); + + // Make sure for good inputs, things work as expected + for (var num = 0; num <= 200; num++) { + Assert.equal( + num == 1 ? "word" : "words", + PluralForm.get(num, "word;words") + ); + } + + // Not having enough plural forms defaults to the first form + Assert.equal("word", PluralForm.get(2, "word")); + + // Empty forms defaults to the first form + Assert.equal("word", PluralForm.get(2, "word;")); +} diff --git a/intl/locale/tests/unit/test_pluralForm_makeGetter.js b/intl/locale/tests/unit/test_pluralForm_makeGetter.js new file mode 100644 index 0000000000..a5478d38e6 --- /dev/null +++ b/intl/locale/tests/unit/test_pluralForm_makeGetter.js @@ -0,0 +1,38 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * This unit test makes sure the plural form for Irish Gaeilge is working by + * using the makeGetter method instead of using the default language (by + * development), English. + */ + +const { PluralForm } = ChromeUtils.import( + "resource://gre/modules/PluralForm.jsm" +); + +function run_test() { + // Irish is plural rule #11 + let [get, numForms] = PluralForm.makeGetter(11); + + // Irish has 5 plural forms + Assert.equal(5, numForms()); + + // I don't really know Irish, so I'll stick in some dummy text + let words = "is 1;is 2;is 3-6;is 7-10;everything else"; + + let test = function(text, low, high) { + for (let num = low; num <= high; num++) { + Assert.equal(text, get(num, words)); + } + }; + + // Make sure for good inputs, things work as expected + test("everything else", 0, 0); + test("is 1", 1, 1); + test("is 2", 2, 2); + test("is 3-6", 3, 6); + test("is 7-10", 7, 10); + test("everything else", 11, 200); +} diff --git a/intl/locale/tests/unit/xpcshell.ini b/intl/locale/tests/unit/xpcshell.ini new file mode 100644 index 0000000000..75ab013434 --- /dev/null +++ b/intl/locale/tests/unit/xpcshell.ini @@ -0,0 +1,21 @@ +[DEFAULT] +head = +support-files = + data/intl_on_workers_worker.js + data/chrome.manifest + +[test_bug22310.js] +skip-if = toolkit != "windows" && toolkit != "cocoa" + +[test_bug1086527.js] +[test_intl_on_workers.js] +skip-if = toolkit == "android" # bug 1309447 + +[test_pluralForm.js] +[test_pluralForm_english.js] +[test_pluralForm_makeGetter.js] + +[test_osPreferences.js] +skip-if = toolkit == "android" # bug 1344596 +[test_localeService.js] +[test_localeService_negotiateLanguages.js] |