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