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/js_plural_rules.h"
17 #include "ecmascript/base/number_helper.h"
18 #include "ecmascript/global_env.h"
19 #include "ecmascript/tests/test_helper.h"
20
21 using namespace panda::ecmascript;
22 using namespace panda::ecmascript::base;
23
24 namespace panda::test {
25 class JSPluralRulesTest : public testing::Test {
26 public:
SetUpTestCase()27 static void SetUpTestCase()
28 {
29 GTEST_LOG_(INFO) << "SetUpTestCase";
30 }
31
TearDownTestCase()32 static void TearDownTestCase()
33 {
34 GTEST_LOG_(INFO) << "TearDownCase";
35 }
36
SetUp()37 void SetUp() override
38 {
39 JSRuntimeOptions options;
40 #if PANDA_TARGET_LINUX
41 // for consistency requirement, use ohos_icu4j/data/icudt67l.dat as icu-data-path
42 options.SetIcuDataPath(ICU_PATH);
43 #endif
44 options.SetEnableForceGC(true);
45 instance = JSNApi::CreateEcmaVM(options);
46 instance->SetEnableForceGC(true);
47 ASSERT_TRUE(instance != nullptr) << "Cannot create EcmaVM";
48 thread = instance->GetJSThread();
49 scope = new EcmaHandleScope(thread);
50 }
51
TearDown()52 void TearDown() override
53 {
54 TestHelper::DestroyEcmaVMWithScope(instance, scope);
55 }
56
57 EcmaVM *instance {nullptr};
58 ecmascript::EcmaHandleScope *scope {nullptr};
59 JSThread *thread {nullptr};
60 };
61
HWTEST_F_L0(JSPluralRulesTest,GetIcuPluralRules)62 HWTEST_F_L0(JSPluralRulesTest, GetIcuPluralRules)
63 {
64 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
65 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
66
67 JSHandle<JSTaggedValue> ctor = env->GetPluralRulesFunction();
68 JSHandle<JSPluralRules> pluralRules =
69 JSHandle<JSPluralRules>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(ctor), ctor));
70 // Create PluralRules
71 icu::Locale icuLocale("en", "US");
72 UErrorCode status = U_ZERO_ERROR;
73 UPluralType icuType = UPLURAL_TYPE_CARDINAL; // Plural rules for cardinal numbers
74 icu::PluralRules *icuPluralRules(icu::PluralRules::forLocale(icuLocale, icuType, status));
75 icu::UnicodeString result1 = icuPluralRules->select(0);
76 JSHandle<EcmaString> stringValue1 = JSLocale::IcuToString(thread, result1);
77
78 JSPluralRules::SetIcuPluralRules(thread, pluralRules, *icuPluralRules, JSPluralRules::FreeIcuPluralRules);
79 icu::PluralRules *getPluralRules = pluralRules->GetIcuPluralRules();
80 icu::UnicodeString result2 = getPluralRules->select(0);
81 JSHandle<EcmaString> stringValue2 = JSLocale::IcuToString(thread, result2);
82 EXPECT_EQ(EcmaStringAccessor::StringsAreEqual(*stringValue1, *stringValue2), true);
83 delete icuPluralRules;
84 }
85
HWTEST_F_L0(JSPluralRulesTest,BuildLocaleSet)86 HWTEST_F_L0(JSPluralRulesTest, BuildLocaleSet)
87 {
88 std::set<std::string> icuAvailableLocales {
89 "en-Latn-US",
90 "zh-Hans-CN",
91 "pt-PT",
92 "de-DE",
93 };
94 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
95 JSHandle<EcmaString> resultStr;
96 JSHandle<EcmaString> localeStr1 = factory->NewFromStdString("en-Latn-US");
97 JSHandle<EcmaString> localeStr2 = factory->NewFromStdString("zh-Hans-CN");
98 JSHandle<EcmaString> localeStr3 = factory->NewFromStdString("pt-PT");
99 JSHandle<EcmaString> localeStr4 = factory->NewFromStdString("de-DE");
100 JSHandle<TaggedArray> localeSet = JSPluralRules::BuildLocaleSet(thread, icuAvailableLocales);
101 EXPECT_EQ(localeSet->GetLength(), 4U);
102
103 resultStr = JSHandle<EcmaString>(thread, localeSet->Get(0).GetTaggedObject());
104 EXPECT_EQ(EcmaStringAccessor::StringsAreEqual(*resultStr, *localeStr4), true);
105 resultStr = JSHandle<EcmaString>(thread, localeSet->Get(1).GetTaggedObject());
106 EXPECT_EQ(EcmaStringAccessor::StringsAreEqual(*resultStr, *localeStr1), true);
107 resultStr = JSHandle<EcmaString>(thread, localeSet->Get(2).GetTaggedObject());
108 EXPECT_EQ(EcmaStringAccessor::StringsAreEqual(*resultStr, *localeStr3), true);
109 resultStr = JSHandle<EcmaString>(thread, localeSet->Get(3).GetTaggedObject());
110 EXPECT_EQ(EcmaStringAccessor::StringsAreEqual(*resultStr, *localeStr2), true);
111 }
112
HWTEST_F_L0(JSPluralRulesTest,InitializePluralRules)113 HWTEST_F_L0(JSPluralRulesTest, InitializePluralRules)
114 {
115 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
116 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
117 JSHandle<JSTaggedValue> optionHandle(thread, JSTaggedValue::Undefined());
118
119 JSHandle<JSTaggedValue> ctor = env->GetPluralRulesFunction();
120 JSHandle<JSPluralRules> pluralRules =
121 JSHandle<JSPluralRules>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(ctor), ctor));
122 JSHandle<JSTaggedValue> localeStr(factory->NewFromASCII("en-GB"));
123 JSHandle<JSPluralRules> initPluralRules =
124 JSPluralRules::InitializePluralRules(thread, pluralRules, localeStr, optionHandle);
125 EXPECT_TRUE(*initPluralRules != nullptr);
126
127 JSHandle<EcmaString> resultLocaleStr(thread, initPluralRules->GetLocale().GetTaggedObject());
128 EXPECT_STREQ("en", EcmaStringAccessor(resultLocaleStr).ToCString().c_str());
129 EXPECT_EQ(initPluralRules->GetType(), TypeOption::CARDINAL);
130 EXPECT_EQ(initPluralRules->GetRoundingType(), RoundingType::FRACTIONDIGITS);
131 EXPECT_EQ(initPluralRules->GetMinimumIntegerDigits().GetInt(), 1); // 1 : 1 default minimum integer
132 EXPECT_EQ(initPluralRules->GetMinimumFractionDigits().GetInt(), 0); // 0 : 0 default minimum fraction
133 EXPECT_EQ(initPluralRules->GetMaximumFractionDigits().GetInt(), 3); // 3 : 3 default maximum fraction
134 EXPECT_EQ(initPluralRules->GetMinimumSignificantDigits().GetInt(), 0); // 0 : 0 default minimum sigfraction
135 EXPECT_EQ(initPluralRules->GetMaximumSignificantDigits().GetInt(), 0); // 0 : 0 default maximum sigfraction
136 }
137
HWTEST_F_L0(JSPluralRulesTest,ResolvePlural)138 HWTEST_F_L0(JSPluralRulesTest, ResolvePlural)
139 {
140 double n = base::NAN_VALUE;
141 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
142 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
143 auto globalConst = thread->GlobalConstants();
144 JSHandle<JSTaggedValue> optionHandle(thread, JSTaggedValue::Undefined());
145 JSHandle<JSTaggedValue> typeKey = globalConst->GetHandledStyleString();
146 JSHandle<JSTaggedValue> typeValue(factory->NewFromASCII("ordinal"));
147 JSHandle<JSTaggedValue> localeStr(factory->NewFromASCII("en-US"));
148
149 JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
150 JSHandle<JSTaggedValue> ctor = env->GetPluralRulesFunction();
151 JSHandle<JSPluralRules> pluralRules =
152 JSHandle<JSPluralRules>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(ctor), ctor));
153 JSHandle<JSObject> optionsObj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
154 JSObject::SetProperty(thread, optionsObj, typeKey, typeValue);
155 // initialize pluralRules
156 JSHandle<JSPluralRules> initPluralRules =
157 JSPluralRules::InitializePluralRules(thread, pluralRules, localeStr, optionHandle);
158 EXPECT_TRUE(*initPluralRules != nullptr);
159 // resolve plural nan
160 JSHandle<EcmaString> resolveRules = JSPluralRules::ResolvePlural(thread, initPluralRules, n);
161 EXPECT_STREQ("other", EcmaStringAccessor(resolveRules).ToCString().c_str());
162 }
163 } // namespace panda::test
164