• 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/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