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