1 /*
2  * Copyright (c) 2021 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 "directory_ex.h"
17 #include <gtest/gtest.h>
18 #include <fcntl.h>
19 #include <algorithm>
20 #include <iostream>
21 #include <fstream>
22 #include <unistd.h>
23 #include <vector>
24 
25 using namespace testing::ext;
26 using namespace std;
27 
28 namespace OHOS {
29 namespace {
30 class UtilsDirectoryTest : public testing::Test {
31 public :
32     static void SetUpTestCase(void);
33     static void TearDownTestCase(void);
34     void SetUp();
35     void TearDown();
36 };
37 
SetUpTestCase(void)38 void UtilsDirectoryTest::SetUpTestCase(void)
39 {
40 }
41 
TearDownTestCase(void)42 void UtilsDirectoryTest::TearDownTestCase(void)
43 {
44 }
45 
SetUp(void)46 void UtilsDirectoryTest::SetUp(void)
47 {
48 }
49 
TearDown(void)50 void UtilsDirectoryTest::TearDown(void)
51 {
52 }
53 
54 /*
55  * @tc.name: testGetCurrentProcFullFileName001
56  * @tc.desc: get the directory of directorytest
57  */
58 HWTEST_F(UtilsDirectoryTest, testGetCurrentProcFullFileName001, TestSize.Level0)
59 {
60     string strBaseName = "/data/test/UtilsDirectoryTest";
61     string strFilename = GetCurrentProcFullFileName();
62     EXPECT_EQ(strFilename, strBaseName);
63 }
64 
65 /*
66  * @tc.name: testGetCurrentProcPath001
67  * @tc.desc: get the path of directorytest
68  */
69 HWTEST_F(UtilsDirectoryTest, testGetCurrentProcPath001, TestSize.Level0)
70 {
71     string strPathName = "/data/test/";
72     string strCurPathName = GetCurrentProcPath();
73     EXPECT_EQ(strCurPathName, strPathName);
74 }
75 
76 /*
77  * @tc.name: testExtractFilePath001
78  * @tc.desc: get the filename of the path
79  */
80 HWTEST_F(UtilsDirectoryTest, testExtractFilePath001, TestSize.Level0)
81 {
82     string strFilePath = "/data/test/";
83     string strPath = ExtractFilePath(GetCurrentProcFullFileName());
84     EXPECT_EQ(strFilePath, strPath);
85 }
86 
87 /*
88  * @tc.name: testExtractFileName001
89  * @tc.desc: get the filename of the path
90  */
91 HWTEST_F(UtilsDirectoryTest, testExtractFileName001, TestSize.Level0)
92 {
93     string strBaseName = "UtilsDirectoryTest";
94     string strName = ExtractFileName(GetCurrentProcFullFileName());
95     EXPECT_EQ(strBaseName, strName);
96 }
97 
98 /*
99  * @tc.name: testExtractFileExt001
100  * @tc.desc: get the filename of the path
101  */
102 HWTEST_F(UtilsDirectoryTest, testExtractFileExt001, TestSize.Level0)
103 {
104     string strBaseName = "test/test.txt";
105     string strTypeName = ExtractFileExt(strBaseName);
106     EXPECT_EQ(strTypeName, "txt");
107 }
108 
109 /*
110  * @tc.name: testExtractFileExt002
111  * @tc.desc: get the filename of the path and test whether the filename contains "."
112  */
113 HWTEST_F(UtilsDirectoryTest, testExtractFileExt002, TestSize.Level0)
114 {
115     string strBaseName = "test/test_txt";
116     string strTypeName = ExtractFileExt(strBaseName);
117     EXPECT_EQ(strTypeName, "");
118 }
119 
120 /*
121  * @tc.name: testExcludeTrailingPathDelimiter001
122  * @tc.desc: directory unit test
123  */
124 HWTEST_F(UtilsDirectoryTest, testExcludeTrailingPathDelimiter001, TestSize.Level0)
125 {
126     string strResult = "data/test/UtilsDirectoryTest";
127     string strName = ExcludeTrailingPathDelimiter("data/test/UtilsDirectoryTest/");
128     EXPECT_EQ(strResult, strName);
129 }
130 
131 /*
132  * @tc.name: testIncludeTrailingPathDelimiter001
133  * @tc.desc: directory unit test
134  */
135 HWTEST_F(UtilsDirectoryTest, testIncludeTrailingPathDelimiter001, TestSize.Level0)
136 {
137     string strResult = "data/test/UtilsDirectoryTest/";
138     string strName = IncludeTrailingPathDelimiter("data/test/UtilsDirectoryTest");
139     EXPECT_EQ(strResult, strName);
140 }
141 
142 /*
143  * @tc.name: testIncludeTrailingPathDelimiter002
144  * @tc.desc: directory unit test
145  */
146 HWTEST_F(UtilsDirectoryTest, testIncludeTrailingPathDelimiter002, TestSize.Level0)
147 {
148     string strResult = "/";
149     string strName = IncludeTrailingPathDelimiter("");
150     EXPECT_EQ(strResult, strName);
151 }
152 
153 /*
154  * @tc.name: testGetDirFiles001
155  * @tc.desc: test GetDirFiles works on multi-level directory
156  */
157 HWTEST_F(UtilsDirectoryTest, testGetDirFiles001, TestSize.Level0)
158 {
159     string parentPath = "/data/test_dir";
160 
161     ForceCreateDirectory(parentPath);
162 
163     string dirs[6] = {
164         "/data/test_dir/level1_1",
165         "/data/test_dir/level1_2",
166         "/data/test_dir/level1_2/level2_1",
167         "/data/test_dir/level1_2/level2_2",
168         "/data/test_dir/level1_2/level2_2/level3_1",
169         "/data/test_dir/level1_3",
170     };
171 
172     string resultfiles[9] = {
173         "/data/test_dir/level1_1/test_file",
174         "/data/test_dir/level1_2/level2_2/level3_1/test_file_1",
175         "/data/test_dir/level1_2/level2_2/level3_1/test_file_2",
176         "/data/test_dir/level1_2/level2_2/test_file_1",
177         "/data/test_dir/level1_2/level2_2/test_file_2",
178         "/data/test_dir/level1_2/level2_2/test_file_3",
179         "/data/test_dir/level1_2/level2_2/test_file_4",
180         "/data/test_dir/level1_2/test_file",
181         "/data/test_dir/level1_3/test_file",
182     };
183 
184     for (auto &path : dirs) {
185         ForceCreateDirectory(path);
186     }
187 
188     for (auto &filepath : resultfiles) {
189         ofstream(filepath, fstream::out);
190     }
191 
192     vector<string> files;
193 
194     GetDirFiles(parentPath, files);
195 
196     for (auto &filepath : resultfiles) {
197         auto pos = find(files.begin(), files.end(), filepath);
198         EXPECT_NE(pos, files.end());
199     }
200 
201     ForceRemoveDirectory(parentPath);
202 }
203 
204 /*
205  * @tc.name: testGetDirFiles002
206  * @tc.desc: test GetDirFiles works on deeply nested directory and handles very long path
207  */
208 HWTEST_F(UtilsDirectoryTest, testGetDirFiles002, TestSize.Level0)
209 {
210     string parentPath = "/data/test_dir/";
211     string veryLongPath = "/data/test_dir/";
212 
213     int length = 10000;
214 
215     for (int i = 0; i < length; i++) {
216         veryLongPath += "0";
217         veryLongPath += "/";
218     }
219 
220     EXPECT_EQ(mkdir("/data/test_dir", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH), 0);
221     chdir(parentPath.c_str());
222 
223     for (int i = 0; i < length; i++) {
224         EXPECT_EQ(mkdir("./0", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH), 0);
225         EXPECT_EQ(chdir("./0"), 0);
226     }
227 
228     ofstream file("./test_file");
229     file.close();
230     EXPECT_EQ(chdir("/data/test"), 0);
231 
232     auto files = vector<string>();
233 
234     GetDirFiles(parentPath, files);
235 
236     EXPECT_EQ(files.size(), 1);
237     EXPECT_EQ((veryLongPath + "test_file").length(), files[0].length());
238     EXPECT_EQ(veryLongPath + "test_file", files[0]);
239 
240     ForceRemoveDirectory(parentPath);
241 }
242 
243 /*
244  * @tc.name: testGetDirFiles003
245  * @tc.desc: test GetDirFiles works on symlink
246  */
247 HWTEST_F(UtilsDirectoryTest, testGetDirFiles003, TestSize.Level0)
248 {
249     // create a test dir
250     string originalDataPath = "/data/original";
251     EXPECT_EQ(ForceCreateDirectory(originalDataPath), true);
252 
253     string originalFilePath = "/data/original/original_file";
254     string originalDirectoryPath = "/data/original/original_directory";
255 
256     ofstream(originalFilePath, fstream::out);
257 
258     ForceCreateDirectory(originalDirectoryPath);
259 
260     string testDataDir = "/data/test_dir";
261 
262     EXPECT_EQ(ForceCreateDirectory(testDataDir), true);
263 
264     // test symlink to directory outside the target directory
265     string linktodir = IncludeTrailingPathDelimiter(testDataDir) + "symlink_dir";
266 
267     EXPECT_EQ(symlink(originalDirectoryPath.c_str(), linktodir.c_str()), 0);
268 
269     vector<string> dirResult;
270     GetDirFiles(testDataDir, dirResult);
271 
272     EXPECT_EQ(dirResult.size(), 1);
273     EXPECT_EQ(dirResult[0], linktodir);
274 
275     EXPECT_EQ(ForceRemoveDirectory(linktodir), true);
276 
277     // test symlink to file outside the target directory
278     string linktofile = IncludeTrailingPathDelimiter(testDataDir) + "symlink_file";
279     EXPECT_EQ(symlink(originalFilePath.c_str(), linktofile.c_str()), 0);
280 
281     vector<string> fileResult;
282     GetDirFiles(testDataDir, fileResult);
283     EXPECT_EQ(fileResult.size(), 1);
284     EXPECT_EQ(fileResult[0], linktofile);
285 
286     EXPECT_EQ(RemoveFile(linktofile), true);
287 
288     // test symlink of files in the same directory
289     string sourceFile = IncludeTrailingPathDelimiter(testDataDir) + "source";
290     string symlinkFile = IncludeTrailingPathDelimiter(testDataDir) + "symlink_file";
291 
292     ofstream(sourceFile, fstream::out);
293     EXPECT_EQ(symlink(sourceFile.c_str(), symlinkFile.c_str()), 0);
294 
295     vector<string> internalFiles;
296     GetDirFiles(testDataDir, internalFiles);
297 
298     EXPECT_NE(find(internalFiles.begin(), internalFiles.end(), sourceFile), internalFiles.end());
299     EXPECT_NE(find(internalFiles.begin(), internalFiles.end(), symlinkFile), internalFiles.end());
300 
301     EXPECT_EQ(RemoveFile(sourceFile), true);
302     EXPECT_EQ(RemoveFile(symlinkFile), true);
303 
304     ForceRemoveDirectory(originalDataPath);
305     ForceRemoveDirectory(testDataDir);
306 }
307 
308 /*
309  * @tc.name: testForceCreateDirectory001
310  * @tc.desc: directory unit test
311  */
312 HWTEST_F(UtilsDirectoryTest, testForceCreateDirectory001, TestSize.Level0)
313 {
314     string dirpath = "/data/test_dir/test2/test3";
315     bool ret = ForceCreateDirectory(dirpath);
316     EXPECT_EQ(ret, true);
317     ret = IsEmptyFolder(dirpath);
318     EXPECT_EQ(ret, true);
319 }
320 
321 /*
322  * @tc.name: testForceRemoveDirectory001
323  * @tc.desc: directory unit test
324  */
325 HWTEST_F(UtilsDirectoryTest, testForceRemoveDirectory001, TestSize.Level0)
326 {
327     string dirpath = "/data/test_dir";
328     bool ret = ForceRemoveDirectory(dirpath);
329     EXPECT_EQ(ret, true);
330 }
331 
332 /*
333  * @tc.name: testForceRemoveDirectory002
334  * @tc.desc: test whether the folder exists
335  */
336 HWTEST_F(UtilsDirectoryTest, testForceRemoveDirectory002, TestSize.Level0)
337 {
338     string dirpath = "/data/test/utils_directory_tmp/";
339     bool ret = ForceRemoveDirectory(dirpath);
340     EXPECT_EQ(ret, false);
341 }
342 
343 
344 /*
345  * @tc.name: testForceRemoveDirectory003
346  * @tc.desc: test whether it works when the full path is over than 255.
347  */
348 HWTEST_F(UtilsDirectoryTest, testForceRemoveDirectory003, TestSize.Level0)
349 {
350     string dirpath = "/data/test/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/"
351         "tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/"
352         "tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/"
353         "tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp/tmp";
354     bool ret = ForceCreateDirectory(dirpath);
355     EXPECT_EQ(ret, true);
356     string rootpath = "/data/test/tmp";
357     ret = ForceRemoveDirectory(rootpath);
358     EXPECT_EQ(ret, true);
359 }
360 
361 /*
362  * @tc.name: testRemoveFile001
363  * @tc.desc: directory unit test
364  */
365 HWTEST_F(UtilsDirectoryTest, testRemoveFile001, TestSize.Level0)
366 {
367     string dirpath = "/data/test_dir";
368     bool ret = ForceCreateDirectory(dirpath);
369     EXPECT_EQ(ret, true);
370     string filename = dirpath + "/test.txt";
371     FILE *fp = fopen(filename.c_str(), "w");
372     if (NULL != fp) {
373         fclose(fp);
374         ret = RemoveFile(filename);
375         EXPECT_EQ(ret, true);
376     }
377     ret = ForceRemoveDirectory(dirpath);
378     EXPECT_EQ(ret, true);
379 }
380 
381 /*
382  * @tc.name: testRemoveFile002
383  * @tc.desc: Remove soft link file.
384  */
385 HWTEST_F(UtilsDirectoryTest, testRemoveFile002, TestSize.Level0)
386 {
387     string dirpath = "/data/test_dir";
388     bool ret = ForceCreateDirectory(dirpath);
389     EXPECT_EQ(ret, true);
390 
391     string targetname = "/data/test_target.txt";
392     FILE *fp = fopen(targetname.c_str(), "w");
393     if (NULL != fp) {
394         fclose(fp);
395     }
396 
397     // symlink to a directory
398     string linkpath = "/data/test_symlink_dir";
399     int res = symlink(dirpath.c_str(), linkpath.c_str());
400     EXPECT_EQ(res, 0);
401 
402     ret = ForceRemoveDirectory(linkpath);
403     EXPECT_EQ(ret, true);
404 
405     // Target dir is not removed.
406     ret = faccessat(AT_FDCWD, dirpath.c_str(), F_OK, AT_SYMLINK_NOFOLLOW);
407     EXPECT_EQ(ret, 0);
408 
409     // symlink to a file
410     string filename = dirpath + "/test.txt";
411     res = symlink(targetname.c_str(), filename.c_str());
412     EXPECT_EQ(res, 0);
413 
414     ret = ForceRemoveDirectory(dirpath);
415     EXPECT_EQ(ret, true);
416 
417     // Target file is not removed.
418     ret = faccessat(AT_FDCWD, targetname.c_str(), F_OK, AT_SYMLINK_NOFOLLOW);
419     EXPECT_EQ(ret, 0);
420 
421     ret = RemoveFile(targetname);
422     EXPECT_EQ(ret, true);
423 }
424 
425 /*
426  * @tc.name: testRemoveFile003
427  * @tc.desc: Remove dangling soft link file.
428  */
429 HWTEST_F(UtilsDirectoryTest, testRemoveFile003, TestSize.Level0)
430 {
431     string dirpath = "/data/test_dir";
432     bool ret = ForceCreateDirectory(dirpath);
433     EXPECT_EQ(ret, true);
434 
435     // symlink to a file
436     string targetname = "/data/nonexisted.txt";
437     string filename = dirpath + "/test.txt";
438     int res = symlink(targetname.c_str(), filename.c_str());
439     EXPECT_EQ(res, 0);
440 
441     ret = ForceRemoveDirectory(dirpath);
442     EXPECT_EQ(ret, true);
443 
444     ret = RemoveFile(targetname);
445     EXPECT_EQ(ret, true);
446 }
447 
448 /*
449  * @tc.name: testGetFolderSize001
450  * @tc.desc: directory unit test
451  */
452 HWTEST_F(UtilsDirectoryTest, testGetFolderSize001, TestSize.Level0)
453 {
454     string dirpath = "/data/test_folder/";
455     bool ret = ForceCreateDirectory(dirpath);
456     EXPECT_EQ(ret, true);
457     ofstream out(dirpath + "test.txt");
458     if (out.is_open()) {
459         out << "This is a line.\n";
460         out << "This is another line.\n";
461         out.close();
462     }
463     uint64_t resultsize = GetFolderSize(dirpath);
464     uint64_t resultcomp = 38;
465     EXPECT_EQ(resultsize, resultcomp);
466 
467     mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
468     ret = ChangeModeFile(dirpath + "test.txt", mode);
469     EXPECT_EQ(ret, true);
470 
471     mode = S_IRUSR  | S_IRGRP | S_IROTH;
472     ret = ChangeModeDirectory(dirpath, mode);
473     EXPECT_EQ(ret, true);
474 
475     ret = ForceRemoveDirectory(dirpath);
476     EXPECT_EQ(ret, true);
477 }
478 
479 /*
480  * @tc.name: testChangeModeFile001
481  * @tc.desc: test whether the folder exists
482  */
483 HWTEST_F(UtilsDirectoryTest, testChangeModeFile001, TestSize.Level0)
484 {
485     string dirpath = "/data/test/utils_directory_tmp/";
486     mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
487     bool ret = ChangeModeFile(dirpath + "test.txt", mode);
488     EXPECT_EQ(ret, false);
489 }
490 
491 /*
492  * @tc.name: testChangeModeDirectory001
493  * @tc.desc: test whether the folder is empty and get the size of the folder
494  */
495 HWTEST_F(UtilsDirectoryTest, testChangeModeDirectory001, TestSize.Level0)
496 {
497     string dirpath = "";
498     mode_t mode = S_IRUSR  | S_IRGRP | S_IROTH;
499     bool ret = ChangeModeDirectory(dirpath, mode);
500     EXPECT_EQ(ret, false);
501 
502     uint64_t resultsize = GetFolderSize(dirpath);
503     uint64_t resultcomp = 0;
504     EXPECT_EQ(resultsize, resultcomp);
505 }
506 
507 /*
508  * @tc.name: testPathToRealPath001
509  * @tc.desc: directory unit test
510  */
511 HWTEST_F(UtilsDirectoryTest, testPathToRealPath001, TestSize.Level0)
512 {
513     string path = "/data/test";
514     string realpath;
515     bool ret = PathToRealPath(path, realpath);
516     EXPECT_EQ(ret, true);
517     EXPECT_EQ(path, realpath);
518 }
519 
520 /*
521  * @tc.name: testPathToRealPath002
522  * @tc.desc: directory unit test
523  */
524 HWTEST_F(UtilsDirectoryTest, testPathToRealPath002, TestSize.Level0)
525 {
526     string path = "/data/../data/test";
527     string realpath;
528     bool ret = PathToRealPath(path, realpath);
529     EXPECT_EQ(ret, true);
530     EXPECT_EQ("/data/test", realpath);
531 }
532 
533 /*
534  * @tc.name: testPathToRealPath003
535  * @tc.desc: directory unit test
536  */
537 HWTEST_F(UtilsDirectoryTest, testPathToRealPath003, TestSize.Level0)
538 {
539     string path = "./";
540     string realpath;
541     bool ret = PathToRealPath(path, realpath);
542     EXPECT_EQ(ret, true);
543     EXPECT_EQ("/data/test", realpath);
544 }
545 
546 /*
547  * @tc.name: testPathToRealPath004
548  * @tc.desc: directory unit test
549  */
550 HWTEST_F(UtilsDirectoryTest, testPathToRealPath004, TestSize.Level0)
551 {
552     string path = "";
553     string realpath;
554     bool ret = PathToRealPath(path, realpath);
555     EXPECT_EQ(ret, false);
556 }
557 
558 /*
559  * @tc.name: testPathToRealPath005
560  * @tc.desc: directory unit test
561  */
562 HWTEST_F(UtilsDirectoryTest, testPathToRealPath005, TestSize.Level0)
563 {
564     string path = "/data/test/data/test/data/test/data/test/data/test/data/ \
565         test/data/test/data/test/data/test/data/test/data/test/data/test/data/ \
566         test/data/test/data/test/data/test/data/test/data/test/data/test/data/ \
567         test/data/test/data/test/data/test/data/test/data/test/data/test/data/ \
568         test/data/test/data/test/data/test";
569     string realpath;
570     bool ret = PathToRealPath(path, realpath);
571     EXPECT_EQ(ret, false);
572 }
573 
574 /*
575  * @tc.name: testPathToRealPath006
576  * @tc.desc: test whether the folder exists
577  */
578 HWTEST_F(UtilsDirectoryTest, testPathToRealPath006, TestSize.Level0)
579 {
580     string path(PATH_MAX, 'x');
581     string realpath;
582     bool ret = PathToRealPath(path, realpath);
583     EXPECT_EQ(ret, false);
584 }
585 }  // namespace
586 }  // namespace OHOS
587