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 class ArkInteropTest : public testing::Test {
45 public:
RunLocalTest()46 static void RunLocalTest()
47 {
48 TestPrime();
49 TestNumber();
50 TestString();
51 TestObject();
52 TestDefineProperty();
53 TestArray();
54 TestBigintInt64();
55 TestBigint16Bytes();
56 TestBigint28Bytes();
57 TestBigint32Bytes();
58 TestPromise();
59 TestSymbol();
60 TestFunction();
61 TestClass();
62 TestInstanceOf();
63 TestArrayBuffer();
64 }
65 private:
66 static void TestPrime();
67 static void TestNumber();
68 static void TestString();
69 static void TestObject();
70 static void TestDefineProperty();
71 static void TestArray();
72 static void TestBigintInt64();
73 static void TestBigint16Bytes();
74 static void TestBigint28Bytes();
75 static void TestBigint32Bytes();
76 static void TestPromise();
77 static void TestSymbol();
78 static void TestFunction();
79 static void TestClass();
80 static void TestArrayBuffer();
81 static void TestInstanceOf();
82 };
83
84 template <typename T>
85 struct Slab {
86 public:
Add__anon2e6194970110::Slab87 int64_t Add(T item)
88 {
89 int64_t result;
90 if (last_ >= 0) {
91 result = last_;
92 auto& last = items_[result];
93 last_ = last.prev;
94 last.data = std::move(item);
95 } else {
96 result = items_.size();
97 items_.push_back({std::move(item), -1});
98 }
99 return result;
100 }
101
Del__anon2e6194970110::Slab102 void Del(int64_t id)
103 {
104 auto& removing = items_[id];
105 removing.data = std::nullopt;
106 removing.prev = last_;
107 last_ = id;
108 }
109
Get__anon2e6194970110::Slab110 T& Get(int64_t id)
111 {
112 return items_[id].data.value();
113 }
114
Get__anon2e6194970110::Slab115 const T& Get(int64_t id) const
116 {
117 return items_[id].data.value();
118 }
119 private:
120 struct Item {
121 std::optional<T> data;
122 int64_t prev;
123 };
124 std::vector<Item> items_ {};
125 int64_t last_ = -1;
126 };
127
128 class MockContext {
129 static MockContext* instance_;
NewId()130 static uint32_t NewId()
131 {
132 static uint32_t id = 0;
133 return id++;
134 }
135
136 public:
GetInstance()137 static MockContext* GetInstance()
138 {
139 return instance_;
140 }
141
GetEngine() const142 ARKTS_Engine GetEngine() const
143 {
144 return engine_;
145 }
146
GetEnv() const147 ARKTS_Env GetEnv() const
148 {
149 return ARKTS_GetContext(engine_);
150 }
151
152 static void Init();
153
MockContext(ARKTS_Engine engine,bool needDestroyEngine=true)154 explicit MockContext(ARKTS_Engine engine, bool needDestroyEngine = true): idPrefix_(NewId()),
155 lastContext_(instance_), engine_(engine), needDestroyEngine_(needDestroyEngine)
156 {
157 instance_ = this;
158 }
159
MockContext()160 MockContext(): idPrefix_(NewId()), lastContext_(instance_), engine_(instance_->GetEngine()),
161 needDestroyEngine_(false)
162 {
163 instance_ = this;
164 }
165
~MockContext()166 ~MockContext()
167 {
168 if (needDestroyEngine_) {
169 ARKTS_DestroyEngine(engine_);
170 }
171 engine_ = nullptr;
172 instance_ = lastContext_;
173 }
174
StoreFunc(std::function<ARKTS_Value (ARKTS_CallInfo)> call)175 int64_t StoreFunc(std::function<ARKTS_Value(ARKTS_CallInfo)> call)
176 {
177 return ToId(callbacks_.Add(std::move(call)));
178 }
179
StoreAsyncFunc(std::function<void ()> call)180 int64_t StoreAsyncFunc(std::function<void ()> call)
181 {
182 return ToId(asyncCallbacks_.Add(std::move(call)));
183 }
184
StoreArrayBufferDeleter(std::function<void (void *)> call)185 int64_t StoreArrayBufferDeleter(std::function<void (void*)> call)
186 {
187 return ToId(nativeDeleters_.Add(std::move(call)));
188 }
189
StoreNativeData(void * data,std::function<void (void *)> deleter)190 int64_t StoreNativeData(void* data, std::function<void (void*)>deleter)
191 {
192 return ToId(data_.Add({data, std::move(deleter)}));
193 }
194
GetNativeData(int64_t id)195 void* GetNativeData(int64_t id)
196 {
197 auto index = ToIndex(id);
198 if (index < 0) {
199 return nullptr;
200 }
201 return data_.Get(index).data;
202 }
203
204 protected:
ExportModule(ARKTS_Env env,const char * dllName,ARKTS_Value exports)205 virtual ARKTS_Value ExportModule(ARKTS_Env env, const char* dllName, ARKTS_Value exports)
206 {
207 return exports;
208 }
209
HasModuleHandle(const char * dllName)210 virtual bool HasModuleHandle(const char* dllName)
211 {
212 return false;
213 }
214
ThrowJSError(ARKTS_Env env,ARKTS_Value)215 virtual void ThrowJSError(ARKTS_Env env, ARKTS_Value)
216 {
217 EXPECT_TRUE(false);
218 }
219
ThrowNativeError(const char * msg)220 virtual void ThrowNativeError(const char* msg)
221 {
222 printf("[Native Error]: %s\n", msg);
223 EXPECT_TRUE(false);
224 }
225
DeleteArrayBufferRawData(void * buffer,int64_t id)226 virtual void DeleteArrayBufferRawData(void* buffer, int64_t id)
227 {
228 auto index = ToIndex(id);
229 if (index < 0) {
230 return;
231 }
232 nativeDeleters_.Get(index)(buffer);
233 nativeDeleters_.Del(index);
234 }
235
DeleteExternal(int64_t id,ARKTS_Env env)236 virtual void DeleteExternal(int64_t id, ARKTS_Env env)
237 {
238 auto index = ToIndex(id);
239 if (index < 0) {
240 return;
241 }
242 auto& data = data_.Get(index);
243 data.deleter(data.data);
244 data_.Del(index);
245 }
246
InvokeLambda(ARKTS_CallInfo info,int64_t id)247 virtual ARKTS_Value InvokeLambda(ARKTS_CallInfo info, int64_t id)
248 {
249 auto index = ToIndex(id);
250 if (index < 0) {
251 return ARKTS_CreateUndefined();
252 }
253 return callbacks_.Get(index)(info);
254 }
255
DeleteLambda(ARKTS_Env env,int64_t id)256 virtual void DeleteLambda(ARKTS_Env env, int64_t id)
257 {
258 auto index = ToIndex(id);
259 if (index < 0) {
260 return;
261 }
262 callbacks_.Del(index);
263 }
264
InvokeAsyncLambda(ARKTS_Env env,int64_t id)265 virtual void InvokeAsyncLambda(ARKTS_Env env, int64_t id)
266 {
267 auto index = ToIndex(id);
268 if (index < 0) {
269 return;
270 }
271 asyncCallbacks_.Get(index)();
272 asyncCallbacks_.Del(index);
273 }
274
DeleteJSContext(ARKTS_Env env)275 virtual void DeleteJSContext(ARKTS_Env env)
276 {
277 }
278
ToId(int64_t index) const279 int64_t ToId(int64_t index) const
280 {
281 return GetPrefixMask() | index;
282 }
283
ToIndex(int64_t id) const284 int64_t ToIndex(int64_t id) const
285 {
286 auto myMask = GetPrefixMask();
287 if ((id & myMask) == myMask) {
288 return id & 0xFFFF'FFFF;
289 }
290 return -1;
291 }
292
293 private:
GetPrefixMask() const294 int64_t GetPrefixMask() const
295 {
296 constexpr auto idBits = 32;
297 return static_cast<int64_t>(idPrefix_) << idBits;
298 }
299
300 uint32_t idPrefix_;
301 MockContext* lastContext_;
302 ARKTS_Engine engine_;
303 bool needDestroyEngine_;
304 Slab<std::function<ARKTS_Value (ARKTS_CallInfo)>> callbacks_;
305 Slab<std::function<void ()>> asyncCallbacks_;
306 Slab<std::function<void (void*)>> nativeDeleters_;
307 struct AnyData {
308 void* data;
309 std::function<void (void*)> deleter;
310 };
311 Slab<AnyData> data_;
312 };
313
Init()314 void MockContext::Init()
315 {
316 static ARKTS_ModuleCallbacks callbacks {
317 .exportModule = [](ARKTS_Env env, const char* dllName, ARKTS_Value exports)->ARKTS_Value {
318 return instance_ ? instance_->ExportModule(env, dllName, exports) : exports;
319 },
320 .hasModuleHandle = [](const char* dllName)->bool {
321 return instance_ ? instance_->HasModuleHandle(dllName) : false;
322 },
323 .throwJSError = [](ARKTS_Env env, ARKTS_Value error)->void {
324 if (instance_) instance_->ThrowJSError(env, error);
325 },
326 .throwNativeError = [](const char* error)->void {
327 if (instance_) instance_->ThrowNativeError(error);
328 },
329 .deleteArrayBufferRawData = [](void* buffer, int64_t lambdaId)->void {
330 if (instance_) instance_->DeleteArrayBufferRawData(buffer, lambdaId);
331 },
332 .deleteExternal = [](int64_t id, ARKTS_Env env)->void {
333 if (instance_) instance_->DeleteExternal(id, env);
334 },
335 .invokerLambda = [](ARKTS_CallInfo callInfo, int64_t lambdaId)->ARKTS_Value {
336 return instance_ ? instance_->InvokeLambda(callInfo, lambdaId) : ARKTS_CreateUndefined();
337 },
338 .deleteLambda = [](ARKTS_Env env, int64_t id)->void {
339 if (instance_) instance_->DeleteLambda(env, id);
340 },
341 .invokeAsyncLambda = [](ARKTS_Env env, int64_t id)->void {
342 if (instance_) instance_->InvokeAsyncLambda(env, id);
343 },
344 .deleteJSContext = [](ARKTS_Env env)->void {
345 if (instance_) instance_->DeleteJSContext(env);
346 }
347 };
348 ARKTS_SetCJModuleCallback(&callbacks);
349 }
350
351 MockContext* MockContext::instance_ = nullptr;
352
TestPrime()353 void ArkInteropTest::TestPrime()
354 {
355 auto env = MockContext::GetInstance()->GetEnv();
356 auto scope = ARKTS_OpenScope(env);
357
358 auto jsUDef = ARKTS_CreateUndefined();
359 EXPECT_TRUE(ARKTS_IsUndefined(jsUDef));
360 EXPECT_EQ(ARKTS_GetValueType(env, jsUDef), N_UNDEFINED);
361
362 auto jsNull = ARKTS_CreateNull();
363 EXPECT_TRUE(ARKTS_IsNull(jsNull));
364 EXPECT_EQ(ARKTS_GetValueType(env, jsNull), N_NULL);
365
366 ARKTS_Value jsBools[] {
367 ARKTS_CreateBool(true),
368 ARKTS_CreateBool(false)
369 };
370 EXPECT_TRUE(ARKTS_IsBool(jsBools[0]));
371 EXPECT_EQ(ARKTS_GetValueType(env, jsBools[0]), N_BOOL);
372 EXPECT_TRUE(ARKTS_GetValueBool(jsBools[0]));
373 EXPECT_FALSE(ARKTS_GetValueBool(jsBools[1]));
374
375 ARKTS_CloseScope(env, scope);
376 }
377
TestNumber()378 void ArkInteropTest::TestNumber()
379 {
380 auto env = MockContext::GetInstance()->GetEnv();
381 auto scope = ARKTS_OpenScope(env);
382 double origins[] {
383 0.1,
384 -12.1,
385 12456.126546
386 };
387 constexpr auto totalCases = std::size(origins);
388 ARKTS_Value jsValues[totalCases];
389 double received[totalCases];
390
391 for (size_t i = 0;i < totalCases; i++) {
392 jsValues[i] = ARKTS_CreateF64(origins[i]);
393 EXPECT_EQ(ARKTS_GetValueType(env, jsValues[i]), N_NUMBER);
394 EXPECT_TRUE(ARKTS_IsNumber(jsValues[i]));
395 received[i] = ARKTS_GetValueNumber(jsValues[i]);
396 EXPECT_EQ(origins[i], received[i]);
397 }
398
399 auto jsNan = ARKTS_CreateF64(NAN);
400 auto nNan = ARKTS_GetValueNumber(jsNan);
401 EXPECT_TRUE(std::isnan(nNan));
402 ARKTS_CloseScope(env, scope);
403 }
404
TestString()405 void ArkInteropTest::TestString()
406 {
407 auto env = MockContext::GetInstance()->GetEnv();
408 auto scope = ARKTS_OpenScope(env);
409 const char* origins[] {
410 "a plain text",
411 "`~!@#$%^&*()_+[]\\",
412 "中文字符",
413 "❤️",
414 };
415 ARKTS_Value jsValues[] {
416 ARKTS_CreateUtf8(env, origins[0], strlen(origins[0])),
417 ARKTS_CreateUtf8(env, origins[1], strlen(origins[1])),
418 ARKTS_CreateUtf8(env, origins[2], strlen(origins[2])),
419 ARKTS_CreateUtf8(env, origins[3], strlen(origins[3])),
420 };
421 EXPECT_TRUE(ARKTS_IsString(env, jsValues[0]));
422 EXPECT_TRUE(ARKTS_IsHeapObject(jsValues[0]));
423 EXPECT_EQ(ARKTS_GetValueType(env, jsValues[0]), N_STRING);
424 for (auto i = 0;i < sizeof(jsValues)/sizeof(ARKTS_Value); i++) {
425 auto size = ARKTS_GetValueUtf8Size(env, jsValues[i]);
426 std::string result;
427 result.resize(size - 1);
428 ARKTS_GetValueUtf8(env, jsValues[i], size - 1, result.data());
429 EXPECT_EQ(result, origins[i]);
430
431 auto cStr = ARKTS_GetValueCString(env, jsValues[i]);
432 result = cStr;
433 EXPECT_EQ(result, origins[i]);
434 ARKTS_FreeCString(cStr);
435 }
436 ARKTS_CloseScope(env, scope);
437 }
438
TestObject()439 void ArkInteropTest::TestObject()
440 {
441 auto env = MockContext::GetInstance()->GetEnv();
442 auto scope = ARKTS_OpenScope(env);
443 auto obj = ARKTS_CreateObject(env);
444 EXPECT_TRUE(ARKTS_IsHeapObject(obj));
445 EXPECT_TRUE(ARKTS_IsObject(env, obj));
446 EXPECT_EQ(ARKTS_GetValueType(env, obj), N_OBJECT);
447 auto keyA = ARKTS_CreateUtf8(env, "a", 1);
448 EXPECT_FALSE(ARKTS_HasOwnProperty(env, obj, keyA));
449 auto valueA = ARKTS_GetProperty(env, obj, keyA);
450 EXPECT_TRUE(ARKTS_IsUndefined(valueA));
451 valueA = ARKTS_CreateBool(true);
452 ARKTS_SetProperty(env, obj, keyA, valueA);
453 EXPECT_TRUE(ARKTS_HasOwnProperty(env, obj, keyA));
454 auto receivedA = ARKTS_GetProperty(env, obj, keyA);
455 EXPECT_TRUE(ARKTS_IsBool(receivedA));
456 EXPECT_TRUE(ARKTS_GetValueBool(receivedA));
457 auto keys = ARKTS_EnumOwnProperties(env, obj);
458 EXPECT_TRUE(ARKTS_IsArray(env, keys));
459 EXPECT_EQ(ARKTS_GetArrayLength(env, keys), 1);
460 auto key = ARKTS_GetElement(env, keys, 0);
461 EXPECT_TRUE(ARKTS_IsString(env, key));
462 EXPECT_TRUE(ARKTS_StrictEqual(env, keyA, key));
463 ARKTS_CloseScope(env, scope);
464 }
465
466 struct PropCase {
467 char k;
468 bool writable;
469 bool enumerable;
470 bool configurable;
471 };
472
TestDefineProperty()473 void ArkInteropTest::TestDefineProperty()
474 {
475 auto env = MockContext::GetInstance()->GetEnv();
476 auto scope = ARKTS_OpenScope(env);
477 auto obj = ARKTS_CreateObject(env);
478 PropCase cases[] {
479 {'a', false, false, false}, {'b', true, false, false}, {'c', false, true, false}, {'d', false, false, true},
480 {'e', true, true, false}, {'f', true, false, true}, {'g', false, true, true}, {'h', true, true, true}
481 };
482 constexpr auto totalCases = std::size(cases);
483 auto valueT = ARKTS_CreateBool(true), valueF = ARKTS_CreateBool(false);
484 ARKTS_Value keys[totalCases];
485 for (auto i = 0; i < totalCases; i++) {
486 keys[i] = ARKTS_CreateUtf8(env, &cases[i].k, 1);
487 ARKTS_DefineOwnProperty(env, obj, keys[i], valueF, static_cast<ARKTS_PropertyFlag>(
488 (cases[i].writable ? N_WRITABLE : 0) |
489 (cases[i].enumerable ? N_ENUMERABLE : 0) |
490 (cases[i].configurable ? N_CONFIGURABLE : 0)
491 ));
492 }
493 constexpr int expectKeys = 4;
494 auto jsKeys = ARKTS_EnumOwnProperties(env, obj);
495 EXPECT_TRUE(ARKTS_IsArray(env, jsKeys));
496 EXPECT_EQ(ARKTS_GetArrayLength(env, jsKeys), expectKeys);
497 for (auto i = 0; i < expectKeys; i++) {
498 auto jsKey = ARKTS_GetElement(env, jsKeys, i);
499 EXPECT_TRUE(ARKTS_IsString(env, jsKey));
500 char buffer = 0;
501 ARKTS_GetValueUtf8(env, jsKey, 1, &buffer);
502 EXPECT_TRUE(buffer == 'c' || buffer == 'e' || buffer == 'g' || buffer == 'h');
503 }
504 for (auto i = 0; i < totalCases; i++) { // writable
505 if (cases[i].writable && cases[i].configurable) {
506 ARKTS_SetProperty(env, obj, keys[i], valueT);
507 auto receivedJS = ARKTS_GetProperty(env, obj, keys[i]);
508 auto recievedN = ARKTS_GetValueBool(receivedJS);
509 EXPECT_TRUE(recievedN);
510 }
511 }
512 for (auto i = 0;i < totalCases; ++i) { // configurable
513 if (cases[i].configurable) {
514 ARKTS_DefineOwnProperty(env, obj, keys[i], valueT,
515 static_cast<ARKTS_PropertyFlag>(N_WRITABLE | N_ENUMERABLE | N_CONFIGURABLE));
516 }
517 }
518 jsKeys = ARKTS_EnumOwnProperties(env, obj);
519 constexpr int expectLength = 6;
520 EXPECT_EQ(ARKTS_GetArrayLength(env, jsKeys), expectLength);
521 ARKTS_CloseScope(env, scope);
522 }
523
TestInstanceOf()524 void ArkInteropTest::TestInstanceOf()
525 {
526 ARKTS_Env env = MockContext::GetInstance()->GetEnv();
527 auto global = ARKTS_GetGlobalConstant(env);
528 char clError[] = "Error";
529 auto jError = ARKTS_CreateUtf8(env, clError, sizeof(clError) - 1);
530 auto errorCls = ARKTS_GetProperty(env, global, jError);
531 auto errorObJ = ARKTS_New(env, errorCls, 0, nullptr);
532 auto isError = ARKTS_InstanceOf(env, errorObJ, errorCls);
533 EXPECT_TRUE(isError);
534 auto jObj = ARKTS_CreateObject(env);
535 EXPECT_FALSE(ARKTS_InstanceOf(env, jObj, errorCls));
536 }
537
TestArray()538 void ArkInteropTest::TestArray()
539 {
540 EXPECT_TRUE(MockContext::GetInstance());
541 ARKTS_Env env = MockContext::GetInstance()->GetEnv();
542 EXPECT_TRUE(env);
543
544 char c = 'c';
545 ARKTS_Value origin[] {
546 ARKTS_CreateBool(true),
547 ARKTS_CreateF64(12.02),
548 ARKTS_CreateUtf8(env, &c, 1),
549 ARKTS_CreateObject(env),
550 };
551 constexpr auto arrSize = std::size(origin);
552 auto arr = ARKTS_CreateArray(env, arrSize);
553 EXPECT_TRUE(ARKTS_IsArray(env, arr));
554 EXPECT_EQ(ARKTS_GetValueType(env, arr), N_OBJECT);
555 EXPECT_EQ(ARKTS_GetArrayLength(env, arr), arrSize);
556 for (auto i = 0; i < arrSize; i++) {
557 auto initialValue = ARKTS_GetElement(env, arr, i);
558 EXPECT_TRUE(ARKTS_IsUndefined(initialValue));
559 ARKTS_SetElement(env, arr, i, origin[i]);
560 auto receivedValue = ARKTS_GetElement(env, arr, i);
561 EXPECT_TRUE(ARKTS_StrictEqual(env, origin[i], receivedValue));
562 }
563 }
564
TestBigintInt64()565 void ArkInteropTest::TestBigintInt64()
566 {
567 EXPECT_TRUE(MockContext::GetInstance());
568 ARKTS_Env env = MockContext::GetInstance()->GetEnv();
569 EXPECT_TRUE(env);
570 {
571 int64_t origins[] {
572 0x123'4567'8945,
573 -0x123'4567'8945,
574 0x7FFF'FFFF'FFFF'FFFF,
575 -0x7FFF'FFFF'FFFF'FFFF,
576 };
577 constexpr auto arrSize = std::size(origins);
578 ARKTS_Value values[arrSize];
579 for (auto i = 0; i < arrSize; i++) {
580 values[i] = ARKTS_CreateBigInt(env, origins[i]);
581 EXPECT_TRUE(ARKTS_IsBigInt(env, values[i]));
582 EXPECT_EQ(ARKTS_GetValueType(env, values[i]), N_BIGINT);
583 ARKTS_BigIntGetByteSize(env, values[i]);
584 }
585 }
586 }
587
TestBigint16Bytes()588 void ArkInteropTest::TestBigint16Bytes()
589 {
590 EXPECT_TRUE(MockContext::GetInstance());
591 ARKTS_Env env = MockContext::GetInstance()->GetEnv();
592 EXPECT_TRUE(env);
593 uint8_t origin[] {
594 0, 10, 20, 30, 40, 50, 60, 70,
595 80, 90, 70, 50, 20, 30, 40, 50
596 };
597 bool isNegative = false;
598 auto value = ARKTS_CreateBigIntWithBytes(env, isNegative, std::size(origin), origin);
599 EXPECT_TRUE(ARKTS_IsBigInt(env, value));
600 EXPECT_EQ(ARKTS_GetValueType(env, value), N_BIGINT);
601 EXPECT_EQ(ARKTS_BigIntGetByteSize(env, value), std::size(origin));
602 uint8_t received[std::size(origin)];
603 ARKTS_BigIntReadBytes(env, value, &isNegative, std::size(origin), received);
604 EXPECT_FALSE(isNegative);
605 for (auto i = 0; i < std::size(origin); i++) {
606 EXPECT_EQ(origin[i], received[i]);
607 }
608 }
609
TestBigint28Bytes()610 void ArkInteropTest::TestBigint28Bytes()
611 {
612 EXPECT_TRUE(MockContext::GetInstance());
613 ARKTS_Env env = MockContext::GetInstance()->GetEnv();
614 EXPECT_TRUE(env);
615 uint8_t origin[] {
616 0, 10, 20, 30, 40, 50, 60, 70,
617 80, 90, 70, 50, 20, 30, 40, 50,
618 1, 2, 3, 4, 5, 6, 7, 8,
619 9, 10, 20, 30,
620 };
621 bool isNegative = false;
622 constexpr int expectSize = 32;
623 // bigint words are 8 bytes aligned, received 32 bytes, and lower 4 bytes would be filled with 0.
624 auto value = ARKTS_CreateBigIntWithBytes(env, isNegative, std::size(origin), origin);
625 EXPECT_TRUE(ARKTS_IsBigInt(env, value));
626 EXPECT_EQ(ARKTS_GetValueType(env, value), N_BIGINT);
627 EXPECT_EQ(ARKTS_BigIntGetByteSize(env, value), expectSize);
628 uint8_t received[expectSize];
629 ARKTS_BigIntReadBytes(env, value, &isNegative, expectSize, received);
630 EXPECT_FALSE(isNegative);
631 for (auto i = 0; i < std::size(origin); i++) {
632 EXPECT_EQ(origin[i], received[i + expectSize - std::size(origin)]);
633 }
634 }
635
TestBigint32Bytes()636 void ArkInteropTest::TestBigint32Bytes()
637 {
638 EXPECT_TRUE(MockContext::GetInstance());
639 ARKTS_Env env = MockContext::GetInstance()->GetEnv();
640 EXPECT_TRUE(env);
641 uint8_t origin[] {
642 0, 10, 20, 30, 40, 50, 60, 70,
643 80, 90, 70, 50, 20, 30, 40, 50,
644 1, 2, 3, 4, 5, 6, 7, 8,
645 9, 10, 20, 30, 40, 50, 60, 70,
646 };
647 bool isNegative = false;
648 auto value = ARKTS_CreateBigIntWithBytes(env, isNegative, std::size(origin), origin);
649 EXPECT_TRUE(ARKTS_IsBigInt(env, value));
650 EXPECT_EQ(ARKTS_GetValueType(env, value), N_BIGINT);
651 EXPECT_EQ(ARKTS_BigIntGetByteSize(env, value), std::size(origin));
652 uint8_t received[std::size(origin)];
653 ARKTS_BigIntReadBytes(env, value, &isNegative, std::size(origin), received);
654 EXPECT_FALSE(isNegative);
655 for (auto i = 0; i < std::size(origin); i++) {
656 EXPECT_EQ(origin[i], received[i]);
657 }
658 }
659
TestSymbol()660 void ArkInteropTest::TestSymbol()
661 {
662 EXPECT_TRUE(MockContext::GetInstance());
663 ARKTS_Env env = MockContext::GetInstance()->GetEnv();
664 EXPECT_TRUE(env);
665
666 const char originDesc[] = "TestSymbol";
667
668 auto symbol = ARKTS_CreateSymbol(env, originDesc, sizeof(originDesc) - 1);
669 EXPECT_TRUE(ARKTS_IsSymbol(env, symbol));
670 EXPECT_EQ(ARKTS_GetValueType(env, symbol), N_SYMBOL);
671
672 auto retDesc = ARKTS_GetSymbolDesc(env, symbol);
673 EXPECT_EQ(std::string(retDesc), originDesc);
674 ARKTS_FreeCString(retDesc);
675
676 auto obj = ARKTS_CreateObject(env);
677 ARKTS_SetProperty(env, obj, symbol, ARKTS_CreateBool(true));
678 auto value = ARKTS_GetProperty(env, obj, symbol);
679 EXPECT_TRUE(ARKTS_IsBool(value));
680 EXPECT_TRUE(ARKTS_GetValueBool(value));
681
682 auto symbol1 = ARKTS_CreateSymbol(env, originDesc, sizeof(originDesc) - 1);
683 ARKTS_SetProperty(env, obj, symbol1, ARKTS_CreateBool(false));
684 auto value1 = ARKTS_GetProperty(env, obj, symbol1);
685 EXPECT_TRUE(ARKTS_IsBool(value1));
686 EXPECT_FALSE(ARKTS_GetValueBool(value1));
687
688 value = ARKTS_GetProperty(env, obj, symbol);
689 EXPECT_TRUE(ARKTS_IsBool(value));
690 EXPECT_TRUE(ARKTS_GetValueBool(value));
691 }
692
TestFunction()693 void ArkInteropTest::TestFunction()
694 {
695 EXPECT_TRUE(MockContext::GetInstance());
696 ARKTS_Env env = MockContext::GetInstance()->GetEnv();
697 EXPECT_TRUE(env);
698
699 bool called = false;
700 auto id = MockContext::GetInstance()->StoreFunc([&called](ARKTS_CallInfo info)->ARKTS_Value {
701 called = true;
702 EXPECT_EQ(ARKTS_GetArgCount(info), 0);
703 EXPECT_TRUE(ARKTS_IsUndefined(ARKTS_GetThisArg(info)));
704 return ARKTS_CreateUndefined();
705 });
706 auto func = ARKTS_CreateFunc(env, id);
707 EXPECT_TRUE(ARKTS_IsCallable(env, func));
708 EXPECT_EQ(ARKTS_GetValueType(env, func), N_FUNCTION);
709 ARKTS_Call(env, func, ARKTS_CreateUndefined(), 0, nullptr);
710 EXPECT_TRUE(called);
711 called = false;
712 ARKTS_Value args[] {
713 ARKTS_CreateNull(),
714 ARKTS_CreateBool(true),
715 ARKTS_CreateF64(45.1),
716 ARKTS_CreateObject(env)
717 };
718 static constexpr auto totalArgs = std::size(args);
719 id = MockContext::GetInstance()->StoreFunc([env, &called, origin = args](ARKTS_CallInfo info)->ARKTS_Value {
720 called = true;
721 auto self = ARKTS_GetThisArg(info);
722 EXPECT_TRUE(ARKTS_IsObject(env, self));
723 EXPECT_EQ(totalArgs, ARKTS_GetArgCount(info));
724 for (auto i = 0; i < totalArgs; i++) {
725 EXPECT_TRUE(ARKTS_StrictEqual(env, ARKTS_GetArg(info, i), origin[i]));
726 }
727 return ARKTS_CreateBool(true);
728 });
729 func = ARKTS_CreateFunc(env, id);
730 ARKTS_Call(env, func, ARKTS_CreateObject(env), std::size(args), args);
731 EXPECT_TRUE(called);
732 }
733
TestClass()734 void ArkInteropTest::TestClass()
735 {
736 EXPECT_TRUE(MockContext::GetInstance());
737 ARKTS_Env env = MockContext::GetInstance()->GetEnv();
738 EXPECT_TRUE(env);
739 auto id = MockContext::GetInstance()->StoreFunc([](ARKTS_CallInfo info)->ARKTS_Value {
740 return ARKTS_GetThisArg(info);
741 });
742 auto clazz = ARKTS_CreateClass(env, id, ARKTS_CreateUndefined());
743 EXPECT_TRUE(ARKTS_IsClass(env, clazz));
744 EXPECT_EQ(ARKTS_GetValueType(env, clazz), N_FUNCTION);
745 auto obj = ARKTS_New(env, clazz, 0, nullptr);
746 EXPECT_TRUE(ARKTS_IsObject(env, obj));
747 EXPECT_TRUE(ARKTS_InstanceOf(env, obj, clazz));
748 }
749
TestPromise()750 void ArkInteropTest::TestPromise()
751 {
752 EXPECT_TRUE(MockContext::GetInstance());
753 ARKTS_Env env = MockContext::GetInstance()->GetEnv();
754 EXPECT_TRUE(env);
755 auto scope = ARKTS_OpenScope(env);
756
757 auto promiseCap = ARKTS_CreatePromiseCapability(env);
758 auto promise = ARKTS_GetPromiseFromCapability(env, promiseCap);
759 EXPECT_TRUE(ARKTS_IsPromise(env, promise));
760 EXPECT_EQ(ARKTS_GetValueType(env, promise), N_OBJECT);
761
762 bool resolved = false;
763 auto id = MockContext::GetInstance()->StoreFunc([&resolved](ARKTS_CallInfo info)->ARKTS_Value {
764 resolved = true;
765 EXPECT_EQ(ARKTS_GetArgCount(info), 1);
766 auto arg = ARKTS_GetArg(info, 0);
767 EXPECT_TRUE(ARKTS_IsUndefined(arg));
768 return ARKTS_CreateBool(true);
769 });
770 auto onResolved = ARKTS_CreateFunc(env, id);
771 ARKTS_PromiseThen(env, promise, onResolved, ARKTS_CreateUndefined());
772 ARKTS_PromiseCapabilityResolve(env, promiseCap, ARKTS_CreateUndefined());
773 EXPECT_TRUE(resolved);
774
775 ARKTS_CloseScope(env, scope);
776 }
777
TestArrayBuffer()778 void ArkInteropTest::TestArrayBuffer()
779 {
780 EXPECT_TRUE(MockContext::GetInstance());
781 ARKTS_Env env = MockContext::GetInstance()->GetEnv();
782 EXPECT_TRUE(env);
783 auto scope = ARKTS_OpenScope(env);
784
785 uint8_t origin[] {
786 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
787 'a', 'b', 'c', 'd', 'e', 'f', 'g'
788 };
789 auto arrSize = std::size(origin);
790 auto buffer = ARKTS_CreateArrayBuffer(env, arrSize);
791 EXPECT_TRUE(ARKTS_IsArrayBuffer(env, buffer));
792 EXPECT_EQ(ARKTS_GetValueType(env, buffer), N_OBJECT);
793 EXPECT_EQ(ARKTS_GetArrayBufferLength(env, buffer), arrSize);
794 auto dst = reinterpret_cast<uint8_t*>(ARKTS_GetArrayBufferRawPtr(env, buffer));
795 for (auto i = 0; i < arrSize; i++) {
796 dst[i] = origin[i];
797 }
798 uint8_t received[std::size(origin)];
799 auto endpoint = ARKTS_ArrayBufferReadBytes(env, buffer, received, arrSize);
800 EXPECT_EQ(endpoint, arrSize);
801
802 for (auto i = 0; i < arrSize; i++) {
803 EXPECT_EQ(origin[i], received[i]);
804 }
805
806 ARKTS_CloseScope(env, scope);
807 }
808
TEST_F(ArkInteropTest,Types)809 TEST_F(ArkInteropTest, Types)
810 {
811 RunLocalTest();
812 }
813
TEST_F(ArkInteropTest,PromiseThen)814 TEST_F(ArkInteropTest, PromiseThen)
815 {
816 MockContext local(ARKTS_CreateEngineWithNewThread());
817 auto env = local.GetEnv();
818 EXPECT_TRUE(env);
819
820 std::condition_variable cv;
821 bool isComplete = false;
822 auto funcId = local.StoreAsyncFunc([&local, &cv, &isComplete, env] {
823 auto scope = ARKTS_OpenScope(env);
824 auto promiseCap = ARKTS_CreatePromiseCapability(env);
825 auto promise = ARKTS_GetPromiseFromCapability(env, promiseCap);
826 auto funcId = local.StoreFunc([&cv, &isComplete](ARKTS_CallInfo info) {
827 isComplete = true;
828 cv.notify_one();
829 return ARKTS_CreateUndefined();
830 });
831 auto func = ARKTS_CreateFunc(env, funcId);
832 ARKTS_PromiseThen(env, promise, func, ARKTS_CreateUndefined());
833 ARKTS_PromiseCapabilityResolve(env, promiseCap, ARKTS_CreateUndefined());
834 ARKTS_CloseScope(env, scope);
835 });
836 ARKTS_CreateAsyncTask(env, funcId);
837 std::mutex mutex;
838 std::unique_lock lock(mutex);
839
840 constexpr int checkDuration = 10;
841 int waitTimes = 10; // set 100ms timeout
842 while (!isComplete && waitTimes--) {
843 cv.wait_for(lock, std::chrono::milliseconds(checkDuration));
844 }
845 // EXPECT no core dump, no timeout
846 EXPECT_TRUE(waitTimes > 0);
847 }
848
849 HWTEST_F(ArkInteropTest, ArkTSInteropNapiCreateEngineNew, TestSize.Level1)
850 {
851 MockContext local(ARKTS_CreateEngineWithNewThread());
852
853 auto curTid = ARKTS_GetPosixThreadId();
854 auto engineTid = ARKTS_GetThreadIdOfEngine(local.GetEngine());
855
856 EXPECT_NE(curTid, engineTid);
857
858 auto env = local.GetEnv();
859 EXPECT_TRUE(env);
860 bool isComplete = false;
861 std::condition_variable cv;
__anon2e6194971202null862 auto funcId = local.StoreAsyncFunc([&isComplete, &cv] {
863 ArkInteropTest::RunLocalTest();
864 isComplete = true;
865 cv.notify_one();
866 });
867 ARKTS_CreateAsyncTask(env, funcId);
868 std::mutex mutex;
869 std::unique_lock lock(mutex);
870 constexpr int checkDuration = 10;
871 int waitTimes = 100; // set 1000ms timeout
872 while (!isComplete && waitTimes--) {
873 cv.wait_for(lock, std::chrono::milliseconds(checkDuration));
874 }
875 EXPECT_TRUE(waitTimes > 0);
876 }
877
TEST_F(ArkInteropTest,ScopeMT)878 TEST_F(ArkInteropTest, ScopeMT)
879 {
880 constexpr int threadCount = 1000;
881 std::thread threads[threadCount];
882 for (int i = 0; i < threadCount; i++) {
883 threads[i] = std::thread([] {
884 panda::RuntimeOption options;
885 auto vm = panda::JSNApi::CreateJSVM(options);
886 EXPECT_TRUE(vm);
887 auto env = P_CAST(vm, ARKTS_Env);
888 auto scope = ARKTS_OpenScope(env);
889 EXPECT_TRUE(scope);
890 ARKTS_CloseScope(env, scope);
891 panda::JSNApi::DestroyJSVM(vm);
892 });
893 }
894 for (auto& thread : threads) {
895 thread.join();
896 }
897 }
898 } // namespace
899
main(int argc,char ** argv)900 int main(int argc, char** argv)
901 {
902 LOGI("main in");
903 testing::GTEST_FLAG(output) = "xml:./";
904 testing::InitGoogleTest(&argc, argv);
905
906 auto runner = OHOS::AppExecFwk::EventRunner::Create(true);
907 EXPECT_TRUE(runner);
908 auto handler = std::make_shared<OHOS::AppExecFwk::EventHandler>(runner);
909 EXPECT_TRUE(handler);
910
911 MockContext::Init();
912
913 int ret = -1;
914 std::condition_variable cv;
915
916 ARKTS_Engine globalEngine;
917
918 auto success = handler->PostTask([&ret, &cv, &globalEngine] {
919 MockContext global(ARKTS_CreateEngine(), false);
920 globalEngine = global.GetEngine();
921 ret = testing::UnitTest::GetInstance()->Run();
922 cv.notify_all();
923 });
924
925 EXPECT_TRUE(success);
926
927 std::mutex mutex;
928 std::unique_lock<std::mutex> lock(mutex);
929 auto status = cv.wait_for(lock, std::chrono::seconds(10));
930
931 EXPECT_EQ(status, std::cv_status::no_timeout);
932 ARKTS_DestroyEngine(globalEngine);
933
934 runner->Stop();
935
936 LOGI("main out");
937 return ret;
938 }
939