• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/builtins/builtins_promise_job.h"
17 #include "ecmascript/global_env.h"
18 #include "ecmascript/tests/test_helper.h"
19 #include "ecmascript/module/napi_module_loader.h"
20 #include "ecmascript/ecma_vm.h"
21 #include "ecmascript/js_promise.h"
22 #include "ecmascript/js_array.h"
23 
24 using namespace panda;
25 using namespace panda::ecmascript;
26 using namespace panda::ecmascript::builtins;
27 
28 using FunctionCallbackInfo = Local<JSValueRef> (*)(JsiRuntimeCallInfo *);
29 namespace panda::test {
30 class BuiltinsPromiseJobTest : public BaseTestWithScope<true> {
31     public:
32         static Local<JSValueRef> MockGetModule(JsiRuntimeCallInfo *runtimeCallInfo);
33         static Local<JSValueRef> MockGetModuleJSError(JsiRuntimeCallInfo *runtimeCallInfo);
34 };
35 
MockGetModule(JsiRuntimeCallInfo * runtimeCallInfo)36 Local<JSValueRef> BuiltinsPromiseJobTest::MockGetModule(JsiRuntimeCallInfo *runtimeCallInfo)
37 {
38     auto *thread = runtimeCallInfo->GetThread();
39     auto vm = thread->GetEcmaVM();
40     Local<StringRef> requestPath = StringRef::NewFromUtf8(vm, "requestPath");
41     Local<ObjectRef> exportObejct = ObjectRef::New(vm);
42     exportObejct->Set(vm, requestPath, runtimeCallInfo->GetCallArgRef(0));
43     return exportObejct;
44 }
45 
MockGetModuleJSError(JsiRuntimeCallInfo * runtimeCallInfo)46 Local<JSValueRef> BuiltinsPromiseJobTest::MockGetModuleJSError(JsiRuntimeCallInfo *runtimeCallInfo)
47 {
48     auto *thread = runtimeCallInfo->GetThread();
49     auto vm = thread->GetEcmaVM();
50     JsiFastNativeScope fastNativeScope(vm);
51     Local<JSValueRef> error(JSValueRef::Undefined(vm));
52     error = Exception::Error(vm, runtimeCallInfo->GetCallArgRef(0));
53     Local<JSValueRef> codeKey = StringRef::NewFromUtf8(vm, "code");
54     Local<JSValueRef> codeValue = runtimeCallInfo->GetCallArgRef(0);
55     Local<ObjectRef> errorObj(error);
56     errorObj->Set(vm, codeKey, codeValue);
57     JSNApi::ThrowException(vm, error);
58     return runtimeCallInfo->GetCallArgRef(0);
59 }
60 
61 // dynamic import static module after load 1.0 module failed
HWTEST_F_L0(BuiltinsPromiseJobTest,DynamicImportJobCatchException)62 HWTEST_F_L0(BuiltinsPromiseJobTest, DynamicImportJobCatchException)
63 {
64     /**
65      * Both the handle and the stack are allocated using maloc.
66      * When newJsError is called, the C interpreter will step back one frame before executing.
67      * In the UT, there is only one frame, and stepping back causes it to step on the handle address.
68      * This is a special scenario caused by the UT, and it would not occur during normal execution.
69      */
70     if (!thread->IsAsmInterpreter()) {
71         return;
72     }
73     auto vm = thread->GetEcmaVM();
74     ObjectFactory *factory = vm->GetFactory();
75     JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
76 
77     auto globalConstants = thread->GlobalConstants();
78     JSArray *arr = JSArray::Cast(JSArray::ArrayCreate(thread, JSTaggedNumber(0)).GetTaggedValue().GetTaggedObject());
79     EXPECT_TRUE(arr != nullptr);
80     JSHandle<JSTaggedValue> pandaObject(thread, arr);
81     JSTaggedValue::SetProperty(thread, pandaObject,
82         globalConstants->GetHandledGetModuleString(),
83         JSNApiHelper::ToJSHandle(FunctionRef::New(const_cast<panda::EcmaVM*>(vm), MockGetModule)));
84     Local<ObjectRef> globalObject = JSNApi::GetGlobalObject(vm);
85     globalObject->Set(vm,
86         JSNApiHelper::ToLocal<StringRef>(globalConstants->GetHandledPandaString()),
87         JSNApiHelper::ToLocal<JSValueRef>(pandaObject));
88 
89     JSHandle<JSTaggedValue> promiseFunc = env->GetPromiseFunction();
90     JSHandle<JSPromise> jsPromise =
91         JSHandle<JSPromise>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(promiseFunc), promiseFunc));
92     JSHandle<ResolvingFunctionsRecord> resolvingFunctions =
93         JSPromise::CreateResolvingFunctions(thread, jsPromise);
94     JSHandle<JSPromiseReactionsFunction> resolve(thread, resolvingFunctions->GetResolveFunction(thread));
95     JSHandle<JSPromiseReactionsFunction> reject(thread, resolvingFunctions->GetRejectFunction(thread));
96     JSHandle<JSTaggedValue> dirPath(factory->NewFromASCII("./main.abc"));
97     JSHandle<JSTaggedValue> specifier(factory->NewFromASCII("exportFile"));
98     auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 14);
99     Local<JSValueRef> contextValue = JSNApi::GetCurrentContext(vm);
100     JSHandle<LexicalEnv> lexicalEnv(JSNApiHelper::ToJSHandle(contextValue));
101     JSHandle<JSFunction> funHandle = factory->NewJSFunction(env);
102     funHandle->SetLexicalEnv(thread, lexicalEnv.GetTaggedValue());
103     ecmaRuntimeCallInfo->SetFunction(funHandle.GetTaggedValue());
104     ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
105     ecmaRuntimeCallInfo->SetCallArg(0, resolve.GetTaggedValue());
106     ecmaRuntimeCallInfo->SetCallArg(1, reject.GetTaggedValue());
107     ecmaRuntimeCallInfo->SetCallArg(2, dirPath.GetTaggedValue());
108     ecmaRuntimeCallInfo->SetCallArg(3, specifier.GetTaggedValue());
109     ecmaRuntimeCallInfo->SetCallArg(4, JSTaggedValue::Undefined());
110     [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
111     BuiltinsPromiseJob::DynamicImportJob(ecmaRuntimeCallInfo);
112     TestHelper::TearDownFrame(thread, prev);
113     JSHandle<JSTaggedValue> result(thread, jsPromise->GetPromiseResult(thread));
114     EXPECT_EQ(result->IsJSProxy(), true);
115     JSHandle<JSTaggedValue> requestPath(factory->NewFromASCII("requestPath"));
116     EXPECT_EQ(JSTaggedValue::SameValue(thread, JSTaggedValue::GetProperty(thread, result, requestPath).GetValue(),
117                                        specifier), true);
118 }
119 
120 // throw 1.2 load failed
HWTEST_F_L0(BuiltinsPromiseJobTest,DynamicImportJobCatchException2)121 HWTEST_F_L0(BuiltinsPromiseJobTest, DynamicImportJobCatchException2)
122 {
123     /**
124      * Both the handle and the stack are allocated using maloc.
125      * When newJsError is called, the C interpreter will step back one frame before executing.
126      * In the UT, there is only one frame, and stepping back causes it to step on the handle address.
127      * This is a special scenario caused by the UT, and it would not occur during normal execution.
128      */
129     if (!thread->IsAsmInterpreter()) {
130         return;
131     }
132     auto vm = thread->GetEcmaVM();
133     ObjectFactory *factory = vm->GetFactory();
134     JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
135 
136     auto globalConstants = thread->GlobalConstants();
137     JSArray *arr = JSArray::Cast(JSArray::ArrayCreate(thread, JSTaggedNumber(0)).GetTaggedValue().GetTaggedObject());
138     EXPECT_TRUE(arr != nullptr);
139     JSHandle<JSTaggedValue> pandaObject(thread, arr);
140     JSTaggedValue::SetProperty(thread, pandaObject,
141         globalConstants->GetHandledGetModuleString(),
142         JSNApiHelper::ToJSHandle(FunctionRef::New(const_cast<panda::EcmaVM*>(vm), MockGetModuleJSError)));
143     Local<ObjectRef> globalObject = JSNApi::GetGlobalObject(vm);
144     globalObject->Set(vm,
145         JSNApiHelper::ToLocal<StringRef>(globalConstants->GetHandledPandaString()),
146         JSNApiHelper::ToLocal<JSValueRef>(pandaObject));
147 
148     JSHandle<JSTaggedValue> promiseFunc = env->GetPromiseFunction();
149     JSHandle<JSPromise> jsPromise =
150         JSHandle<JSPromise>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(promiseFunc), promiseFunc));
151     JSHandle<ResolvingFunctionsRecord> resolvingFunctions =
152         JSPromise::CreateResolvingFunctions(thread, jsPromise);
153     JSHandle<JSPromiseReactionsFunction> resolve(thread, resolvingFunctions->GetResolveFunction(thread));
154     JSHandle<JSPromiseReactionsFunction> reject(thread, resolvingFunctions->GetRejectFunction(thread));
155     JSHandle<JSTaggedValue> dirPath(factory->NewFromASCII("./main.abc"));
156     JSHandle<JSTaggedValue> specifier(factory->NewFromASCII("exportFile"));
157     auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 14);
158     Local<JSValueRef> contextValue = JSNApi::GetCurrentContext(vm);
159     JSHandle<LexicalEnv> lexicalEnv(JSNApiHelper::ToJSHandle(contextValue));
160     JSHandle<JSFunction> funHandle = factory->NewJSFunction(env);
161     funHandle->SetLexicalEnv(thread, lexicalEnv.GetTaggedValue());
162     ecmaRuntimeCallInfo->SetFunction(funHandle.GetTaggedValue());
163     ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
164     ecmaRuntimeCallInfo->SetCallArg(0, resolve.GetTaggedValue());
165     ecmaRuntimeCallInfo->SetCallArg(1, reject.GetTaggedValue());
166     ecmaRuntimeCallInfo->SetCallArg(2, dirPath.GetTaggedValue());
167     ecmaRuntimeCallInfo->SetCallArg(3, specifier.GetTaggedValue());
168     ecmaRuntimeCallInfo->SetCallArg(4, JSTaggedValue::Undefined());
169     [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo);
170     BuiltinsPromiseJob::DynamicImportJob(ecmaRuntimeCallInfo);
171     TestHelper::TearDownFrame(thread, prev);
172     JSHandle<JSTaggedValue> error(thread, jsPromise->GetPromiseResult(thread));
173     JSHandle<JSTaggedValue> code(factory->NewFromASCII("code"));
174     JSHandle<JSTaggedValue> message = JSTaggedValue::GetProperty(thread, error, code).GetValue();
175     EXPECT_EQ(JSTaggedValue::SameValue(thread, message, specifier), true);
176     thread->ClearException();
177 }
178 }
179