1 /*
2  * Copyright (c) 2021-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 "ark_interop_external.h"
17 #include "ark_interop_hitrace.h"
18 #include "ark_interop_internal.h"
19 #include "ark_interop_log.h"
20 #include "ark_interop_napi.h"
21 #include "gtest/gtest.h"
22 #include "uv_loop_handler.h"
23 
24 #include <cmath>
25 #include <thread>
26 
27 using namespace testing;
28 using namespace testing::ext;
29 
30 struct ARKTS_ModuleCallbacks {
31     ARKTS_Value (*exportModule)(ARKTS_Env env, const char* dllName, ARKTS_Value exports) = nullptr;
32     bool (*hasModuleHandle)(const char* dllName) = nullptr;
33     void (*throwJSError)(ARKTS_Env env, ARKTS_Value) = nullptr;
34     void (*throwNativeError)(const char*) = nullptr;
35     void (*deleteArrayBufferRawData)(void* buffer, int64_t lambdaId) = nullptr;
36     void (*deleteExternal)(int64_t id, ARKTS_Env env) = nullptr;
37     ARKTS_Value (*invokerLambda)(ARKTS_CallInfo, int64_t lambdaId) = nullptr;
38     void (*deleteLambda)(ARKTS_Env env, int64_t lambdaId) = nullptr;
39     void (*invokeAsyncLambda)(ARKTS_Env env, int64_t lambdaId) = nullptr;
40     void (*deleteJSContext)(ARKTS_Env env) = nullptr;
41 };
42 
43 namespace {
44 ARKTS_Engine engine_ = nullptr;
45 
46 class ArkInteropTest : public testing::Test {};
47 
TEST_F(ArkInteropTest, Prime)48 TEST_F(ArkInteropTest, Prime)
49 {
50     auto env = ARKTS_GetContext(engine_);
51     auto scope = ARKTS_OpenScope(env);
52 
53     auto jsUDef = ARKTS_CreateUndefined();
54     EXPECT_TRUE(ARKTS_IsUndefined(jsUDef));
55     EXPECT_EQ(ARKTS_GetValueType(env, jsUDef), N_UNDEFINED);
56 
57     auto jsNull = ARKTS_CreateNull();
58     EXPECT_TRUE(ARKTS_IsNull(jsNull));
59     EXPECT_EQ(ARKTS_GetValueType(env, jsNull), N_NULL);
60 
61     ARKTS_Value jsBools[] {
62         ARKTS_CreateBool(true),
63         ARKTS_CreateBool(false)
64     };
65     EXPECT_TRUE(ARKTS_IsBool(jsBools[0]));
66     EXPECT_EQ(ARKTS_GetValueType(env, jsBools[0]), N_BOOL);
67     EXPECT_TRUE(ARKTS_GetValueBool(jsBools[0]));
68     EXPECT_FALSE(ARKTS_GetValueBool(jsBools[1]));
69 
70     ARKTS_CloseScope(env, scope);
71 }
72 
TEST_F(ArkInteropTest, Number)73 TEST_F(ArkInteropTest, Number)
74 {
75     auto env = ARKTS_GetContext(engine_);
76     auto scope = ARKTS_OpenScope(env);
77     double origins[] {
78         0.1,
79         -12.1,
80         12456.126546
81     };
82     constexpr auto totalCases = std::size(origins);
83     ARKTS_Value jsValues[totalCases];
84     double received[totalCases];
85 
86     for (size_t i = 0;i < totalCases; i++) {
87         jsValues[i] = ARKTS_CreateF64(origins[i]);
88         EXPECT_EQ(ARKTS_GetValueType(env, jsValues[i]), N_NUMBER);
89         EXPECT_TRUE(ARKTS_IsNumber(jsValues[i]));
90         received[i] = ARKTS_GetValueNumber(jsValues[i]);
91         EXPECT_EQ(origins[i], received[i]);
92     }
93 
94     auto jsNan = ARKTS_CreateF64(NAN);
95     auto nNan = ARKTS_GetValueNumber(jsNan);
96     EXPECT_TRUE(std::isnan(nNan));
97     ARKTS_CloseScope(env, scope);
98 }
99 
TEST_F(ArkInteropTest, String)100 TEST_F(ArkInteropTest, String)
101 {
102     auto env = ARKTS_GetContext(engine_);
103     auto scope = ARKTS_OpenScope(env);
104     const char* origins[] {
105         "a plain text",
106         "`~!@#$%^&*()_+[]\\",
107         "中文字符",
108         "���❤️����",
109     };
110     ARKTS_Value jsValues[] {
111         ARKTS_CreateUtf8(env, origins[0], strlen(origins[0])),
112         ARKTS_CreateUtf8(env, origins[1], strlen(origins[1])),
113         ARKTS_CreateUtf8(env, origins[2], strlen(origins[2])),
114         ARKTS_CreateUtf8(env, origins[3], strlen(origins[3])),
115     };
116     EXPECT_TRUE(ARKTS_IsString(env, jsValues[0]));
117     EXPECT_TRUE(ARKTS_IsHeapObject(jsValues[0]));
118     EXPECT_EQ(ARKTS_GetValueType(env, jsValues[0]), N_STRING);
119     for (auto i = 0;i < sizeof(jsValues)/sizeof(ARKTS_Value); i++) {
120         auto size = ARKTS_GetValueUtf8Size(env, jsValues[i]);
121         std::string result;
122         result.resize(size - 1);
123         ARKTS_GetValueUtf8(env, jsValues[i], size - 1, result.data());
124         EXPECT_EQ(result, origins[i]);
125 
126         auto cStr = ARKTS_GetValueCString(env, jsValues[i]);
127         result = cStr;
128         EXPECT_EQ(result, origins[i]);
129         ARKTS_FreeCString(cStr);
130     }
131     ARKTS_CloseScope(env, scope);
132 }
133 
TEST_F(ArkInteropTest, Object)134 TEST_F(ArkInteropTest, Object)
135 {
136     auto env = ARKTS_GetContext(engine_);
137     auto scope = ARKTS_OpenScope(env);
138     auto obj = ARKTS_CreateObject(env);
139     EXPECT_TRUE(ARKTS_IsHeapObject(obj));
140     EXPECT_TRUE(ARKTS_IsObject(env, obj));
141     EXPECT_EQ(ARKTS_GetValueType(env, obj), N_OBJECT);
142     auto keyA = ARKTS_CreateUtf8(env, "a", 1);
143     EXPECT_FALSE(ARKTS_HasOwnProperty(env, obj, keyA));
144     auto valueA = ARKTS_GetProperty(env, obj, keyA);
145     EXPECT_TRUE(ARKTS_IsUndefined(valueA));
146     valueA = ARKTS_CreateBool(true);
147     ARKTS_SetProperty(env, obj, keyA, valueA);
148     EXPECT_TRUE(ARKTS_HasOwnProperty(env, obj, keyA));
149     auto receivedA = ARKTS_GetProperty(env, obj, keyA);
150     EXPECT_TRUE(ARKTS_IsBool(receivedA));
151     EXPECT_TRUE(ARKTS_GetValueBool(receivedA));
152     auto keys = ARKTS_EnumOwnProperties(env, obj);
153     EXPECT_TRUE(ARKTS_IsArray(env, keys));
154     EXPECT_EQ(ARKTS_GetArrayLength(env, keys), 1);
155     auto key = ARKTS_GetElement(env, keys, 0);
156     EXPECT_TRUE(ARKTS_IsString(env, key));
157     EXPECT_TRUE(ARKTS_StrictEqual(env, keyA, key));
158     ARKTS_CloseScope(env, scope);
159 }
160 
161 struct PropCase {
162     char k;
163     bool writable;
164     bool enumerable;
165     bool configurable;
166 };
167 
TEST_F(ArkInteropTest, DefineProperty)168 TEST_F(ArkInteropTest, DefineProperty)
169 {
170     auto env = ARKTS_GetContext(engine_);
171     auto scope = ARKTS_OpenScope(env);
172     auto obj = ARKTS_CreateObject(env);
173     PropCase cases[] {
174         {'a', false, false, false}, {'b', true, false, false}, {'c', false, true, false}, {'d', false, false, true},
175         {'e', true, true, false}, {'f', true, false, true}, {'g', false, true, true}, {'h', true, true, true}
176     };
177     constexpr auto totalCases = std::size(cases);
178     auto valueT = ARKTS_CreateBool(true), valueF = ARKTS_CreateBool(false);
179     ARKTS_Value keys[totalCases];
180     for (auto i = 0; i < totalCases; i++) {
181         keys[i] = ARKTS_CreateUtf8(env, &cases[i].k, 1);
182         ARKTS_DefineOwnProperty(env, obj, keys[i], valueF, static_cast<ARKTS_PropertyFlag>(
183             (cases[i].writable ? N_WRITABLE : 0) |
184             (cases[i].enumerable ? N_ENUMERABLE : 0) |
185             (cases[i].configurable ? N_CONFIGURABLE : 0)
186         ));
187     }
188     constexpr int expectKeys = 4;
189     auto jsKeys = ARKTS_EnumOwnProperties(env, obj);
190     EXPECT_TRUE(ARKTS_IsArray(env, jsKeys));
191     EXPECT_EQ(ARKTS_GetArrayLength(env, jsKeys), expectKeys);
192     for (auto i = 0; i < expectKeys; i++) {
193         auto jsKey = ARKTS_GetElement(env, jsKeys, i);
194         EXPECT_TRUE(ARKTS_IsString(env, jsKey));
195         char buffer = 0;
196         ARKTS_GetValueUtf8(env, jsKey, 1, &buffer);
197         EXPECT_TRUE(buffer == 'c' || buffer == 'e' || buffer == 'g' || buffer == 'h');
198     }
199     for (auto i = 0; i < totalCases; i++) { // writable
200         if (cases[i].writable && cases[i].configurable) {
201             ARKTS_SetProperty(env, obj, keys[i], valueT);
202             auto receivedJS = ARKTS_GetProperty(env, obj, keys[i]);
203             auto recievedN = ARKTS_GetValueBool(receivedJS);
204             EXPECT_TRUE(recievedN);
205         }
206     }
207     for (auto i = 0;i < totalCases; ++i) { // configurable
208         if (cases[i].configurable) {
209             ARKTS_DefineOwnProperty(env, obj, keys[i], valueT,
210                 static_cast<ARKTS_PropertyFlag>(N_WRITABLE | N_ENUMERABLE | N_CONFIGURABLE));
211         }
212     }
213     jsKeys = ARKTS_EnumOwnProperties(env, obj);
214     constexpr int expectLength = 6;
215     EXPECT_EQ(ARKTS_GetArrayLength(env, jsKeys), expectLength);
216     ARKTS_CloseScope(env, scope);
217 }
218 
HWTEST_F(ArkInteropTest, ArkTSInteropNapiInstanceOf, TestSize.Level1)219 HWTEST_F(ArkInteropTest, ArkTSInteropNapiInstanceOf, TestSize.Level1)
220 {
221     ARKTS_Env env = ARKTS_GetContext(engine_);
222     auto global = ARKTS_GetGlobalConstant(env);
223     char clError[] = "Error";
224     auto jError = ARKTS_CreateUtf8(env, clError, sizeof(clError) - 1);
225     auto errorCls = ARKTS_GetProperty(env, global, jError);
226     auto errorObJ = ARKTS_New(env, errorCls, 0, nullptr);
227     auto isError = ARKTS_InstanceOf(env, errorObJ, errorCls);
228     EXPECT_TRUE(isError);
229     auto jObj = ARKTS_CreateObject(env);
230     EXPECT_FALSE(ARKTS_InstanceOf(env, jObj, errorCls));
231 }
232 
HWTEST_F(ArkInteropTest, ArkTSInteropNapiCreateEngineNew, TestSize.Level1)233 HWTEST_F(ArkInteropTest, ArkTSInteropNapiCreateEngineNew, TestSize.Level1)
234 {
235     auto engine = ARKTS_CreateEngineWithNewThread();
236 
237     auto curTid = ARKTS_GetPosixThreadId();
238     auto engineTid = ARKTS_GetThreadIdOfEngine(engine);
239 
240     EXPECT_NE(curTid, engineTid);
241 
242     ARKTS_DestroyEngine(engine);
243 }
244 } // namespace
245 
main(int argc, char** argv)246 int main(int argc, char** argv)
247 {
248     LOGI("main in");
249     testing::GTEST_FLAG(output) = "xml:./";
250     testing::InitGoogleTest(&argc, argv);
251 
252     auto runner = OHOS::AppExecFwk::EventRunner::Create(true);
253     EXPECT_TRUE(runner);
254     auto handler = std::make_shared<OHOS::AppExecFwk::EventHandler>(runner);
255     EXPECT_TRUE(handler);
256 
257     int ret = -1;
258     std::condition_variable cv;
259 
260     auto success = handler->PostTask([&ret, &cv] {
261         engine_ = ARKTS_CreateEngine();
262 
263         ret = testing::UnitTest::GetInstance()->Run();
264         cv.notify_all();
265     });
266 
267     EXPECT_TRUE(success);
268 
269     std::mutex mutex;
270     std::unique_lock<std::mutex> lock(mutex);
271     auto status = cv.wait_for(lock, std::chrono::seconds(10));
272 
273     EXPECT_EQ(status, std::cv_status::no_timeout);
274 
275     ARKTS_DestroyEngine(engine_);
276     engine_ = nullptr;
277     runner->Stop();
278 
279     LOGI("main out");
280     return ret;
281 }
282