• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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