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 #include "libpandafile/class_data_accessor-inl.h"
19 #include "libziparchive/zip_archive.h"
20
21 #include "ecmascript/global_env.h"
22 #include "ecmascript/jspandafile/js_pandafile.h"
23 #include "ecmascript/jspandafile/js_pandafile_manager.h"
24 #include "ecmascript/jspandafile/program_object.h"
25 #include "ecmascript/tests/test_helper.h"
26
27 using namespace panda::ecmascript;
28 using namespace panda::panda_file;
29 using namespace panda::pandasm;
30
31 namespace panda::test {
32 class JSPandaFileManagerTest : public testing::Test {
33 public:
SetUpTestCase()34 static void SetUpTestCase()
35 {
36 GTEST_LOG_(INFO) << "SetUpTestCase";
37 }
38
TearDownTestCase()39 static void TearDownTestCase()
40 {
41 GTEST_LOG_(INFO) << "TearDownCase";
42 }
43
SetUp()44 void SetUp() override
45 {
46 TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
47 }
48
TearDown()49 void TearDown() override
50 {
51 TestHelper::DestroyEcmaVMWithScope(instance, scope);
52 }
53
54 EcmaVM *instance {nullptr};
55 EcmaHandleScope *scope {nullptr};
56 JSThread *thread {nullptr};
57 };
58
HWTEST_F_L0(JSPandaFileManagerTest,GetInstance)59 HWTEST_F_L0(JSPandaFileManagerTest, GetInstance)
60 {
61 JSPandaFileManager *manager = JSPandaFileManager::GetInstance();
62 EXPECT_TRUE(manager != nullptr);
63 }
64
HWTEST_F_L0(JSPandaFileManagerTest,NewJSPandaFile)65 HWTEST_F_L0(JSPandaFileManagerTest, NewJSPandaFile)
66 {
67 Parser parser;
68 std::string fileName = "__JSPandaFileManagerTest.pa";
69 const char *source = R"(
70 .function void foo() {}
71 )";
72 auto res = parser.Parse(source, fileName);
73 EXPECT_EQ(parser.ShowError().err, Error::ErrorType::ERR_NONE);
74
75 std::unique_ptr<const File> pfPtr = pandasm::AsmEmitter::Emit(res.Value());
76 JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance();
77 JSPandaFile *pf = pfManager->NewJSPandaFile(pfPtr.release(), CString(fileName.c_str()));
78 EXPECT_TRUE(pf != nullptr);
79
80 auto expectFileName = pf->GetJSPandaFileDesc();
81 EXPECT_STREQ(expectFileName.c_str(), "__JSPandaFileManagerTest.pa");
82 remove(fileName.c_str());
83 JSPandaFileManager::RemoveJSPandaFile(pf);
84 }
85
HWTEST_F_L0(JSPandaFileManagerTest,OpenJSPandaFile)86 HWTEST_F_L0(JSPandaFileManagerTest, OpenJSPandaFile)
87 {
88 const char *filename = "__JSPandaFileManagerTest.pa";
89 const char *data = R"(
90 .function void foo() {}
91 )";
92 JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance();
93 JSPandaFile *ojspf = pfManager->OpenJSPandaFile(filename);
94 EXPECT_TRUE(ojspf == nullptr);
95
96 Parser parser;
97 auto res = parser.Parse(data);
98 EXPECT_TRUE(pandasm::AsmEmitter::Emit(filename, res.Value()));
99
100 ojspf = pfManager->OpenJSPandaFile(filename);
101 EXPECT_TRUE(ojspf != nullptr);
102 EXPECT_STREQ(ojspf->GetJSPandaFileDesc().c_str(), "__JSPandaFileManagerTest.pa");
103 JSPandaFileManager::RemoveJSPandaFile(ojspf);
104
105 remove(filename);
106 ojspf = pfManager->OpenJSPandaFile(filename);
107 EXPECT_TRUE(ojspf == nullptr);
108 }
109
HWTEST_F_L0(JSPandaFileManagerTest,Insert_Find_Remove_JSPandaFile)110 HWTEST_F_L0(JSPandaFileManagerTest, Insert_Find_Remove_JSPandaFile)
111 {
112 const char *filename1 = "__JSPandaFileManagerTest1.pa";
113 const char *filename2 = "__JSPandaFileManagerTest2.pa";
114 const char *data = R"(
115 .function void foo() {}
116 )";
117 JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance();
118 Parser parser;
119 auto res = parser.Parse(data);
120 std::unique_ptr<const File> pfPtr1 = pandasm::AsmEmitter::Emit(res.Value());
121 std::unique_ptr<const File> pfPtr2 = pandasm::AsmEmitter::Emit(res.Value());
122 JSPandaFile *pf1 = pfManager->NewJSPandaFile(pfPtr1.release(), CString(filename1));
123 JSPandaFile *pf2 = pfManager->NewJSPandaFile(pfPtr2.release(), CString(filename2));
124 pfManager->InsertJSPandaFile(pf1);
125 pfManager->InsertJSPandaFile(pf2);
126 const JSPandaFile *foundPf1 = pfManager->FindJSPandaFile(filename1);
127 const JSPandaFile *foundPf2 = pfManager->FindJSPandaFile(filename2);
128 EXPECT_STREQ(foundPf1->GetJSPandaFileDesc().c_str(), "__JSPandaFileManagerTest1.pa");
129 EXPECT_STREQ(foundPf2->GetJSPandaFileDesc().c_str(), "__JSPandaFileManagerTest2.pa");
130
131 pfManager->RemoveJSPandaFile((void *)pf1);
132 pfManager->RemoveJSPandaFile((void *)pf2);
133 const JSPandaFile *afterRemovePf1 = pfManager->FindJSPandaFile(filename1);
134 const JSPandaFile *afterRemovePf2 = pfManager->FindJSPandaFile(filename2);
135 EXPECT_EQ(afterRemovePf1, nullptr);
136 EXPECT_EQ(afterRemovePf2, nullptr);
137 }
138
HWTEST_F_L0(JSPandaFileManagerTest,LoadJSPandaFile)139 HWTEST_F_L0(JSPandaFileManagerTest, LoadJSPandaFile)
140 {
141 const char *filename1 = "__JSPandaFileManagerTest1.pa";
142 const char *filename2 = "__JSPandaFileManagerTest2.pa";
143 const char *data = R"(
144 .function void foo() {}
145 )";
146 JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance();
147 Parser parser;
148 auto res = parser.Parse(data);
149 std::unique_ptr<const File> pfPtr1 = pandasm::AsmEmitter::Emit(res.Value());
150 std::unique_ptr<const File> pfPtr2 = pandasm::AsmEmitter::Emit(res.Value());
151 JSPandaFile *pf1 = pfManager->NewJSPandaFile(pfPtr1.release(), CString(filename1));
152 JSPandaFile *pf2 = pfManager->NewJSPandaFile(pfPtr2.release(), CString(filename2));
153 pfManager->InsertJSPandaFile(pf1);
154 pfManager->InsertJSPandaFile(pf2);
155 const JSPandaFile *loadedPf1 = pfManager->LoadJSPandaFile(thread, filename1, JSPandaFile::ENTRY_MAIN_FUNCTION);
156 const JSPandaFile *loadedPf2 =
157 pfManager->LoadJSPandaFile(thread, filename2, JSPandaFile::ENTRY_MAIN_FUNCTION, (void *)data, sizeof(data));
158 EXPECT_TRUE(loadedPf1 != nullptr);
159 EXPECT_TRUE(loadedPf2 != nullptr);
160 EXPECT_STREQ(loadedPf1->GetJSPandaFileDesc().c_str(), "__JSPandaFileManagerTest1.pa");
161 EXPECT_STREQ(loadedPf2->GetJSPandaFileDesc().c_str(), "__JSPandaFileManagerTest2.pa");
162
163 pfManager->RemoveJSPandaFile((void *)pf1);
164 pfManager->RemoveJSPandaFile((void *)pf2);
165 pfManager->RemoveJSPandaFile((void *)loadedPf1);
166 pfManager->RemoveJSPandaFile((void *)loadedPf2);
167 }
168
HWTEST_F_L0(JSPandaFileManagerTest,GenerateProgram)169 HWTEST_F_L0(JSPandaFileManagerTest, GenerateProgram)
170 {
171 Parser parser;
172 auto vm = thread->GetEcmaVM();
173 const char *filename = "__JSPandaFileManagerTest.pa";
174 const uint8_t *typeDesc = utf::CStringAsMutf8("L_GLOBAL;");
175 const char *data = R"(
176 .function void foo() {}
177 )";
178 auto res = parser.Parse(data);
179 JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance();
180 std::unique_ptr<const File> pfPtr = pandasm::AsmEmitter::Emit(res.Value());
181 JSPandaFile *pf = pfManager->NewJSPandaFile(pfPtr.release(), CString(filename));
182 const File *file = pf->GetPandaFile();
183 File::EntityId class_id = file->GetClassId(typeDesc);
184 ClassDataAccessor cda(*file, class_id);
185 std::vector<File::EntityId> methodId {};
186 cda.EnumerateMethods([&](panda_file::MethodDataAccessor &mda) {
187 methodId.push_back(mda.GetMethodId());
188 });
189 pf->UpdateMainMethodIndex(methodId[0].GetOffset());
190 MethodLiteral method(pf, methodId[0]);
191 pf->SetMethodLiteralToMap(&method);
192 pfManager->InsertJSPandaFile(pf);
193
194 JSHandle<ecmascript::Program> program = pfManager->GenerateProgram(vm, pf, JSPandaFile::ENTRY_FUNCTION_NAME);
195 JSHandle<JSFunction> mainFunc(thread, program->GetMainFunction());
196 JSHandle<JSTaggedValue> funcName = JSFunction::GetFunctionName(thread, JSHandle<JSFunctionBase>(mainFunc));
197 EXPECT_STREQ(EcmaStringAccessor(JSHandle<EcmaString>::Cast(funcName)).ToCString().c_str(), "foo");
198
199 pfManager->RemoveJSPandaFile((void *)pf);
200 }
201
HWTEST_F_L0(JSPandaFileManagerTest,GetJSPtExtractor)202 HWTEST_F_L0(JSPandaFileManagerTest, GetJSPtExtractor)
203 {
204 const char *filename = "__JSPandaFileManagerTest.pa";
205 const char *data = R"(
206 .function void foo() {}
207 )";
208 Parser parser;
209 auto res = parser.Parse(data);
210 JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance();
211 std::unique_ptr<const File> pfPtr = pandasm::AsmEmitter::Emit(res.Value());
212 JSPandaFile *pf = pfManager->NewJSPandaFile(pfPtr.release(), CString(filename));
213 pfManager->InsertJSPandaFile(pf);
214 DebugInfoExtractor *extractor = pfManager->GetJSPtExtractor(pf);
215 EXPECT_TRUE(extractor != nullptr);
216
217 pfManager->RemoveJSPandaFile((void *)pf);
218 }
219
HWTEST_F_L0(JSPandaFileManagerTest,EnumerateJSPandaFiles)220 HWTEST_F_L0(JSPandaFileManagerTest, EnumerateJSPandaFiles)
221 {
222 const char *filename1 = "__JSPandaFileManagerTest3.pa";
223 const char *filename2 = "__JSPandaFileManagerTest4.pa";
224 const char *data = R"(
225 .function void foo() {}
226 )";
227 Parser parser;
228 auto res = parser.Parse(data);
229 JSPandaFileManager *pfManager = JSPandaFileManager::GetInstance();
230 std::unique_ptr<const File> pfPtr1 = pandasm::AsmEmitter::Emit(res.Value());
231 std::unique_ptr<const File> pfPtr2 = pandasm::AsmEmitter::Emit(res.Value());
232 JSPandaFile *pf1 = pfManager->NewJSPandaFile(pfPtr1.release(), CString(filename1));
233 JSPandaFile *pf2 = pfManager->NewJSPandaFile(pfPtr2.release(), CString(filename2));
234 pfManager->InsertJSPandaFile(pf1);
235 pfManager->InsertJSPandaFile(pf2);
236 std::vector<CString> descList{};
237 int count = 0;
238 pfManager->EnumerateJSPandaFiles([&](const JSPandaFile *file) -> bool {
239 auto desc = file->GetJSPandaFileDesc();
240 descList.push_back(desc);
241 count++;
242 return true;
243 });
244 EXPECT_EQ(count, 2); // 2 : test number of files
245 // Sort by the hash value of the element, the output is unordered
246 EXPECT_STREQ(descList[0].c_str(), "__JSPandaFileManagerTest4.pa");
247 EXPECT_STREQ(descList[1].c_str(), "__JSPandaFileManagerTest3.pa");
248
249 pfManager->RemoveJSPandaFile((void *)pf1);
250 pfManager->RemoveJSPandaFile((void *)pf2);
251 }
252 } // namespace panda::test
253