1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ecmascript/intl/locale_helper.h"
17 #include "ecmascript/js_plural_rules.h"
18 #include "ecmascript/base/number_helper.h"
19 #include "ecmascript/global_env.h"
20 #include "ecmascript/tests/test_helper.h"
21
22 using namespace panda::ecmascript;
23 using namespace panda::ecmascript::base;
24
25 namespace panda::test {
26 class JSPluralRulesTest : public testing::Test {
27 public:
SetUpTestCase()28 static void SetUpTestCase()
29 {
30 GTEST_LOG_(INFO) << "SetUpTestCase";
31 }
32
TearDownTestCase()33 static void TearDownTestCase()
34 {
35 GTEST_LOG_(INFO) << "TearDownCase";
36 }
37
SetUp()38 void SetUp() override
39 {
40 JSRuntimeOptions options;
41 #if PANDA_TARGET_LINUX
42 // for consistency requirement, use ohos_icu4j/data/icudt67l.dat as icu-data-path
43 options.SetIcuDataPath(ICU_PATH);
44 #endif
45 options.SetEnableForceGC(true);
46 instance = JSNApi::CreateEcmaVM(options);
47 instance->SetEnableForceGC(true);
48 ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM";
49 thread = instance->GetJSThread();
50 scope = new EcmaHandleScope(thread);
51 }
52
TearDown()53 void TearDown() override
54 {
55 TestHelper::DestroyEcmaVMWithScope(instance, scope);
56 }
57
58 EcmaVM *instance {nullptr};
59 ecmascript::EcmaHandleScope *scope {nullptr};
60 JSThread *thread {nullptr};
61 };
62
HWTEST_F_L0(JSPluralRulesTest,GetIcuPluralRules)63 HWTEST_F_L0(JSPluralRulesTest, GetIcuPluralRules)
64 {
65 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
66 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
67
68 JSHandle<JSTaggedValue> ctor = env->GetPluralRulesFunction();
69 JSHandle<JSPluralRules> pluralRules =
70 JSHandle<JSPluralRules>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(ctor), ctor));
71 // Create PluralRules
72 icu::Locale icuLocale("en", "US");
73 UErrorCode status = U_ZERO_ERROR;
74 UPluralType icuType = UPLURAL_TYPE_CARDINAL; // Plural rules for cardinal numbers
75 icu::PluralRules *icuPluralRules(icu::PluralRules::forLocale(icuLocale, icuType, status));
76 icu::UnicodeString result1 = icuPluralRules->select(0);
77 JSHandle<EcmaString> stringValue1 = intl::LocaleHelper::UStringToString(thread, result1);
78
79 JSPluralRules::SetIcuPluralRules(thread, pluralRules, *icuPluralRules, JSPluralRules::FreeIcuPluralRules);
80 icu::PluralRules *getPluralRules = pluralRules->GetIcuPluralRules();
81 icu::UnicodeString result2 = getPluralRules->select(0);
82 JSHandle<EcmaString> stringValue2 = intl::LocaleHelper::UStringToString(thread, result2);
83 EXPECT_EQ(EcmaStringAccessor::StringsAreEqual(*stringValue1, *stringValue2), true);
84 delete icuPluralRules;
85 }
86
HWTEST_F_L0(JSPluralRulesTest,BuildLocaleSet)87 HWTEST_F_L0(JSPluralRulesTest, BuildLocaleSet)
88 {
89 std::set<std::string> icuAvailableLocales {
90 "en-Latn-US",
91 "zh-Hans-CN",
92 "pt-PT",
93 "de-DE",
94 };
95 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
96 JSHandle<EcmaString> resultStr;
97 JSHandle<EcmaString> localeStr1 = factory->NewFromStdString("en-Latn-US");
98 JSHandle<EcmaString> localeStr2 = factory->NewFromStdString("zh-Hans-CN");
99 JSHandle<EcmaString> localeStr3 = factory->NewFromStdString("pt-PT");
100 JSHandle<EcmaString> localeStr4 = factory->NewFromStdString("de-DE");
101 JSHandle<TaggedArray> localeSet = JSPluralRules::BuildLocaleSet(thread, icuAvailableLocales);
102 EXPECT_EQ(localeSet->GetLength(), 4U);
103
104 resultStr = JSHandle<EcmaString>(thread, localeSet->Get(0).GetTaggedObject());
105 EXPECT_EQ(EcmaStringAccessor::StringsAreEqual(*resultStr, *localeStr4), true);
106 resultStr = JSHandle<EcmaString>(thread, localeSet->Get(1).GetTaggedObject());
107 EXPECT_EQ(EcmaStringAccessor::StringsAreEqual(*resultStr, *localeStr1), true);
108 resultStr = JSHandle<EcmaString>(thread, localeSet->Get(2).GetTaggedObject());
109 EXPECT_EQ(EcmaStringAccessor::StringsAreEqual(*resultStr, *localeStr3), true);
110 resultStr = JSHandle<EcmaString>(thread, localeSet->Get(3).GetTaggedObject());
111 EXPECT_EQ(EcmaStringAccessor::StringsAreEqual(*resultStr, *localeStr2), true);
112 }
113
HWTEST_F_L0(JSPluralRulesTest,InitializePluralRules)114 HWTEST_F_L0(JSPluralRulesTest, InitializePluralRules)
115 {
116 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
117 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
118 JSHandle<JSTaggedValue> optionHandle(thread, JSTaggedValue::Undefined());
119
120 JSHandle<JSTaggedValue> ctor = env->GetPluralRulesFunction();
121 JSHandle<JSPluralRules> pluralRules =
122 JSHandle<JSPluralRules>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(ctor), ctor));
123 JSHandle<JSTaggedValue> localeStr(factory->NewFromASCII("en-GB"));
124 JSHandle<JSPluralRules> initPluralRules =
125 JSPluralRules::InitializePluralRules(thread, pluralRules, localeStr, optionHandle);
126 EXPECT_TRUE(*initPluralRules != nullptr);
127
128 JSHandle<EcmaString> resultLocaleStr(thread, initPluralRules->GetLocale().GetTaggedObject());
129 EXPECT_STREQ("en", EcmaStringAccessor(resultLocaleStr).ToCString().c_str());
130 EXPECT_EQ(initPluralRules->GetType(), TypeOption::CARDINAL);
131 EXPECT_EQ(initPluralRules->GetRoundingType(), RoundingType::FRACTIONDIGITS);
132 EXPECT_EQ(initPluralRules->GetMinimumIntegerDigits().GetInt(), 1); // 1 : 1 default minimum integer
133 EXPECT_EQ(initPluralRules->GetMinimumFractionDigits().GetInt(), 0); // 0 : 0 default minimum fraction
134 EXPECT_EQ(initPluralRules->GetMaximumFractionDigits().GetInt(), 3); // 3 : 3 default maximum fraction
135 EXPECT_EQ(initPluralRules->GetMinimumSignificantDigits().GetInt(), 0); // 0 : 0 default minimum sigfraction
136 EXPECT_EQ(initPluralRules->GetMaximumSignificantDigits().GetInt(), 0); // 0 : 0 default maximum sigfraction
137 }
138
HWTEST_F_L0(JSPluralRulesTest,ResolvePlural)139 HWTEST_F_L0(JSPluralRulesTest, ResolvePlural)
140 {
141 double n = base::NAN_VALUE;
142 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
143 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
144 auto globalConst = thread->GlobalConstants();
145 JSHandle<JSTaggedValue> optionHandle(thread, JSTaggedValue::Undefined());
146 JSHandle<JSTaggedValue> typeKey = globalConst->GetHandledStyleString();
147 JSHandle<JSTaggedValue> typeValue(factory->NewFromASCII("ordinal"));
148 JSHandle<JSTaggedValue> localeStr(factory->NewFromASCII("en-US"));
149
150 JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
151 JSHandle<JSTaggedValue> ctor = env->GetPluralRulesFunction();
152 JSHandle<JSPluralRules> pluralRules =
153 JSHandle<JSPluralRules>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(ctor), ctor));
154 JSHandle<JSObject> optionsObj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
155 JSObject::SetProperty(thread, optionsObj, typeKey, typeValue);
156 // initialize pluralRules
157 JSHandle<JSPluralRules> initPluralRules =
158 JSPluralRules::InitializePluralRules(thread, pluralRules, localeStr, optionHandle);
159 EXPECT_TRUE(*initPluralRules != nullptr);
160 // resolve plural nan
161 JSHandle<EcmaString> resolveRules = JSPluralRules::ResolvePlural(thread, initPluralRules, n);
162 EXPECT_STREQ("other", EcmaStringAccessor(resolveRules).ToCString().c_str());
163 }
164 } // namespace panda::test
165