1/*
2 * Copyright (c) 2021 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/builtins/builtins_plural_rules.h"
17
18#include "ecmascript/global_env.h"
19#include "ecmascript/js_plural_rules.h"
20#include "ecmascript/tests/test_helper.h"
21
22using namespace panda::ecmascript;
23using namespace panda::ecmascript::builtins;
24
25namespace panda::test {
26class BuiltinsPluralRulesTest : public BaseTestWithScope<true> {
27};
28
29// new DateTimeFormat(newTarget is defined)
30HWTEST_F_L0(BuiltinsPluralRulesTest, PluralRulesConstructor)
31{
32    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
33    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
34    JSHandle<JSFunction> newTarget(env->GetPluralRulesFunction());
35
36    JSHandle<JSTaggedValue> localesString(factory->NewFromASCII("en-US"));
37    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue(*newTarget), 8);
38    ecmaRuntimeCallInfo->SetFunction(newTarget.GetTaggedValue());
39    ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
40    ecmaRuntimeCallInfo->SetCallArg(0, localesString.GetTaggedValue());
41    // option tag is default value
42    ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue::Undefined());
43
44    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
45    JSTaggedValue result = BuiltinsPluralRules::PluralRulesConstructor(ecmaRuntimeCallInfo);
46    TestHelper::TearDownFrame(thread, prev);
47
48    EXPECT_TRUE(result.IsJSPluralRules());
49}
50
51static JSTaggedValue JSPluralRulesCreateWithLocaleTest(JSThread *thread, JSHandle<JSTaggedValue> &locale,
52                                                       JSHandle<JSTaggedValue> &typeValue)
53{
54    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
55    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
56    JSHandle<JSFunction> newTarget(env->GetPluralRulesFunction());
57    JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
58    JSHandle<JSObject> optionsObj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
59
60    JSHandle<JSTaggedValue> typeKey = thread->GlobalConstants()->GetHandledTypeString();
61    JSObject::SetProperty(thread, optionsObj, typeKey, typeValue);
62
63    JSHandle<JSTaggedValue> localesString = locale;
64    std::vector<JSTaggedValue> args{ localesString.GetTaggedValue(), optionsObj.GetTaggedValue()};
65    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, newTarget, args, 8);
66
67    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
68    JSTaggedValue result = BuiltinsPluralRules::PluralRulesConstructor(ecmaRuntimeCallInfo);
69    TestHelper::TearDownFrame(thread, prev);
70
71    EXPECT_TRUE(result.IsJSPluralRules());
72    return result;
73}
74
75static void SelectTest(JSThread *thread, std::string_view data, std::string_view expectStr, int v)
76{
77    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
78    JSHandle<JSTaggedValue> locale(factory->NewFromASCII("en-US"));
79    JSHandle<JSTaggedValue> typeValue(factory->NewFromASCII(data));
80    JSHandle<JSPluralRules> jsPluralRules =
81        JSHandle<JSPluralRules>(thread, JSPluralRulesCreateWithLocaleTest(thread, locale, typeValue));
82
83    JSHandle<JSTaggedValue> value(thread, JSTaggedValue(v));
84    auto ecmaRuntimeCallInfo =
85        TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);  // 6 : argv length
86    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
87    ecmaRuntimeCallInfo->SetThis(jsPluralRules.GetTaggedValue());
88    ecmaRuntimeCallInfo->SetCallArg(0, value.GetTaggedValue());
89
90    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
91    JSTaggedValue result = BuiltinsPluralRules::Select(ecmaRuntimeCallInfo);
92    TestHelper::TearDownFrame(thread, prev);
93
94    EXPECT_TRUE(result.IsString());
95    JSHandle<EcmaString> handleEcmaStr(thread, result);
96    EXPECT_STREQ(expectStr.data(), EcmaStringAccessor(handleEcmaStr).ToCString().c_str());
97}
98
99// select(0, type(cardinal))
100HWTEST_F_L0(BuiltinsPluralRulesTest, Select_001)
101{
102    SelectTest(thread, "cardinal", "other", 0);
103}
104
105// select(1, type(cardinal))
106HWTEST_F_L0(BuiltinsPluralRulesTest, Select_002)
107{
108    SelectTest(thread, "cardinal", "one", 1);
109}
110
111// select(2, type(cardinal))
112HWTEST_F_L0(BuiltinsPluralRulesTest, Select_003)
113{
114    SelectTest(thread, "cardinal", "other", 2);
115}
116
117// select(3, type(ordinal))
118HWTEST_F_L0(BuiltinsPluralRulesTest, Select_004)
119{
120    SelectTest(thread, "ordinal", "few", 3);
121}
122
123// select(2, type(ordinal))
124HWTEST_F_L0(BuiltinsPluralRulesTest, Select_005)
125{
126    SelectTest(thread, "ordinal", "two", 2);
127}
128
129// select(0, type(ordinal))
130HWTEST_F_L0(BuiltinsPluralRulesTest, Select_006)
131{
132    SelectTest(thread, "ordinal", "other", 0);
133}
134
135// select(1, type(ordinal))
136HWTEST_F_L0(BuiltinsPluralRulesTest, Select_007)
137{
138    SelectTest(thread, "ordinal", "one", 1);
139}
140
141HWTEST_F_L0(BuiltinsPluralRulesTest, SupportedLocalesOf)
142{
143    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
144    JSHandle<JSTaggedValue> locale(factory->NewFromASCII("id-u-co-pinyin-de-ID"));
145
146    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
147    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
148    ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
149    ecmaRuntimeCallInfo->SetCallArg(0, locale.GetTaggedValue());
150    // set the tag is default value
151    ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue::Undefined());
152
153    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
154    JSTaggedValue resultArr = BuiltinsPluralRules::SupportedLocalesOf(ecmaRuntimeCallInfo);
155    TestHelper::TearDownFrame(thread, prev);
156
157    JSHandle<JSArray> resultHandle(thread, resultArr);
158    JSHandle<TaggedArray> elements(thread, resultHandle->GetElements());
159    EXPECT_EQ(elements->GetLength(), 1U);
160    JSHandle<EcmaString> handleEcmaStr(thread, elements->Get(0));
161    EXPECT_STREQ("id-u-co-pinyin-de-id", EcmaStringAccessor(handleEcmaStr).ToCString().c_str());
162}
163
164HWTEST_F_L0(BuiltinsPluralRulesTest, ResolvedOptions)
165{
166    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
167    auto globalConst = thread->GlobalConstants();
168    JSHandle<JSTaggedValue> locale(factory->NewFromASCII("en-US"));
169    JSHandle<JSTaggedValue> typeValue(factory->NewFromASCII("ordinal"));
170    JSHandle<JSPluralRules> jsPluralRules =
171        JSHandle<JSPluralRules>(thread, JSPluralRulesCreateWithLocaleTest(thread, locale, typeValue));
172
173    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 4);
174    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
175    ecmaRuntimeCallInfo->SetThis(jsPluralRules.GetTaggedValue());
176
177    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
178    JSTaggedValue result = BuiltinsPluralRules::ResolvedOptions(ecmaRuntimeCallInfo);
179    TestHelper::TearDownFrame(thread, prev);
180
181    JSHandle<JSTaggedValue> resultObj =
182        JSHandle<JSTaggedValue>(thread, JSTaggedValue(static_cast<JSTaggedType>(result.GetRawData())));
183    // judge whether the properties of the object are the same as those of jspluralrulesformat tag
184    JSHandle<JSTaggedValue> localeKey = globalConst->GetHandledLocaleString();
185    JSHandle<JSTaggedValue> localeValue(factory->NewFromASCII("en"));
186    EXPECT_EQ(JSTaggedValue::SameValue(
187        JSObject::GetProperty(thread, resultObj, localeKey).GetValue(), localeValue), true);
188    JSHandle<JSTaggedValue> typeKey = globalConst->GetHandledTypeString();
189    EXPECT_EQ(JSTaggedValue::SameValue(
190        JSObject::GetProperty(thread, resultObj, typeKey).GetValue(), typeValue), true);
191}
192} // namespace panda::test
193