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 #include "napi/native_api.h"
28
29 using namespace testing;
30 using namespace testing::ext;
31
32 struct ARKTS_ModuleCallbacks {
33 ARKTS_Value (*exportModule)(ARKTS_Env env, const char* dllName, ARKTS_Value exports) = nullptr;
34 bool (*hasModuleHandle)(const char* dllName) = nullptr;
35 void (*throwJSError)(ARKTS_Env env, ARKTS_Value) = nullptr;
36 void (*throwNativeError)(const char*) = nullptr;
37 void (*deleteArrayBufferRawData)(void* buffer, int64_t lambdaId) = nullptr;
38 void (*deleteExternal)(int64_t id, ARKTS_Env env) = nullptr;
39 ARKTS_Value (*invokerLambda)(ARKTS_CallInfo, int64_t lambdaId) = nullptr;
40 void (*deleteLambda)(ARKTS_Env env, int64_t lambdaId) = nullptr;
41 void (*invokeAsyncLambda)(ARKTS_Env env, int64_t lambdaId) = nullptr;
42 void (*deleteJSContext)(ARKTS_Env env) = nullptr;
43 };
44
45 enum StackInfoOpKind : uint32_t {
46 SWITCH_TO_SUB_STACK_INFO = 0,
47 SWITCH_TO_MAIN_STACK_INFO,
48 };
49
50 struct StackInfo {
51 uint64_t stackLimit;
52 uint64_t lastLeaveFrame;
53 };
54
55 namespace {
56 class ArkInteropTest : public testing::Test {
57 public:
RunLocalTest()58 static void RunLocalTest()
59 {
60 TestPrime();
61 TestNumber();
62 TestString();
63 TestUtf16String();
64 TestObject();
65 TestKeyable();
66 TestDefineProperty();
67 TestDefinePropertyWritable();
68 TestDefinePropertyConfigurable();
69 TestDefinePropertyConfigurableV2();
70 TestArray();
71 TestBigintInt64();
72 TestBigint16Bytes();
73 TestBigint28Bytes();
74 TestBigint32Bytes();
75 TestPromise();
76 TestSymbol();
77 TestFunction();
78 TestClass();
79 TestInstanceOf();
80 TestArrayBuffer();
81 TestUpdateStackInfo();
82 }
83 private:
84 static void TestPrime();
85 static void TestNumber();
86 static void TestString();
87 static void TestUtf16String();
88 static void TestObject();
89 static void TestKeyable();
90 static void TestDefineProperty();
91 static void TestDefinePropertyWritable();
92 static void TestDefinePropertyConfigurable();
93 static void TestDefinePropertyConfigurableV2();
94 static void TestArray();
95 static void TestBigintInt64();
96 static void TestBigint16Bytes();
97 static void TestBigint28Bytes();
98 static void TestBigint32Bytes();
99 static void TestPromise();
100 static void TestSymbol();
101 static void TestFunction();
102 static void TestClass();
103 static void TestArrayBuffer();
104 static void TestInstanceOf();
105 static void TestUpdateStackInfo();
106 };
107
108 template <typename T>
109 struct Slab {
110 public:
Add__anon9b38f4010111::Slab111 int64_t Add(T item)
112 {
113 int64_t result;
114 if (last_ >= 0) {
115 result = last_;
116 auto& last = items_[result];
117 last_ = last.prev;
118 last.data = std::move(item);
119 } else {
120 result = items_.size();
121 items_.push_back({std::move(item), -1});
122 }
123 ++length;
124 return result;
125 }
126
Del__anon9b38f4010111::Slab127 void Del(int64_t id)
128 {
129 auto& removing = items_[id];
130 if (!removing.data.has_value()) {
131 return;
132 }
133 removing.data = std::nullopt;
134 removing.prev = last_;
135 last_ = id;
136 --length;
137 }
138
Size__anon9b38f4010111::Slab139 size_t Size() const
140 {
141 return length;
142 }
143
Get__anon9b38f4010111::Slab144 T& Get(int64_t id)
145 {
146 return items_[id].data.value();
147 }
148
Get__anon9b38f4010111::Slab149 const T& Get(int64_t id) const
150 {
151 return items_[id].data.value();
152 }
153 private:
154 struct Item {
155 std::optional<T> data;
156 int64_t prev;
157 };
158 std::vector<Item> items_ {};
159 int64_t last_ = -1;
160 size_t length = 0;
161 };
162
163 class MockContext {
164 static MockContext* instance_;
NewId()165 static uint32_t NewId()
166 {
167 static uint32_t id = 0;
168 return id++;
169 }
170
171 public:
GetInstance()172 static MockContext* GetInstance()
173 {
174 return instance_;
175 }
176
GetEngine() const177 ARKTS_Engine GetEngine() const
178 {
179 return engine_;
180 }
181
GetEnv() const182 ARKTS_Env GetEnv() const
183 {
184 return ARKTS_GetContext(engine_);
185 }
186
187 static void Init();
188
MockContext(ARKTS_Engine engine,bool needDestroyEngine=true)189 explicit MockContext(ARKTS_Engine engine, bool needDestroyEngine = true): idPrefix_(NewId()),
190 lastContext_(instance_), engine_(engine), needDestroyEngine_(needDestroyEngine)
191 {
192 instance_ = this;
193 }
194
MockContext()195 MockContext(): idPrefix_(NewId()), lastContext_(instance_), engine_(instance_->GetEngine()),
196 needDestroyEngine_(false)
197 {
198 instance_ = this;
199 }
200
~MockContext()201 ~MockContext()
202 {
203 if (needDestroyEngine_) {
204 ARKTS_DestroyEngine(engine_);
205 }
206 engine_ = nullptr;
207 instance_ = lastContext_;
208 }
209
StoreFunc(std::function<ARKTS_Value (ARKTS_CallInfo)> call)210 int64_t StoreFunc(std::function<ARKTS_Value(ARKTS_CallInfo)> call)
211 {
212 return ToId(callbacks_.Add(std::move(call)));
213 }
214
StoreAsyncFunc(std::function<void ()> call)215 int64_t StoreAsyncFunc(std::function<void ()> call)
216 {
217 return ToId(asyncCallbacks_.Add(std::move(call)));
218 }
219
StoreArrayBufferDeleter(std::function<void (void *)> call)220 int64_t StoreArrayBufferDeleter(std::function<void (void*)> call)
221 {
222 return ToId(nativeDeleters_.Add(std::move(call)));
223 }
224
StoreNativeData(void * data,std::function<void (void *)> deleter)225 int64_t StoreNativeData(void* data, std::function<void (void*)>deleter)
226 {
227 return ToId(data_.Add({data, std::move(deleter)}));
228 }
229
GetNativeData(int64_t id)230 void* GetNativeData(int64_t id)
231 {
232 auto index = ToIndex(id);
233 if (index < 0) {
234 return nullptr;
235 }
236 return data_.Get(index).data;
237 }
238
SetFinalizerCallback(std::function<void (ARKTS_Env)> callback)239 void SetFinalizerCallback(std::function<void (ARKTS_Env)> callback)
240 {
241 finalizerCallback_ = std::move(callback);
242 }
243
244 protected:
ExportModule(ARKTS_Env env,const char * dllName,ARKTS_Value exports)245 virtual ARKTS_Value ExportModule(ARKTS_Env env, const char* dllName, ARKTS_Value exports)
246 {
247 return exports;
248 }
249
HasModuleHandle(const char * dllName)250 virtual bool HasModuleHandle(const char* dllName)
251 {
252 return false;
253 }
254
ThrowJSError(ARKTS_Env env,ARKTS_Value)255 virtual void ThrowJSError(ARKTS_Env env, ARKTS_Value)
256 {
257 EXPECT_TRUE(false);
258 }
259
ThrowNativeError(const char * msg)260 virtual void ThrowNativeError(const char* msg)
261 {
262 printf("[Native Error]: %s\n", msg);
263 EXPECT_TRUE(false);
264 }
265
DeleteArrayBufferRawData(void * buffer,int64_t id)266 virtual void DeleteArrayBufferRawData(void* buffer, int64_t id)
267 {
268 auto index = ToIndex(id);
269 if (index < 0) {
270 return;
271 }
272 nativeDeleters_.Get(index)(buffer);
273 nativeDeleters_.Del(index);
274 }
275
DeleteExternal(int64_t id,ARKTS_Env env)276 virtual void DeleteExternal(int64_t id, ARKTS_Env env)
277 {
278 auto index = ToIndex(id);
279 if (index < 0) {
280 return;
281 }
282 auto& data = data_.Get(index);
283 data.deleter(data.data);
284 data_.Del(index);
285 }
286
InvokeLambda(ARKTS_CallInfo info,int64_t id)287 virtual ARKTS_Value InvokeLambda(ARKTS_CallInfo info, int64_t id)
288 {
289 auto index = ToIndex(id);
290 if (index < 0) {
291 return ARKTS_CreateUndefined();
292 }
293 return callbacks_.Get(index)(info);
294 }
295
DeleteLambda(ARKTS_Env env,int64_t id)296 virtual void DeleteLambda(ARKTS_Env env, int64_t id)
297 {
298 auto index = ToIndex(id);
299 if (index < 0) {
300 return;
301 }
302 callbacks_.Del(index);
303 }
304
InvokeAsyncLambda(ARKTS_Env env,int64_t id)305 virtual void InvokeAsyncLambda(ARKTS_Env env, int64_t id)
306 {
307 auto index = ToIndex(id);
308 if (index < 0) {
309 return;
310 }
311 asyncCallbacks_.Get(index)();
312 asyncCallbacks_.Del(index);
313 }
314
DeleteJSContext(ARKTS_Env env)315 virtual void DeleteJSContext(ARKTS_Env env)
316 {
317 if (finalizerCallback_) {
318 finalizerCallback_(env);
319 }
320 }
321
InvokeCycleFreeFunc(ARKTS_CallInfo callInfo,uint32_t id)322 virtual ARKTS_Value InvokeCycleFreeFunc(ARKTS_CallInfo callInfo, uint32_t id)
323 {
324 return ARKTS_CreateUndefined();
325 }
326
ReleaseCycleFreeExt(uint32_t id)327 virtual void ReleaseCycleFreeExt(uint32_t id)
328 {
329 }
330
ToId(int64_t index) const331 int64_t ToId(int64_t index) const
332 {
333 return GetPrefixMask() | index;
334 }
335
ToIndex(int64_t id) const336 int64_t ToIndex(int64_t id) const
337 {
338 auto myMask = GetPrefixMask();
339 if ((id & myMask) == myMask) {
340 return id & 0xFFFF'FFFF;
341 }
342 return -1;
343 }
344
345 private:
GetPrefixMask() const346 int64_t GetPrefixMask() const
347 {
348 constexpr auto idBits = 32;
349 return static_cast<int64_t>(idPrefix_) << idBits;
350 }
351
352 uint32_t idPrefix_;
353 MockContext* lastContext_;
354 ARKTS_Engine engine_;
355 bool needDestroyEngine_;
356 Slab<std::function<ARKTS_Value (ARKTS_CallInfo)>> callbacks_;
357 Slab<std::function<void ()>> asyncCallbacks_;
358 Slab<std::function<void (void*)>> nativeDeleters_;
359 struct AnyData {
360 void* data;
361 std::function<void (void*)> deleter;
362 };
363 Slab<AnyData> data_;
364 std::function<void (ARKTS_Env)> finalizerCallback_;
365 };
366
Init()367 void MockContext::Init()
368 {
369 static ARKTS_ModuleCallbacks callbacks {
370 .exportModule = [](ARKTS_Env env, const char* dllName, ARKTS_Value exports)->ARKTS_Value {
371 return instance_ ? instance_->ExportModule(env, dllName, exports) : exports;
372 },
373 .hasModuleHandle = [](const char* dllName)->bool {
374 return instance_ ? instance_->HasModuleHandle(dllName) : false;
375 },
376 .throwJSError = [](ARKTS_Env env, ARKTS_Value error)->void {
377 if (instance_) instance_->ThrowJSError(env, error);
378 },
379 .throwNativeError = [](const char* error)->void {
380 if (instance_) instance_->ThrowNativeError(error);
381 },
382 .deleteArrayBufferRawData = [](void* buffer, int64_t lambdaId)->void {
383 if (instance_) instance_->DeleteArrayBufferRawData(buffer, lambdaId);
384 },
385 .deleteExternal = [](int64_t id, ARKTS_Env env)->void {
386 if (instance_) instance_->DeleteExternal(id, env);
387 },
388 .invokerLambda = [](ARKTS_CallInfo callInfo, int64_t lambdaId)->ARKTS_Value {
389 return instance_ ? instance_->InvokeLambda(callInfo, lambdaId) : ARKTS_CreateUndefined();
390 },
391 .deleteLambda = [](ARKTS_Env env, int64_t id)->void {
392 if (instance_) instance_->DeleteLambda(env, id);
393 },
394 .invokeAsyncLambda = [](ARKTS_Env env, int64_t id)->void {
395 if (instance_) instance_->InvokeAsyncLambda(env, id);
396 },
397 .deleteJSContext = [](ARKTS_Env env)->void {
398 if (instance_) instance_->DeleteJSContext(env);
399 }
400 };
401 ARKTS_SetCJModuleCallback(&callbacks);
402 static ARKTS_CycleFreeCallback cycleFreeCallback {
403 .funcInvoker = [](ARKTS_CallInfo callInfo, int64_t id) {
404 if (instance_) {
405 return instance_->InvokeCycleFreeFunc(callInfo, id);
406 }
407 return ARKTS_CreateUndefined();
408 },
409 .refRelease = [](int64_t id) {
410 if (instance_) {
411 instance_->ReleaseCycleFreeExt(id);
412 }
413 }
414 };
415 ARKTS_RegisterCycleFreeCallback(cycleFreeCallback);
416 }
417
418 MockContext* MockContext::instance_ = nullptr;
419
420 class ErrorCaptureContext : public MockContext {
421 public:
422 ErrorCaptureContext() = default;
ErrorCaptureContext(ARKTS_Engine engine,bool needDestroyEngine=true)423 explicit ErrorCaptureContext(ARKTS_Engine engine, bool needDestroyEngine = true)
424 : MockContext(engine, needDestroyEngine) {}
~ErrorCaptureContext()425 ~ErrorCaptureContext()
426 {
427 if (hasJSError_ || hasNativeError_) {
428 printf("has unhandled js error or native error\n");
429 std::abort();
430 }
431 }
432
HasAndClearJSError()433 bool HasAndClearJSError()
434 {
435 if (hasJSError_) {
436 hasJSError_ = false;
437 return true;
438 }
439 return false;
440 }
441
HasAndClearNativeError()442 bool HasAndClearNativeError()
443 {
444 if (hasNativeError_) {
445 hasNativeError_ = false;
446 return true;
447 }
448 return false;
449 }
450 protected:
ThrowJSError(ARKTS_Env env,ARKTS_Value)451 void ThrowJSError(ARKTS_Env env, ARKTS_Value) override
452 {
453 if (hasJSError_) {
454 printf("has unhandled js error\n");
455 std::abort();
456 }
457 hasJSError_ = true;
458 }
459
ThrowNativeError(const char * error)460 void ThrowNativeError(const char* error) override
461 {
462 if (hasNativeError_) {
463 printf("has unhandled native error: %s\n", error);
464 std::abort();
465 }
466 hasNativeError_ = true;
467 }
468 private:
469 bool hasJSError_ = false;
470 bool hasNativeError_ = false;
471 };
472
473 class CycleFreeContext : public ErrorCaptureContext {
474 public:
475 CycleFreeContext() = default;
CycleFreeContext(ARKTS_Engine engine,bool needDestroyEngine=true)476 explicit CycleFreeContext(ARKTS_Engine engine, bool needDestroyEngine = true)
477 : ErrorCaptureContext(engine, needDestroyEngine) {}
StoreCycleFreeFunc(std::function<ARKTS_Value (ARKTS_CallInfo)> callback)478 uint32_t StoreCycleFreeFunc(std::function<ARKTS_Value(ARKTS_CallInfo)> callback)
479 {
480 std::lock_guard lock(callbackMutex_);
481 return callbacks_.Add(std::move(callback));
482 }
483
GetCycleFreeFuncCount() const484 size_t GetCycleFreeFuncCount() const
485 {
486 return callbacks_.Size();
487 }
488
489 protected:
InvokeCycleFreeFunc(ARKTS_CallInfo callInfo,uint32_t id)490 ARKTS_Value InvokeCycleFreeFunc(ARKTS_CallInfo callInfo, uint32_t id) override
491 {
492 std::lock_guard lock(callbackMutex_);
493 auto callback = callbacks_.Get(id);
494 if (!callback) {
495 return ARKTS_CreateUndefined();
496 }
497 return callback(callInfo);
498 }
499
ReleaseCycleFreeExt(uint32_t id)500 void ReleaseCycleFreeExt(uint32_t id) override
501 {
502 callbacks_.Del(id);
503 }
504 private:
505 static Slab<std::function<ARKTS_Value(ARKTS_CallInfo)>> callbacks_;
506 static std::mutex callbackMutex_;
507 };
508
509 Slab<std::function<ARKTS_Value(ARKTS_CallInfo)>> CycleFreeContext::callbacks_;
510 std::mutex CycleFreeContext::callbackMutex_;
511
TestPrime()512 void ArkInteropTest::TestPrime()
513 {
514 auto env = MockContext::GetInstance()->GetEnv();
515 auto scope = ARKTS_OpenScope(env);
516
517 auto jsUDef = ARKTS_CreateUndefined();
518 EXPECT_TRUE(ARKTS_IsUndefined(jsUDef));
519 EXPECT_EQ(ARKTS_GetValueType(env, jsUDef), N_UNDEFINED);
520
521 auto jsNull = ARKTS_CreateNull();
522 EXPECT_TRUE(ARKTS_IsNull(jsNull));
523 EXPECT_EQ(ARKTS_GetValueType(env, jsNull), N_NULL);
524
525 ARKTS_Value jsBools[] {
526 ARKTS_CreateBool(true),
527 ARKTS_CreateBool(false)
528 };
529 EXPECT_TRUE(ARKTS_IsBool(jsBools[0]));
530 EXPECT_EQ(ARKTS_GetValueType(env, jsBools[0]), N_BOOL);
531 EXPECT_TRUE(ARKTS_GetValueBool(jsBools[0]));
532 EXPECT_FALSE(ARKTS_GetValueBool(jsBools[1]));
533
534 ARKTS_CloseScope(env, scope);
535 }
536
TestNumber()537 void ArkInteropTest::TestNumber()
538 {
539 auto env = MockContext::GetInstance()->GetEnv();
540 auto scope = ARKTS_OpenScope(env);
541 double origins[] {
542 0.1,
543 -12.1,
544 12456.126546
545 };
546 constexpr auto totalCases = std::size(origins);
547 ARKTS_Value jsValues[totalCases];
548 double received[totalCases];
549
550 for (size_t i = 0;i < totalCases; i++) {
551 jsValues[i] = ARKTS_CreateF64(origins[i]);
552 EXPECT_EQ(ARKTS_GetValueType(env, jsValues[i]), N_NUMBER);
553 EXPECT_TRUE(ARKTS_IsNumber(jsValues[i]));
554 received[i] = ARKTS_GetValueNumber(jsValues[i]);
555 EXPECT_EQ(origins[i], received[i]);
556 }
557
558 auto jsNan = ARKTS_CreateF64(NAN);
559 auto nNan = ARKTS_GetValueNumber(jsNan);
560 EXPECT_TRUE(std::isnan(nNan));
561 ARKTS_CloseScope(env, scope);
562 }
563
TestString()564 void ArkInteropTest::TestString()
565 {
566 auto env = MockContext::GetInstance()->GetEnv();
567 auto scope = ARKTS_OpenScope(env);
568 const char* origins[] {
569 "a plain text",
570 "`~!@#$%^&*()_+[]\\",
571 "中文字符",
572 "❤️",
573 };
574 ARKTS_Value jsValues[] {
575 ARKTS_CreateUtf8(env, origins[0], strlen(origins[0])),
576 ARKTS_CreateUtf8(env, origins[1], strlen(origins[1])),
577 ARKTS_CreateUtf8(env, origins[2], strlen(origins[2])),
578 ARKTS_CreateUtf8(env, origins[3], strlen(origins[3])),
579 };
580 EXPECT_TRUE(ARKTS_IsString(env, jsValues[0]));
581 EXPECT_TRUE(ARKTS_IsHeapObject(jsValues[0]));
582 EXPECT_EQ(ARKTS_GetValueType(env, jsValues[0]), N_STRING);
583 for (auto i = 0;i < sizeof(jsValues)/sizeof(ARKTS_Value); i++) {
584 auto size = ARKTS_GetValueUtf8Size(env, jsValues[i]);
585 std::string result;
586 result.resize(size - 1);
587 ARKTS_GetValueUtf8(env, jsValues[i], size - 1, result.data());
588 EXPECT_EQ(result, origins[i]);
589
590 auto cStr = ARKTS_GetValueCString(env, jsValues[i]);
591 result = cStr;
592 EXPECT_EQ(result, origins[i]);
593 ARKTS_FreeCString(cStr);
594 }
595 ARKTS_CloseScope(env, scope);
596 }
597
TestUtf16String()598 void ArkInteropTest::TestUtf16String()
599 {
600 auto env = MockContext::GetInstance()->GetEnv();
601 auto scope = ARKTS_OpenScope(env);
602
603 std::string latin1Case[] {
604 "a plain text",
605 "hello, world!",
606 "./[]124"
607 };
608 std::u16string utf16Cases[] {
609 u"a plain text, 和",
610 u"你好,世界!",
611 u""
612 };
613
614 for (const auto& one : latin1Case) {
615 auto value = ARKTS_CreateString(env, true, one.size(), one.data());
616 EXPECT_TRUE(ARKTS_IsString(env, value));
617 auto header = ARKTS_GetStringInfo(env, value);
618 EXPECT_EQ(header.length, one.size());
619 EXPECT_TRUE(header.isCompressed);
620 }
621
622 for (const auto& one : utf16Cases) {
623 auto value = ARKTS_CreateString(env, false, one.size(), one.data());
624 EXPECT_TRUE(ARKTS_IsString(env, value));
625 auto header = ARKTS_GetStringInfo(env, value);
626 EXPECT_EQ(header.length, one.size());
627 EXPECT_FALSE(header.isCompressed);
628 }
629
630 ARKTS_CloseScope(env, scope);
631 }
632
TestObject()633 void ArkInteropTest::TestObject()
634 {
635 auto env = MockContext::GetInstance()->GetEnv();
636 auto scope = ARKTS_OpenScope(env);
637 auto obj = ARKTS_CreateObject(env);
638 EXPECT_TRUE(ARKTS_IsHeapObject(obj));
639 EXPECT_TRUE(ARKTS_IsObject(env, obj));
640 EXPECT_EQ(ARKTS_GetValueType(env, obj), N_OBJECT);
641 auto keyA = ARKTS_CreateUtf8(env, "a", 1);
642 EXPECT_FALSE(ARKTS_HasOwnProperty(env, obj, keyA));
643 auto valueA = ARKTS_GetProperty(env, obj, keyA);
644 EXPECT_TRUE(ARKTS_IsUndefined(valueA));
645 valueA = ARKTS_CreateBool(true);
646 ARKTS_SetProperty(env, obj, keyA, valueA);
647 EXPECT_TRUE(ARKTS_HasOwnProperty(env, obj, keyA));
648 auto receivedA = ARKTS_GetProperty(env, obj, keyA);
649 EXPECT_TRUE(ARKTS_IsBool(receivedA));
650 EXPECT_TRUE(ARKTS_GetValueBool(receivedA));
651 auto keys = ARKTS_EnumOwnProperties(env, obj);
652 EXPECT_TRUE(ARKTS_IsArray(env, keys));
653 EXPECT_EQ(ARKTS_GetArrayLength(env, keys), 1);
654 auto key = ARKTS_GetElement(env, keys, 0);
655 EXPECT_TRUE(ARKTS_IsString(env, key));
656 EXPECT_TRUE(ARKTS_StrictEqual(env, keyA, key));
657 ARKTS_CloseScope(env, scope);
658 }
659
TestKeyable()660 void ArkInteropTest::TestKeyable()
661 {
662 auto env = MockContext::GetInstance()->GetEnv();
663 auto scope = ARKTS_OpenScope(env);
664 auto obj = ARKTS_CreateObject(env);
665 ARKTS_Value allowedKeys[] {
666 ARKTS_CreateUtf8(env, "a", 1),
667 ARKTS_CreateI32(12),
668 ARKTS_CreateSymbol(env, "a", 1)
669 };
670 auto value = ARKTS_CreateBool(true);
671 for (auto key : allowedKeys) {
672 ARKTS_SetProperty(env, obj, key, value);
673 auto received = ARKTS_GetProperty(env, obj, key);
674 EXPECT_TRUE(ARKTS_IsBool(received));
675 EXPECT_TRUE(ARKTS_GetValueBool(received));
676 }
677 ARKTS_CloseScope(env, scope);
678 }
679
680 struct PropCase {
681 char k;
682 bool writable;
683 bool enumerable;
684 bool configurable;
685
686 static PropCase cases[];
687 };
688
689 PropCase PropCase::cases[] {
690 {'a', false, false, false},
691 {'b', true, false, false},
692 {'c', false, true, false},
693 {'d', false, false, true},
694 {'e', true, true, false},
695 {'f', true, false, true},
696 {'g', false, true, true},
697 {'h', true, true, true}
698 };
699
TestDefineProperty()700 void ArkInteropTest::TestDefineProperty()
701 {
702 ErrorCaptureContext local;
703 auto env = local.GetEnv();
704 auto scope = ARKTS_OpenScope(env);
705 auto obj = ARKTS_CreateObject(env);
706
707 constexpr auto totalCases = std::size(PropCase::cases);
708 auto valueF = ARKTS_CreateBool(false);
709 ARKTS_Value keys[totalCases];
710 for (auto i = 0; i < totalCases; i++) {
711 keys[i] = ARKTS_CreateUtf8(env, &PropCase::cases[i].k, 1);
712 ARKTS_DefineOwnProperty(env, obj, keys[i], valueF, static_cast<ARKTS_PropertyFlag>(
713 (PropCase::cases[i].writable ? N_WRITABLE : 0) |
714 (PropCase::cases[i].enumerable ? N_ENUMERABLE : 0) |
715 (PropCase::cases[i].configurable ? N_CONFIGURABLE : 0)
716 ));
717 }
718 constexpr int expectKeys = 4;
719 auto jsKeys = ARKTS_EnumOwnProperties(env, obj);
720 EXPECT_TRUE(ARKTS_IsArray(env, jsKeys));
721 EXPECT_EQ(ARKTS_GetArrayLength(env, jsKeys), expectKeys);
722 for (auto i = 0; i < expectKeys; i++) {
723 auto jsKey = ARKTS_GetElement(env, jsKeys, i);
724 EXPECT_TRUE(ARKTS_IsString(env, jsKey));
725 char buffer = 0;
726 ARKTS_GetValueUtf8(env, jsKey, 1, &buffer);
727 EXPECT_TRUE(buffer == 'c' || buffer == 'e' || buffer == 'g' || buffer == 'h');
728 }
729
730 ARKTS_CloseScope(env, scope);
731 }
732
TestDefinePropertyWritable()733 void ArkInteropTest::TestDefinePropertyWritable()
734 {
735 ErrorCaptureContext local;
736 auto env = local.GetEnv();
737 auto scope = ARKTS_OpenScope(env);
738 auto obj = ARKTS_CreateObject(env);
739
740 constexpr auto totalCases = std::size(PropCase::cases);
741 auto valueT = ARKTS_CreateBool(true);
742 auto valueF = ARKTS_CreateBool(false);
743 ARKTS_Value keys[totalCases];
744 for (auto i = 0; i < totalCases; i++) {
745 keys[i] = ARKTS_CreateUtf8(env, &PropCase::cases[i].k, 1);
746 ARKTS_DefineOwnProperty(env, obj, keys[i], valueF, static_cast<ARKTS_PropertyFlag>(
747 (PropCase::cases[i].writable ? N_WRITABLE : 0) |
748 (PropCase::cases[i].enumerable ? N_ENUMERABLE : 0) |
749 (PropCase::cases[i].configurable ? N_CONFIGURABLE : 0)
750 ));
751 }
752
753 for (auto i = 0; i < totalCases; i++) { // writable
754 if (PropCase::cases[i].writable && PropCase::cases[i].configurable) {
755 ARKTS_SetProperty(env, obj, keys[i], valueT);
756 auto receivedJS = ARKTS_GetProperty(env, obj, keys[i]);
757 auto recievedN = ARKTS_GetValueBool(receivedJS);
758 EXPECT_TRUE(recievedN);
759 }
760 }
761
762 ARKTS_CloseScope(env, scope);
763 }
764
TestDefinePropertyConfigurable()765 void ArkInteropTest::TestDefinePropertyConfigurable()
766 {
767 ErrorCaptureContext local;
768 auto env = local.GetEnv();
769 auto scope = ARKTS_OpenScope(env);
770 auto obj = ARKTS_CreateObject(env);
771
772 constexpr auto totalCases = std::size(PropCase::cases);
773 auto valueT = ARKTS_CreateBool(true);
774 auto valueF = ARKTS_CreateBool(false);
775 ARKTS_Value keys[totalCases];
776 for (auto i = 0; i < totalCases; i++) {
777 keys[i] = ARKTS_CreateUtf8(env, &PropCase::cases[i].k, 1);
778 ARKTS_DefineOwnProperty(env, obj, keys[i], valueF, static_cast<ARKTS_PropertyFlag>(
779 (PropCase::cases[i].writable ? N_WRITABLE : 0) |
780 (PropCase::cases[i].enumerable ? N_ENUMERABLE : 0) |
781 (PropCase::cases[i].configurable ? N_CONFIGURABLE : 0)
782 ));
783 }
784
785 for (auto i = 0;i < totalCases; ++i) { // configurable
786 if (PropCase::cases[i].configurable) {
787 ARKTS_DefineOwnProperty(env, obj, keys[i], valueT,
788 static_cast<ARKTS_PropertyFlag>(N_WRITABLE | N_ENUMERABLE | N_CONFIGURABLE));
789 auto received = ARKTS_GetProperty(env, obj, keys[i]);
790 EXPECT_TRUE(ARKTS_IsBool(received));
791 EXPECT_TRUE(ARKTS_GetValueBool(received));
792 }
793 }
794 auto jsKeys = ARKTS_EnumOwnProperties(env, obj);
795 constexpr int expectLength = 6;
796 EXPECT_EQ(ARKTS_GetArrayLength(env, jsKeys), expectLength);
797
798 ARKTS_CloseScope(env, scope);
799 }
800
TestDefinePropertyConfigurableV2()801 void ArkInteropTest::TestDefinePropertyConfigurableV2()
802 {
803 ErrorCaptureContext local;
804 auto env = local.GetEnv();
805 auto scope = ARKTS_OpenScope(env);
806 auto obj = ARKTS_CreateObject(env);
807
808 constexpr auto totalCases = std::size(PropCase::cases);
809 auto valueT = ARKTS_CreateBool(true);
810 auto valueF = ARKTS_CreateBool(false);
811 ARKTS_Value keys[totalCases];
812 for (auto i = 0; i < totalCases; i++) {
813 keys[i] = ARKTS_CreateUtf8(env, &PropCase::cases[i].k, 1);
814 ARKTS_DefineOwnProperty(env, obj, keys[i], valueF, static_cast<ARKTS_PropertyFlag>(
815 (PropCase::cases[i].writable ? N_WRITABLE : 0) |
816 (PropCase::cases[i].enumerable ? N_ENUMERABLE : 0) |
817 (PropCase::cases[i].configurable ? N_CONFIGURABLE : 0)
818 ));
819 }
820
821 for (auto i = 0;i < totalCases; ++i) { // configurable
822 auto result = ARKTS_DefineOwnPropertyV2(env, obj, keys[i], valueT,
823 static_cast<ARKTS_PropertyFlag>(N_WRITABLE | N_ENUMERABLE | N_CONFIGURABLE));
824 if (PropCase::cases[i].configurable) {
825 EXPECT_TRUE(result);
826 } else {
827 EXPECT_TRUE(local.HasAndClearJSError());
828 }
829 }
830 auto jsKeys = ARKTS_EnumOwnProperties(env, obj);
831 constexpr int expectLength = 6;
832 EXPECT_EQ(ARKTS_GetArrayLength(env, jsKeys), expectLength);
833
834 ARKTS_CloseScope(env, scope);
835 }
836
TestInstanceOf()837 void ArkInteropTest::TestInstanceOf()
838 {
839 ARKTS_Env env = MockContext::GetInstance()->GetEnv();
840 auto global = ARKTS_GetGlobalConstant(env);
841 char clError[] = "Error";
842 auto jError = ARKTS_CreateUtf8(env, clError, sizeof(clError) - 1);
843 auto errorCls = ARKTS_GetProperty(env, global, jError);
844 auto errorObJ = ARKTS_New(env, errorCls, 0, nullptr);
845 auto isError = ARKTS_InstanceOf(env, errorObJ, errorCls);
846 EXPECT_TRUE(isError);
847 auto jObj = ARKTS_CreateObject(env);
848 EXPECT_FALSE(ARKTS_InstanceOf(env, jObj, errorCls));
849 }
850
TestArray()851 void ArkInteropTest::TestArray()
852 {
853 EXPECT_TRUE(MockContext::GetInstance());
854 ARKTS_Env env = MockContext::GetInstance()->GetEnv();
855 EXPECT_TRUE(env);
856
857 char c = 'c';
858 ARKTS_Value origin[] {
859 ARKTS_CreateBool(true),
860 ARKTS_CreateF64(12.02),
861 ARKTS_CreateUtf8(env, &c, 1),
862 ARKTS_CreateObject(env),
863 };
864 constexpr auto arrSize = std::size(origin);
865 auto arr = ARKTS_CreateArray(env, arrSize);
866 EXPECT_TRUE(ARKTS_IsArray(env, arr));
867 EXPECT_EQ(ARKTS_GetValueType(env, arr), N_OBJECT);
868 EXPECT_EQ(ARKTS_GetArrayLength(env, arr), arrSize);
869 for (auto i = 0; i < arrSize; i++) {
870 auto initialValue = ARKTS_GetElement(env, arr, i);
871 EXPECT_TRUE(ARKTS_IsUndefined(initialValue));
872 ARKTS_SetElement(env, arr, i, origin[i]);
873 auto receivedValue = ARKTS_GetElement(env, arr, i);
874 EXPECT_TRUE(ARKTS_StrictEqual(env, origin[i], receivedValue));
875 }
876 }
877
TestBigintInt64()878 void ArkInteropTest::TestBigintInt64()
879 {
880 EXPECT_TRUE(MockContext::GetInstance());
881 ARKTS_Env env = MockContext::GetInstance()->GetEnv();
882 EXPECT_TRUE(env);
883 {
884 int64_t origins[] {
885 0x123'4567'8945,
886 -0x123'4567'8945,
887 0x7FFF'FFFF'FFFF'FFFF,
888 -0x7FFF'FFFF'FFFF'FFFF,
889 };
890 constexpr auto arrSize = std::size(origins);
891 ARKTS_Value values[arrSize];
892 for (auto i = 0; i < arrSize; i++) {
893 values[i] = ARKTS_CreateBigInt(env, origins[i]);
894 EXPECT_TRUE(ARKTS_IsBigInt(env, values[i]));
895 EXPECT_EQ(ARKTS_GetValueType(env, values[i]), N_BIGINT);
896 ARKTS_BigIntGetByteSize(env, values[i]);
897 }
898 }
899 }
900
TestBigint16Bytes()901 void ArkInteropTest::TestBigint16Bytes()
902 {
903 EXPECT_TRUE(MockContext::GetInstance());
904 ARKTS_Env env = MockContext::GetInstance()->GetEnv();
905 EXPECT_TRUE(env);
906 uint8_t origin[] {
907 0, 10, 20, 30, 40, 50, 60, 70,
908 80, 90, 70, 50, 20, 30, 40, 50
909 };
910 bool isNegative = false;
911 auto value = ARKTS_CreateBigIntWithBytes(env, isNegative, std::size(origin), origin);
912 EXPECT_TRUE(ARKTS_IsBigInt(env, value));
913 EXPECT_EQ(ARKTS_GetValueType(env, value), N_BIGINT);
914 EXPECT_EQ(ARKTS_BigIntGetByteSize(env, value), std::size(origin));
915 uint8_t received[std::size(origin)];
916 ARKTS_BigIntReadBytes(env, value, &isNegative, std::size(origin), received);
917 EXPECT_FALSE(isNegative);
918 for (auto i = 0; i < std::size(origin); i++) {
919 EXPECT_EQ(origin[i], received[i]);
920 }
921 }
922
TestBigint28Bytes()923 void ArkInteropTest::TestBigint28Bytes()
924 {
925 EXPECT_TRUE(MockContext::GetInstance());
926 ARKTS_Env env = MockContext::GetInstance()->GetEnv();
927 EXPECT_TRUE(env);
928 uint8_t origin[] {
929 0, 10, 20, 30, 40, 50, 60, 70,
930 80, 90, 70, 50, 20, 30, 40, 50,
931 1, 2, 3, 4, 5, 6, 7, 8,
932 9, 10, 20, 30,
933 };
934 bool isNegative = false;
935 constexpr int expectSize = 32;
936 // bigint words are 8 bytes aligned, received 32 bytes, and lower 4 bytes would be filled with 0.
937 auto value = ARKTS_CreateBigIntWithBytes(env, isNegative, std::size(origin), origin);
938 EXPECT_TRUE(ARKTS_IsBigInt(env, value));
939 EXPECT_EQ(ARKTS_GetValueType(env, value), N_BIGINT);
940 EXPECT_EQ(ARKTS_BigIntGetByteSize(env, value), expectSize);
941 uint8_t received[expectSize];
942 ARKTS_BigIntReadBytes(env, value, &isNegative, expectSize, received);
943 EXPECT_FALSE(isNegative);
944 for (auto i = 0; i < std::size(origin); i++) {
945 EXPECT_EQ(origin[i], received[i + expectSize - std::size(origin)]);
946 }
947 }
948
TestBigint32Bytes()949 void ArkInteropTest::TestBigint32Bytes()
950 {
951 EXPECT_TRUE(MockContext::GetInstance());
952 ARKTS_Env env = MockContext::GetInstance()->GetEnv();
953 EXPECT_TRUE(env);
954 uint8_t origin[] {
955 0, 10, 20, 30, 40, 50, 60, 70,
956 80, 90, 70, 50, 20, 30, 40, 50,
957 1, 2, 3, 4, 5, 6, 7, 8,
958 9, 10, 20, 30, 40, 50, 60, 70,
959 };
960 bool isNegative = false;
961 auto value = ARKTS_CreateBigIntWithBytes(env, isNegative, std::size(origin), origin);
962 EXPECT_TRUE(ARKTS_IsBigInt(env, value));
963 EXPECT_EQ(ARKTS_GetValueType(env, value), N_BIGINT);
964 EXPECT_EQ(ARKTS_BigIntGetByteSize(env, value), std::size(origin));
965 uint8_t received[std::size(origin)];
966 ARKTS_BigIntReadBytes(env, value, &isNegative, std::size(origin), received);
967 EXPECT_FALSE(isNegative);
968 for (auto i = 0; i < std::size(origin); i++) {
969 EXPECT_EQ(origin[i], received[i]);
970 }
971 }
972
TestSymbol()973 void ArkInteropTest::TestSymbol()
974 {
975 EXPECT_TRUE(MockContext::GetInstance());
976 ARKTS_Env env = MockContext::GetInstance()->GetEnv();
977 EXPECT_TRUE(env);
978
979 const char originDesc[] = "TestSymbol";
980
981 auto symbol = ARKTS_CreateSymbol(env, originDesc, sizeof(originDesc) - 1);
982 EXPECT_TRUE(ARKTS_IsSymbol(env, symbol));
983 EXPECT_EQ(ARKTS_GetValueType(env, symbol), N_SYMBOL);
984
985 auto retDesc = ARKTS_GetSymbolDesc(env, symbol);
986 EXPECT_EQ(std::string(retDesc), originDesc);
987 ARKTS_FreeCString(retDesc);
988
989 auto obj = ARKTS_CreateObject(env);
990 ARKTS_SetProperty(env, obj, symbol, ARKTS_CreateBool(true));
991 auto value = ARKTS_GetProperty(env, obj, symbol);
992 EXPECT_TRUE(ARKTS_IsBool(value));
993 EXPECT_TRUE(ARKTS_GetValueBool(value));
994
995 auto symbol1 = ARKTS_CreateSymbol(env, originDesc, sizeof(originDesc) - 1);
996 ARKTS_SetProperty(env, obj, symbol1, ARKTS_CreateBool(false));
997 auto value1 = ARKTS_GetProperty(env, obj, symbol1);
998 EXPECT_TRUE(ARKTS_IsBool(value1));
999 EXPECT_FALSE(ARKTS_GetValueBool(value1));
1000
1001 value = ARKTS_GetProperty(env, obj, symbol);
1002 EXPECT_TRUE(ARKTS_IsBool(value));
1003 EXPECT_TRUE(ARKTS_GetValueBool(value));
1004 }
1005
TestFunction()1006 void ArkInteropTest::TestFunction()
1007 {
1008 EXPECT_TRUE(MockContext::GetInstance());
1009 ARKTS_Env env = MockContext::GetInstance()->GetEnv();
1010 EXPECT_TRUE(env);
1011
1012 bool called = false;
1013 auto id = MockContext::GetInstance()->StoreFunc([&called](ARKTS_CallInfo info)->ARKTS_Value {
1014 called = true;
1015 EXPECT_EQ(ARKTS_GetArgCount(info), 0);
1016 EXPECT_TRUE(ARKTS_IsUndefined(ARKTS_GetThisArg(info)));
1017 return ARKTS_CreateUndefined();
1018 });
1019 auto func = ARKTS_CreateFunc(env, id);
1020 EXPECT_TRUE(ARKTS_IsCallable(env, func));
1021 EXPECT_EQ(ARKTS_GetValueType(env, func), N_FUNCTION);
1022 ARKTS_Call(env, func, ARKTS_CreateUndefined(), 0, nullptr);
1023 EXPECT_TRUE(called);
1024 called = false;
1025 ARKTS_Value args[] {
1026 ARKTS_CreateNull(),
1027 ARKTS_CreateBool(true),
1028 ARKTS_CreateF64(45.1),
1029 ARKTS_CreateObject(env)
1030 };
1031 static constexpr auto totalArgs = std::size(args);
1032 id = MockContext::GetInstance()->StoreFunc([env, &called, origin = args](ARKTS_CallInfo info)->ARKTS_Value {
1033 called = true;
1034 auto self = ARKTS_GetThisArg(info);
1035 EXPECT_TRUE(ARKTS_IsObject(env, self));
1036 EXPECT_EQ(totalArgs, ARKTS_GetArgCount(info));
1037 for (auto i = 0; i < totalArgs; i++) {
1038 EXPECT_TRUE(ARKTS_StrictEqual(env, ARKTS_GetArg(info, i), origin[i]));
1039 }
1040 return ARKTS_CreateBool(true);
1041 });
1042 func = ARKTS_CreateFunc(env, id);
1043 ARKTS_Call(env, func, ARKTS_CreateObject(env), std::size(args), args);
1044 EXPECT_TRUE(called);
1045 }
1046
TestClass()1047 void ArkInteropTest::TestClass()
1048 {
1049 EXPECT_TRUE(MockContext::GetInstance());
1050 ARKTS_Env env = MockContext::GetInstance()->GetEnv();
1051 EXPECT_TRUE(env);
1052 auto id = MockContext::GetInstance()->StoreFunc([](ARKTS_CallInfo info)->ARKTS_Value {
1053 return ARKTS_GetThisArg(info);
1054 });
1055 auto clazz = ARKTS_CreateClass(env, id, ARKTS_CreateUndefined());
1056 EXPECT_TRUE(ARKTS_IsClass(env, clazz));
1057 EXPECT_EQ(ARKTS_GetValueType(env, clazz), N_FUNCTION);
1058 auto obj = ARKTS_New(env, clazz, 0, nullptr);
1059 EXPECT_TRUE(ARKTS_IsObject(env, obj));
1060 EXPECT_TRUE(ARKTS_InstanceOf(env, obj, clazz));
1061 }
1062
TestPromise()1063 void ArkInteropTest::TestPromise()
1064 {
1065 EXPECT_TRUE(MockContext::GetInstance());
1066 ARKTS_Env env = MockContext::GetInstance()->GetEnv();
1067 EXPECT_TRUE(env);
1068 auto scope = ARKTS_OpenScope(env);
1069
1070 auto promiseCap = ARKTS_CreatePromiseCapability(env);
1071 auto promise = ARKTS_GetPromiseFromCapability(env, promiseCap);
1072 EXPECT_TRUE(ARKTS_IsPromise(env, promise));
1073 EXPECT_EQ(ARKTS_GetValueType(env, promise), N_OBJECT);
1074
1075 bool resolved = false;
1076 auto id = MockContext::GetInstance()->StoreFunc([&resolved](ARKTS_CallInfo info)->ARKTS_Value {
1077 resolved = true;
1078 EXPECT_EQ(ARKTS_GetArgCount(info), 1);
1079 auto arg = ARKTS_GetArg(info, 0);
1080 EXPECT_TRUE(ARKTS_IsUndefined(arg));
1081 return ARKTS_CreateBool(true);
1082 });
1083 auto onResolved = ARKTS_CreateFunc(env, id);
1084 ARKTS_PromiseThen(env, promise, onResolved, ARKTS_CreateUndefined());
1085 ARKTS_PromiseCapabilityResolve(env, promiseCap, ARKTS_CreateUndefined());
1086 EXPECT_TRUE(resolved);
1087
1088 ARKTS_CloseScope(env, scope);
1089 }
1090
TestArrayBuffer()1091 void ArkInteropTest::TestArrayBuffer()
1092 {
1093 EXPECT_TRUE(MockContext::GetInstance());
1094 ARKTS_Env env = MockContext::GetInstance()->GetEnv();
1095 EXPECT_TRUE(env);
1096 auto scope = ARKTS_OpenScope(env);
1097
1098 uint8_t origin[] {
1099 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
1100 'a', 'b', 'c', 'd', 'e', 'f', 'g'
1101 };
1102 auto arrSize = std::size(origin);
1103 auto buffer = ARKTS_CreateArrayBuffer(env, arrSize);
1104 EXPECT_TRUE(ARKTS_IsArrayBuffer(env, buffer));
1105 EXPECT_EQ(ARKTS_GetValueType(env, buffer), N_OBJECT);
1106 EXPECT_EQ(ARKTS_GetArrayBufferLength(env, buffer), arrSize);
1107 auto dst = reinterpret_cast<uint8_t*>(ARKTS_GetArrayBufferRawPtr(env, buffer));
1108 for (auto i = 0; i < arrSize; i++) {
1109 dst[i] = origin[i];
1110 }
1111 uint8_t received[std::size(origin)];
1112 auto endpoint = ARKTS_ArrayBufferReadBytes(env, buffer, received, arrSize);
1113 EXPECT_EQ(endpoint, arrSize);
1114
1115 for (auto i = 0; i < arrSize; i++) {
1116 EXPECT_EQ(origin[i], received[i]);
1117 }
1118
1119 ARKTS_CloseScope(env, scope);
1120 }
1121
TestUpdateStackInfo()1122 void ArkInteropTest::TestUpdateStackInfo()
1123 {
1124 EXPECT_TRUE(MockContext::GetInstance());
1125 ARKTS_Env env = MockContext::GetInstance()->GetEnv();
1126 EXPECT_TRUE(env);
1127 auto scope = ARKTS_OpenScope(env);
1128 unsigned long long vmAddress = reinterpret_cast<unsigned long long>(env);
1129 StackInfo stackInfo;
1130 stackInfo.stackLimit = 0x5be506e000;
1131 stackInfo.lastLeaveFrame = 0;
1132 ARKTS_UpdateStackInfo(vmAddress, &stackInfo, SWITCH_TO_SUB_STACK_INFO);
1133 ARKTS_UpdateStackInfo(vmAddress, &stackInfo, SWITCH_TO_MAIN_STACK_INFO);
1134 ARKTS_CloseScope(env, scope);
1135 }
1136
TEST_F(ArkInteropTest,Types)1137 TEST_F(ArkInteropTest, Types)
1138 {
1139 RunLocalTest();
1140 }
1141
TEST_F(ArkInteropTest,PromiseThen)1142 TEST_F(ArkInteropTest, PromiseThen)
1143 {
1144 MockContext local(ARKTS_CreateEngineWithNewThread());
1145 auto env = local.GetEnv();
1146 EXPECT_TRUE(env);
1147
1148 std::condition_variable cv;
1149 bool isComplete = false;
1150 auto funcId = local.StoreAsyncFunc([&local, &cv, &isComplete, env] {
1151 auto scope = ARKTS_OpenScope(env);
1152 auto promiseCap = ARKTS_CreatePromiseCapability(env);
1153 auto promise = ARKTS_GetPromiseFromCapability(env, promiseCap);
1154 auto funcId = local.StoreFunc([&cv, &isComplete](ARKTS_CallInfo info) {
1155 isComplete = true;
1156 cv.notify_one();
1157 return ARKTS_CreateUndefined();
1158 });
1159 auto func = ARKTS_CreateFunc(env, funcId);
1160 ARKTS_PromiseThen(env, promise, func, ARKTS_CreateUndefined());
1161 ARKTS_PromiseCapabilityResolve(env, promiseCap, ARKTS_CreateUndefined());
1162 ARKTS_CloseScope(env, scope);
1163 });
1164 ARKTS_CreateAsyncTask(env, funcId);
1165 std::mutex mutex;
1166 std::unique_lock lock(mutex);
1167
1168 constexpr int checkDuration = 10;
1169 int waitTimes = 10; // set 100ms timeout
1170 while (!isComplete && waitTimes--) {
1171 cv.wait_for(lock, std::chrono::milliseconds(checkDuration));
1172 }
1173 // EXPECT no core dump, no timeout
1174 EXPECT_TRUE(waitTimes > 0);
1175 }
1176
TEST_F(ArkInteropTest,CycleFreeFunc)1177 TEST_F(ArkInteropTest, CycleFreeFunc)
1178 {
1179 CycleFreeContext local;
1180 auto env = local.GetEnv();
1181 auto funcCount = local.GetCycleFreeFuncCount();
1182 auto scope = ARKTS_OpenScope(env);
1183 auto isCalled = false;
1184 auto id = local.StoreCycleFreeFunc([&isCalled](ARKTS_CallInfo callInfo) {
1185 isCalled = true;
1186 return ARKTS_CreateUndefined();
1187 });
1188 EXPECT_EQ(local.GetCycleFreeFuncCount(), funcCount + 1);
1189 auto func = ARKTS_CreateCycleFreeFunc(local.GetEnv(), id);
1190 EXPECT_TRUE(ARKTS_IsCallable(env, func));
1191 ARKTS_Call(env, func, ARKTS_CreateUndefined(), 0, nullptr);
1192 EXPECT_TRUE(isCalled);
1193 ARKTS_CloseScope(env, scope);
1194 }
1195
TEST_F(ArkInteropTest,CycleFreeExtern)1196 TEST_F(ArkInteropTest, CycleFreeExtern)
1197 {
1198 CycleFreeContext local;
1199 auto env = local.GetEnv();
1200 auto funcCount = local.GetCycleFreeFuncCount();
1201 {
1202 auto scope = ARKTS_OpenScope(env);
1203 auto id = local.StoreCycleFreeFunc(nullptr);
1204 EXPECT_EQ(local.GetCycleFreeFuncCount(), funcCount + 1);
1205 auto object = ARKTS_CreateCycleFreeExtern(local.GetEnv(), id);
1206 EXPECT_TRUE(ARKTS_IsExternal(env, object));
1207 auto handle = ARKTS_GetExternalData(env, object);
1208 uint32_t resid = reinterpret_cast<uint64_t>(handle);
1209 EXPECT_EQ(resid, id);
1210
1211 ARKTS_CloseScope(env, scope);
1212 }
1213 }
1214
1215 class GlobalWeakTest {
1216 public:
GlobalWeakTest()1217 GlobalWeakTest(): local(ARKTS_CreateEngineWithNewThread()), status(CREATING)
1218 {
1219 }
1220
Start()1221 void Start()
1222 {
1223 ScheduleNext();
1224 }
1225
WaitForComplete()1226 void WaitForComplete()
1227 {
1228 std::mutex mutex;
1229 std::unique_lock lock(mutex);
1230 while (status != COMPLETE) {
1231 cv.wait(lock);
1232 }
1233 }
1234
IsComplete() const1235 bool IsComplete() const
1236 {
1237 return status == COMPLETE;
1238 }
1239
IsAllDisposed() const1240 bool IsAllDisposed() const
1241 {
1242 for (auto one : globals) {
1243 if (ARKTS_GlobalIsAlive(local.GetEnv(), one)) {
1244 return false;
1245 }
1246 }
1247 return true;
1248 }
1249
1250 private:
1251 static constexpr int objectCnt = 1000;
1252
CreateWeakObjects()1253 void CreateWeakObjects()
1254 {
1255 auto env = local.GetEnv();
1256 auto scope = ARKTS_OpenScope(env);
1257 for (auto i = 0; i < objectCnt; i++) {
1258 auto object = ARKTS_CreateObject(env);
1259 auto global = ARKTS_CreateGlobal(env, object);
1260 ARKTS_GlobalSetWeak(env, global);
1261 globals.push_back(global);
1262 }
1263 ARKTS_CloseScope(env, scope);
1264 panda::JSNApi::TriggerGC(P_CAST(env, EcmaVM*), panda::JSNApi::TRIGGER_GC_TYPE::FULL_GC);
1265 }
1266
DoAssertion()1267 void DoAssertion()
1268 {
1269 for (auto one : globals) {
1270 EXPECT_TRUE(!ARKTS_GlobalIsAlive(local.GetEnv(), one));
1271 }
1272 }
1273
ReleaseGlobals()1274 void ReleaseGlobals()
1275 {
1276 for (auto one : globals) {
1277 ARKTS_DisposeGlobalSync(local.GetEnv(), one);
1278 }
1279 }
1280
1281 enum Status {
1282 CREATING,
1283 ASSERTION,
1284 DISPOSE,
1285 COMPLETE
1286 };
1287
ScheduleNext()1288 void ScheduleNext()
1289 {
1290 auto id = local.StoreAsyncFunc([this] {
1291 DoNext();
1292 });
1293 ARKTS_CreateAsyncTask(local.GetEnv(), id);
1294 }
1295
DoNext()1296 void DoNext()
1297 {
1298 switch (status) {
1299 case CREATING:
1300 CreateWeakObjects();
1301 status = ASSERTION;
1302 break;
1303 case ASSERTION:
1304 DoAssertion();
1305 status = DISPOSE;
1306 break;
1307 case DISPOSE:
1308 ReleaseGlobals();
1309 status = COMPLETE;
1310 cv.notify_all();
1311 return;
1312 default: ;
1313 }
1314 ScheduleNext();
1315 }
1316
1317 CycleFreeContext local;
1318 Status status;
1319 std::condition_variable cv;
1320 std::vector<ARKTS_Global> globals;
1321 };
1322
TEST_F(ArkInteropTest,GlobalWeak)1323 TEST_F(ArkInteropTest, GlobalWeak)
1324 {
1325 GlobalWeakTest weakTest;
1326 weakTest.Start();
1327 weakTest.WaitForComplete();
1328 EXPECT_TRUE(weakTest.IsComplete());
1329 EXPECT_TRUE(weakTest.IsAllDisposed());
1330 }
1331
TEST_F(ArkInteropTest,GlobalToValue)1332 TEST_F(ArkInteropTest, GlobalToValue)
1333 {
1334 MockContext local;
1335 auto env = local.GetEnv();
1336 {
1337 auto scope = ARKTS_OpenScope(env);
1338 auto object = ARKTS_CreateObject(env);
1339 auto global = ARKTS_CreateGlobal(env, object);
1340 auto value = ARKTS_GlobalToValue(env, global);
1341 auto received = ARKTS_GlobalFromValue(env, value);
1342 EXPECT_EQ(received, global);
1343 ARKTS_DisposeGlobalSync(env, global);
1344 ARKTS_CloseScope(env, scope);
1345 }
1346 }
1347
1348 HWTEST_F(ArkInteropTest, ArkTSInteropNapiCreateEngineNew, TestSize.Level1)
1349 {
1350 MockContext local(ARKTS_CreateEngineWithNewThread());
1351
1352 auto curTid = ARKTS_GetPosixThreadId();
1353 auto engineTid = ARKTS_GetThreadIdOfEngine(local.GetEngine());
1354
1355 EXPECT_NE(curTid, engineTid);
1356
1357 auto env = local.GetEnv();
1358 EXPECT_TRUE(env);
1359 bool isComplete = false;
1360 std::condition_variable cv;
__anon9b38f4011602null1361 auto funcId = local.StoreAsyncFunc([&isComplete, &cv] {
1362 ArkInteropTest::RunLocalTest();
1363 isComplete = true;
1364 cv.notify_one();
1365 });
1366 ARKTS_CreateAsyncTask(env, funcId);
1367 std::mutex mutex;
1368 std::unique_lock lock(mutex);
1369 constexpr int checkDuration = 10;
1370 int waitTimes = 100; // set 1000ms timeout
1371 while (!isComplete && waitTimes--) {
1372 cv.wait_for(lock, std::chrono::milliseconds(checkDuration));
1373 }
1374 EXPECT_TRUE(waitTimes > 0);
1375 }
1376
TEST_F(ArkInteropTest,ScopeMT)1377 TEST_F(ArkInteropTest, ScopeMT)
1378 {
1379 constexpr int threadCount = 1000;
1380 std::thread threads[threadCount];
1381 for (int i = 0; i < threadCount; i++) {
1382 threads[i] = std::thread([] {
1383 panda::RuntimeOption options;
1384 auto vm = panda::JSNApi::CreateJSVM(options);
1385 EXPECT_TRUE(vm);
1386 auto env = P_CAST(vm, ARKTS_Env);
1387 auto scope = ARKTS_OpenScope(env);
1388 EXPECT_TRUE(scope);
1389 ARKTS_CloseScope(env, scope);
1390 panda::JSNApi::DestroyJSVM(vm);
1391 });
1392 }
1393 for (auto& thread : threads) {
1394 thread.join();
1395 }
1396 }
1397
TEST_F(ArkInteropTest,GlobalRelease)1398 TEST_F(ArkInteropTest, GlobalRelease)
1399 {
1400 MockContext local(ARKTS_CreateEngineWithNewThread());
1401 auto env = local.GetEnv();
1402
1403 bool isComplete = false;
1404 int loops = 10;
1405 std::condition_variable cv;
1406 std::function <void()> callback;
1407 callback = [&isComplete, &cv, &loops, env, &callback] {
1408 if (loops == 0) {
1409 isComplete = true;
1410 cv.notify_one();
1411 return;
1412 }
1413 auto scope = ARKTS_OpenScope(env);
1414 auto totalRepeat = 500000;
1415 for (int i = 0;i < totalRepeat; ++i) {
1416 auto object = ARKTS_CreateObject(env);
1417 auto global = ARKTS_CreateGlobal(env, object);
1418 ARKTS_DisposeGlobal(env, global);
1419 }
1420 ARKTS_CloseScope(env, scope);
1421 --loops;
1422 auto funcId = MockContext::GetInstance()->StoreAsyncFunc(callback);
1423 ARKTS_CreateAsyncTask(env, funcId);
1424 };
1425 auto funcId = local.StoreAsyncFunc(callback);
1426 ARKTS_CreateAsyncTask(env, funcId);
1427 std::mutex mutex;
1428 std::unique_lock lock(mutex);
1429 int waitTimes = 200;
1430 int msEachTime = 100;
1431 while (!isComplete && waitTimes--) {
1432 cv.wait_for(lock, std::chrono::milliseconds(msEachTime));
1433 }
1434 EXPECT_TRUE(isComplete);
1435 }
1436
TEST_F(ArkInteropTest,GlobalReleaseSync)1437 TEST_F(ArkInteropTest, GlobalReleaseSync)
1438 {
1439 MockContext local(ARKTS_CreateEngineWithNewThread());
1440 auto env = local.GetEnv();
1441 int loops = 10;
1442 auto totalRepeat = 500000;
1443 for (int i = 0;i < loops; ++i) {
1444 auto scope = ARKTS_OpenScope(env);
1445 for (int j = 0;j < totalRepeat; ++j) {
1446 auto object = ARKTS_CreateObject(env);
1447 auto global = ARKTS_CreateGlobal(env, object);
1448 ARKTS_DisposeGlobalSync(env, global);
1449 }
1450 EXPECT_FALSE(panda::JSNApi::HasPendingException(P_CAST(env, EcmaVM*)));
1451 ARKTS_CloseScope(env, scope);
1452 }
1453 }
1454
TEST_F(ArkInteropTest,PromiseRelease)1455 TEST_F(ArkInteropTest, PromiseRelease)
1456 {
1457 MockContext local;
1458 auto env = local.GetEnv();
1459 int loops = 20;
1460 auto totalRepeat = 50000;
1461 auto undefined = ARKTS_CreateUndefined();
1462 for (int i = 0;i < loops; ++i) {
1463 auto scope = ARKTS_OpenScope(env);
1464 for (int j = 0;j < totalRepeat; ++j) {
1465 auto promiseCap = ARKTS_CreatePromiseCapability(env);
1466 ARKTS_PromiseCapabilityResolve(env, promiseCap, undefined);
1467 }
1468 EXPECT_FALSE(panda::JSNApi::HasPendingException(P_CAST(env, EcmaVM*)));
1469 ARKTS_CloseScope(env, scope);
1470 }
1471 }
1472
TEST_F(ArkInteropTest,CheckFreeContext)1473 TEST_F(ArkInteropTest, CheckFreeContext)
1474 {
1475 bool isDisposed = false;
1476 {
1477 MockContext local(ARKTS_CreateEngineWithNewThread());
1478 local.SetFinalizerCallback([&isDisposed](ARKTS_Env) {
1479 isDisposed = true;
1480 });
1481 }
1482 EXPECT_TRUE(isDisposed);
1483 }
1484 } // namespace
1485
main(int argc,char ** argv)1486 int main(int argc, char** argv)
1487 {
1488 LOGI("main in");
1489 testing::GTEST_FLAG(output) = "xml:./";
1490 testing::InitGoogleTest(&argc, argv);
1491
1492 auto runner = OHOS::AppExecFwk::EventRunner::Create(true);
1493 EXPECT_TRUE(runner);
1494 auto handler = std::make_shared<OHOS::AppExecFwk::EventHandler>(runner);
1495 EXPECT_TRUE(handler);
1496
1497 MockContext::Init();
1498
1499 int ret = -1;
1500 std::condition_variable cv;
1501
1502 ARKTS_Engine globalEngine;
1503
1504 auto success = handler->PostTask([&ret, &cv, &globalEngine] {
1505 MockContext global(ARKTS_CreateEngine(), false);
1506 globalEngine = global.GetEngine();
1507 ret = testing::UnitTest::GetInstance()->Run();
1508 cv.notify_all();
1509 });
1510
1511 EXPECT_TRUE(success);
1512
1513 std::mutex mutex;
1514 std::unique_lock<std::mutex> lock(mutex);
1515 auto status = cv.wait_for(lock, std::chrono::seconds(30));
1516
1517 EXPECT_EQ(status, std::cv_status::no_timeout);
1518 ARKTS_DestroyEngine(globalEngine);
1519
1520 runner->Stop();
1521
1522 LOGI("main out");
1523 return ret;
1524 }
1525