1 /*
2 * Copyright (c) 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 "assembler/assembly-emitter.h"
17 #include "assembler/assembly-parser.h"
18
19 #include "ecmascript/jspandafile/js_pandafile.h"
20 #include "ecmascript/jspandafile/js_pandafile_manager.h"
21 #include "ecmascript/jspandafile/quick_fix_manager.h"
22 #include "ecmascript/tests/test_helper.h"
23 #include "ecmascript/napi/include/jsnapi.h"
24
25 using namespace panda::ecmascript;
26 using namespace panda::panda_file;
27 using namespace panda::pandasm;
28
29 namespace panda::test {
30 class QuickFixTest : public testing::Test {
31 public:
SetUpTestCase()32 static void SetUpTestCase()
33 {
34 GTEST_LOG_(INFO) << "SetUpTestCase";
35 }
36
TearDownTestCase()37 static void TearDownTestCase()
38 {
39 GTEST_LOG_(INFO) << "TearDownCase";
40 }
41
SetUp()42 void SetUp() override
43 {
44 TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
45 }
46
TearDown()47 void TearDown() override
48 {
49 TestHelper::DestroyEcmaVMWithScope(instance, scope);
50 }
51
52 EcmaVM *instance {nullptr};
53 EcmaHandleScope *scope {nullptr};
54 JSThread *thread {nullptr};
55 };
56
HWTEST_F_L0(QuickFixTest,HotReload_SingleFile)57 HWTEST_F_L0(QuickFixTest, HotReload_SingleFile)
58 {
59 std::string baseFileName = QUICKFIX_ABC_PATH "single_file/base/index.abc";
60 std::string patchFileName = QUICKFIX_ABC_PATH "single_file/patch/index.abc";
61
62 JSNApi::EnableUserUncaughtErrorHandler(instance);
63
64 JSNApi::SetBundle(instance, false);
65
66 bool result = JSNApi::Execute(instance, baseFileName, "index");
67 EXPECT_TRUE(result);
68
69 result = JSNApi::LoadPatch(instance, patchFileName, baseFileName);
70 EXPECT_TRUE(result);
71
72 Local<ObjectRef> exception = JSNApi::GetAndClearUncaughtException(instance);
73 result = JSNApi::IsQuickFixCausedException(instance, exception, patchFileName);
74 EXPECT_FALSE(result);
75
76 result = JSNApi::UnloadPatch(instance, patchFileName);
77 EXPECT_TRUE(result);
78 }
79
HWTEST_F_L0(QuickFixTest,HotReload_MultiFile)80 HWTEST_F_L0(QuickFixTest, HotReload_MultiFile)
81 {
82 std::string baseFileName = QUICKFIX_ABC_PATH "multi_file/base/merge.abc";
83 std::string patchFileName = QUICKFIX_ABC_PATH "multi_file/patch/merge.abc";
84
85 JSNApi::EnableUserUncaughtErrorHandler(instance);
86
87 JSNApi::SetBundle(instance, false);
88
89 bool result = JSNApi::Execute(instance, baseFileName, "index");
90 EXPECT_TRUE(result);
91
92 result = JSNApi::LoadPatch(instance, patchFileName, baseFileName);
93 EXPECT_TRUE(result);
94
95 Local<ObjectRef> exception = JSNApi::GetAndClearUncaughtException(instance);
96 result = JSNApi::IsQuickFixCausedException(instance, exception, patchFileName);
97 EXPECT_FALSE(result);
98
99 result = JSNApi::UnloadPatch(instance, patchFileName);
100 EXPECT_TRUE(result);
101 }
102
HWTEST_F_L0(QuickFixTest,HotReload_Buffer)103 HWTEST_F_L0(QuickFixTest, HotReload_Buffer)
104 {
105 const char *baseFileName = "__base.pa";
106 const char *patchFileName = "__patch.pa";
107 const char *data = R"(
108 .function void foo() {}
109 )";
110
111 JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance();
112 Parser parser;
113 auto res = parser.Parse(data);
114 std::unique_ptr<const File> basePF = pandasm::AsmEmitter::Emit(res.Value());
115 std::unique_ptr<const File> patchPF = pandasm::AsmEmitter::Emit(res.Value());
116 JSPandaFile *baseFile = pfManager->NewJSPandaFile(basePF.release(), CString(baseFileName));
117 JSPandaFile *patchFile = pfManager->NewJSPandaFile(patchPF.release(), CString(patchFileName));
118 pfManager->InsertJSPandaFile(baseFile);
119 pfManager->InsertJSPandaFile(patchFile);
120
121 bool result = JSNApi::LoadPatch(instance, patchFileName, (void *)data, sizeof(data), baseFileName);
122 EXPECT_FALSE(result);
123
124 pfManager->RemoveJSPandaFile((void *)baseFile);
125 pfManager->RemoveJSPandaFile((void *)patchFile);
126 }
127
QuickFixQueryFunc(std::string baseFileName,std::string & patchFileName,void ** patchBuffer,size_t patchBufferSize)128 bool QuickFixQueryFunc(
129 std::string baseFileName, std::string &patchFileName, void ** patchBuffer, size_t patchBufferSize)
130 {
131 if (baseFileName != QUICKFIX_ABC_PATH "multi_file/base/merge.abc") {
132 return false;
133 }
134
135 patchFileName = "__index.pa";
136 const char *data = R"(
137 .function void foo() {}
138 )";
139
140 Parser parser;
141 auto res = parser.Parse(data);
142 std::unique_ptr<const File> patchPF = pandasm::AsmEmitter::Emit(res.Value());
143 JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance();
144 JSPandaFile *patchFile = pfManager->NewJSPandaFile(patchPF.release(), patchFileName.c_str());
145 pfManager->InsertJSPandaFile(patchFile);
146 patchBuffer = (void **) data;
147 patchBufferSize = sizeof(data);
148 return true;
149 }
150
HWTEST_F_L0(QuickFixTest,HotReload_RegisterQuickFixQueryFunc)151 HWTEST_F_L0(QuickFixTest, HotReload_RegisterQuickFixQueryFunc)
152 {
153 std::string baseFileName = QUICKFIX_ABC_PATH "multi_file/base/merge.abc";
154 std::string patchFileName = "__index.pa";
155 JSNApi::RegisterQuickFixQueryFunc(instance, QuickFixQueryFunc);
156
157 QuickFixManager *quickFixManager = instance->GetQuickFixManager();
158 quickFixManager->LoadPatchIfNeeded(thread, baseFileName);
159
160 const JSPandaFile *baseFile = JSPandaFileManager::GetInstance()->FindJSPandaFile(baseFileName.c_str());
161 const JSPandaFile *patchFile = JSPandaFileManager::GetInstance()->FindJSPandaFile(patchFileName.c_str());
162 EXPECT_TRUE(baseFile != nullptr);
163 EXPECT_TRUE(patchFile != nullptr);
164
165 JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance();
166 pfManager->RemoveJSPandaFile((void *)baseFile);
167 pfManager->RemoveJSPandaFile((void *)patchFile);
168 }
169 } // namespace panda::test
170