133eb0b6dSopenharmony_ci/*
233eb0b6dSopenharmony_ci * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
333eb0b6dSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
433eb0b6dSopenharmony_ci * you may not use this file except in compliance with the License.
533eb0b6dSopenharmony_ci * You may obtain a copy of the License at
633eb0b6dSopenharmony_ci *
733eb0b6dSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
833eb0b6dSopenharmony_ci *
933eb0b6dSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
1033eb0b6dSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
1133eb0b6dSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1233eb0b6dSopenharmony_ci * See the License for the specific language governing permissions and
1333eb0b6dSopenharmony_ci * limitations under the License.
1433eb0b6dSopenharmony_ci */
1533eb0b6dSopenharmony_ci
1633eb0b6dSopenharmony_ci#include "ark_interop_external.h"
1733eb0b6dSopenharmony_ci#include "ark_interop_hitrace.h"
1833eb0b6dSopenharmony_ci#include "ark_interop_internal.h"
1933eb0b6dSopenharmony_ci#include "ark_interop_log.h"
2033eb0b6dSopenharmony_ci#include "ark_interop_napi.h"
2133eb0b6dSopenharmony_ci#include "gtest/gtest.h"
2233eb0b6dSopenharmony_ci#include "uv_loop_handler.h"
2333eb0b6dSopenharmony_ci
2433eb0b6dSopenharmony_ci#include <cmath>
2533eb0b6dSopenharmony_ci#include <thread>
2633eb0b6dSopenharmony_ci
2733eb0b6dSopenharmony_ciusing namespace testing;
2833eb0b6dSopenharmony_ciusing namespace testing::ext;
2933eb0b6dSopenharmony_ci
3033eb0b6dSopenharmony_cistruct ARKTS_ModuleCallbacks {
3133eb0b6dSopenharmony_ci    ARKTS_Value (*exportModule)(ARKTS_Env env, const char* dllName, ARKTS_Value exports) = nullptr;
3233eb0b6dSopenharmony_ci    bool (*hasModuleHandle)(const char* dllName) = nullptr;
3333eb0b6dSopenharmony_ci    void (*throwJSError)(ARKTS_Env env, ARKTS_Value) = nullptr;
3433eb0b6dSopenharmony_ci    void (*throwNativeError)(const char*) = nullptr;
3533eb0b6dSopenharmony_ci    void (*deleteArrayBufferRawData)(void* buffer, int64_t lambdaId) = nullptr;
3633eb0b6dSopenharmony_ci    void (*deleteExternal)(int64_t id, ARKTS_Env env) = nullptr;
3733eb0b6dSopenharmony_ci    ARKTS_Value (*invokerLambda)(ARKTS_CallInfo, int64_t lambdaId) = nullptr;
3833eb0b6dSopenharmony_ci    void (*deleteLambda)(ARKTS_Env env, int64_t lambdaId) = nullptr;
3933eb0b6dSopenharmony_ci    void (*invokeAsyncLambda)(ARKTS_Env env, int64_t lambdaId) = nullptr;
4033eb0b6dSopenharmony_ci    void (*deleteJSContext)(ARKTS_Env env) = nullptr;
4133eb0b6dSopenharmony_ci};
4233eb0b6dSopenharmony_ci
4333eb0b6dSopenharmony_cinamespace {
4433eb0b6dSopenharmony_ciARKTS_Engine engine_ = nullptr;
4533eb0b6dSopenharmony_ci
4633eb0b6dSopenharmony_ciclass ArkInteropTest : public testing::Test {};
4733eb0b6dSopenharmony_ci
4833eb0b6dSopenharmony_ciTEST_F(ArkInteropTest, Prime)
4933eb0b6dSopenharmony_ci{
5033eb0b6dSopenharmony_ci    auto env = ARKTS_GetContext(engine_);
5133eb0b6dSopenharmony_ci    auto scope = ARKTS_OpenScope(env);
5233eb0b6dSopenharmony_ci
5333eb0b6dSopenharmony_ci    auto jsUDef = ARKTS_CreateUndefined();
5433eb0b6dSopenharmony_ci    EXPECT_TRUE(ARKTS_IsUndefined(jsUDef));
5533eb0b6dSopenharmony_ci    EXPECT_EQ(ARKTS_GetValueType(env, jsUDef), N_UNDEFINED);
5633eb0b6dSopenharmony_ci
5733eb0b6dSopenharmony_ci    auto jsNull = ARKTS_CreateNull();
5833eb0b6dSopenharmony_ci    EXPECT_TRUE(ARKTS_IsNull(jsNull));
5933eb0b6dSopenharmony_ci    EXPECT_EQ(ARKTS_GetValueType(env, jsNull), N_NULL);
6033eb0b6dSopenharmony_ci
6133eb0b6dSopenharmony_ci    ARKTS_Value jsBools[] {
6233eb0b6dSopenharmony_ci        ARKTS_CreateBool(true),
6333eb0b6dSopenharmony_ci        ARKTS_CreateBool(false)
6433eb0b6dSopenharmony_ci    };
6533eb0b6dSopenharmony_ci    EXPECT_TRUE(ARKTS_IsBool(jsBools[0]));
6633eb0b6dSopenharmony_ci    EXPECT_EQ(ARKTS_GetValueType(env, jsBools[0]), N_BOOL);
6733eb0b6dSopenharmony_ci    EXPECT_TRUE(ARKTS_GetValueBool(jsBools[0]));
6833eb0b6dSopenharmony_ci    EXPECT_FALSE(ARKTS_GetValueBool(jsBools[1]));
6933eb0b6dSopenharmony_ci
7033eb0b6dSopenharmony_ci    ARKTS_CloseScope(env, scope);
7133eb0b6dSopenharmony_ci}
7233eb0b6dSopenharmony_ci
7333eb0b6dSopenharmony_ciTEST_F(ArkInteropTest, Number)
7433eb0b6dSopenharmony_ci{
7533eb0b6dSopenharmony_ci    auto env = ARKTS_GetContext(engine_);
7633eb0b6dSopenharmony_ci    auto scope = ARKTS_OpenScope(env);
7733eb0b6dSopenharmony_ci    double origins[] {
7833eb0b6dSopenharmony_ci        0.1,
7933eb0b6dSopenharmony_ci        -12.1,
8033eb0b6dSopenharmony_ci        12456.126546
8133eb0b6dSopenharmony_ci    };
8233eb0b6dSopenharmony_ci    constexpr auto totalCases = std::size(origins);
8333eb0b6dSopenharmony_ci    ARKTS_Value jsValues[totalCases];
8433eb0b6dSopenharmony_ci    double received[totalCases];
8533eb0b6dSopenharmony_ci
8633eb0b6dSopenharmony_ci    for (size_t i = 0;i < totalCases; i++) {
8733eb0b6dSopenharmony_ci        jsValues[i] = ARKTS_CreateF64(origins[i]);
8833eb0b6dSopenharmony_ci        EXPECT_EQ(ARKTS_GetValueType(env, jsValues[i]), N_NUMBER);
8933eb0b6dSopenharmony_ci        EXPECT_TRUE(ARKTS_IsNumber(jsValues[i]));
9033eb0b6dSopenharmony_ci        received[i] = ARKTS_GetValueNumber(jsValues[i]);
9133eb0b6dSopenharmony_ci        EXPECT_EQ(origins[i], received[i]);
9233eb0b6dSopenharmony_ci    }
9333eb0b6dSopenharmony_ci
9433eb0b6dSopenharmony_ci    auto jsNan = ARKTS_CreateF64(NAN);
9533eb0b6dSopenharmony_ci    auto nNan = ARKTS_GetValueNumber(jsNan);
9633eb0b6dSopenharmony_ci    EXPECT_TRUE(std::isnan(nNan));
9733eb0b6dSopenharmony_ci    ARKTS_CloseScope(env, scope);
9833eb0b6dSopenharmony_ci}
9933eb0b6dSopenharmony_ci
10033eb0b6dSopenharmony_ciTEST_F(ArkInteropTest, String)
10133eb0b6dSopenharmony_ci{
10233eb0b6dSopenharmony_ci    auto env = ARKTS_GetContext(engine_);
10333eb0b6dSopenharmony_ci    auto scope = ARKTS_OpenScope(env);
10433eb0b6dSopenharmony_ci    const char* origins[] {
10533eb0b6dSopenharmony_ci        "a plain text",
10633eb0b6dSopenharmony_ci        "`~!@#$%^&*()_+[]\\",
10733eb0b6dSopenharmony_ci        "中文字符",
10833eb0b6dSopenharmony_ci        "���❤️����",
10933eb0b6dSopenharmony_ci    };
11033eb0b6dSopenharmony_ci    ARKTS_Value jsValues[] {
11133eb0b6dSopenharmony_ci        ARKTS_CreateUtf8(env, origins[0], strlen(origins[0])),
11233eb0b6dSopenharmony_ci        ARKTS_CreateUtf8(env, origins[1], strlen(origins[1])),
11333eb0b6dSopenharmony_ci        ARKTS_CreateUtf8(env, origins[2], strlen(origins[2])),
11433eb0b6dSopenharmony_ci        ARKTS_CreateUtf8(env, origins[3], strlen(origins[3])),
11533eb0b6dSopenharmony_ci    };
11633eb0b6dSopenharmony_ci    EXPECT_TRUE(ARKTS_IsString(env, jsValues[0]));
11733eb0b6dSopenharmony_ci    EXPECT_TRUE(ARKTS_IsHeapObject(jsValues[0]));
11833eb0b6dSopenharmony_ci    EXPECT_EQ(ARKTS_GetValueType(env, jsValues[0]), N_STRING);
11933eb0b6dSopenharmony_ci    for (auto i = 0;i < sizeof(jsValues)/sizeof(ARKTS_Value); i++) {
12033eb0b6dSopenharmony_ci        auto size = ARKTS_GetValueUtf8Size(env, jsValues[i]);
12133eb0b6dSopenharmony_ci        std::string result;
12233eb0b6dSopenharmony_ci        result.resize(size - 1);
12333eb0b6dSopenharmony_ci        ARKTS_GetValueUtf8(env, jsValues[i], size - 1, result.data());
12433eb0b6dSopenharmony_ci        EXPECT_EQ(result, origins[i]);
12533eb0b6dSopenharmony_ci
12633eb0b6dSopenharmony_ci        auto cStr = ARKTS_GetValueCString(env, jsValues[i]);
12733eb0b6dSopenharmony_ci        result = cStr;
12833eb0b6dSopenharmony_ci        EXPECT_EQ(result, origins[i]);
12933eb0b6dSopenharmony_ci        ARKTS_FreeCString(cStr);
13033eb0b6dSopenharmony_ci    }
13133eb0b6dSopenharmony_ci    ARKTS_CloseScope(env, scope);
13233eb0b6dSopenharmony_ci}
13333eb0b6dSopenharmony_ci
13433eb0b6dSopenharmony_ciTEST_F(ArkInteropTest, Object)
13533eb0b6dSopenharmony_ci{
13633eb0b6dSopenharmony_ci    auto env = ARKTS_GetContext(engine_);
13733eb0b6dSopenharmony_ci    auto scope = ARKTS_OpenScope(env);
13833eb0b6dSopenharmony_ci    auto obj = ARKTS_CreateObject(env);
13933eb0b6dSopenharmony_ci    EXPECT_TRUE(ARKTS_IsHeapObject(obj));
14033eb0b6dSopenharmony_ci    EXPECT_TRUE(ARKTS_IsObject(env, obj));
14133eb0b6dSopenharmony_ci    EXPECT_EQ(ARKTS_GetValueType(env, obj), N_OBJECT);
14233eb0b6dSopenharmony_ci    auto keyA = ARKTS_CreateUtf8(env, "a", 1);
14333eb0b6dSopenharmony_ci    EXPECT_FALSE(ARKTS_HasOwnProperty(env, obj, keyA));
14433eb0b6dSopenharmony_ci    auto valueA = ARKTS_GetProperty(env, obj, keyA);
14533eb0b6dSopenharmony_ci    EXPECT_TRUE(ARKTS_IsUndefined(valueA));
14633eb0b6dSopenharmony_ci    valueA = ARKTS_CreateBool(true);
14733eb0b6dSopenharmony_ci    ARKTS_SetProperty(env, obj, keyA, valueA);
14833eb0b6dSopenharmony_ci    EXPECT_TRUE(ARKTS_HasOwnProperty(env, obj, keyA));
14933eb0b6dSopenharmony_ci    auto receivedA = ARKTS_GetProperty(env, obj, keyA);
15033eb0b6dSopenharmony_ci    EXPECT_TRUE(ARKTS_IsBool(receivedA));
15133eb0b6dSopenharmony_ci    EXPECT_TRUE(ARKTS_GetValueBool(receivedA));
15233eb0b6dSopenharmony_ci    auto keys = ARKTS_EnumOwnProperties(env, obj);
15333eb0b6dSopenharmony_ci    EXPECT_TRUE(ARKTS_IsArray(env, keys));
15433eb0b6dSopenharmony_ci    EXPECT_EQ(ARKTS_GetArrayLength(env, keys), 1);
15533eb0b6dSopenharmony_ci    auto key = ARKTS_GetElement(env, keys, 0);
15633eb0b6dSopenharmony_ci    EXPECT_TRUE(ARKTS_IsString(env, key));
15733eb0b6dSopenharmony_ci    EXPECT_TRUE(ARKTS_StrictEqual(env, keyA, key));
15833eb0b6dSopenharmony_ci    ARKTS_CloseScope(env, scope);
15933eb0b6dSopenharmony_ci}
16033eb0b6dSopenharmony_ci
16133eb0b6dSopenharmony_cistruct PropCase {
16233eb0b6dSopenharmony_ci    char k;
16333eb0b6dSopenharmony_ci    bool writable;
16433eb0b6dSopenharmony_ci    bool enumerable;
16533eb0b6dSopenharmony_ci    bool configurable;
16633eb0b6dSopenharmony_ci};
16733eb0b6dSopenharmony_ci
16833eb0b6dSopenharmony_ciTEST_F(ArkInteropTest, DefineProperty)
16933eb0b6dSopenharmony_ci{
17033eb0b6dSopenharmony_ci    auto env = ARKTS_GetContext(engine_);
17133eb0b6dSopenharmony_ci    auto scope = ARKTS_OpenScope(env);
17233eb0b6dSopenharmony_ci    auto obj = ARKTS_CreateObject(env);
17333eb0b6dSopenharmony_ci    PropCase cases[] {
17433eb0b6dSopenharmony_ci        {'a', false, false, false}, {'b', true, false, false}, {'c', false, true, false}, {'d', false, false, true},
17533eb0b6dSopenharmony_ci        {'e', true, true, false}, {'f', true, false, true}, {'g', false, true, true}, {'h', true, true, true}
17633eb0b6dSopenharmony_ci    };
17733eb0b6dSopenharmony_ci    constexpr auto totalCases = std::size(cases);
17833eb0b6dSopenharmony_ci    auto valueT = ARKTS_CreateBool(true), valueF = ARKTS_CreateBool(false);
17933eb0b6dSopenharmony_ci    ARKTS_Value keys[totalCases];
18033eb0b6dSopenharmony_ci    for (auto i = 0; i < totalCases; i++) {
18133eb0b6dSopenharmony_ci        keys[i] = ARKTS_CreateUtf8(env, &cases[i].k, 1);
18233eb0b6dSopenharmony_ci        ARKTS_DefineOwnProperty(env, obj, keys[i], valueF, static_cast<ARKTS_PropertyFlag>(
18333eb0b6dSopenharmony_ci            (cases[i].writable ? N_WRITABLE : 0) |
18433eb0b6dSopenharmony_ci            (cases[i].enumerable ? N_ENUMERABLE : 0) |
18533eb0b6dSopenharmony_ci            (cases[i].configurable ? N_CONFIGURABLE : 0)
18633eb0b6dSopenharmony_ci        ));
18733eb0b6dSopenharmony_ci    }
18833eb0b6dSopenharmony_ci    constexpr int expectKeys = 4;
18933eb0b6dSopenharmony_ci    auto jsKeys = ARKTS_EnumOwnProperties(env, obj);
19033eb0b6dSopenharmony_ci    EXPECT_TRUE(ARKTS_IsArray(env, jsKeys));
19133eb0b6dSopenharmony_ci    EXPECT_EQ(ARKTS_GetArrayLength(env, jsKeys), expectKeys);
19233eb0b6dSopenharmony_ci    for (auto i = 0; i < expectKeys; i++) {
19333eb0b6dSopenharmony_ci        auto jsKey = ARKTS_GetElement(env, jsKeys, i);
19433eb0b6dSopenharmony_ci        EXPECT_TRUE(ARKTS_IsString(env, jsKey));
19533eb0b6dSopenharmony_ci        char buffer = 0;
19633eb0b6dSopenharmony_ci        ARKTS_GetValueUtf8(env, jsKey, 1, &buffer);
19733eb0b6dSopenharmony_ci        EXPECT_TRUE(buffer == 'c' || buffer == 'e' || buffer == 'g' || buffer == 'h');
19833eb0b6dSopenharmony_ci    }
19933eb0b6dSopenharmony_ci    for (auto i = 0; i < totalCases; i++) { // writable
20033eb0b6dSopenharmony_ci        if (cases[i].writable && cases[i].configurable) {
20133eb0b6dSopenharmony_ci            ARKTS_SetProperty(env, obj, keys[i], valueT);
20233eb0b6dSopenharmony_ci            auto receivedJS = ARKTS_GetProperty(env, obj, keys[i]);
20333eb0b6dSopenharmony_ci            auto recievedN = ARKTS_GetValueBool(receivedJS);
20433eb0b6dSopenharmony_ci            EXPECT_TRUE(recievedN);
20533eb0b6dSopenharmony_ci        }
20633eb0b6dSopenharmony_ci    }
20733eb0b6dSopenharmony_ci    for (auto i = 0;i < totalCases; ++i) { // configurable
20833eb0b6dSopenharmony_ci        if (cases[i].configurable) {
20933eb0b6dSopenharmony_ci            ARKTS_DefineOwnProperty(env, obj, keys[i], valueT,
21033eb0b6dSopenharmony_ci                static_cast<ARKTS_PropertyFlag>(N_WRITABLE | N_ENUMERABLE | N_CONFIGURABLE));
21133eb0b6dSopenharmony_ci        }
21233eb0b6dSopenharmony_ci    }
21333eb0b6dSopenharmony_ci    jsKeys = ARKTS_EnumOwnProperties(env, obj);
21433eb0b6dSopenharmony_ci    constexpr int expectLength = 6;
21533eb0b6dSopenharmony_ci    EXPECT_EQ(ARKTS_GetArrayLength(env, jsKeys), expectLength);
21633eb0b6dSopenharmony_ci    ARKTS_CloseScope(env, scope);
21733eb0b6dSopenharmony_ci}
21833eb0b6dSopenharmony_ci
21933eb0b6dSopenharmony_ciHWTEST_F(ArkInteropTest, ArkTSInteropNapiInstanceOf, TestSize.Level1)
22033eb0b6dSopenharmony_ci{
22133eb0b6dSopenharmony_ci    ARKTS_Env env = ARKTS_GetContext(engine_);
22233eb0b6dSopenharmony_ci    auto global = ARKTS_GetGlobalConstant(env);
22333eb0b6dSopenharmony_ci    char clError[] = "Error";
22433eb0b6dSopenharmony_ci    auto jError = ARKTS_CreateUtf8(env, clError, sizeof(clError) - 1);
22533eb0b6dSopenharmony_ci    auto errorCls = ARKTS_GetProperty(env, global, jError);
22633eb0b6dSopenharmony_ci    auto errorObJ = ARKTS_New(env, errorCls, 0, nullptr);
22733eb0b6dSopenharmony_ci    auto isError = ARKTS_InstanceOf(env, errorObJ, errorCls);
22833eb0b6dSopenharmony_ci    EXPECT_TRUE(isError);
22933eb0b6dSopenharmony_ci    auto jObj = ARKTS_CreateObject(env);
23033eb0b6dSopenharmony_ci    EXPECT_FALSE(ARKTS_InstanceOf(env, jObj, errorCls));
23133eb0b6dSopenharmony_ci}
23233eb0b6dSopenharmony_ci
23333eb0b6dSopenharmony_ciHWTEST_F(ArkInteropTest, ArkTSInteropNapiCreateEngineNew, TestSize.Level1)
23433eb0b6dSopenharmony_ci{
23533eb0b6dSopenharmony_ci    auto engine = ARKTS_CreateEngineWithNewThread();
23633eb0b6dSopenharmony_ci
23733eb0b6dSopenharmony_ci    auto curTid = ARKTS_GetPosixThreadId();
23833eb0b6dSopenharmony_ci    auto engineTid = ARKTS_GetThreadIdOfEngine(engine);
23933eb0b6dSopenharmony_ci
24033eb0b6dSopenharmony_ci    EXPECT_NE(curTid, engineTid);
24133eb0b6dSopenharmony_ci
24233eb0b6dSopenharmony_ci    ARKTS_DestroyEngine(engine);
24333eb0b6dSopenharmony_ci}
24433eb0b6dSopenharmony_ci} // namespace
24533eb0b6dSopenharmony_ci
24633eb0b6dSopenharmony_ciint main(int argc, char** argv)
24733eb0b6dSopenharmony_ci{
24833eb0b6dSopenharmony_ci    LOGI("main in");
24933eb0b6dSopenharmony_ci    testing::GTEST_FLAG(output) = "xml:./";
25033eb0b6dSopenharmony_ci    testing::InitGoogleTest(&argc, argv);
25133eb0b6dSopenharmony_ci
25233eb0b6dSopenharmony_ci    auto runner = OHOS::AppExecFwk::EventRunner::Create(true);
25333eb0b6dSopenharmony_ci    EXPECT_TRUE(runner);
25433eb0b6dSopenharmony_ci    auto handler = std::make_shared<OHOS::AppExecFwk::EventHandler>(runner);
25533eb0b6dSopenharmony_ci    EXPECT_TRUE(handler);
25633eb0b6dSopenharmony_ci
25733eb0b6dSopenharmony_ci    int ret = -1;
25833eb0b6dSopenharmony_ci    std::condition_variable cv;
25933eb0b6dSopenharmony_ci
26033eb0b6dSopenharmony_ci    auto success = handler->PostTask([&ret, &cv] {
26133eb0b6dSopenharmony_ci        engine_ = ARKTS_CreateEngine();
26233eb0b6dSopenharmony_ci
26333eb0b6dSopenharmony_ci        ret = testing::UnitTest::GetInstance()->Run();
26433eb0b6dSopenharmony_ci        cv.notify_all();
26533eb0b6dSopenharmony_ci    });
26633eb0b6dSopenharmony_ci
26733eb0b6dSopenharmony_ci    EXPECT_TRUE(success);
26833eb0b6dSopenharmony_ci
26933eb0b6dSopenharmony_ci    std::mutex mutex;
27033eb0b6dSopenharmony_ci    std::unique_lock<std::mutex> lock(mutex);
27133eb0b6dSopenharmony_ci    auto status = cv.wait_for(lock, std::chrono::seconds(10));
27233eb0b6dSopenharmony_ci
27333eb0b6dSopenharmony_ci    EXPECT_EQ(status, std::cv_status::no_timeout);
27433eb0b6dSopenharmony_ci
27533eb0b6dSopenharmony_ci    ARKTS_DestroyEngine(engine_);
27633eb0b6dSopenharmony_ci    engine_ = nullptr;
27733eb0b6dSopenharmony_ci    runner->Stop();
27833eb0b6dSopenharmony_ci
27933eb0b6dSopenharmony_ci    LOGI("main out");
28033eb0b6dSopenharmony_ci    return ret;
28133eb0b6dSopenharmony_ci}
282