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
27using namespace testing;
28using namespace testing::ext;
29
30struct 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
43namespace {
44ARKTS_Engine engine_ = nullptr;
45
46class ArkInteropTest : public testing::Test {};
47
48TEST_F(ArkInteropTest, Prime)
49{
50    auto env = ARKTS_GetContext(engine_);
51    auto scope = ARKTS_OpenScope(env);
52
53    auto jsUDef = ARKTS_CreateUndefined();
54    EXPECT_TRUE(ARKTS_IsUndefined(jsUDef));
55    EXPECT_EQ(ARKTS_GetValueType(env, jsUDef), N_UNDEFINED);
56
57    auto jsNull = ARKTS_CreateNull();
58    EXPECT_TRUE(ARKTS_IsNull(jsNull));
59    EXPECT_EQ(ARKTS_GetValueType(env, jsNull), N_NULL);
60
61    ARKTS_Value jsBools[] {
62        ARKTS_CreateBool(true),
63        ARKTS_CreateBool(false)
64    };
65    EXPECT_TRUE(ARKTS_IsBool(jsBools[0]));
66    EXPECT_EQ(ARKTS_GetValueType(env, jsBools[0]), N_BOOL);
67    EXPECT_TRUE(ARKTS_GetValueBool(jsBools[0]));
68    EXPECT_FALSE(ARKTS_GetValueBool(jsBools[1]));
69
70    ARKTS_CloseScope(env, scope);
71}
72
73TEST_F(ArkInteropTest, Number)
74{
75    auto env = ARKTS_GetContext(engine_);
76    auto scope = ARKTS_OpenScope(env);
77    double origins[] {
78        0.1,
79        -12.1,
80        12456.126546
81    };
82    constexpr auto totalCases = std::size(origins);
83    ARKTS_Value jsValues[totalCases];
84    double received[totalCases];
85
86    for (size_t i = 0;i < totalCases; i++) {
87        jsValues[i] = ARKTS_CreateF64(origins[i]);
88        EXPECT_EQ(ARKTS_GetValueType(env, jsValues[i]), N_NUMBER);
89        EXPECT_TRUE(ARKTS_IsNumber(jsValues[i]));
90        received[i] = ARKTS_GetValueNumber(jsValues[i]);
91        EXPECT_EQ(origins[i], received[i]);
92    }
93
94    auto jsNan = ARKTS_CreateF64(NAN);
95    auto nNan = ARKTS_GetValueNumber(jsNan);
96    EXPECT_TRUE(std::isnan(nNan));
97    ARKTS_CloseScope(env, scope);
98}
99
100TEST_F(ArkInteropTest, String)
101{
102    auto env = ARKTS_GetContext(engine_);
103    auto scope = ARKTS_OpenScope(env);
104    const char* origins[] {
105        "a plain text",
106        "`~!@#$%^&*()_+[]\\",
107        "中文字符",
108        "���❤️����",
109    };
110    ARKTS_Value jsValues[] {
111        ARKTS_CreateUtf8(env, origins[0], strlen(origins[0])),
112        ARKTS_CreateUtf8(env, origins[1], strlen(origins[1])),
113        ARKTS_CreateUtf8(env, origins[2], strlen(origins[2])),
114        ARKTS_CreateUtf8(env, origins[3], strlen(origins[3])),
115    };
116    EXPECT_TRUE(ARKTS_IsString(env, jsValues[0]));
117    EXPECT_TRUE(ARKTS_IsHeapObject(jsValues[0]));
118    EXPECT_EQ(ARKTS_GetValueType(env, jsValues[0]), N_STRING);
119    for (auto i = 0;i < sizeof(jsValues)/sizeof(ARKTS_Value); i++) {
120        auto size = ARKTS_GetValueUtf8Size(env, jsValues[i]);
121        std::string result;
122        result.resize(size - 1);
123        ARKTS_GetValueUtf8(env, jsValues[i], size - 1, result.data());
124        EXPECT_EQ(result, origins[i]);
125
126        auto cStr = ARKTS_GetValueCString(env, jsValues[i]);
127        result = cStr;
128        EXPECT_EQ(result, origins[i]);
129        ARKTS_FreeCString(cStr);
130    }
131    ARKTS_CloseScope(env, scope);
132}
133
134TEST_F(ArkInteropTest, Object)
135{
136    auto env = ARKTS_GetContext(engine_);
137    auto scope = ARKTS_OpenScope(env);
138    auto obj = ARKTS_CreateObject(env);
139    EXPECT_TRUE(ARKTS_IsHeapObject(obj));
140    EXPECT_TRUE(ARKTS_IsObject(env, obj));
141    EXPECT_EQ(ARKTS_GetValueType(env, obj), N_OBJECT);
142    auto keyA = ARKTS_CreateUtf8(env, "a", 1);
143    EXPECT_FALSE(ARKTS_HasOwnProperty(env, obj, keyA));
144    auto valueA = ARKTS_GetProperty(env, obj, keyA);
145    EXPECT_TRUE(ARKTS_IsUndefined(valueA));
146    valueA = ARKTS_CreateBool(true);
147    ARKTS_SetProperty(env, obj, keyA, valueA);
148    EXPECT_TRUE(ARKTS_HasOwnProperty(env, obj, keyA));
149    auto receivedA = ARKTS_GetProperty(env, obj, keyA);
150    EXPECT_TRUE(ARKTS_IsBool(receivedA));
151    EXPECT_TRUE(ARKTS_GetValueBool(receivedA));
152    auto keys = ARKTS_EnumOwnProperties(env, obj);
153    EXPECT_TRUE(ARKTS_IsArray(env, keys));
154    EXPECT_EQ(ARKTS_GetArrayLength(env, keys), 1);
155    auto key = ARKTS_GetElement(env, keys, 0);
156    EXPECT_TRUE(ARKTS_IsString(env, key));
157    EXPECT_TRUE(ARKTS_StrictEqual(env, keyA, key));
158    ARKTS_CloseScope(env, scope);
159}
160
161struct PropCase {
162    char k;
163    bool writable;
164    bool enumerable;
165    bool configurable;
166};
167
168TEST_F(ArkInteropTest, DefineProperty)
169{
170    auto env = ARKTS_GetContext(engine_);
171    auto scope = ARKTS_OpenScope(env);
172    auto obj = ARKTS_CreateObject(env);
173    PropCase cases[] {
174        {'a', false, false, false}, {'b', true, false, false}, {'c', false, true, false}, {'d', false, false, true},
175        {'e', true, true, false}, {'f', true, false, true}, {'g', false, true, true}, {'h', true, true, true}
176    };
177    constexpr auto totalCases = std::size(cases);
178    auto valueT = ARKTS_CreateBool(true), valueF = ARKTS_CreateBool(false);
179    ARKTS_Value keys[totalCases];
180    for (auto i = 0; i < totalCases; i++) {
181        keys[i] = ARKTS_CreateUtf8(env, &cases[i].k, 1);
182        ARKTS_DefineOwnProperty(env, obj, keys[i], valueF, static_cast<ARKTS_PropertyFlag>(
183            (cases[i].writable ? N_WRITABLE : 0) |
184            (cases[i].enumerable ? N_ENUMERABLE : 0) |
185            (cases[i].configurable ? N_CONFIGURABLE : 0)
186        ));
187    }
188    constexpr int expectKeys = 4;
189    auto jsKeys = ARKTS_EnumOwnProperties(env, obj);
190    EXPECT_TRUE(ARKTS_IsArray(env, jsKeys));
191    EXPECT_EQ(ARKTS_GetArrayLength(env, jsKeys), expectKeys);
192    for (auto i = 0; i < expectKeys; i++) {
193        auto jsKey = ARKTS_GetElement(env, jsKeys, i);
194        EXPECT_TRUE(ARKTS_IsString(env, jsKey));
195        char buffer = 0;
196        ARKTS_GetValueUtf8(env, jsKey, 1, &buffer);
197        EXPECT_TRUE(buffer == 'c' || buffer == 'e' || buffer == 'g' || buffer == 'h');
198    }
199    for (auto i = 0; i < totalCases; i++) { // writable
200        if (cases[i].writable && cases[i].configurable) {
201            ARKTS_SetProperty(env, obj, keys[i], valueT);
202            auto receivedJS = ARKTS_GetProperty(env, obj, keys[i]);
203            auto recievedN = ARKTS_GetValueBool(receivedJS);
204            EXPECT_TRUE(recievedN);
205        }
206    }
207    for (auto i = 0;i < totalCases; ++i) { // configurable
208        if (cases[i].configurable) {
209            ARKTS_DefineOwnProperty(env, obj, keys[i], valueT,
210                static_cast<ARKTS_PropertyFlag>(N_WRITABLE | N_ENUMERABLE | N_CONFIGURABLE));
211        }
212    }
213    jsKeys = ARKTS_EnumOwnProperties(env, obj);
214    constexpr int expectLength = 6;
215    EXPECT_EQ(ARKTS_GetArrayLength(env, jsKeys), expectLength);
216    ARKTS_CloseScope(env, scope);
217}
218
219HWTEST_F(ArkInteropTest, ArkTSInteropNapiInstanceOf, TestSize.Level1)
220{
221    ARKTS_Env env = ARKTS_GetContext(engine_);
222    auto global = ARKTS_GetGlobalConstant(env);
223    char clError[] = "Error";
224    auto jError = ARKTS_CreateUtf8(env, clError, sizeof(clError) - 1);
225    auto errorCls = ARKTS_GetProperty(env, global, jError);
226    auto errorObJ = ARKTS_New(env, errorCls, 0, nullptr);
227    auto isError = ARKTS_InstanceOf(env, errorObJ, errorCls);
228    EXPECT_TRUE(isError);
229    auto jObj = ARKTS_CreateObject(env);
230    EXPECT_FALSE(ARKTS_InstanceOf(env, jObj, errorCls));
231}
232
233HWTEST_F(ArkInteropTest, ArkTSInteropNapiCreateEngineNew, TestSize.Level1)
234{
235    auto engine = ARKTS_CreateEngineWithNewThread();
236
237    auto curTid = ARKTS_GetPosixThreadId();
238    auto engineTid = ARKTS_GetThreadIdOfEngine(engine);
239
240    EXPECT_NE(curTid, engineTid);
241
242    ARKTS_DestroyEngine(engine);
243}
244} // namespace
245
246int main(int argc, char** argv)
247{
248    LOGI("main in");
249    testing::GTEST_FLAG(output) = "xml:./";
250    testing::InitGoogleTest(&argc, argv);
251
252    auto runner = OHOS::AppExecFwk::EventRunner::Create(true);
253    EXPECT_TRUE(runner);
254    auto handler = std::make_shared<OHOS::AppExecFwk::EventHandler>(runner);
255    EXPECT_TRUE(handler);
256
257    int ret = -1;
258    std::condition_variable cv;
259
260    auto success = handler->PostTask([&ret, &cv] {
261        engine_ = ARKTS_CreateEngine();
262
263        ret = testing::UnitTest::GetInstance()->Run();
264        cv.notify_all();
265    });
266
267    EXPECT_TRUE(success);
268
269    std::mutex mutex;
270    std::unique_lock<std::mutex> lock(mutex);
271    auto status = cv.wait_for(lock, std::chrono::seconds(10));
272
273    EXPECT_EQ(status, std::cv_status::no_timeout);
274
275    ARKTS_DestroyEngine(engine_);
276    engine_ = nullptr;
277    runner->Stop();
278
279    LOGI("main out");
280    return ret;
281}
282