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/builtins/builtins_displaynames.h"
17
18#include "ecmascript/global_env.h"
19#include "ecmascript/js_displaynames.h"
20#include "ecmascript/tests/test_helper.h"
21
22using namespace panda::ecmascript;
23using namespace panda::ecmascript::builtins;
24namespace panda::test {
25class BuiltinsDisplayNamesTest : public BaseTestWithScope<true> {
26};
27
28static JSTaggedValue JSDisplayNamesCreateWithOptionTest(JSThread *thread, JSHandle<JSTaggedValue> &locale,
29                                                        JSHandle<JSTaggedValue> &typeValue)
30{
31    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
32    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
33    JSHandle<JSFunction> newTarget(env->GetDisplayNamesFunction());
34    JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
35    JSHandle<JSObject> optionsObj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
36
37    JSHandle<JSTaggedValue> typeKey = thread->GlobalConstants()->GetHandledTypeString();
38    JSObject::SetProperty(thread, optionsObj, typeKey, typeValue);
39
40    JSHandle<JSTaggedValue> localesString = locale;
41    std::vector<JSTaggedValue> args{localesString.GetTaggedValue(), optionsObj.GetTaggedValue()};
42    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, newTarget, args, 8);
43
44    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
45    JSTaggedValue result = BuiltinsDisplayNames::DisplayNamesConstructor(ecmaRuntimeCallInfo);
46    TestHelper::TearDownFrame(thread, prev);
47
48    EXPECT_TRUE(result.IsJSDisplayNames());
49    return result;
50}
51
52// new DisplayNames(locales, options)
53HWTEST_F_L0(BuiltinsDisplayNamesTest, DisplayNamesConstructor)
54{
55    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
56    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
57    JSHandle<JSFunction> newTarget(env->GetDisplayNamesFunction());
58    JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
59
60    JSHandle<JSTaggedValue> typeKey = thread->GlobalConstants()->GetHandledTypeString();
61    JSHandle<JSTaggedValue> styleKey = thread->GlobalConstants()->GetHandledStyleString();
62    JSHandle<JSTaggedValue> fallbackKey = thread->GlobalConstants()->GetHandledFallbackString();
63
64    JSHandle<JSTaggedValue> localeString(factory->NewFromASCII("en"));
65    JSHandle<JSTaggedValue> typeValue(factory->NewFromASCII("language"));
66    JSHandle<JSTaggedValue> styleValue(factory->NewFromASCII("narrow"));
67    JSHandle<JSTaggedValue> fallbackValue(factory->NewFromASCII("code"));
68
69    JSHandle<JSObject> optionsObj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
70    JSObject::SetProperty(thread, optionsObj, typeKey, typeValue);
71    JSObject::SetProperty(thread, optionsObj, styleKey, styleValue);
72    JSObject::SetProperty(thread, optionsObj, fallbackKey, fallbackValue);
73
74    std::vector<JSTaggedValue> args{localeString.GetTaggedValue(), optionsObj.GetTaggedValue()};
75    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, newTarget, args, 8);
76
77    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
78    JSTaggedValue result = BuiltinsDisplayNames::DisplayNamesConstructor(ecmaRuntimeCallInfo);
79    TestHelper::TearDownFrame(thread, prev);
80    EXPECT_TRUE(result.IsJSDisplayNames());
81}
82
83// Of(fr, type(language))
84HWTEST_F_L0(BuiltinsDisplayNamesTest, Of_001)
85{
86    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
87    JSHandle<JSTaggedValue> locale(factory->NewFromASCII("en"));
88    JSHandle<JSTaggedValue> typeValue(factory->NewFromASCII("language"));
89    JSHandle<JSDisplayNames> jsDisplayNames =
90        JSHandle<JSDisplayNames>(thread, JSDisplayNamesCreateWithOptionTest(thread, locale, typeValue));
91
92    JSHandle<JSTaggedValue> stringValue(factory->NewFromASCII("fr"));
93    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
94    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
95    ecmaRuntimeCallInfo->SetThis(jsDisplayNames.GetTaggedValue());
96    ecmaRuntimeCallInfo->SetCallArg(0, stringValue.GetTaggedValue());
97
98    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
99    JSTaggedValue result = BuiltinsDisplayNames::Of(ecmaRuntimeCallInfo);
100    TestHelper::TearDownFrame(thread, prev);
101
102    EXPECT_TRUE(result.IsString());
103    JSHandle<EcmaString> handleEcmaStr(thread, result);
104    EXPECT_STREQ("French", EcmaStringAccessor(handleEcmaStr).ToCString().c_str());
105}
106
107// Of(419, type(region))
108HWTEST_F_L0(BuiltinsDisplayNamesTest, Of_002)
109{
110    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
111    JSHandle<JSTaggedValue> locale(factory->NewFromASCII("en"));
112    JSHandle<JSTaggedValue> typeValue(factory->NewFromASCII("region"));
113    JSHandle<JSDisplayNames> jsDisplayNames =
114        JSHandle<JSDisplayNames>(thread, JSDisplayNamesCreateWithOptionTest(thread, locale, typeValue));
115
116    JSHandle<JSTaggedValue> stringValue(factory->NewFromASCII("419"));
117    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
118    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
119    ecmaRuntimeCallInfo->SetThis(jsDisplayNames.GetTaggedValue());
120    ecmaRuntimeCallInfo->SetCallArg(0, stringValue.GetTaggedValue());
121
122    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
123    JSTaggedValue result = BuiltinsDisplayNames::Of(ecmaRuntimeCallInfo);
124    TestHelper::TearDownFrame(thread, prev);
125
126    EXPECT_TRUE(result.IsString());
127    JSHandle<EcmaString> handleEcmaStr(thread, result);
128    EXPECT_STREQ("Latin America", EcmaStringAccessor(handleEcmaStr).ToCString().c_str());
129}
130
131// Of(EUR, type(currency))
132HWTEST_F_L0(BuiltinsDisplayNamesTest, Of_003)
133{
134    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
135    JSHandle<JSTaggedValue> locale(factory->NewFromASCII("en"));
136    JSHandle<JSTaggedValue> typeValue(factory->NewFromASCII("currency"));
137    JSHandle<JSDisplayNames> jsDisplayNames =
138        JSHandle<JSDisplayNames>(thread, JSDisplayNamesCreateWithOptionTest(thread, locale, typeValue));
139
140    JSHandle<JSTaggedValue> stringValue(factory->NewFromASCII("EUR"));
141    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
142    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
143    ecmaRuntimeCallInfo->SetThis(jsDisplayNames.GetTaggedValue());
144    ecmaRuntimeCallInfo->SetCallArg(0, stringValue.GetTaggedValue());
145
146    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
147    JSTaggedValue result = BuiltinsDisplayNames::Of(ecmaRuntimeCallInfo);
148    TestHelper::TearDownFrame(thread, prev);
149
150    EXPECT_TRUE(result.IsString());
151    JSHandle<EcmaString> handleEcmaStr(thread, result);
152    EXPECT_STREQ("Euro", EcmaStringAccessor(handleEcmaStr).ToCString().c_str());
153}
154
155// Of(Code Cover)
156HWTEST_F_L0(BuiltinsDisplayNamesTest, Of_004)
157{
158    // IsNotJSDisplayNames
159    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
160    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
161    ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
162    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue::Undefined());
163
164    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
165    JSTaggedValue result = BuiltinsDisplayNames::Of(ecmaRuntimeCallInfo);
166    TestHelper::TearDownFrame(thread, prev);
167    EXPECT_TRUE(thread->HasPendingException());
168    EXPECT_EQ(result, JSTaggedValue::Exception());
169    thread->ClearException();
170}
171
172// SupportedLocalesOf("best fit")
173HWTEST_F_L0(BuiltinsDisplayNamesTest, SupportedLocalesOf_001)
174{
175    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
176    JSHandle<JSTaggedValue> locale(factory->NewFromASCII("id-u-co-pinyin-de-ID"));
177
178    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
179    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
180    ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
181    ecmaRuntimeCallInfo->SetCallArg(0, locale.GetTaggedValue());
182    // set the tag is default value
183    ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue::Undefined());
184
185    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
186    JSTaggedValue resultArr = BuiltinsDisplayNames::SupportedLocalesOf(ecmaRuntimeCallInfo);
187    TestHelper::TearDownFrame(thread, prev);
188
189    JSHandle<JSArray> resultHandle(thread, resultArr);
190    JSHandle<TaggedArray> elements(thread, resultHandle->GetElements());
191    EXPECT_EQ(elements->GetLength(), 1U);
192    JSHandle<EcmaString> handleEcmaStr(thread, elements->Get(0));
193    EXPECT_STREQ("id-u-co-pinyin-de-id", EcmaStringAccessor(handleEcmaStr).ToCString().c_str());
194}
195
196// SupportedLocalesOf("look up")
197HWTEST_F_L0(BuiltinsDisplayNamesTest, SupportedLocalesOf_002)
198{
199    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
200    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
201    JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
202
203    JSHandle<JSTaggedValue> localeMatcherKey = thread->GlobalConstants()->GetHandledLocaleMatcherString();
204    JSHandle<JSTaggedValue> localeMatcherValue(factory->NewFromASCII("lookup"));
205    JSHandle<JSObject> optionsObj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
206    JSObject::SetProperty(thread, optionsObj, localeMatcherKey, localeMatcherValue);
207    JSHandle<JSTaggedValue> locale(factory->NewFromASCII("de-DE-u-co-phonebk"));
208
209    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
210    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
211    ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
212    ecmaRuntimeCallInfo->SetCallArg(0, locale.GetTaggedValue());
213    ecmaRuntimeCallInfo->SetCallArg(1, optionsObj.GetTaggedValue());
214
215    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
216    JSTaggedValue resultArr = BuiltinsDisplayNames::SupportedLocalesOf(ecmaRuntimeCallInfo);
217    TestHelper::TearDownFrame(thread, prev);
218
219    JSHandle<JSArray> resultHandle(thread, resultArr);
220    JSHandle<TaggedArray> elements(thread, resultHandle->GetElements());
221    EXPECT_EQ(elements->GetLength(), 1U);
222    JSHandle<EcmaString> handleEcmaStr(thread, elements->Get(0));
223    EXPECT_STREQ("de-DE-u-co-phonebk", EcmaStringAccessor(handleEcmaStr).ToCString().c_str());
224}
225
226HWTEST_F_L0(BuiltinsDisplayNamesTest, ResolvedOptions)
227{
228    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
229    auto globalConst = thread->GlobalConstants();
230    JSHandle<JSTaggedValue> locale(factory->NewFromASCII("de-DE"));
231    JSHandle<JSTaggedValue> typeValue(factory->NewFromASCII("currency"));
232    JSHandle<JSDisplayNames> jsDisplayNames =
233        JSHandle<JSDisplayNames>(thread, JSDisplayNamesCreateWithOptionTest(
234                                            thread, locale, typeValue));
235    std::vector<JSTaggedValue> args{};
236    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, args, 4, jsDisplayNames.GetTaggedValue());
237
238    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
239    JSTaggedValue result = BuiltinsDisplayNames::ResolvedOptions(ecmaRuntimeCallInfo);
240    TestHelper::TearDownFrame(thread, prev);
241
242    JSHandle<JSTaggedValue> resultObj =
243        JSHandle<JSTaggedValue>(thread, JSTaggedValue(static_cast<JSTaggedType>(result.GetRawData())));
244    // judge whether the properties of the object are the same as those of jsdatetimeformat tag
245    JSHandle<JSTaggedValue> localeKey = globalConst->GetHandledLocaleString();
246    JSHandle<JSTaggedValue> localeValue(factory->NewFromASCII("de-DE"));
247    EXPECT_EQ(JSTaggedValue::SameValue(
248        JSObject::GetProperty(thread, resultObj, localeKey).GetValue(), localeValue), true);
249    JSHandle<JSTaggedValue> typeKey = globalConst->GetHandledTypeString();
250    EXPECT_EQ(JSTaggedValue::SameValue(
251        JSObject::GetProperty(thread, resultObj, typeKey).GetValue(), typeValue), true);
252}
253}
254