1 /**
2  * Copyright (c) 2023 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 <cmath>
17 
18 #include "arkplatform_jsnapi.h"
19 #include "libpandabase/utils/bit_utils.h"
20 #include <gtest/gtest.h>
21 
22 namespace arkplatform {
23 namespace test {
24 class JSNapiTest :  public ::testing::Test {
25 public:
26 
ToJSTaggedValue(JSValueRef *obj)27     JSTaggedType ToJSTaggedValue(JSValueRef *obj)
28     {
29         return *reinterpret_cast<JSTaggedType*>(obj);
30     }
31 
ConvertDouble(double val)32     JSTaggedType ConvertDouble(double val)
33     {
34         return panda::bit_cast<JSTaggedType>(val) + JSValueRefInternals::DOUBLE_ENCODE_OFFSET;
35     }
36 
37     template<typename T>
TestNumberRef(T val, JSTaggedType expected)38     void TestNumberRef(T val, JSTaggedType expected)
39     {
40         LocalScope scope(vm_);
41         Local<NumberRef> obj = NumberRef::New(vm_, val);
42         ASSERT_TRUE(obj->IsNumber());
43         JSTaggedType res = ToJSTaggedValue(*obj);
44         ASSERT_EQ(res, expected);
45         if constexpr (std::is_floating_point_v<T>) {
46             if (std::isnan(val)) {
47                 ASSERT_TRUE(std::isnan(obj->Value()));
48             } else {
49                 ASSERT_EQ(obj->Value(), val);
50             }
51         } else if constexpr (sizeof(T) >= sizeof(int32_t)) {
52             ASSERT_EQ(obj->IntegerValue(vm_), val);
53         } else if constexpr (std::is_signed_v<T>) {
54             ASSERT_EQ(obj->Int32Value(vm_), val);
55         } else {
56             ASSERT_EQ(obj->Uint32Value(vm_), val);
57         }
58     }
59 
60     void SetUp() override
61     {
62         panda::RuntimeOption option;
63         option.SetLogLevel(panda::RuntimeOption::LOG_LEVEL::ERROR);
64         vm_ = JSNApi::CreateJSVM(option);
65         ASSERT_TRUE(vm_ != nullptr) << "Cannot create Runtime";
66     }
67 
68     void TearDown() override
69     {
70         JSNApi::DestroyJSVM(vm_);
71     }
72 
73 protected:
74     panda::JSThread *thread_ = nullptr;
75     panda::ecmascript::EcmaVM *vm_ = nullptr;
76 };
77 
78 // If this test failed, please contact with Chernykh Sergey
TEST_F(JSNapiTest, ArkplatformJSNApiTest_NumberRef)79 TEST_F(JSNapiTest, ArkplatformJSNApiTest_NumberRef)
80 {
81     // double
82     double dinput = 0.;
83     TestNumberRef(dinput, JSValueRefInternals::DOUBLE_ENCODE_OFFSET);
84     static constexpr double NAN_VALUE = std::numeric_limits<double>::quiet_NaN();
85     TestNumberRef(NAN_VALUE, ConvertDouble(NAN_VALUE));
86 
87     // int32_t
88     TestNumberRef(static_cast<int32_t>(0), JSValueRefInternals::TAG_INT);
89     TestNumberRef(INT32_MIN, static_cast<JSTaggedType>(INT32_MIN) | JSValueRefInternals::TAG_INT);
90     TestNumberRef(INT32_MAX, static_cast<JSTaggedType>(INT32_MAX) | JSValueRefInternals::TAG_INT);
91 
92     // uint32_t
93     TestNumberRef(static_cast<uint32_t>(0), JSValueRefInternals::TAG_INT);
94     auto u32input = static_cast<uint32_t>(INT32_MAX);
95     TestNumberRef(u32input, u32input | JSValueRefInternals::TAG_INT);
96     u32input = static_cast<uint32_t>(INT32_MAX + 1UL);
97     TestNumberRef(u32input, ConvertDouble(static_cast<double>(u32input)));
98     TestNumberRef(UINT32_MAX, ConvertDouble(static_cast<double>(UINT32_MAX)));
99 
100     // int64_t
101     auto i64input = static_cast<int64_t>(INT32_MIN);
102     TestNumberRef(i64input, i64input | JSValueRefInternals::TAG_INT);
103     i64input = static_cast<int64_t>(INT32_MIN);
104     TestNumberRef(i64input, i64input | JSValueRefInternals::TAG_INT);
105     TestNumberRef(INT64_MIN, ConvertDouble(static_cast<double>(INT64_MIN)));
106     TestNumberRef(INT64_MAX, ConvertDouble(static_cast<double>(INT64_MAX)));
107 }
108 
109 // If this test failed, please contact with Chernykh Sergey
TEST_F(JSNapiTest, ArkplatformJSNApiTest_BooleanRef)110 TEST_F(JSNapiTest, ArkplatformJSNApiTest_BooleanRef)
111 {
112     bool input = true;
113     Local<BooleanRef> res = BooleanRef::New(vm_, input);
114     EXPECT_TRUE(res->IsBoolean());
115     EXPECT_TRUE(res->BooleaValue(vm_));
116     ASSERT_EQ(ToJSTaggedValue(*res), JSValueRefInternals::VALUE_TRUE);
117 
118     input = false;
119     res = BooleanRef::New(vm_, input);
120     EXPECT_TRUE(res->IsBoolean());
121     EXPECT_FALSE(res->BooleaValue(vm_));
122     ASSERT_EQ(ToJSTaggedValue(*res), JSValueRefInternals::VALUE_FALSE);
123 }
124 
125 // If this test failed, please contact with Chernykh Sergey
TEST_F(JSNapiTest, ArkplatformJSNApiTest_NullUndefined)126 TEST_F(JSNapiTest, ArkplatformJSNApiTest_NullUndefined)
127 {
128     LocalScope scope(vm_);
129     Local<JSValueRef> null = JSValueRef::Null(vm_);
130     ASSERT_TRUE(null->IsNull());
131     ASSERT_EQ(ToJSTaggedValue(*null), JSValueRefInternals::VALUE_NULL);
132 
133     Local<JSValueRef> undefined = JSValueRef::Undefined(vm_);
134     ASSERT_TRUE(undefined->IsUndefined());
135     ASSERT_EQ(ToJSTaggedValue(*undefined), JSValueRefInternals::VALUE_UNDEFINED);
136 }
137 
138 } // namespace test
139 } // namespace arkplatform
140