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_number.h"
17
18#include <cmath>
19#include <iostream>
20
21#include "ecmascript/base/number_helper.h"
22#include "ecmascript/base/string_helper.h"
23#include "ecmascript/ecma_runtime_call_info.h"
24#include "ecmascript/ecma_string.h"
25#include "ecmascript/ecma_vm.h"
26#include "ecmascript/global_env.h"
27#include "ecmascript/js_function.h"
28#include "ecmascript/js_global_object.h"
29#include "ecmascript/js_handle.h"
30#include "ecmascript/js_primitive_ref.h"
31#include "ecmascript/js_tagged_value-inl.h"
32#include "ecmascript/js_thread.h"
33#include "ecmascript/object_factory.h"
34#include "ecmascript/tests/test_helper.h"
35
36using namespace panda::ecmascript;
37using namespace panda::ecmascript::builtins;
38
39namespace panda::test {
40class BuiltinsNumberTest : public BaseTestWithScope<false> {
41};
42
43// new Number(10)
44HWTEST_F_L0(BuiltinsNumberTest, NumberConstructor)
45{
46    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
47
48    JSHandle<JSFunction> number(env->GetNumberFunction());
49    JSHandle<JSObject> globalObject(thread, env->GetGlobalObject());
50
51    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue(*number), 6);
52    ecmaRuntimeCallInfo->SetFunction(number.GetTaggedValue());
53    ecmaRuntimeCallInfo->SetThis(globalObject.GetTaggedValue());
54    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<double>(5)));
55
56    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
57    JSTaggedValue result = BuiltinsNumber::NumberConstructor(ecmaRuntimeCallInfo);
58    TestHelper::TearDownFrame(thread, prev);
59    JSTaggedValue value(static_cast<JSTaggedType>(result.GetRawData()));
60    ASSERT_TRUE(value.IsECMAObject());
61    JSPrimitiveRef *ref = JSPrimitiveRef::Cast(value.GetTaggedObject());
62    ASSERT_EQ(ref->GetValue().GetDouble(), 5.0);
63}
64
65// Number.isFinite(-10)
66HWTEST_F_L0(BuiltinsNumberTest, IsFinite)
67{
68    const double value = -10;
69    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
70    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
71    ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
72    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<double>(value)));
73
74    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
75    JSTaggedValue result = BuiltinsNumber::IsFinite(ecmaRuntimeCallInfo);
76    ASSERT_EQ(result.GetRawData(), JSTaggedValue::True().GetRawData());
77    TestHelper::TearDownFrame(thread, prev);
78}
79
80// Number.isFinite(Number.MAX_VALUE)
81HWTEST_F_L0(BuiltinsNumberTest, IsFinite1)
82{
83    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
84    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
85    ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
86    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(base::MAX_VALUE));
87
88    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
89    JSTaggedValue result = BuiltinsNumber::IsFinite(ecmaRuntimeCallInfo);
90    ASSERT_EQ(result.GetRawData(), JSTaggedValue::True().GetRawData());
91    TestHelper::TearDownFrame(thread, prev);
92}
93
94// Number.isFinite("helloworld")
95HWTEST_F_L0(BuiltinsNumberTest, IsFinite2)
96{
97    JSHandle<EcmaString> test = thread->GetEcmaVM()->GetFactory()->NewFromASCII("helloworld");
98    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
99    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
100    ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
101    ecmaRuntimeCallInfo->SetCallArg(0, test.GetTaggedValue());
102
103    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
104    JSTaggedValue result = BuiltinsNumber::IsFinite(ecmaRuntimeCallInfo);
105    ASSERT_EQ(result.GetRawData(), JSTaggedValue::False().GetRawData());
106    TestHelper::TearDownFrame(thread, prev);
107}
108
109// Number.isFinite(NaN)
110HWTEST_F_L0(BuiltinsNumberTest, IsFinite3)
111{
112    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
113    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
114    ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
115    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(base::NAN_VALUE));
116
117    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
118    JSTaggedValue result = BuiltinsNumber::IsFinite(ecmaRuntimeCallInfo);
119    ASSERT_EQ(result.GetRawData(), JSTaggedValue::False().GetRawData());
120    TestHelper::TearDownFrame(thread, prev);
121}
122
123// Number.isFinite(Infinity)
124HWTEST_F_L0(BuiltinsNumberTest, IsFinite4)
125{
126    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
127    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
128    ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
129    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(base::POSITIVE_INFINITY));
130
131    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
132    JSTaggedValue result = BuiltinsNumber::IsFinite(ecmaRuntimeCallInfo);
133    ASSERT_EQ(result.GetRawData(), JSTaggedValue::False().GetRawData());
134    TestHelper::TearDownFrame(thread, prev);
135}
136
137// Number.isFinite(undefined)
138HWTEST_F_L0(BuiltinsNumberTest, IsFinite5)
139{
140    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
141    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
142    ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
143    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue::Undefined());
144
145    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
146    JSTaggedValue result = BuiltinsNumber::IsFinite(ecmaRuntimeCallInfo);
147    ASSERT_EQ(result.GetRawData(), JSTaggedValue::False().GetRawData());
148    TestHelper::TearDownFrame(thread, prev);
149}
150
151// Number.isFinite(null)
152HWTEST_F_L0(BuiltinsNumberTest, IsFinite6)
153{
154    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
155    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
156    ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
157    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue::Null());
158
159    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
160    JSTaggedValue result = BuiltinsNumber::IsFinite(ecmaRuntimeCallInfo);
161    ASSERT_EQ(result.GetRawData(), JSTaggedValue::False().GetRawData());
162    TestHelper::TearDownFrame(thread, prev);
163}
164
165// Number.isInteger(0.1)
166HWTEST_F_L0(BuiltinsNumberTest, IsInteger)
167{
168    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
169    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
170    ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
171    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(0.1));
172
173    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
174    JSTaggedValue result = BuiltinsNumber::IsInteger(ecmaRuntimeCallInfo);
175    ASSERT_EQ(result.GetRawData(), JSTaggedValue::False().GetRawData());
176    TestHelper::TearDownFrame(thread, prev);
177}
178
179// Number.isNaN(0.1)
180HWTEST_F_L0(BuiltinsNumberTest, IsNaN)
181{
182    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
183    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
184    ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
185    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(0.1));
186
187    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
188    JSTaggedValue result = BuiltinsNumber::IsNaN(ecmaRuntimeCallInfo);
189    ASSERT_EQ(result.GetRawData(), JSTaggedValue::False().GetRawData());
190    TestHelper::TearDownFrame(thread, prev);
191}
192
193HWTEST_F_L0(BuiltinsNumberTest, ToString1)
194{
195    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
196    auto ecmaVM = thread->GetEcmaVM();
197    JSHandle<GlobalEnv> env = ecmaVM->GetGlobalEnv();
198
199    // new Number(123.456).toString(7)
200    JSHandle<JSFunction> numberObject(env->GetNumberFunction());
201    JSHandle<JSTaggedValue> value(thread, JSTaggedValue(123.456));
202    JSHandle<JSPrimitiveRef> number = thread->GetEcmaVM()->GetFactory()->NewJSPrimitiveRef(numberObject, value);
203
204    auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
205    ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
206    ecmaRuntimeCallInfo1->SetThis(number.GetTaggedValue());
207    ecmaRuntimeCallInfo1->SetCallArg(0, JSTaggedValue(7.0));
208
209    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1);
210    JSTaggedValue result1 = BuiltinsNumber::ToString(ecmaRuntimeCallInfo1);
211    ASSERT_TRUE(result1.IsString());
212    JSHandle<EcmaString> res1(thread, reinterpret_cast<EcmaString *>(result1.GetRawData()));
213    JSHandle<EcmaString> correctResult1 = factory->NewFromASCII("234.312256641535441");
214    ASSERT_TRUE(EcmaStringAccessor::StringsAreEqual(*res1, *correctResult1));
215    TestHelper::TearDownFrame(thread, prev);
216
217    // (15).toString(4)
218    auto ecmaRuntimeCallInfo2 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
219    ecmaRuntimeCallInfo2->SetFunction(JSTaggedValue::Undefined());
220    ecmaRuntimeCallInfo2->SetThis(JSTaggedValue(15));
221    ecmaRuntimeCallInfo2->SetCallArg(0, JSTaggedValue(4));
222
223    prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo2);
224    JSTaggedValue result2 = BuiltinsNumber::ToString(ecmaRuntimeCallInfo2);
225    ASSERT_TRUE(result2.IsString());
226    JSHandle<EcmaString> res2(thread, reinterpret_cast<EcmaString *>(result2.GetRawData()));
227    JSHandle<EcmaString> correctResult2 = factory->NewFromASCII("33");
228    ASSERT_TRUE(EcmaStringAccessor::StringsAreEqual(*res2, *correctResult2));
229    TestHelper::TearDownFrame(thread, prev);
230
231    // (5).toString(8)
232    auto ecmaRuntimeCallInfo3 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
233    ecmaRuntimeCallInfo3->SetFunction(JSTaggedValue::Undefined());
234    ecmaRuntimeCallInfo3->SetThis(JSTaggedValue(5));
235    ecmaRuntimeCallInfo3->SetCallArg(0, JSTaggedValue(8));
236
237    prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo3);
238    JSTaggedValue result3 = BuiltinsNumber::ToString(ecmaRuntimeCallInfo3);
239    ASSERT_TRUE(result3.IsString());
240    JSHandle<EcmaString> res3(thread, reinterpret_cast<EcmaString *>(result3.GetRawData()));
241    JSHandle<EcmaString> correctResult3 = factory->NewFromASCII("5");
242    ASSERT_TRUE(EcmaStringAccessor::StringsAreEqual(*res3, *correctResult3));
243    TestHelper::TearDownFrame(thread, prev);
244
245    // (0).toString(8)
246    auto ecmaRuntimeCallInfo4 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
247    ecmaRuntimeCallInfo4->SetFunction(JSTaggedValue::Undefined());
248    ecmaRuntimeCallInfo4->SetThis(JSTaggedValue(0));
249    ecmaRuntimeCallInfo4->SetCallArg(0, JSTaggedValue(8));
250
251    prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo4);
252    JSTaggedValue result4 = BuiltinsNumber::ToString(ecmaRuntimeCallInfo4);
253    ASSERT_TRUE(result4.IsString());
254    JSHandle<EcmaString> res4(thread, reinterpret_cast<EcmaString *>(result4.GetRawData()));
255    JSHandle<EcmaString> correctResult4 = factory->NewFromASCII("0");
256    ASSERT_TRUE(EcmaStringAccessor::StringsAreEqual(*res4, *correctResult4));
257    TestHelper::TearDownFrame(thread, prev);
258}
259HWTEST_F_L0(BuiltinsNumberTest, ToString2)
260{
261    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
262    // (-50).toString(35)
263    auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
264    ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
265    ecmaRuntimeCallInfo1->SetThis(JSTaggedValue(-50));
266    ecmaRuntimeCallInfo1->SetCallArg(0, JSTaggedValue(35));
267
268    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1);
269    JSTaggedValue result1 = BuiltinsNumber::ToString(ecmaRuntimeCallInfo1);
270    ASSERT_TRUE(result1.IsString());
271    JSHandle<EcmaString> res1(thread, reinterpret_cast<EcmaString *>(result1.GetRawData()));
272    JSHandle<EcmaString> correctResult1 = factory->NewFromASCII("-1f");
273    ASSERT_TRUE(EcmaStringAccessor::StringsAreEqual(*res1, *correctResult1));
274    TestHelper::TearDownFrame(thread, prev);
275
276    // (2).toString(2.5)
277    auto ecmaRuntimeCallInfo2 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
278    ecmaRuntimeCallInfo2->SetFunction(JSTaggedValue::Undefined());
279    ecmaRuntimeCallInfo2->SetThis(JSTaggedValue(2));
280    ecmaRuntimeCallInfo2->SetCallArg(0, JSTaggedValue(2.5));
281
282    prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo2);
283    JSTaggedValue result2 = BuiltinsNumber::ToString(ecmaRuntimeCallInfo2);
284    ASSERT_TRUE(result2.IsString());
285    JSHandle<EcmaString> res2(thread, reinterpret_cast<EcmaString *>(result2.GetRawData()));
286    JSHandle<EcmaString> correctResult2 = factory->NewFromASCII("10");
287    ASSERT_TRUE(EcmaStringAccessor::StringsAreEqual(*res2, *correctResult2));
288    TestHelper::TearDownFrame(thread, prev);
289}
290
291// new Number(123.456).toExponential(5)
292HWTEST_F_L0(BuiltinsNumberTest, IsExponential)
293{
294    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
295    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
296
297    JSHandle<JSFunction> numberObject(env->GetNumberFunction());
298    JSHandle<JSTaggedValue> value(thread, JSTaggedValue(123.456));
299    JSHandle<JSPrimitiveRef> number = factory->NewJSPrimitiveRef(numberObject, value);
300
301    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
302    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
303    ecmaRuntimeCallInfo->SetThis(number.GetTaggedValue());
304    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(5.0));
305
306    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
307    JSTaggedValue result = BuiltinsNumber::ToExponential(ecmaRuntimeCallInfo);
308    ASSERT_TRUE(result.IsString());
309    JSHandle<EcmaString> res(thread, reinterpret_cast<EcmaString *>(result.GetRawData()));
310    JSHandle<EcmaString> correctResult = factory->NewFromASCII("1.23456e+2");
311    ASSERT_TRUE(EcmaStringAccessor::StringsAreEqual(*res, *correctResult));
312    TestHelper::TearDownFrame(thread, prev);
313}
314
315// new Number(123.456).toFixed(10)
316HWTEST_F_L0(BuiltinsNumberTest, ToFixed)
317{
318    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
319    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
320
321    JSHandle<JSFunction> numberObject(env->GetNumberFunction());
322    JSHandle<JSTaggedValue> value(thread, JSTaggedValue(123.456));
323    JSHandle<JSPrimitiveRef> number = factory->NewJSPrimitiveRef(numberObject, value);
324
325    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
326    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
327    ecmaRuntimeCallInfo->SetThis(number.GetTaggedValue());
328    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(10.0));
329
330    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
331    JSTaggedValue result = BuiltinsNumber::ToFixed(ecmaRuntimeCallInfo);
332    ASSERT_TRUE(result.IsString());
333    JSHandle<EcmaString> res(thread, reinterpret_cast<EcmaString *>(result.GetRawData()));
334    JSHandle<EcmaString> correctResult = factory->NewFromASCII("123.4560000000");
335    ASSERT_TRUE(EcmaStringAccessor::StringsAreEqual(*res, *correctResult));
336    TestHelper::TearDownFrame(thread, prev);
337}
338
339// new Number(123.456).toFixed(30)
340HWTEST_F_L0(BuiltinsNumberTest, ToFixed1)
341{
342    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
343    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
344
345    JSHandle<JSFunction> numberObject(env->GetNumberFunction());
346    JSHandle<JSTaggedValue> value(thread, JSTaggedValue(123.456));
347    JSHandle<JSPrimitiveRef> number = factory->NewJSPrimitiveRef(numberObject, value);
348
349    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
350    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
351    ecmaRuntimeCallInfo->SetThis(number.GetTaggedValue());
352    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(30.0));
353
354    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
355    JSTaggedValue result = BuiltinsNumber::ToFixed(ecmaRuntimeCallInfo);
356    ASSERT_TRUE(result.IsString());
357    JSHandle<EcmaString> res(thread, reinterpret_cast<EcmaString *>(result.GetRawData()));
358    JSHandle<EcmaString> correctResult = factory->NewFromASCII("123.456000000000003069544618483633");
359    ASSERT_TRUE(EcmaStringAccessor::StringsAreEqual(*res, *correctResult));
360    TestHelper::TearDownFrame(thread, prev);
361}
362
363// new Number(1e21).toFixed(20)
364HWTEST_F_L0(BuiltinsNumberTest, ToFixed2) {
365    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
366    auto ecmaVM = thread->GetEcmaVM();
367    JSHandle<GlobalEnv> env = ecmaVM->GetGlobalEnv();
368
369    JSHandle<JSFunction> numberObject(env->GetNumberFunction());
370    JSHandle<JSTaggedValue> value(thread, JSTaggedValue(1e21));
371    JSHandle<JSPrimitiveRef> number = factory->NewJSPrimitiveRef(numberObject, value);
372
373    auto ecmaRuntimeCallInfo =
374        TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
375    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
376    ecmaRuntimeCallInfo->SetThis(number.GetTaggedValue());
377    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(20.0));
378
379    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
380    JSTaggedValue result = BuiltinsNumber::ToFixed(ecmaRuntimeCallInfo);
381    ASSERT_TRUE(result.IsString());
382    JSHandle<EcmaString> res(thread, reinterpret_cast<EcmaString *>(result.GetRawData()));
383    JSHandle<EcmaString> correctResult = factory->NewFromASCII("1e+21");
384    ASSERT_TRUE(EcmaStringAccessor::StringsAreEqual(*res, *correctResult));
385    TestHelper::TearDownFrame(thread, prev);
386}
387
388// new Number(123.456).toPrecision(8)
389HWTEST_F_L0(BuiltinsNumberTest, ToPrecision)
390{
391    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
392    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
393
394    JSHandle<JSFunction> numberObject(env->GetNumberFunction());
395    JSHandle<JSTaggedValue> value(thread, JSTaggedValue(123.456));
396    JSHandle<JSPrimitiveRef> number = factory->NewJSPrimitiveRef(numberObject, value);
397
398    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
399    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
400    ecmaRuntimeCallInfo->SetThis(number.GetTaggedValue());
401    ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(8.0));
402
403    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
404    JSTaggedValue result = BuiltinsNumber::ToPrecision(ecmaRuntimeCallInfo);
405    ASSERT_TRUE(result.IsString());
406    JSHandle<EcmaString> res(thread, reinterpret_cast<EcmaString *>(result.GetRawData()));
407    JSHandle<EcmaString> correctResult = factory->NewFromASCII("123.45600");
408    ASSERT_TRUE(EcmaStringAccessor::StringsAreEqual(*res, *correctResult));
409    TestHelper::TearDownFrame(thread, prev);
410}
411
412// Number.parseFloat(0x123)
413HWTEST_F_L0(BuiltinsNumberTest, parseFloat)
414{
415    JSHandle<EcmaString> param = thread->GetEcmaVM()->GetFactory()->NewFromASCII("0x123");
416    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
417    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
418    ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
419    ecmaRuntimeCallInfo->SetCallArg(0, param.GetTaggedValue());
420
421    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
422    JSTaggedValue result = BuiltinsNumber::ParseFloat(ecmaRuntimeCallInfo);
423    ASSERT_EQ(result.GetRawData(), JSTaggedValue(static_cast<double>(0)).GetRawData());
424    TestHelper::TearDownFrame(thread, prev);
425}
426
427// Number.parseFloat(0x123xx)
428HWTEST_F_L0(BuiltinsNumberTest, parseFloat1)
429{
430    JSHandle<EcmaString> param = thread->GetEcmaVM()->GetFactory()->NewFromASCII("0x123xx");
431    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
432    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
433    ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
434    ecmaRuntimeCallInfo->SetCallArg(0, param.GetTaggedValue());
435
436    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
437    JSTaggedValue result = BuiltinsNumber::ParseFloat(ecmaRuntimeCallInfo);
438    ASSERT_EQ(result.GetRawData(), JSTaggedValue(static_cast<double>(0)).GetRawData());
439    TestHelper::TearDownFrame(thread, prev);
440}
441
442// Number.parseInt(0x123)
443HWTEST_F_L0(BuiltinsNumberTest, parseInt)
444{
445    const char *number = "0x123";
446
447    JSHandle<EcmaString> param = thread->GetEcmaVM()->GetFactory()->NewFromASCII(number);
448    auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
449    ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
450    ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
451    ecmaRuntimeCallInfo->SetCallArg(0, param.GetTaggedValue());
452    ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(16.0));
453
454    [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
455    JSTaggedValue result = BuiltinsNumber::ParseInt(ecmaRuntimeCallInfo);
456    ASSERT_EQ(result.GetRawData(), JSTaggedValue(static_cast<int>(291)).GetRawData());
457    TestHelper::TearDownFrame(thread, prev);
458}
459
460// testcases of StringToDouble flags
461HWTEST_F_L0(BuiltinsNumberTest, StringToDoubleFlags)
462{
463    JSHandle<EcmaString> str;
464    Span<const uint8_t> sp;
465    CVector<uint8_t> buf;
466
467    // flags of IGNORE_TRAILING
468
469    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("0a");
470    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
471    ASSERT_EQ(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), 0, base::IGNORE_TRAILING), 0);
472    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("0b");
473    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
474    ASSERT_EQ(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), 0, base::IGNORE_TRAILING), 0);
475    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("0o");
476    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
477    ASSERT_EQ(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), 0, base::IGNORE_TRAILING), 0);
478    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII(" 00x");
479    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
480    ASSERT_EQ(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), 0, base::IGNORE_TRAILING), 0);
481    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII(" 000.4_");
482    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
483    ASSERT_EQ(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), 0, base::IGNORE_TRAILING), 0.4);
484    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII(" 0010.s ");
485    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
486    ASSERT_EQ(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), 0, base::IGNORE_TRAILING), 10);
487    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII(" 0010e2");
488    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
489    ASSERT_EQ(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), 0, base::IGNORE_TRAILING), 1000);
490    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII(" 0010e+3_0");
491    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
492    ASSERT_EQ(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), 0, base::IGNORE_TRAILING), 10000);
493
494    // flags of ALLOW_HEX
495    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("0x");
496    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
497    ASSERT_TRUE(std::isnan(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), 0, base::ALLOW_HEX)));
498    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("  0x10 ");
499    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
500    ASSERT_EQ(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), 0, base::ALLOW_HEX), 16);
501    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("0x1g");
502    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
503    ASSERT_EQ(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), 0, base::ALLOW_HEX + base::IGNORE_TRAILING), 1);
504    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("0xh");
505    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
506    ASSERT_TRUE(std::isnan(
507        base::NumberHelper::StringToDouble(sp.begin(), sp.end(), 0, base::ALLOW_HEX + base::IGNORE_TRAILING)));
508
509    // flags of ALLOW_OCTAL
510    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("0O");
511    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
512    ASSERT_TRUE(std::isnan(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), 0, base::ALLOW_OCTAL)));
513    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("  0o10 ");
514    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
515    ASSERT_EQ(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), 0, base::ALLOW_OCTAL), 8);
516    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("0o1d");
517    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
518    ASSERT_EQ(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), 0, base::ALLOW_OCTAL | base::IGNORE_TRAILING),
519              1);
520    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("0o8");
521    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
522    ASSERT_TRUE(std::isnan(
523        base::NumberHelper::StringToDouble(sp.begin(), sp.end(), 0, base::ALLOW_OCTAL | base::IGNORE_TRAILING)));
524
525    // flags of ALLOW_BINARY
526    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("0b");
527    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
528    ASSERT_TRUE(std::isnan(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), 0, base::ALLOW_BINARY)));
529    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("  0b10 ");
530    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
531    ASSERT_EQ(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), 0, base::ALLOW_BINARY), 2);
532    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("0b1d");
533    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
534    ASSERT_EQ(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), 0, base::ALLOW_BINARY | base::IGNORE_TRAILING),
535              1);
536    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("0b2");
537    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
538    ASSERT_TRUE(std::isnan(
539        base::NumberHelper::StringToDouble(sp.begin(), sp.end(), 0, base::ALLOW_BINARY | base::IGNORE_TRAILING)));
540}
541
542// testcases of StringToDouble radix
543HWTEST_F_L0(BuiltinsNumberTest, StringToDoubleRadix)
544{
545    JSHandle<EcmaString> str;
546    Span<const uint8_t> sp;
547    CVector<uint8_t> buf;
548    int radix;
549
550    radix = 0;  // default 10
551    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII(" 100 ");
552    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
553    ASSERT_EQ(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), radix, base::NO_FLAGS), 100);
554    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII(" 100.3e2 ");
555    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
556    ASSERT_EQ(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), radix, base::NO_FLAGS), 10030);
557    radix = 1;
558    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("  0000 ");
559    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
560    ASSERT_EQ(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), radix, base::NO_FLAGS), 0);
561    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("  0001 ");
562    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
563    ASSERT_TRUE(std::isnan(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), radix, base::NO_FLAGS)));
564    radix = 2;
565    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("  100 ");
566    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
567    ASSERT_EQ(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), radix, base::NO_FLAGS), 4);
568    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("  11 ");
569    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
570    ASSERT_EQ(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), radix, base::NO_FLAGS), 3);
571    radix = 3;
572    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("  100 ");
573    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
574    ASSERT_EQ(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), radix, base::NO_FLAGS), 9);
575    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("  21 ");
576    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
577    ASSERT_EQ(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), radix, base::NO_FLAGS), 7);
578    radix = 4;
579    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("  100 ");
580    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
581    ASSERT_EQ(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), radix, base::NO_FLAGS), 16);
582    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("  31 ");
583    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
584    ASSERT_EQ(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), radix, base::NO_FLAGS), 13);
585    radix = 8;
586    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("  100 ");
587    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
588    ASSERT_EQ(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), radix, base::NO_FLAGS), 64);
589    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("  71 ");
590    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
591    ASSERT_EQ(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), radix, base::NO_FLAGS), 57);
592    radix = 10;
593    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("  100 ");
594    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
595    ASSERT_EQ(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), radix, base::NO_FLAGS), 100);
596    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("  0020 ");
597    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
598    ASSERT_EQ(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), radix, base::NO_FLAGS), 20);
599    radix = 16;
600    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("  100 ");
601    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
602    ASSERT_EQ(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), radix, base::NO_FLAGS), 256);
603    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("  1e ");
604    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
605    ASSERT_EQ(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), radix, base::NO_FLAGS), 30);
606    radix = 18;
607    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("  100 ");
608    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
609    ASSERT_EQ(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), radix, base::NO_FLAGS), 324);
610    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("  1g ");
611    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
612    ASSERT_EQ(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), radix, base::NO_FLAGS), 34);
613    radix = 25;
614    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("  100 ");
615    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
616    ASSERT_EQ(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), radix, base::NO_FLAGS), 625);
617    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("  1g ");
618    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
619    ASSERT_EQ(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), radix, base::NO_FLAGS), 41);
620    radix = 36;
621    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("  100 ");
622    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
623    ASSERT_EQ(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), radix, base::NO_FLAGS), 1296);
624    str = thread->GetEcmaVM()->GetFactory()->NewFromASCII("  1z ");
625    sp = EcmaStringAccessor(str).ToUtf8Span(buf);
626    ASSERT_EQ(base::NumberHelper::StringToDouble(sp.begin(), sp.end(), radix, base::NO_FLAGS), 71);
627}
628
629HWTEST_F_L0(BuiltinsNumberTest, NumberToString)
630{
631    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
632    JSHandle<EcmaString> res = factory->NewFromASCII("100");
633    ASSERT_EQ(EcmaStringAccessor::Compare(instance,
634        base::NumberHelper::NumberToString(thread, JSTaggedValue(100)), res), 0);
635    res = factory->NewFromASCII("11223344");
636    ASSERT_EQ(EcmaStringAccessor::Compare(instance,
637        base::NumberHelper::NumberToString(thread, JSTaggedValue(11223344)), res), 0);
638    res = factory->NewFromASCII("1234567890");
639    ASSERT_EQ(EcmaStringAccessor::Compare(instance,
640        base::NumberHelper::NumberToString(thread, JSTaggedValue(1234567890)), res), 0);
641    res = factory->NewFromASCII("100");
642    ASSERT_EQ(EcmaStringAccessor::Compare(instance,
643        base::NumberHelper::NumberToString(thread, JSTaggedValue(double(100.0))), res), 0);
644    res = factory->NewFromASCII("100.5");
645    ASSERT_EQ(EcmaStringAccessor::Compare(instance,
646        base::NumberHelper::NumberToString(thread, JSTaggedValue(double(100.5))), res), 0);
647    res = factory->NewFromASCII("100.25");
648    ASSERT_EQ(EcmaStringAccessor::Compare(instance,
649        base::NumberHelper::NumberToString(thread, JSTaggedValue(double(100.25))), res), 0);
650    res = factory->NewFromASCII("100.125");
651    ASSERT_EQ(EcmaStringAccessor::Compare(instance,
652        base::NumberHelper::NumberToString(thread, JSTaggedValue(double(100.125))), res), 0);
653    res = factory->NewFromASCII("100.6125");
654    ASSERT_EQ(EcmaStringAccessor::Compare(instance,
655        base::NumberHelper::NumberToString(thread, JSTaggedValue(double(100.6125))), res), 0);
656    res = factory->NewFromASCII("0.0006125");
657    ASSERT_EQ(EcmaStringAccessor::Compare(instance,
658        base::NumberHelper::NumberToString(thread, JSTaggedValue(double(0.0006125))), res), 0);
659    res = factory->NewFromASCII("-0.0006125");
660    ASSERT_EQ(EcmaStringAccessor::Compare(instance,
661        base::NumberHelper::NumberToString(thread, JSTaggedValue(double(-0.0006125))), res), 0);
662    res = factory->NewFromASCII("-1234567890.0006125");
663    ASSERT_EQ(EcmaStringAccessor::Compare(instance,
664        base::NumberHelper::NumberToString(thread, JSTaggedValue(double(-1234567890.0006125))), res), 0);
665    res = factory->NewFromASCII("1234567890.0006125");
666    ASSERT_EQ(EcmaStringAccessor::Compare(instance,
667        base::NumberHelper::NumberToString(thread, JSTaggedValue(double(1234567890.0006125))), res), 0);
668    res = factory->NewFromASCII("11234567890.000612");
669    ASSERT_EQ(EcmaStringAccessor::Compare(instance,
670        base::NumberHelper::NumberToString(thread, JSTaggedValue(double(11234567890.0006125))), res), 0);
671}
672}  // namespace panda::test
673