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/module/js_module_manager.h"
18 #include "ecmascript/module/js_module_source_text.h"
19 #include "ecmascript/module/module_snapshot.h"
20 #include "ecmascript/module/module_value_accessor.h"
21 #include "ecmascript/tests/test_helper.h"
22
23 using namespace panda::ecmascript;
24 namespace panda::test {
25 class MockModuleSnapshot : public ModuleSnapshot {
26 public:
SerializeDataAndSaving(const EcmaVM * vm,const CString & path,const CString & version)27 static bool SerializeDataAndSaving(const EcmaVM *vm, const CString &path, const CString &version)
28 {
29 CString filePath = base::ConcatToCString(path, MODULE_SNAPSHOT_FILE_NAME);
30 if (FileExist(filePath.c_str())) {
31 LOG_ECMA(INFO) << "Module serialize file already exist";
32 return false;
33 }
34 JSThread *thread = vm->GetJSThread();
35 std::unique_ptr<SerializeData> serializeData = GetSerializeData(thread);
36 if (serializeData == nullptr) {
37 return false;
38 }
39 return WriteDataToFile(thread, serializeData, filePath, version);
40 }
MockSerializeAndSavingBufferEmpty(const EcmaVM * vm,const CString & path,const CString & version)41 static bool MockSerializeAndSavingBufferEmpty(const EcmaVM *vm, const CString &path, const CString &version)
42 {
43 CString filePath = base::ConcatToCString(path, MODULE_SNAPSHOT_FILE_NAME);
44 JSThread *thread = vm->GetJSThread();
45 std::unique_ptr<SerializeData> serializeData = GetSerializeData(thread);
46 serializeData->SetBuffer(nullptr);
47 if (serializeData == nullptr) {
48 return false;
49 }
50 return WriteDataToFile(thread, serializeData, filePath, version);
51 }
MockSerializeAndSavingHasIncompleteData(const EcmaVM * vm,const CString & path,const CString & version)52 static bool MockSerializeAndSavingHasIncompleteData(const EcmaVM *vm, const CString &path, const CString &version)
53 {
54 CString filePath = base::ConcatToCString(path, MODULE_SNAPSHOT_FILE_NAME);
55 JSThread *thread = vm->GetJSThread();
56 std::unique_ptr<SerializeData> serializeData = GetSerializeData(thread);
57 serializeData->SetIncompleteData(true);
58 if (serializeData == nullptr) {
59 return false;
60 }
61 return WriteDataToFile(thread, serializeData, filePath, version);
62 }
63 };
64 class ModuleSnapshotTest : public testing::Test {
65 public:
SetUpTestCase()66 static void SetUpTestCase()
67 {
68 GTEST_LOG_(INFO) << "SetUpTestCase";
69 }
70
TearDownTestCase()71 static void TearDownTestCase()
72 {
73 GTEST_LOG_(INFO) << "TearDownCase";
74 }
75
SetUp()76 void SetUp() override
77 {
78 CString path = GetSnapshotPath();
79 CString fileName = path + ModuleSnapshot::MODULE_SNAPSHOT_FILE_NAME.data();
80 if (remove(fileName.c_str()) != 0) {
81 GTEST_LOG_(ERROR) << "remove " << fileName << " failed";
82 }
83 TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
84 }
85
TearDown()86 void TearDown() override
87 {
88 CString path = GetSnapshotPath();
89 CString fileName = path + ModuleSnapshot::MODULE_SNAPSHOT_FILE_NAME.data();
90 if (remove(fileName.c_str()) != 0) {
91 GTEST_LOG_(ERROR) << "remove " << fileName << " failed";
92 }
93 TestHelper::DestroyEcmaVMWithScope(instance, scope);
94 }
95
GetSnapshotPath()96 static CString GetSnapshotPath()
97 {
98 char buff[FILENAME_MAX];
99 getcwd(buff, FILENAME_MAX);
100 CString currentPath(buff);
101 if (currentPath.back() != '/') {
102 currentPath += "/";
103 }
104 return currentPath;
105 }
106
InitEntries(JSHandle<SourceTextModule> module) const107 void InitEntries(JSHandle<SourceTextModule> module) const
108 {
109 ObjectFactory *objectFactory = thread->GetEcmaVM()->GetFactory();
110 JSHandle<JSTaggedValue> val = JSHandle<JSTaggedValue>::Cast(objectFactory->NewFromUtf8("val"));
111 size_t importEntryArrayLen = 2;
112 JSHandle<JSTaggedValue> importName = val;
113 JSHandle<JSTaggedValue> localName = val;
114 JSHandle<ImportEntry> importEntry1 =
115 objectFactory->NewImportEntry(index0, importName, localName, SharedTypes::UNSENDABLE_MODULE);
116 SourceTextModule::AddImportEntry(thread, module, importEntry1, index0, importEntryArrayLen);
117 JSHandle<JSTaggedValue> starString = thread->GlobalConstants()->GetHandledStarString();
118 JSHandle<ImportEntry> importEntry2 =
119 objectFactory->NewImportEntry(index1, starString, localName, SharedTypes::UNSENDABLE_MODULE);
120 SourceTextModule::AddImportEntry(thread, module, importEntry2, index1, importEntryArrayLen);
121
122 size_t localExportEntryLen = 1;
123 JSHandle<LocalExportEntry> localExportEntry =
124 objectFactory->NewLocalExportEntry(val, val, index0, SharedTypes::UNSENDABLE_MODULE);
125 JSHandle<TaggedArray> localExportEntries = objectFactory->NewTaggedArray(localExportEntryLen);
126 localExportEntries->Set(thread, index0, localExportEntry);
127 SourceTextModule::AddLocalExportEntry(thread, module, localExportEntry, index0, localExportEntryLen);
128
129 size_t indirectExportEntryLen = 1;
130 JSHandle<IndirectExportEntry> indirectExportEntry =
131 objectFactory->NewIndirectExportEntry(val, index0, val, SharedTypes::UNSENDABLE_MODULE);
132 JSHandle<TaggedArray> indirectExportEntries = objectFactory->NewTaggedArray(indirectExportEntryLen);
133 indirectExportEntries->Set(thread, index0, indirectExportEntry);
134 module->SetIndirectExportEntries(thread, indirectExportEntries);
135 }
136
InitEnv(JSHandle<SourceTextModule> module,JSHandle<SourceTextModule> bindingModule) const137 void InitEnv(JSHandle<SourceTextModule> module, JSHandle<SourceTextModule> bindingModule) const
138 {
139 ObjectFactory *objectFactory = thread->GetEcmaVM()->GetFactory();
140 size_t environmentArraySize = 4;
141 JSHandle<TaggedArray> environmentArray = objectFactory->NewTaggedArray(environmentArraySize);
142 // sendable binding
143 JSHandle<EcmaString> recordNameHdl = objectFactory->NewFromUtf8("sendable binding recordName");
144 JSHandle<EcmaString> baseFileNameHdl = objectFactory->NewFromUtf8("sendable binding baseFileNameHdl");
145 JSHandle<ResolvedRecordIndexBinding> recordIndexBinding =
146 objectFactory->NewSResolvedRecordIndexBindingRecord(recordNameHdl, baseFileNameHdl, index0);
147 environmentArray->Set(thread, index0, recordIndexBinding.GetTaggedValue());
148
149 JSHandle<JSTaggedValue> val2 = JSHandle<JSTaggedValue>::Cast(objectFactory->NewFromUtf8("val2"));
150 JSHandle<ResolvedRecordBinding> nameBinding =
151 objectFactory->NewSResolvedRecordBindingRecord(recordNameHdl, val2);
152 environmentArray->Set(thread, index1, nameBinding.GetTaggedValue());
153 // mormal binding
154 JSHandle<ResolvedBinding> resolvedBinding = objectFactory->NewResolvedBindingRecord(bindingModule, val2);
155 environmentArray->Set(thread, index2, resolvedBinding.GetTaggedValue());
156 JSHandle<ResolvedIndexBinding> resolvedIndexBinding =
157 objectFactory->NewResolvedIndexBindingRecord(bindingModule, index0);
158 environmentArray->Set(thread, index3, resolvedIndexBinding.GetTaggedValue());
159 module->SetEnvironment(thread, environmentArray);
160 }
161
InitMockSourceTextModule() const162 void InitMockSourceTextModule() const
163 {
164 auto vm = thread->GetEcmaVM();
165 ObjectFactory *objectFactory = vm->GetFactory();
166 JSHandle<SourceTextModule> module = objectFactory->NewSourceTextModule();
167 CString baseFileName = "modules.abc";
168 CString recordName = "a";
169 module->SetEcmaModuleFilenameString(baseFileName);
170 module->SetEcmaModuleRecordNameString(recordName);
171 module->SetTypes(ModuleTypes::ECMA_MODULE);
172 module->SetStatus(ModuleStatus::INSTANTIATED);
173 JSHandle<TaggedArray> requestedModules = objectFactory->NewTaggedArray(1);
174 module->SetRequestedModules(thread, requestedModules.GetTaggedValue());
175 JSHandle<SourceTextModule> module1 = objectFactory->NewSourceTextModule();
176 CString recordName1 = "b";
177 module1->SetEcmaModuleFilenameString(baseFileName);
178 module1->SetEcmaModuleRecordNameString(recordName1);
179 requestedModules->Set(thread, index0, module1);
180 JSHandle<SourceTextModule> module2 = objectFactory->NewSourceTextModule();
181 CString recordName2 = "c";
182 module2->SetEcmaModuleFilenameString(baseFileName);
183 module2->SetEcmaModuleRecordNameString(recordName2);
184 module2->SetStatus(ModuleStatus::EVALUATED);
185
186 InitEntries(module);
187 InitEnv(module, module2);
188
189 thread->GetModuleManager()->AddResolveImportedModule(recordName, module.GetTaggedValue());
190 thread->GetModuleManager()->AddResolveImportedModule(recordName1, module1.GetTaggedValue());
191 thread->GetModuleManager()->AddResolveImportedModule(recordName2, module2.GetTaggedValue());
192 }
193
CheckEntries(JSHandle<SourceTextModule> serializeModule,JSHandle<SourceTextModule> deserializeModule) const194 void CheckEntries(JSHandle<SourceTextModule> serializeModule, JSHandle<SourceTextModule> deserializeModule) const
195 {
196 // check import entry
197 if (!serializeModule->GetImportEntries(thread).IsUndefined() &&
198 !deserializeModule->GetImportEntries(thread).IsUndefined()) {
199 JSHandle<TaggedArray> serializeImportArray(thread, serializeModule->GetImportEntries(thread));
200 JSHandle<TaggedArray> deserializeImportArray(thread, deserializeModule->GetImportEntries(thread));
201 ASSERT_EQ(serializeImportArray->GetLength(), deserializeImportArray->GetLength());
202 for (size_t i = 0; i < serializeImportArray->GetLength(); i++) {
203 JSHandle<ImportEntry> serializeEntry(thread, serializeImportArray->Get(thread, i));
204 JSHandle<ImportEntry> deserializeEntry(thread, deserializeImportArray->Get(thread, i));
205 EXPECT_EQ(serializeEntry->GetModuleRequestIndex(), deserializeEntry->GetModuleRequestIndex());
206 EXPECT_EQ(serializeEntry->GetImportName(thread), deserializeEntry->GetImportName(thread));
207 EXPECT_EQ(serializeEntry->GetLocalName(thread), deserializeEntry->GetLocalName(thread));
208 }
209 }
210
211 // check local export entry
212 if (!serializeModule->GetLocalExportEntries(thread).IsUndefined() &&
213 !deserializeModule->GetLocalExportEntries(thread).IsUndefined()) {
214 JSHandle<TaggedArray> serializeEntries(thread, serializeModule->GetLocalExportEntries(thread));
215 JSHandle<TaggedArray> deserializeEntries(thread, deserializeModule->GetLocalExportEntries(thread));
216 ASSERT_EQ(serializeEntries->GetLength(), deserializeEntries->GetLength());
217 for (size_t i = 0; i < serializeEntries->GetLength(); i++) {
218 JSHandle<LocalExportEntry> serializeEntry(thread, serializeEntries->Get(thread, i));
219 JSHandle<LocalExportEntry> deserializeEntry(thread, deserializeEntries->Get(thread, i));
220 EXPECT_EQ(serializeEntry->GetLocalIndex(), deserializeEntry->GetLocalIndex());
221 EXPECT_EQ(serializeEntry->GetExportName(thread), deserializeEntry->GetExportName(thread));
222 EXPECT_EQ(serializeEntry->GetLocalName(thread), deserializeEntry->GetLocalName(thread));
223 }
224 }
225 // check indirect export entry
226 if (!serializeModule->GetIndirectExportEntries(thread).IsUndefined() &&
227 !deserializeModule->GetIndirectExportEntries(thread).IsUndefined()) {
228 JSHandle<TaggedArray> serializeEntries(thread, serializeModule->GetIndirectExportEntries(thread));
229 JSHandle<TaggedArray> deserializeEntries(thread, deserializeModule->GetIndirectExportEntries(thread));
230 ASSERT_EQ(serializeEntries->GetLength(), deserializeEntries->GetLength());
231 for (size_t i = 0; i < serializeEntries->GetLength(); i++) {
232 JSHandle<IndirectExportEntry> serializeEntry(thread, serializeEntries->Get(thread, i));
233 JSHandle<IndirectExportEntry> deserializeEntry(thread, deserializeEntries->Get(thread, i));
234 EXPECT_EQ(serializeEntry->GetModuleRequestIndex(), deserializeEntry->GetModuleRequestIndex());
235 EXPECT_EQ(serializeEntry->GetExportName(thread), deserializeEntry->GetExportName(thread));
236 EXPECT_EQ(serializeEntry->GetImportName(thread), deserializeEntry->GetImportName(thread));
237 }
238 }
239 }
240
CheckEnv(JSHandle<SourceTextModule> serializeModule,JSHandle<SourceTextModule> deserializeModule) const241 void CheckEnv(JSHandle<SourceTextModule> serializeModule, JSHandle<SourceTextModule> deserializeModule) const
242 {
243 if (!serializeModule->GetEnvironment(thread).IsUndefined() &&
244 !deserializeModule->GetEnvironment(thread).IsUndefined()) {
245 JSHandle<TaggedArray> serializeEnvironment(thread, serializeModule->GetEnvironment(thread));
246 JSHandle<TaggedArray> deserializeEnvironment(thread, deserializeModule->GetEnvironment(thread));
247 ASSERT_EQ(serializeEnvironment->GetLength(), deserializeEnvironment->GetLength());
248 for (size_t i = 0; i < serializeEnvironment->GetLength(); i++) {
249 JSTaggedValue serializeResolvedBinding = serializeEnvironment->Get(thread, i);
250 JSTaggedValue deserializeResolvedBinding = deserializeEnvironment->Get(thread, i);
251 if (serializeResolvedBinding.IsResolvedIndexBinding()) {
252 ASSERT_TRUE(serializeResolvedBinding.IsResolvedIndexBinding());
253 auto serializeBinding = ResolvedIndexBinding::Cast(serializeResolvedBinding.GetTaggedObject());
254 auto deserializeBinding = ResolvedIndexBinding::Cast(deserializeResolvedBinding.GetTaggedObject());
255 EXPECT_EQ(serializeBinding->GetIndex(), deserializeBinding->GetIndex());
256 JSHandle<SourceTextModule> seriBindingModule(thread, serializeBinding->GetModule(thread));
257 JSHandle<SourceTextModule> deSeriBindingModule(thread, deserializeBinding->GetModule(thread));
258 CheckModule(seriBindingModule, deSeriBindingModule);
259 } else if (serializeResolvedBinding.IsResolvedBinding()) {
260 ASSERT_TRUE(serializeResolvedBinding.IsResolvedBinding());
261 auto serializeBinding = ResolvedBinding::Cast(serializeResolvedBinding.GetTaggedObject());
262 auto deserializeBinding = ResolvedBinding::Cast(deserializeResolvedBinding.GetTaggedObject());
263 EXPECT_EQ(serializeBinding->GetBindingName(thread), deserializeBinding->GetBindingName(thread));
264 JSHandle<SourceTextModule> seriBindingModule(thread, serializeBinding->GetModule(thread));
265 JSHandle<SourceTextModule> deSeriBindingModule(thread, deserializeBinding->GetModule(thread));
266 CheckModule(seriBindingModule, deSeriBindingModule);
267 } else if (serializeResolvedBinding.IsResolvedRecordIndexBinding()) {
268 ASSERT_TRUE(serializeResolvedBinding.IsResolvedRecordIndexBinding());
269 auto serializeBinding =
270 ResolvedRecordIndexBinding::Cast(serializeResolvedBinding.GetTaggedObject());
271 auto deserializeBinding =
272 ResolvedRecordIndexBinding::Cast(deserializeResolvedBinding.GetTaggedObject());
273 EXPECT_EQ(serializeBinding->GetModuleRecord(thread), deserializeBinding->GetModuleRecord(thread));
274 EXPECT_EQ(serializeBinding->GetAbcFileName(thread), deserializeBinding->GetAbcFileName(thread));
275 EXPECT_EQ(serializeBinding->GetIndex(), deserializeBinding->GetIndex());
276 } else if (serializeResolvedBinding.IsResolvedRecordBinding()) {
277 ASSERT_TRUE(serializeResolvedBinding.IsResolvedRecordBinding());
278 auto serializeBinding = ResolvedRecordBinding::Cast(serializeResolvedBinding.GetTaggedObject());
279 auto deserializeBinding = ResolvedRecordBinding::Cast(deserializeResolvedBinding.GetTaggedObject());
280 EXPECT_EQ(serializeBinding->GetModuleRecord(thread), deserializeBinding->GetModuleRecord(thread));
281 EXPECT_EQ(serializeBinding->GetBindingName(thread), deserializeBinding->GetBindingName(thread));
282 }
283 }
284 }
285 }
286
CheckModule(JSHandle<SourceTextModule> serializeModule,JSHandle<SourceTextModule> deserializeModule) const287 void CheckModule(JSHandle<SourceTextModule> serializeModule, JSHandle<SourceTextModule> deserializeModule) const
288 {
289 EXPECT_EQ(serializeModule->GetEcmaModuleFilenameString(), deserializeModule->GetEcmaModuleFilenameString());
290 EXPECT_EQ(serializeModule->GetEcmaModuleRecordNameString(), deserializeModule->GetEcmaModuleRecordNameString());
291 EXPECT_EQ(serializeModule->GetTypes(), deserializeModule->GetTypes());
292 if (serializeModule->GetStatus() > ModuleStatus::INSTANTIATED) {
293 EXPECT_EQ(deserializeModule->GetStatus(), ModuleStatus::INSTANTIATED);
294 } else {
295 EXPECT_EQ(serializeModule->GetStatus(), deserializeModule->GetStatus());
296 }
297 // check request module
298 if (!serializeModule->GetRequestedModules(thread).IsUndefined() &&
299 !deserializeModule->GetRequestedModules(thread).IsUndefined()) {
300 JSHandle<TaggedArray> serializeRequestedModules(thread,
301 serializeModule->GetRequestedModules(thread));
302 JSHandle<TaggedArray> deserializeRequestedModules(thread,
303 deserializeModule->GetRequestedModules(thread));
304 ASSERT_EQ(serializeRequestedModules->GetLength(), deserializeRequestedModules->GetLength());
305 size_t requestModuleLen = serializeRequestedModules->GetLength();
306 for (size_t i = 0; i < requestModuleLen; i++) {
307 JSHandle<SourceTextModule> serializeImportModule(thread,
308 serializeRequestedModules->Get(thread, i));
309 JSHandle<SourceTextModule> deserializeImportModule(thread,
310 deserializeRequestedModules->Get(thread, i));
311 CheckModule(serializeImportModule, deserializeImportModule);
312 }
313 // check lazy array
314 for (size_t i = 0; i < requestModuleLen; i++) {
315 EXPECT_EQ(serializeModule->IsLazyImportModule(i), deserializeModule->IsLazyImportModule(i));
316 }
317 }
318 CheckEntries(serializeModule, deserializeModule);
319 CheckEnv(serializeModule, deserializeModule);
320 }
321
InitMockUpdateBindingModule(bool isDictionaryMode) const322 void InitMockUpdateBindingModule(bool isDictionaryMode) const
323 {
324 auto vm = thread->GetEcmaVM();
325 ObjectFactory *factory = vm->GetFactory();
326 JSHandle<SourceTextModule> etsModule = factory->NewSourceTextModule();
327 CString baseFileName = "modules.abc";
328 CString recordName = "etsModule";
329 etsModule->SetEcmaModuleFilenameString(baseFileName);
330 etsModule->SetEcmaModuleRecordNameString(recordName);
331 etsModule->SetTypes(ModuleTypes::ECMA_MODULE);
332 etsModule->SetStatus(ModuleStatus::INSTANTIATED);
333 JSHandle<TaggedArray> requestedModules = factory->NewTaggedArray(1);
334 etsModule->SetRequestedModules(thread, requestedModules.GetTaggedValue());
335 JSHandle<SourceTextModule> nativeModule = factory->NewSourceTextModule();
336 CString nativeModuleRecordName = "nativeModule";
337 nativeModule->SetEcmaModuleFilenameString(baseFileName);
338 nativeModule->SetEcmaModuleRecordNameString(nativeModuleRecordName);
339 nativeModule->SetTypes(ModuleTypes::APP_MODULE);
340 nativeModule->SetStatus(ModuleStatus::INSTANTIATED);
341 requestedModules->Set(thread, index0, nativeModule);
342 JSHandle<EcmaString> str = factory->NewFromStdString("nativeModuleValue");
343 size_t localExportEntryLen = 1;
344 JSHandle<JSTaggedValue> val = JSHandle<JSTaggedValue>::Cast(str);
345 JSHandle<LocalExportEntry> localExportEntry =
346 factory->NewLocalExportEntry(val, val, index0, SharedTypes::UNSENDABLE_MODULE);
347 SourceTextModule::AddLocalExportEntry(thread, nativeModule, localExportEntry, index0, localExportEntryLen);
348 JSHandle<JSTaggedValue> objFuncProto = vm->GetGlobalEnv()->GetObjectFunctionPrototype();
349 JSHandle<JSHClass> hClassHandle = factory->NewEcmaHClass(JSObject::SIZE, 0, JSType::JS_OBJECT, objFuncProto);
350 hClassHandle->SetIsDictionaryMode(isDictionaryMode);
351 JSHandle<JSObject> object = factory->NewJSObject(hClassHandle);
352 if (isDictionaryMode) {
353 JSMutableHandle<NameDictionary> dict(thread,
354 NameDictionary::Create(thread, NameDictionary::ComputeHashTableSize(1)));
355 dict->SetKey(thread, index0, str.GetTaggedValue());
356 object->SetProperties(thread, dict);
357 } else {
358 JSHandle<LayoutInfo> layoutInfo(thread, hClassHandle->GetLayout(thread));
359 JSHandle<TaggedArray>::Cast(layoutInfo)->Set(thread, layoutInfo->GetKeyIndex(index0), str.GetTaggedValue());
360 }
361 SourceTextModule::StoreModuleValue(thread, nativeModule, index0, JSHandle<JSTaggedValue>::Cast(object));
362 size_t environmentArraySize = 1;
363 JSHandle<TaggedArray> environmentArray = factory->NewTaggedArray(environmentArraySize);
364 JSHandle<ResolvedIndexBinding> resolvedIndexBinding =
365 factory->NewResolvedIndexBindingRecord(nativeModule, index0);
366 resolvedIndexBinding->SetIsUpdatedFromResolvedBinding(true);
367 environmentArray->Set(thread, index0, resolvedIndexBinding.GetTaggedValue());
368 etsModule->SetEnvironment(thread, environmentArray);
369 thread->GetModuleManager()->AddResolveImportedModule(recordName, etsModule.GetTaggedValue());
370 thread->GetModuleManager()->AddResolveImportedModule(nativeModuleRecordName, nativeModule.GetTaggedValue());
371 }
372
CheckRestoreUpdatedBindingBeforeSerialize(bool isDictionaryMode) const373 void CheckRestoreUpdatedBindingBeforeSerialize(bool isDictionaryMode) const
374 {
375 // construct Module
376 CString path = GetSnapshotPath();
377 CString fileName = path + ModuleSnapshot::MODULE_SNAPSHOT_FILE_NAME.data();
378 CString version = "version 205.0.1.120(SP20)";
379 EcmaVM *vm = thread->GetEcmaVM();
380 InitMockUpdateBindingModule(isDictionaryMode);
381 // the origin binding is indexBinding
382 ModuleManager *moduleManager = thread->GetModuleManager();
383 JSHandle<SourceTextModule> serializeModule = moduleManager->HostGetImportedModule("etsModule");
384 JSHandle<SourceTextModule> serializeNativeModule = moduleManager->HostGetImportedModule("nativeModule");
385 JSHandle<TaggedArray> serializeEnvironment(thread, serializeModule->GetEnvironment(thread));
386 JSTaggedValue serializeResolvedBinding = serializeEnvironment->Get(thread, index0);
387 ASSERT_TRUE(serializeResolvedBinding.IsResolvedIndexBinding());
388 auto serializeBinding = ResolvedIndexBinding::Cast(serializeResolvedBinding.GetTaggedObject());
389 ASSERT_TRUE(serializeBinding->GetIsUpdatedFromResolvedBinding());
390 ASSERT_EQ(serializeBinding->GetModule(thread), serializeNativeModule.GetTaggedValue());
391 // serialize and persist
392 ASSERT_TRUE(MockModuleSnapshot::SerializeDataAndSaving(vm, path, version));
393 // after serialize, indexBinding has been restore to binding
394 serializeResolvedBinding = serializeEnvironment->Get(thread, index0);
395 ASSERT_TRUE(serializeResolvedBinding.IsResolvedBinding());
396 auto newSerializeBinding = ResolvedBinding::Cast(serializeResolvedBinding.GetTaggedObject());
397 ASSERT_EQ(newSerializeBinding->GetModule(thread), serializeNativeModule.GetTaggedValue());
398 auto str = EcmaStringAccessor(newSerializeBinding->GetBindingName(thread)).Utf8ConvertToString(thread);
399 ASSERT_EQ(str, "nativeModuleValue");
400 moduleManager->ClearResolvedModules();
401 // deserialize
402 ASSERT_TRUE(ModuleSnapshot::DeserializeData(vm, path, version));
403 // deserializeModule stored binding
404 JSHandle<SourceTextModule> deserializeModule = moduleManager->HostGetImportedModule("etsModule");
405 JSHandle<SourceTextModule> deserializeNativeModule = moduleManager->HostGetImportedModule("nativeModule");
406 JSHandle<TaggedArray> deserializeEnvironment(thread, deserializeModule->GetEnvironment(thread));
407 ASSERT_EQ(serializeEnvironment->GetLength(), deserializeEnvironment->GetLength());
408 JSTaggedValue deserializeResolvedBinding = deserializeEnvironment->Get(thread, index0);
409 ASSERT_TRUE(deserializeResolvedBinding.IsResolvedBinding());
410 auto deserializeBinding = ResolvedBinding::Cast(deserializeResolvedBinding.GetTaggedObject());
411 ASSERT_EQ(deserializeBinding->GetModule(thread), deserializeNativeModule.GetTaggedValue());
412 str = EcmaStringAccessor(deserializeBinding->GetBindingName(thread)).Utf8ConvertToString(thread);
413 ASSERT_EQ(str, "nativeModuleValue");
414 }
415
416 EcmaVM *instance {nullptr};
417 EcmaHandleScope *scope {nullptr};
418 JSThread *thread {nullptr};
419 size_t index0 { 0 };
420 size_t index1 { 1 };
421 size_t index2 { 2 };
422 size_t index3 { 3 };
423 };
424
HWTEST_F_L0(ModuleSnapshotTest,SerializeAndDeserializeTest)425 HWTEST_F_L0(ModuleSnapshotTest, SerializeAndDeserializeTest)
426 {
427 // construct JSPandaFile
428 CString path = GetSnapshotPath();
429 CString version = "version 205.0.1.120(SP20)";
430 InitMockSourceTextModule();
431 // serialize and persist
432 EcmaVM *vm = thread->GetEcmaVM();
433 ModuleManager *moduleManager = thread->GetModuleManager();
434 JSHandle<SourceTextModule> serializeModule = moduleManager->HostGetImportedModule("a");
435 JSHandle<SourceTextModule> serializeModule1 = moduleManager->HostGetImportedModule("b");
436 JSHandle<SourceTextModule> serializeModule2 = moduleManager->HostGetImportedModule("c");
437 ASSERT_TRUE(MockModuleSnapshot::SerializeDataAndSaving(vm, path, version));
438 moduleManager->ClearResolvedModules();
439 // deserialize
440 ASSERT_TRUE(ModuleSnapshot::DeserializeData(vm, path, version));
441 JSHandle<SourceTextModule> deserializeModule = moduleManager->HostGetImportedModule("a");
442 JSHandle<SourceTextModule> deserializeModule1 = moduleManager->HostGetImportedModule("b");
443 JSHandle<SourceTextModule> deserializeModule2 = moduleManager->HostGetImportedModule("c");
444 CheckModule(serializeModule, deserializeModule);
445 CheckModule(serializeModule1, deserializeModule1);
446 CheckModule(serializeModule2, deserializeModule2);
447 }
448
HWTEST_F_L0(ModuleSnapshotTest,ShouldNotSerializeWhenFileIsExists)449 HWTEST_F_L0(ModuleSnapshotTest, ShouldNotSerializeWhenFileIsExists)
450 {
451 // construct Module
452 CString path = GetSnapshotPath();
453 CString fileName = path + ModuleSnapshot::MODULE_SNAPSHOT_FILE_NAME.data();
454 CString version = "version 205.0.1.120(SP20)";
455 EcmaVM *vm = thread->GetEcmaVM();
456 InitMockSourceTextModule();
457 // serialize and persist
458 ASSERT_TRUE(MockModuleSnapshot::SerializeDataAndSaving(vm, path, version));
459 ASSERT_TRUE(FileExist(fileName.c_str()));
460 // return false when file is already exists
461 ASSERT_FALSE(MockModuleSnapshot::SerializeDataAndSaving(vm, path, version));
462 }
463
HWTEST_F_L0(ModuleSnapshotTest,ShouldNotDeSerializeWhenFileIsNotExists)464 HWTEST_F_L0(ModuleSnapshotTest, ShouldNotDeSerializeWhenFileIsNotExists)
465 {
466 // construct Module
467 CString path = GetSnapshotPath();
468 CString fileName = path + ModuleSnapshot::MODULE_SNAPSHOT_FILE_NAME.data();
469 CString version = "version 205.0.1.120(SP20)";
470 EcmaVM *vm = thread->GetEcmaVM();
471 InitMockSourceTextModule();
472 // return false when file is not exists
473 ASSERT_FALSE(FileExist(fileName.c_str()));
474 ASSERT_FALSE(ModuleSnapshot::DeserializeData(vm, path, version));
475 }
476
HWTEST_F_L0(ModuleSnapshotTest,ShouldSerializeFailedWhenBufferIsNotMatchBufferSize)477 HWTEST_F_L0(ModuleSnapshotTest, ShouldSerializeFailedWhenBufferIsNotMatchBufferSize)
478 {
479 // construct Module
480 CString path = GetSnapshotPath();
481 CString fileName = path + ModuleSnapshot::MODULE_SNAPSHOT_FILE_NAME.data();
482 CString version = "version 205.0.1.120(SP20)";
483 EcmaVM *vm = thread->GetEcmaVM();
484 InitMockSourceTextModule();
485 // return false when bufferSize > 0 and buffer is nullptr
486 ASSERT_FALSE(MockModuleSnapshot::MockSerializeAndSavingBufferEmpty(vm, path, version));
487 }
488
HWTEST_F_L0(ModuleSnapshotTest,ShouldDeSerializeFailedWhenFileIsEmpty)489 HWTEST_F_L0(ModuleSnapshotTest, ShouldDeSerializeFailedWhenFileIsEmpty)
490 {
491 // construct Module
492 CString path = GetSnapshotPath();
493 CString fileName = path + ModuleSnapshot::MODULE_SNAPSHOT_FILE_NAME.data();
494 CString version = "version 205.0.1.120(SP20)";
495 EcmaVM *vm = thread->GetEcmaVM();
496 InitMockSourceTextModule();
497 std::ofstream ofStream(fileName.c_str());
498 ofStream.close();
499 // return false when file is empty
500 ASSERT_TRUE(FileExist(fileName.c_str()));
501 ASSERT_FALSE(ModuleSnapshot::DeserializeData(vm, path, version));
502 // check file is deleted
503 ASSERT_FALSE(FileExist(fileName.c_str()));
504 }
505
HWTEST_F_L0(ModuleSnapshotTest,ShouldDeSerializeFailedWhenCheckSumIsNotMatch)506 HWTEST_F_L0(ModuleSnapshotTest, ShouldDeSerializeFailedWhenCheckSumIsNotMatch)
507 {
508 // construct Module
509 CString path = GetSnapshotPath();
510 CString fileName = path + ModuleSnapshot::MODULE_SNAPSHOT_FILE_NAME.data();
511 CString version = "version 205.0.1.120(SP20)";
512 EcmaVM *vm = thread->GetEcmaVM();
513 InitMockSourceTextModule();
514 // serialize and persist
515 ASSERT_TRUE(MockModuleSnapshot::SerializeDataAndSaving(vm, path, version));
516 ASSERT_TRUE(FileExist(fileName.c_str()));
517 // modify file content
518 std::ofstream ofStream(fileName.c_str(), std::ios::app);
519 uint32_t mockCheckSum = 123456;
520 ofStream << mockCheckSum;
521 ofStream.close();
522 // deserialize failed when checksum is not match
523 ASSERT_FALSE(ModuleSnapshot::DeserializeData(vm, path, version));
524 // check file is deleted
525 ASSERT_FALSE(FileExist(fileName.c_str()));
526 }
527
HWTEST_F_L0(ModuleSnapshotTest,ShouldDeSerializeFailedWhenAppVersionCodeIsNotMatch)528 HWTEST_F_L0(ModuleSnapshotTest, ShouldDeSerializeFailedWhenAppVersionCodeIsNotMatch)
529 {
530 // construct Module
531 CString path = GetSnapshotPath();
532 CString fileName = path + ModuleSnapshot::MODULE_SNAPSHOT_FILE_NAME.data();
533 CString version = "version 205.0.1.120(SP20)";
534 EcmaVM *vm = thread->GetEcmaVM();
535 InitMockSourceTextModule();
536 // serialize and persist
537 ASSERT_TRUE(MockModuleSnapshot::SerializeDataAndSaving(vm, path, version));
538 ASSERT_TRUE(FileExist(fileName.c_str()));
539 // modify app version code
540 thread->GetEcmaVM()->SetApplicationVersionCode(1);
541 // deserialize failed when app version code is not match
542 ASSERT_FALSE(ModuleSnapshot::DeserializeData(vm, path, version));
543 // check file is deleted
544 ASSERT_FALSE(FileExist(fileName.c_str()));
545 }
546
HWTEST_F_L0(ModuleSnapshotTest,ShouldDeSerializeFailedWhenVersionCodeIsNotMatch)547 HWTEST_F_L0(ModuleSnapshotTest, ShouldDeSerializeFailedWhenVersionCodeIsNotMatch)
548 {
549 // construct Module
550 CString path = GetSnapshotPath();
551 CString fileName = path + ModuleSnapshot::MODULE_SNAPSHOT_FILE_NAME.data();
552 CString version = "version 205.0.1.120(SP20)";
553 EcmaVM *vm = thread->GetEcmaVM();
554 InitMockSourceTextModule();
555 // serialize and persist
556 ASSERT_TRUE(MockModuleSnapshot::SerializeDataAndSaving(vm, path, version));
557 ASSERT_TRUE(FileExist(fileName.c_str()));
558 // deserialize failed when version code is not match
559 CString updatedVersion = "version 205.0.1.125(SP20)";
560 ASSERT_FALSE(ModuleSnapshot::DeserializeData(vm, path, updatedVersion));
561 // check file is deleted
562 ASSERT_FALSE(FileExist(fileName.c_str()));
563 }
564
HWTEST_F_L0(ModuleSnapshotTest,ShouldDeSerializeFailedWhenHasIncompleteData)565 HWTEST_F_L0(ModuleSnapshotTest, ShouldDeSerializeFailedWhenHasIncompleteData)
566 {
567 // construct Module
568 CString path = GetSnapshotPath();
569 CString fileName = path + ModuleSnapshot::MODULE_SNAPSHOT_FILE_NAME.data();
570 CString version = "version 205.0.1.120(SP20)";
571 EcmaVM *vm = thread->GetEcmaVM();
572 InitMockSourceTextModule();
573 // serialize and persist
574 ASSERT_TRUE(MockModuleSnapshot::MockSerializeAndSavingHasIncompleteData(vm, path, version));
575 ASSERT_TRUE(FileExist(fileName.c_str()));
576 // deserialize failed when has incomplete data
577 ASSERT_FALSE(ModuleSnapshot::DeserializeData(vm, path, version));
578 // check file is deleted
579 ASSERT_FALSE(FileExist(fileName.c_str()));
580 }
581
HWTEST_F_L0(ModuleSnapshotTest,ShouldRestoreUpdatedBindingBeforeSerializeWhenIsDictionaryMode)582 HWTEST_F_L0(ModuleSnapshotTest, ShouldRestoreUpdatedBindingBeforeSerializeWhenIsDictionaryMode)
583 {
584 CheckRestoreUpdatedBindingBeforeSerialize(true);
585 }
HWTEST_F_L0(ModuleSnapshotTest,ShouldRestoreUpdatedBindingBeforeSerializeWhenIsNotDictionaryMode)586 HWTEST_F_L0(ModuleSnapshotTest, ShouldRestoreUpdatedBindingBeforeSerializeWhenIsNotDictionaryMode)
587 {
588 CheckRestoreUpdatedBindingBeforeSerialize(false);
589 }
590 } // namespace panda::test
591