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