1 /*
2 * Copyright (c) 2025 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 "ecmascript/js_object-inl.h"
17 #include "ecmascript/tests/test_helper.h"
18 #include "ecmascript/ecma_vm.h"
19 #include "ecmascript/module/static/static_module_loader.h"
20 #include "ecmascript/js_promise.h"
21 #include "ecmascript/module/napi_module_loader.h"
22 #include "ecmascript/js_array.h"
23 #include "ecmascript/global_env.h"
24 #include "ecmascript/module/module_path_helper.h"
25
26 using namespace panda;
27 using namespace panda::ecmascript;
28 using namespace panda::ecmascript::builtins;
29 using FunctionCallbackInfo = Local<JSValueRef> (*)(JsiRuntimeCallInfo *);
30 using namespace panda::ecmascript;
31 using ModulePathHelper = ecmascript::ModulePathHelper;
32
33 namespace panda::test {
34 class StaticModuleLoaderTest : public testing::Test {
35 public:
SetUpTestCase()36 static void SetUpTestCase()
37 {
38 GTEST_LOG_(INFO) << "SetUpTestCase";
39 }
40
TearDownTestCase()41 static void TearDownTestCase()
42 {
43 GTEST_LOG_(INFO) << "TearDownCase";
44 }
45
SetUp()46 void SetUp() override
47 {
48 TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
49 }
50
TearDown()51 void TearDown() override
52 {
53 TestHelper::DestroyEcmaVMWithScope(instance, scope);
54 }
55 static Local<JSValueRef> MockGetModule(JsiRuntimeCallInfo *runtimeCallInfo);
56 static Local<JSValueRef> MockGetModuleJSError(JsiRuntimeCallInfo *runtimeCallInfo);
57 EcmaVM *instance {nullptr};
58 ecmascript::EcmaHandleScope *scope {nullptr};
59 JSThread *thread {nullptr};
60 };
61
MockGetModule(JsiRuntimeCallInfo * runtimeCallInfo)62 Local<JSValueRef> StaticModuleLoaderTest::MockGetModule(JsiRuntimeCallInfo *runtimeCallInfo)
63 {
64 auto *thread = runtimeCallInfo->GetThread();
65 auto vm = thread->GetEcmaVM();
66 Local<StringRef> requestPath = StringRef::NewFromUtf8(vm, "requestPath");
67 Local<ObjectRef> exportObejct = ObjectRef::New(vm);
68 exportObejct->Set(vm, requestPath, runtimeCallInfo->GetCallArgRef(0));
69 return exportObejct;
70 }
71
72
MockGetModuleJSError(JsiRuntimeCallInfo * runtimeCallInfo)73 Local<JSValueRef> StaticModuleLoaderTest::MockGetModuleJSError(JsiRuntimeCallInfo *runtimeCallInfo)
74 {
75 auto *thread = runtimeCallInfo->GetThread();
76 auto vm = thread->GetEcmaVM();
77 JsiFastNativeScope fastNativeScope(vm);
78 Local<JSValueRef> error(JSValueRef::Undefined(vm));
79 error = Exception::Error(vm, runtimeCallInfo->GetCallArgRef(0));
80 Local<JSValueRef> codeKey = StringRef::NewFromUtf8(vm, "code");
81 Local<JSValueRef> codeValue = runtimeCallInfo->GetCallArgRef(0);
82 Local<ObjectRef> errorObj(error);
83 errorObj->Set(vm, codeKey, codeValue);
84 JSNApi::ThrowException(vm, error);
85 return runtimeCallInfo->GetCallArgRef(0);
86 }
87
HWTEST_F_L0(StaticModuleLoaderTest,CanTryLoadStaticModulePath)88 HWTEST_F_L0(StaticModuleLoaderTest, CanTryLoadStaticModulePath)
89 {
90 CString inputFileName = "./test";
91 bool res1 = StaticModuleLoader::CanTryLoadStaticModulePath(inputFileName);
92 EXPECT_FALSE(res1);
93
94 inputFileName = "test";
95 bool res2 = StaticModuleLoader::CanTryLoadStaticModulePath(inputFileName);
96 EXPECT_TRUE(res2);
97
98 inputFileName = "test.js";
99 bool res3 = StaticModuleLoader::CanTryLoadStaticModulePath(inputFileName);
100 EXPECT_FALSE(res3);
101
102 inputFileName = "test.ts";
103 bool res4 = StaticModuleLoader::CanTryLoadStaticModulePath(inputFileName);
104 EXPECT_FALSE(res4);
105
106 inputFileName = "test.ets";
107 bool res5 = StaticModuleLoader::CanTryLoadStaticModulePath(inputFileName);
108 EXPECT_FALSE(res5);
109
110 inputFileName = "@bundle:";
111 bool res6 = StaticModuleLoader::CanTryLoadStaticModulePath(inputFileName);
112 EXPECT_FALSE(res6);
113
114 inputFileName = "@normalized:";
115 bool res7 = StaticModuleLoader::CanTryLoadStaticModulePath(inputFileName);
116 EXPECT_FALSE(res7);
117
118 inputFileName = "@package:";
119 bool res8 = StaticModuleLoader::CanTryLoadStaticModulePath(inputFileName);
120 EXPECT_FALSE(res8);
121 }
122
HWTEST_F_L0(StaticModuleLoaderTest,GetStaticModuleLoadFunc)123 HWTEST_F_L0(StaticModuleLoaderTest, GetStaticModuleLoadFunc)
124 {
125 auto vm = thread->GetEcmaVM();
126 Local<JSValueRef> undefinedFunc = StaticModuleLoader::GetStaticModuleLoadFunc(vm);
127 EXPECT_TRUE(undefinedFunc->IsUndefined());
128
129 auto globalConstants = thread->GlobalConstants();
130 JSArray *arr = JSArray::Cast(JSArray::ArrayCreate(thread, JSTaggedNumber(0)).GetTaggedValue().GetTaggedObject());
131 EXPECT_TRUE(arr != nullptr);
132 JSHandle<JSTaggedValue> pandaObject(thread, arr);
133 JSTaggedValue::SetProperty(thread, pandaObject,
134 globalConstants->GetHandledGetModuleString(),
135 JSNApiHelper::ToJSHandle(FunctionRef::New(const_cast<panda::EcmaVM*>(vm), MockGetModule)));
136 Local<ObjectRef> globalObject = JSNApi::GetGlobalObject(vm);
137 globalObject->Set(vm,
138 JSNApiHelper::ToLocal<StringRef>(globalConstants->GetHandledPandaString()),
139 JSNApiHelper::ToLocal<JSValueRef>(pandaObject));
140 Local<JSValueRef> func = StaticModuleLoader::GetStaticModuleLoadFunc(vm);
141 EXPECT_FALSE(func->IsUndefined());
142 }
143
HWTEST_F_L0(StaticModuleLoaderTest,LoadStaticModule)144 HWTEST_F_L0(StaticModuleLoaderTest, LoadStaticModule)
145 {
146 auto vm = thread->GetEcmaVM();
147 ObjectFactory *factory = vm->GetFactory();
148
149 Local<FunctionRef> func = FunctionRef::New(const_cast<panda::EcmaVM *>(vm), MockGetModule);
150 JSHandle<JSTaggedValue> specifier(factory->NewFromASCII("exportFile"));
151 JSHandle<EcmaString> specifierString = JSTaggedValue::ToString(thread, specifier);
152 CString path = ModulePathHelper::Utf8ConvertToString(thread, specifierString.GetTaggedValue());
153 JSHandle<JSTaggedValue> result = StaticModuleLoader::LoadStaticModule(thread, func, path);
154
155 EXPECT_EQ(result->IsJSProxy(), true);
156 JSHandle<JSTaggedValue> requestPath(factory->NewFromASCII("requestPath"));
157 EXPECT_EQ(JSTaggedValue::SameValue(thread, JSTaggedValue::GetProperty(thread, result, requestPath).GetValue(),
158 specifier), true);
159 }
160
161
HWTEST_F_L0(StaticModuleLoaderTest,LoadStaticModuleError)162 HWTEST_F_L0(StaticModuleLoaderTest, LoadStaticModuleError)
163 {
164 auto vm = thread->GetEcmaVM();
165 ObjectFactory *factory = vm->GetFactory();
166
167 Local<FunctionRef> func = FunctionRef::New(const_cast<panda::EcmaVM *>(vm), MockGetModuleJSError);
168 JSHandle<JSTaggedValue> specifier(factory->NewFromASCII("exportFile"));
169 JSHandle<EcmaString> specifierString = JSTaggedValue::ToString(thread, specifier);
170 CString path = ModulePathHelper::Utf8ConvertToString(thread, specifierString.GetTaggedValue());
171 StaticModuleLoader::LoadStaticModule(thread, func, path);
172 EXPECT_EQ(thread->HasPendingException(), true);
173 JSHandle<JSTaggedValue> error(thread, thread->GetException());
174 JSHandle<JSTaggedValue> code(factory->NewFromASCII("code"));
175 JSHandle<JSTaggedValue> message = JSTaggedValue::GetProperty(thread, error, code).GetValue();
176 EXPECT_EQ(JSTaggedValue::SameValue(thread, message, specifier), true);
177 thread->ClearException();
178 }
179
180 } // namespace panda::test
181