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_number_format.h"
18 #include "ecmascript/napi/jsnapi_helper.h"
19 #include "ecmascript/tests/test_helper.h"
20
21 using namespace panda::ecmascript;
22
23 namespace panda::test {
24 class JSNumberFormatTest : public BaseTestWithScope<true> {
25 };
26
27 /**
28 * @tc.name: GetIcuCallTarget
29 * @tc.desc: Call "NewJSIntlIcuData" function Set IcuCallTarget,check whether the IcuCallTarget through
30 * "GetIcuCallTarget" function is within expectations then call "formatInt" function format
31 * Int type data and check the returned value is within expectations.
32 * @tc.type: FUNC
33 * @tc.require:
34 */
HWTEST_F_L0(JSNumberFormatTest,GetIcuCallTarget)35 HWTEST_F_L0(JSNumberFormatTest, GetIcuCallTarget)
36 {
37 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
38 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
39
40 JSHandle<JSTaggedValue> ctor = env->GetNumberFormatFunction();
41 JSHandle<JSNumberFormat> numberFormat =
42 JSHandle<JSNumberFormat>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(ctor), ctor));
43
44 icu::Locale icuLocale("en", "US");
45 icu::number::LocalizedNumberFormatter icuNumberFormatter =
46 icu::number::NumberFormatter::withLocale(icuLocale).roundingMode(UNUM_ROUND_HALFUP);
47 // Set IcuCallTarget
48 factory->NewJSIntlIcuData(numberFormat, icuNumberFormatter, JSNumberFormat::FreeIcuNumberformat);
49 icu::number::LocalizedNumberFormatter *resultIcuNumberFormatter = numberFormat->GetIcuCallTarget();
50 EXPECT_TRUE(resultIcuNumberFormatter != nullptr);
51 // Use IcuCallTarget format Int
52 int64_t value = -123456;
53 UErrorCode status = U_ZERO_ERROR;
54 icu::number::FormattedNumber formattedNumber = resultIcuNumberFormatter->formatInt(value, status);
55 icu::UnicodeString result = formattedNumber.toString(status);
56 JSHandle<EcmaString> stringValue = intl::LocaleHelper::UStringToString(thread, result);
57 EXPECT_STREQ("-123,456", EcmaStringAccessor(stringValue).ToCString().c_str());
58 }
59
60 /**
61 * @tc.name: InitializeNumberFormat
62 * @tc.desc: Call "InitializeNumberFormat" function Initialize NumberFormat,and check whether the properties of
63 * the object is within expectations.
64 * @tc.type: FUNC
65 * @tc.require:
66 */
HWTEST_F_L0(JSNumberFormatTest,InitializeNumberFormat)67 HWTEST_F_L0(JSNumberFormatTest, InitializeNumberFormat)
68 {
69 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
70 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
71
72 JSHandle<JSTaggedValue> ctor = env->GetNumberFormatFunction();
73 JSHandle<JSNumberFormat> numberFormat =
74 JSHandle<JSNumberFormat>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(ctor), ctor));
75 EXPECT_TRUE(*numberFormat != nullptr);
76
77 JSHandle<JSTaggedValue> locales(factory->NewFromASCII("zh-Hans-CN"));
78 JSHandle<JSTaggedValue> undefinedOptions(thread, JSTaggedValue::Undefined());
79 JSNumberFormat::InitializeNumberFormat(thread, numberFormat, locales, undefinedOptions);
80 // Initialize attribute comparison
81 EXPECT_TRUE(numberFormat->GetNumberingSystem().IsUndefined());
82 JSHandle<EcmaString> localeStr(thread, numberFormat->GetLocale().GetTaggedObject());
83 EXPECT_STREQ("zh-Hans-CN", EcmaStringAccessor(localeStr).ToCString().c_str());
84 EXPECT_EQ(NotationOption::STANDARD, numberFormat->GetNotation());
85 EXPECT_EQ(CompactDisplayOption::SHORT, numberFormat->GetCompactDisplay());
86 EXPECT_EQ(SignDisplayOption::AUTO, numberFormat->GetSignDisplay());
87 EXPECT_EQ(CurrencyDisplayOption::SYMBOL, numberFormat->GetCurrencyDisplay());
88 EXPECT_EQ(CurrencySignOption::STANDARD, numberFormat->GetCurrencySign());
89 EXPECT_EQ(UnitDisplayOption::SHORT, numberFormat->GetUnitDisplay());
90 EXPECT_EQ(numberFormat->GetMinimumIntegerDigits().GetInt(), 1); // 1 : 1 default minimum integer
91 EXPECT_EQ(numberFormat->GetMinimumFractionDigits().GetInt(), 0); // 0 : 0 default minimum fraction
92 EXPECT_EQ(numberFormat->GetMaximumFractionDigits().GetInt(), 3); // 1 : 1 default maximum fraction
93 EXPECT_EQ(numberFormat->GetMinimumSignificantDigits().GetInt(), 0); // 0 : 0 default minimum sigfraction
94 EXPECT_EQ(numberFormat->GetMaximumSignificantDigits().GetInt(), 0); // 0 : 0 default maximum sigfraction
95 EXPECT_TRUE(numberFormat->GetUseGrouping().IsTrue());
96 EXPECT_TRUE(numberFormat->GetBoundFormat().IsUndefined());
97 EXPECT_TRUE(numberFormat->GetUnit().IsUndefined());
98 EXPECT_TRUE(numberFormat->GetCurrency().IsUndefined());
99 }
100
101 /**
102 * @tc.name: CurrencyDigits
103 * @tc.desc: If the ISO 4217 currency contains currency as an alphabetic code, return the minor unit value
104 * corresponding to the currency from the list
105 * @tc.type: FUNC
106 * @tc.require:
107 */
HWTEST_F_L0(JSNumberFormatTest,CurrencyDigits)108 HWTEST_F_L0(JSNumberFormatTest, CurrencyDigits)
109 {
110 // Alphabetic code:USD
111 icu::UnicodeString usdCurrency("USD");
112 // 2 : 2 fraction digits
113 EXPECT_EQ(JSNumberFormat::CurrencyDigits(usdCurrency), 2);
114 // Alphabetic code:EUR
115 icu::UnicodeString eurCurrency("EUR");
116 // 2 : 2 fraction digits
117 EXPECT_EQ(JSNumberFormat::CurrencyDigits(eurCurrency), 2);
118 // Alphabetic code:CHF
119 icu::UnicodeString numberCurrency("CHF");
120 // 2 : 2 fraction digits
121 EXPECT_EQ(JSNumberFormat::CurrencyDigits(numberCurrency), 2);
122 }
123
124 /**
125 * @tc.name: FormatNumeric
126 * @tc.desc: Call "InitializeNumberFormat" function Initialize NumberFormat,Set the sytle attribute of the object to
127 * decimal,construct a bigint type data,and the object calls the FormatNumeric method to interpret the bigint
128 * type data into the corresponding decimal, and check whether the decimal meets the expectation.
129 * @tc.type: FUNC
130 * @tc.require:
131 */
HWTEST_F_L0(JSNumberFormatTest,FormatNumeric)132 HWTEST_F_L0(JSNumberFormatTest, FormatNumeric)
133 {
134 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
135 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
136 auto globalConst = thread->GlobalConstants();
137
138 JSHandle<JSTaggedValue> objFun = env->GetObjectFunction();
139 JSHandle<JSTaggedValue> ctor = env->GetNumberFormatFunction();
140 JSHandle<JSNumberFormat> numberFormat =
141 JSHandle<JSNumberFormat>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(ctor), ctor));
142
143 JSHandle<JSTaggedValue> styleKey = globalConst->GetHandledStyleString();
144 JSHandle<JSTaggedValue> styleValue(factory->NewFromASCII("decimal"));
145 JSHandle<JSTaggedValue> localeString(factory->NewFromASCII("en-US"));
146 JSHandle<JSObject> optionsObj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFun), objFun);
147 JSObject::SetProperty(thread, optionsObj, styleKey, styleValue);
148 JSNumberFormat::InitializeNumberFormat(thread, numberFormat, localeString, JSHandle<JSTaggedValue>(optionsObj));
149 // format BigInt
150 JSHandle<JSTaggedValue> number(thread, JSTaggedValue(123456789));
151 JSHandle<BigInt> jsBigInt(thread, BigInt::NumberToBigInt(thread, number));
152 JSHandle<JSTaggedValue> formatResult =
153 JSNumberFormat::FormatNumeric(thread, numberFormat, jsBigInt.GetTaggedValue());
154
155 JSHandle<EcmaString> resultEcmaStr(thread, formatResult.GetTaggedValue());
156 EXPECT_STREQ("123,456,789", EcmaStringAccessor(resultEcmaStr).ToCString().c_str());
157 }
158
159 /**
160 * @tc.name: UnwrapNumberFormat
161 * @tc.desc: Construct an object,If it is a numberformat object,it will be returned.If it is an object of other types
162 * and inherits the numberformat object, it will get value from the fallbacksymbol key and return.
163 * @tc.type: FUNC
164 * @tc.require:
165 */
HWTEST_F_L0(JSNumberFormatTest,UnwrapNumberFormat)166 HWTEST_F_L0(JSNumberFormatTest, UnwrapNumberFormat)
167 {
168 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
169 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
170 EcmaVM *vm = thread->GetEcmaVM();
171
172 JSHandle<JSTaggedValue> numberFormatFunc = env->GetNumberFormatFunction();
173 JSHandle<JSTaggedValue> numberFormat(
174 factory->NewJSObjectByConstructor(JSHandle<JSFunction>(numberFormatFunc), numberFormatFunc));
175
176 Local<FunctionRef> numberFormatLocal = JSNApiHelper::ToLocal<FunctionRef>(numberFormatFunc);
177 JSHandle<JSTaggedValue> disPlayNamesFunc = env->GetDisplayNamesFunction();
178 Local<FunctionRef> disPlayNamesLocal = JSNApiHelper::ToLocal<FunctionRef>(disPlayNamesFunc);
179 // displaynames Inherit numberformat
180 disPlayNamesLocal->Inherit(vm, numberFormatLocal);
181 JSHandle<JSTaggedValue> disPlayNamesHandle = JSNApiHelper::ToJSHandle(disPlayNamesLocal);
182 JSHandle<JSTaggedValue> disPlayNamesObj(
183 factory->NewJSObjectByConstructor(JSHandle<JSFunction>::Cast(disPlayNamesHandle), disPlayNamesHandle));
184 // object has no Instance
185 JSHandle<JSTaggedValue> unwrapNumberFormat1 = JSNumberFormat::UnwrapNumberFormat(thread, numberFormat);
186 EXPECT_TRUE(JSTaggedValue::SameValue(numberFormat, unwrapNumberFormat1));
187 // object has Instance
188 JSHandle<JSTaggedValue> unwrapNumberFormat2 = JSNumberFormat::UnwrapNumberFormat(thread, disPlayNamesObj);
189 EXPECT_TRUE(unwrapNumberFormat2->IsUndefined());
190 }
191 } // namespace panda::test