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