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