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