1/*
2 * Copyright (c) 2024 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 <cstdio>
17#include <fstream>
18#include <ostream>
19#include <string>
20
21#include "gtest/gtest.h"
22#include "ecmascript/extractortool/src/zip_file.h"
23#include "ecmascript/tests/test_helper.h"
24#include "ecmascript/extractortool/src/zip_file_reader.h"
25
26using namespace panda::ecmascript;
27namespace panda::ecmascript {
28class ZipFileFriend {
29public:
30    explicit ZipFileFriend(const std::string &path) : zipFile_(path)
31    {
32    }
33
34    ~ZipFileFriend()
35    {
36        Close();
37    }
38
39    void SetContentLocation(ZipPos start, size_t length)
40    {
41        zipFile_.SetContentLocation(start, length);
42    }
43
44    bool CheckEndDir(EndDir &endDir) const
45    {
46        return zipFile_.CheckEndDir(endDir);
47    }
48
49    bool ParseEndDirectory()
50    {
51        return zipFile_.ParseEndDirectory();
52    }
53
54    bool ParseOneEntry(uint8_t *&entryPtr)
55    {
56        return zipFile_.ParseOneEntry(entryPtr);
57    }
58
59    void AddEntryToTree(const std::string &fileName)
60    {
61        return zipFile_.AddEntryToTree(fileName);
62    }
63
64    bool ParseAllEntries()
65    {
66        return zipFile_.ParseAllEntries();
67    }
68
69    bool Open()
70    {
71        return zipFile_.Open();
72    }
73
74    void Close()
75    {
76        zipFile_.Close();
77    }
78
79    bool IsDirExist(const std::string &dir) const
80    {
81        return zipFile_.IsDirExist(dir);
82    }
83
84    void GetAllFileList(const std::string &srcPath, std::vector<std::string> &assetList)
85    {
86        zipFile_.GetAllFileList(srcPath, assetList);
87    }
88
89    void GetChildNames(const std::string &srcPath, std::set<std::string> &fileSet)
90    {
91        zipFile_.GetChildNames(srcPath, fileSet);
92    }
93
94    bool GetEntry(const std::string &entryName, ZipEntry &resultEntry) const
95    {
96        return zipFile_.GetEntry(entryName, resultEntry);
97    }
98
99    bool CheckCoherencyLocalHeader(const ZipEntry &zipEntry, uint16_t &extraSize) const
100    {
101        return zipFile_.CheckCoherencyLocalHeader(zipEntry, extraSize);
102    }
103
104    std::unique_ptr<FileMapper> CreateFileMapper(const std::string &fileName, FileMapperType type) const
105    {
106        return zipFile_.CreateFileMapper(fileName, type);
107    }
108
109    bool ExtractToBufByName(const std::string &fileName, std::unique_ptr<uint8_t[]> &dataPtr, size_t &len) const
110    {
111        return zipFile_.ExtractToBufByName(fileName, dataPtr, len);
112    }
113
114    void SetIsOpen(bool isOpen)
115    {
116        zipFile_.isOpen_ = isOpen;
117    }
118
119    ZipPos GetFileStartPos() const
120    {
121        return zipFile_.fileStartPos_;
122    }
123
124    void SetFileLength(ZipPos length)
125    {
126        zipFile_.fileLength_ = length;
127    }
128
129    ZipPos GetFileLength() const
130    {
131        return zipFile_.fileLength_;
132    }
133
134    const std::string &GetPathName() const
135    {
136        return zipFile_.pathName_;
137    }
138
139    void SetPathName(const std::string &newPathName)
140    {
141        zipFile_.pathName_ = newPathName;
142    }
143
144    std::shared_ptr<ZipFileReader> GetZipFileReader() const
145    {
146        return zipFile_.zipFileReader_;
147    }
148
149    void SetZipFileReader(const std::shared_ptr<ZipFileReader> &newZipFileReader)
150    {
151        zipFile_.zipFileReader_ = newZipFileReader;
152    }
153
154private:
155    ZipFile zipFile_;
156};
157}
158
159namespace panda::test {
160class ZipFileTest : public testing::Test {
161public:
162    static void SetUpTestCase()
163    {
164        GTEST_LOG_(INFO) << "SetUpTestCase";
165    }
166
167    static void TearDownTestCase()
168    {
169        GTEST_LOG_(INFO) << "TearDownCase";
170    }
171
172    void SetUp() override
173    {
174        TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
175        instance->SetEnableForceGC(false);
176    }
177
178    void TearDown() override
179    {
180        TestHelper::DestroyEcmaVMWithScope(instance, scope);
181    }
182
183    EcmaVM *instance{nullptr};
184    EcmaHandleScope *scope{nullptr};
185    JSThread *thread{nullptr};
186};
187
188int CreateTestFile()
189{
190    const std::string fileName = "TestFile.zip";
191    std::ofstream file(fileName);
192    if (!file.is_open()) {
193        return 1;
194    }
195    file << "This is a test file." << std::endl;
196    file.close();
197    if (!file) {
198        return 1;
199    }
200    return 0;
201}
202
203int DeleteTestFile()
204{
205    const char *fileName = "TestFile.zip";
206    if (std::remove(fileName) != 0) {
207        return 1;
208    }
209    return 0;
210}
211
212HWTEST_F_L0(ZipFileTest, SetContentLocationTest)
213{
214    std::string pathName = "path/to/zip.hap";
215    ZipFileFriend zipFileFriend(pathName);
216    zipFileFriend.SetIsOpen(true);
217    zipFileFriend.SetContentLocation(1, 1);
218    EXPECT_EQ(zipFileFriend.GetFileStartPos(), 0);
219    EXPECT_EQ(zipFileFriend.GetFileLength(), 0);
220
221    zipFileFriend.SetIsOpen(false);
222    zipFileFriend.SetContentLocation(1, 1);
223    EXPECT_EQ(zipFileFriend.GetFileStartPos(), 1);
224    EXPECT_EQ(zipFileFriend.GetFileLength(), 1);
225}
226
227HWTEST_F_L0(ZipFileTest, CheckEndDirTest)
228{
229    std::string pathName = "path/to/zip.hap";
230    ZipFileFriend zipFileFriend(pathName);
231    EndDir endDir;
232    EXPECT_FALSE(zipFileFriend.CheckEndDir(endDir));
233
234    zipFileFriend.SetFileLength(100);
235    EndDir endDir2;
236    endDir2.signature = 0x06054b50;
237    endDir2.numDisk = 0;
238    endDir2.startDiskOfCentralDir = 0;
239    endDir2.totalEntriesInThisDisk = 1;
240    endDir2.totalEntries = 1;
241    endDir2.sizeOfCentralDir = 78;
242    endDir2.offset = 0;
243    endDir2.commentLen = 0;
244
245    EXPECT_TRUE(zipFileFriend.CheckEndDir(endDir2));
246}
247
248HWTEST_F_L0(ZipFileTest, ParseEndDirectoryTest)
249{
250    std::string pathName = "path/to/zip.hap";
251    ZipFileFriend zipFileFriend(pathName);
252    zipFileFriend.SetFileLength(22);
253    EXPECT_FALSE(zipFileFriend.ParseEndDirectory());
254}
255
256HWTEST_F_L0(ZipFileTest, OpenTest)
257{
258    std::string pathName = "test_files/long_path_name.txt";
259    ZipFileFriend zipFileFriend(pathName);
260    zipFileFriend.SetIsOpen(true);
261    EXPECT_TRUE(zipFileFriend.Open());
262
263    zipFileFriend.SetIsOpen(false);
264    std::string longPathName(4097, 'a');
265    zipFileFriend.SetPathName(longPathName);
266    EXPECT_FALSE(zipFileFriend.Open());
267}
268
269HWTEST_F_L0(ZipFileTest, CloseTest)
270{
271    std::string pathName = "zipFileTest.zip";
272    ZipFileFriend zipFileFriend(pathName);
273    zipFileFriend.Close();
274    EXPECT_EQ(zipFileFriend.GetPathName(), "zipFileTest.zip");
275
276    EXPECT_EQ(CreateTestFile(), 0);
277    std::shared_ptr<ZipFileReader> zipFileReader = ZipFileReader::CreateZipFileReader(pathName);
278    zipFileFriend.SetZipFileReader(zipFileReader);
279    EXPECT_EQ(DeleteTestFile(), 0);
280    zipFileFriend.Close();
281}
282
283HWTEST_F_L0(ZipFileTest, IsDirExistTest)
284{
285    std::string pathName = "zipFileTest.zip";
286    ZipFileFriend zipFileFriend(pathName);
287    EXPECT_FALSE(zipFileFriend.IsDirExist(""));
288    std::string dir = ".";
289    EXPECT_FALSE(zipFileFriend.IsDirExist(dir));
290    dir = "path/to/nonexistent";
291    EXPECT_FALSE(zipFileFriend.IsDirExist(dir));
292    dir = "/";
293    EXPECT_TRUE(zipFileFriend.IsDirExist(dir));
294}
295
296HWTEST_F_L0(ZipFileTest, GetAllFileListTest)
297{
298    std::string pathName = "zipFileTest.zip";
299    ZipFileFriend zipFileFriend(pathName);
300    std::vector<std::string> assetList;
301    zipFileFriend.GetAllFileList("", assetList);
302    EXPECT_TRUE(assetList.empty());
303
304    assetList.clear();
305    zipFileFriend.GetAllFileList(".", assetList);
306    EXPECT_TRUE(assetList.empty());
307
308    assetList.clear();
309    zipFileFriend.GetAllFileList("./", assetList);
310    EXPECT_TRUE(assetList.empty());
311
312    assetList.clear();
313    zipFileFriend.GetAllFileList("path/to/nonexistent", assetList);
314    EXPECT_TRUE(assetList.empty());
315}
316
317HWTEST_F_L0(ZipFileTest, GetChildNamesTest)
318{
319    std::string pathName = "zipFileTest.zip";
320    ZipFileFriend zipFileFriend(pathName);
321    std::set<std::string> fileSet;
322
323    zipFileFriend.GetChildNames("", fileSet);
324    EXPECT_TRUE(fileSet.empty());
325
326    fileSet.clear();
327    zipFileFriend.GetChildNames("/", fileSet);
328    EXPECT_TRUE(fileSet.empty());
329
330    fileSet.clear();
331    zipFileFriend.GetChildNames(".", fileSet);
332    EXPECT_TRUE(fileSet.empty());
333
334    fileSet.clear();
335    zipFileFriend.GetChildNames(".", fileSet);
336    EXPECT_TRUE(fileSet.empty());
337
338    fileSet.clear();
339    zipFileFriend.GetChildNames("path/to/nonexistent", fileSet);
340    EXPECT_TRUE(fileSet.empty());
341}
342
343HWTEST_F_L0(ZipFileTest, GetEntryTest)
344{
345    std::string pathName = "zipFileTest.zip";
346    ZipFileFriend zipFileFriend(pathName);
347    ZipEntry resultEntry;
348    std::string nonExistingEntryName = "nonExistingEntry";
349    EXPECT_FALSE(zipFileFriend.GetEntry(nonExistingEntryName, resultEntry));
350}
351
352HWTEST_F_L0(ZipFileTest, CheckCoherencyLocalHeaderTest)
353{
354    std::string pathName = "zipFileTest.zip";
355    ZipFileFriend zipFileFriend(pathName);
356    ZipEntry zipEntry;
357    uint16_t extraSize;
358    size_t fileStartPos_;
359    fileStartPos_ = 0;
360    zipEntry.compressionMethod = 8;
361    zipEntry.localHeaderOffset = 0;
362    zipEntry.fileName = "testFile.txt";
363    zipEntry.compressionMethod = 9;
364    EXPECT_FALSE(zipFileFriend.CheckCoherencyLocalHeader(zipEntry, extraSize));
365    zipEntry.fileName = std::string(4096, 'a');
366    EXPECT_FALSE(zipFileFriend.CheckCoherencyLocalHeader(zipEntry, extraSize));
367    zipEntry.fileName = "differentName.txt";
368    EXPECT_FALSE(zipFileFriend.CheckCoherencyLocalHeader(zipEntry, extraSize));
369}
370}