1 /*
2  * Copyright (c) 2023 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 #include "mapped_file.h"
16 
17 #include <fstream>
18 #include <gtest/gtest.h>
19 #include <iostream>
20 #include <sys/stat.h>
21 #include <unistd.h>
22 #include "common_mapped_file_errors.h"
23 #include "directory_ex.h"
24 #include "errors.h"
25 #include "file_ex.h"
26 
27 using namespace testing::ext;
28 using namespace OHOS::Utils;
29 
30 namespace OHOS {
31 namespace {
32 
33 class UtilsMappedFileTest : public testing::Test {
34 public:
35     static constexpr char BASE_PATH[] = "/data/test/commonlibrary_c_utils/";
36     static constexpr char SUITE_PATH[] = "mapped_file/";
37     static void SetUpTestCase(void);
38     static void TearDownTestCase(void);
39 };
40 
SetUpTestCase()41 void UtilsMappedFileTest::SetUpTestCase()
42 {
43     std::string dir = std::string(BASE_PATH).append(SUITE_PATH);
44     if (ForceCreateDirectory(dir)) {
45         std::cout << "Create test dir:" << dir.c_str() << std::endl;
46     } else {
47         std::cout << "Create test dir Failed:" << dir.c_str() << std::endl;
48     }
49 
50     std::cout << "Page size:" << MappedFile::PageSize() << std::endl;
51 }
52 
TearDownTestCase()53 void UtilsMappedFileTest::TearDownTestCase()
54 {
55     if (ForceRemoveDirectory(std::string(BASE_PATH))) {
56         std::cout << "Remove test dir:" << BASE_PATH << std::endl;
57     }
58 }
59 
PrintStatus(MappedFile & mf)60 void PrintStatus(MappedFile& mf)
61 {
62     std::cout << "Mapped Region Start:" << reinterpret_cast<void*>(mf.RegionStart()) << std::endl <<
63                  "Mapped Region End:" << reinterpret_cast<void*>(mf.RegionEnd()) << std::endl <<
64                  "View start:" << reinterpret_cast<void*>(mf.Begin()) << std::endl <<
65                  "View End:" << reinterpret_cast<void*>(mf.End()) << std::endl <<
66                  "View Size:" << mf.Size() << std::endl <<
67                  "File Offset Start:" << mf.StartOffset() << std::endl <<
68                  "File Offset Start:" << mf.EndOffset() << std::endl;
69 }
70 
CreateTestFile(const std::string & path,const std::string & content)71 bool CreateTestFile(const std::string& path, const std::string& content)
72 {
73     std::ofstream out(path, std::ios_base::out | std::ios_base::trunc);
74     if (out.is_open()) {
75         out << content.c_str();
76         return true;
77     }
78 
79     std::cout << "open file failed!" << path.c_str() << std::endl;
80     return false;
81 }
82 
RemoveTestFile(const std::string & path)83 int RemoveTestFile(const std::string& path)
84 {
85     return unlink(path.c_str());
86 }
87 
SaveStringToFile(const std::string & filePath,const std::string & content,off_t offset,bool truncated)88 bool SaveStringToFile(const std::string& filePath, const std::string& content, off_t offset, bool truncated /*= true*/)
89 {
90     if (content.empty()) {
91         return true;
92     }
93 
94     std::ofstream file;
95     if (truncated) {
96         file.open(filePath.c_str(), std::ios::out | std::ios::trunc);
97     } else {
98         file.open(filePath.c_str(), std::ios::out | std::ios::app);
99     }
100 
101     if (!file.is_open()) {
102         return false;
103     }
104 
105     file.seekp(offset, std::ios::beg);
106 
107     file.write(content.c_str(), content.length());
108     if (file.fail()) {
109         return false;
110     }
111     return true;
112 }
113 
ReCreateFile(std::string & filename,const std::string & content)114 void ReCreateFile(std::string& filename, const std::string& content)
115 {
116     filename.insert(0, UtilsMappedFileTest::SUITE_PATH).insert(0, UtilsMappedFileTest::BASE_PATH);
117     RemoveTestFile(filename);
118 
119     ASSERT_TRUE(CreateTestFile(filename, content));
120 }
121 
TestFileStatusAndRead(MappedFile & mf,const std::string & filename,const std::string & content,struct stat * stb)122 void TestFileStatusAndRead(MappedFile& mf,
123                            const std::string& filename,
124                            const std::string& content,
125                            struct stat* stb)
126 {
127     ASSERT_NE(stb, nullptr);
128     ASSERT_EQ(mf.Map(), MAPPED_FILE_ERR_OK);
129 
130     // check status after mapping
131     ASSERT_TRUE(mf.IsMapped());
132     ASSERT_TRUE(mf.IsNormed());
133 
134     // check size
135     stat(filename.c_str(), stb);
136     ASSERT_TRUE(stb->st_size == mf.Size() || mf.PageSize() == mf.Size());
137 
138     // read from Mapped File
139     std::string readout;
140     char* cur = mf.Begin();
141     for (; cur <= mf.End(); cur++) {
142         readout.push_back(*cur);
143     }
144     EXPECT_EQ(readout, content);
145 
146     // write to the extended region
147     *(cur) = 'E';
148     EXPECT_EQ((*cur), 'E');
149 }
150 
TestFileReadAndWrite(const MappedFile & mf,const std::string & content)151 void TestFileReadAndWrite(const MappedFile& mf, const std::string& content)
152 {
153     // read from mapped file
154     std::string readout;
155     for (char* cur = mf.Begin(); cur <= mf.End(); cur++) {
156         readout.push_back(*cur);
157     }
158     EXPECT_EQ(readout, content);
159 
160     // write to mapped file
161     std::string toWrite("Complete.");
162     char* newCur = mf.Begin();
163     for (std::string::size_type i = 0; i < toWrite.length(); i++) {
164         (*newCur) = toWrite[i];
165         newCur++;
166     }
167 }
168 
TestFileStat(MappedFile & mf,const std::string & filename,const std::string & content,struct stat * stb)169 void TestFileStat(MappedFile& mf,
170                   const std::string& filename,
171                   const std::string& content,
172                   struct stat* stb)
173 {
174     ASSERT_NE(stb, nullptr);
175     ASSERT_EQ(mf.Map(), MAPPED_FILE_ERR_OK);
176 
177     // check status after mapping
178     ASSERT_TRUE(mf.IsMapped());
179     ASSERT_TRUE(mf.IsNormed());
180 
181     // check size
182     stat(filename.c_str(), stb);
183     ASSERT_TRUE(stb->st_size == mf.Size() || mf.PageSize() == mf.Size());
184 
185     // read from Mapped File
186     std::string readout;
187     for (char* cur = mf.Begin(); cur <= mf.End(); cur++) {
188         readout.push_back(*cur);
189     }
190     EXPECT_EQ(readout, content);
191 }
192 
TestFileContentEqual(const MappedFile & mf,const std::string & filename,std::string & filename1,std::string & content1,struct stat * stb)193 void TestFileContentEqual(const MappedFile& mf,
194                           const std::string& filename,
195                           std::string& filename1,
196                           std::string& content1,
197                           struct stat* stb)
198 {
199     // check pointer not null
200     ASSERT_NE(stb, nullptr);
201     // check status after remapping
202     EXPECT_TRUE(mf.IsMapped());
203     EXPECT_TRUE(mf.IsNormed());
204 
205     // check size
206     stat(filename1.c_str(), stb);
207     EXPECT_TRUE(stb->st_size == mf.Size());
208 
209     // read from Mapped File
210     std::string readout1;
211     for (char* cur1 = mf.Begin(); cur1 <= mf.End(); cur1++) {
212         readout1.push_back(*cur1);
213     }
214     EXPECT_EQ(readout1, content1);
215 
216     RemoveTestFile(filename);
217     RemoveTestFile(filename1);
218 }
219 
TestFileRegion(MappedFile & mf,const off_t orig)220 void TestFileRegion(MappedFile& mf, const off_t orig)
221 {
222     off_t endOff;
223     // keep turnNext within a page
224     ASSERT_NE(orig, 0);
225     if (orig != 0) {
226         for (unsigned int cnt = 2; cnt < (MappedFile::PageSize() / orig); cnt++) { // 2: start from 2 to take the first
227                                                                                 // TunrNext() calling in consideration.
228             endOff = mf.EndOffset();
229             EXPECT_EQ(mf.TurnNext(), MAPPED_FILE_ERR_OK);
230             EXPECT_EQ(mf.StartOffset(), endOff + 1);
231             EXPECT_EQ(mf.Size(), orig);
232         }
233     }
234     std::cout << "==Last TurnNext() with The Same Size==" << std::endl;
235     PrintStatus(mf);
236 
237     // this turn will reach the bottom of a page
238     endOff = mf.EndOffset();
239     char* rEnd = mf.RegionEnd();
240     char* end = mf.End();
241     EXPECT_EQ(mf.TurnNext(), MAPPED_FILE_ERR_OK);
242     EXPECT_EQ(mf.StartOffset(), endOff + 1);
243     EXPECT_EQ(mf.Size(), static_cast<off_t>(rEnd - end));
244     std::cout << "==Reached Bottom of A Page==" << std::endl;
245     PrintStatus(mf);
246 }
247 
TestFileWrite(const MappedFile & mfNew,const std::string & filename,const std::string & content)248 void TestFileWrite(const MappedFile& mfNew, const std::string& filename, const std::string& content)
249 {
250     // read from mapped file
251     std::string readout;
252     for (char* cur = mfNew.Begin(); cur <= mfNew.End(); cur++) {
253         readout.push_back(*cur);
254     }
255     EXPECT_EQ(readout, content);
256 
257     // write to mapped file
258     std::string toWrite("Complete.");
259     char* newCur = mfNew.Begin();
260     for (std::string::size_type i = 0; i < toWrite.length(); i++) {
261         (*newCur) = toWrite[i];
262         newCur++;
263     }
264     std::string res;
265     LoadStringFromFile(filename, res);
266     EXPECT_EQ(res, "Complete.move use.");
267 
268     RemoveTestFile(filename);
269 }
270 
TestTwoFileWrite(const MappedFile & mf,const std::string & filename,const std::string & filename1,const std::string & content1)271 void TestTwoFileWrite(const MappedFile& mf,
272                       const std::string& filename,
273                       const std::string& filename1,
274                       const std::string& content1)
275 {
276     std::string readout;
277     for (char* cur = mf.Begin(); cur <= mf.End(); cur++) {
278         readout.push_back(*cur);
279     }
280     EXPECT_EQ(readout, content1);
281 
282     //write to mapped file
283     std::string toWrite("Complete.");
284     char* newCur = mf.Begin();
285     for (std::string::size_type i = 0; i < toWrite.length(); i++) {
286         (*newCur) = toWrite[i];
287         newCur++;
288     }
289     std::string res;
290     LoadStringFromFile(filename1, res);
291     EXPECT_EQ(res, "Complete.move use.");
292 
293     RemoveTestFile(filename);
294     RemoveTestFile(filename1);
295 }
296 
297 /*
298  * @tc.name: testDefaultMapping001
299  * @tc.desc: Test file mapping with default params.
300  */
301 HWTEST_F(UtilsMappedFileTest, testDefaultMapping001, TestSize.Level0)
302 {
303     // 1. Create a new file
304     std::string filename = "test_read_write_1.txt";
305     std::string content = "Test for normal use.";
306     ReCreateFile(filename, content);
307 
308     // 2. map file
309     MappedFile mf(filename);
310     ASSERT_EQ(mf.Map(), MAPPED_FILE_ERR_OK);
311 
312     // check status
313     ASSERT_TRUE(mf.IsMapped());
314     ASSERT_TRUE(mf.IsNormed());
315 
316     // check size
317     struct stat stb = {0};
318     stat(filename.c_str(), &stb);
319     ASSERT_TRUE(stb.st_size == mf.Size() || mf.PageSize() == mf.Size());
320 
321     // check map-mode
322     ASSERT_EQ(MapMode::DEFAULT, mf.GetMode());
323 
324     // check offset
325     ASSERT_EQ(mf.StartOffset(), 0u);
326 
327     // 3. read from mapped file
328     // write to mapped file
329     TestFileReadAndWrite(mf, content);
330 
331     std::string res;
332     LoadStringFromFile(filename, res);
333     EXPECT_EQ(res, "Complete.normal use.");
334 
335     // 5. test default mapping and write to addr which excess End() but not across this memory page.
336     EXPECT_LE(mf.Size(), mf.PageSize());
337     char* trueEnd = mf.RegionEnd();
338     ASSERT_GT(trueEnd, mf.Begin());
339     // write to mapped file
340     (*trueEnd) = 'E'; // It is allowed to write to this address which excess the End()
341 
342     EXPECT_EQ((*trueEnd), 'E'); // and of course it is allowed to read from that same address.
343 
344     std::string res1;
345     LoadStringFromFile(filename, res1);
346     EXPECT_EQ(res1, "Complete.normal use."); // While no changes will be sync in the original file.
347 
348     RemoveTestFile(filename);
349 }
350 
351 /*
352  * @tc.name: testNewSharedMappingDefaultSize001
353  * @tc.desc: Test mapping which will create a new file with default size.
354  */
355 HWTEST_F(UtilsMappedFileTest, testNewSharedMappingDefaultSize001, TestSize.Level0)
356 {
357     // 1. Create a new file
358     std::string filename = "test_read_write_2.txt";
359     filename.insert(0, SUITE_PATH).insert(0, BASE_PATH);
360     RemoveTestFile(filename);
361 
362     // 2. map file
363     MappedFile mf(filename, MapMode::DEFAULT | MapMode::CREATE_IF_ABSENT);
364     ASSERT_EQ(mf.Map(), MAPPED_FILE_ERR_OK);
365 
366     // check if file is created
367     ASSERT_TRUE(FileExists(filename));
368 
369     // check status
370     ASSERT_TRUE(mf.IsMapped());
371     ASSERT_TRUE(mf.IsNormed());
372 
373     // check map-mode
374     ASSERT_EQ(MapMode::DEFAULT | MapMode::CREATE_IF_ABSENT, mf.GetMode());
375 
376     // check default size
377     struct stat stb = {0};
378     if (stat(filename.c_str(), &stb) == 0) {
379         EXPECT_EQ(stb.st_size, mf.PageSize()); // contents will be zero-filled.
380     }
381     ASSERT_EQ(mf.Size(), mf.PageSize());
382 
383     // 3. write to mapped file
384     std::string toWrite("Write to newly created file.");
385     char* newCur = mf.Begin();
386     for (std::string::size_type i = 0; i < toWrite.length(); i++) {
387         (*newCur) = toWrite[i];
388         newCur++;
389     }
390     std::string res;
391     LoadStringFromFile(filename, res);
392     EXPECT_STREQ(res.c_str(), toWrite.c_str()); // note that `res` contains filled '0',
393                                                 // use c_str() to compare conveniently.
394 
395     // 4. read from mapped file
396     std::string toRead("Waiting to be read.");
397     SaveStringToFile(filename, toRead, 0, true);
398     std::string readout;
399     for (char* cur = mf.Begin(); *cur != '\0'; cur++) {
400         readout.push_back(*cur);
401     }
402     EXPECT_EQ(readout, toRead);
403 
404     RemoveTestFile(filename);
405 }
406 
407 /*
408  * @tc.name: testNewSharedMapping001
409  * @tc.desc: Test mapping which will create a new file with specified params.
410  */
411 HWTEST_F(UtilsMappedFileTest, testNewSharedMapping001, TestSize.Level0)
412 {
413     std::string filename = "test_read_write_3.txt";
414     filename.insert(0, SUITE_PATH).insert(0, BASE_PATH);
415     RemoveTestFile(filename);
416 
417     // set params
418     // new mapping region will not guaranteed to be located at `hint`
419     char* hint = reinterpret_cast<char*>(0x80000); // 0x80000: hint(expected address).
420     off_t size = 1024;
421     off_t offset = 4 * 1024;
422 
423     // 1. map a non-existed file
424     MappedFile mf(filename, MapMode::DEFAULT | MapMode::CREATE_IF_ABSENT, offset, size, hint);
425     ASSERT_EQ(mf.Map(), MAPPED_FILE_ERR_OK);
426 
427     // check if file is created
428     ASSERT_TRUE(FileExists(filename));
429 
430     // check status
431     ASSERT_TRUE(mf.IsMapped());
432     ASSERT_TRUE(mf.IsNormed());
433 
434     // check specified size
435     struct stat stb = {0};
436     if (stat(filename.c_str(), &stb) == 0) {
437         // Exact file size should be offset + mapped size, contents will be zero-filled.
438         EXPECT_EQ(stb.st_size, offset + size);
439     }
440     ASSERT_EQ(mf.Size(), size);
441 
442     // check specified offset
443     ASSERT_EQ(mf.StartOffset(), offset);
444 
445     // check hint
446     ASSERT_TRUE(mf.GetHint() == nullptr || mf.GetHint() == hint);
447     std::cout << "Exact addr:" <<
448               reinterpret_cast<void*>(mf.Begin()) << std::endl <<
449               "Input hint:" << reinterpret_cast<void*>(hint) << std::endl;
450 
451     // 2. write to mapped file
452     std::string toWrite("Write to newly created file.");
453     char* newCur = mf.Begin();
454     for (std::string::size_type i = 0; i < toWrite.length(); i++) {
455         (*newCur) = toWrite[i];
456         newCur++;
457     }
458     std::cout << "Write finished" << std::endl;
459     EXPECT_TRUE(StringExistsInFile(filename, toWrite));
460 
461     // 3. read from mapped file
462     std::string toRead("Waiting to be read.");
463     SaveStringToFile(filename, toRead, offset, true);
464     std::string readout;
465     for (char* cur = mf.Begin(); cur <= mf.End() && *cur != '\0'; cur++) {
466         readout.push_back(*cur);
467     }
468     std::cout << "Read finished" << std::endl;
469     EXPECT_EQ(readout, toRead);
470 
471     RemoveTestFile(filename);
472 }
473 
474 /*
475  * @tc.name: testPrivateMapping001
476  * @tc.desc: Test mapping which will create a new file with specified params.
477  */
478 HWTEST_F(UtilsMappedFileTest, testPrivateMapping001, TestSize.Level0)
479 {
480     // 1. create a new file
481     std::string filename = "test_read_write_4.txt";
482     std::string content = "Test for private use.";
483     ReCreateFile(filename, content);
484 
485     // 2. map file
486     MappedFile mf(filename, MapMode::DEFAULT | MapMode::PRIVATE);
487     ASSERT_EQ(mf.Map(), MAPPED_FILE_ERR_OK);
488 
489     // 3. check status
490     ASSERT_TRUE(mf.IsMapped());
491     ASSERT_TRUE(mf.IsNormed());
492 
493     // 4. read from mapped file
494     // write to mapped file
495     TestFileReadAndWrite(mf, content);
496 
497     std::string res;
498     LoadStringFromFile(filename, res);
499     EXPECT_EQ(res, content); // changes to private mapped file will not write back to the original file
500 
501     RemoveTestFile(filename);
502 }
503 
504 /*
505  * @tc.name: testSharedReadOnlyMapping001
506  * @tc.desc: Test mapping which will create a new file with specified params.
507  */
508 HWTEST_F(UtilsMappedFileTest, testSharedReadOnlyMapping001, TestSize.Level0)
509 {
510     // 1. create a new file
511     std::string filename = "test_read_write_5.txt";
512     std::string content = "Test for readonly use.";
513 
514     ReCreateFile(filename, content);
515 
516     // 2. map file
517     MappedFile mf(filename, MapMode::DEFAULT | MapMode::READ_ONLY);
518     ASSERT_EQ(mf.Map(), MAPPED_FILE_ERR_OK);
519 
520     // 3. check status
521     ASSERT_TRUE(mf.IsMapped());
522     ASSERT_TRUE(mf.IsNormed());
523 
524     // 4. read from mapped file
525     std::string readout;
526     for (char* cur = mf.Begin(); cur <= mf.End(); cur++) {
527         readout.push_back(*cur);
528     }
529     EXPECT_EQ(readout, content);
530     // !Note: write operation is not permitted, which will raise a signal 11.
531 
532     RemoveTestFile(filename);
533 }
534 
535 /*
536  * @tc.name: testReMap001
537  * @tc.desc: Test remapping using `Unmap()` and `Map()`
538  */
539 HWTEST_F(UtilsMappedFileTest, testReMap001, TestSize.Level0)
540 {
541     // 1. create a new file
542     std::string filename = "test_remap_1.txt";
543     std::string content = "Test for remapping use.";
544     ReCreateFile(filename, content);
545 
546     // 2. map file
547     MappedFile mf(filename);
548     ASSERT_EQ(mf.Map(), MAPPED_FILE_ERR_OK);
549 
550     // 3. check status after mapping
551     ASSERT_TRUE(mf.IsMapped());
552     ASSERT_TRUE(mf.IsNormed());
553 
554     ASSERT_EQ(mf.Unmap(), MAPPED_FILE_ERR_OK);
555 
556     // 4. check status after unmapping
557     EXPECT_FALSE(mf.IsMapped());
558     EXPECT_TRUE(mf.IsNormed());
559     EXPECT_EQ(mf.Begin(), nullptr);
560 
561     ASSERT_EQ(mf.Map(), MAPPED_FILE_ERR_OK);
562     // 5. check status after remapping
563     EXPECT_TRUE(mf.IsMapped());
564     EXPECT_TRUE(mf.IsNormed());
565 
566     // 6. check default size
567     struct stat stb = {0};
568     stat(filename.c_str(), &stb);
569     EXPECT_TRUE(stb.st_size == mf.Size() || mf.PageSize() == mf.Size());
570 
571     RemoveTestFile(filename);
572 }
573 
574 /*
575  * @tc.name: testReMap002
576  * @tc.desc: Test remapping via changing params.
577  */
578 HWTEST_F(UtilsMappedFileTest, testReMap002, TestSize.Level0)
579 {
580     // 1. create a new file
581     std::string filename = "test_remap.txt";
582     std::string content = "Test for default use.";
583     ReCreateFile(filename, content);
584 
585     std::string filename1 = "test_remap_1.txt";
586     std::string content1 = "Test for remapping use.";
587     ReCreateFile(filename1, content1);
588 
589     MappedFile mf(filename);
590 
591     // Change params when unmapped.
592     ASSERT_TRUE(mf.ChangeSize(mf.Size() + 1024));
593     ASSERT_TRUE(mf.ChangeSize(MappedFile::DEFAULT_LENGTH));
594     ASSERT_TRUE(mf.ChangeOffset(mf.PageSize()));
595     ASSERT_TRUE(mf.ChangeOffset(0));
596     ASSERT_TRUE(mf.ChangePath(filename1));
597     ASSERT_TRUE(mf.ChangePath(filename));
598     ASSERT_TRUE(mf.ChangeHint(reinterpret_cast<char*>(0x89000))); // 0x89000: random address.
599     ASSERT_TRUE(mf.ChangeMode(MapMode::READ_ONLY));
600 
601     struct stat stb = {0};
602 
603     // 3. check status after mapping
604     // check size
605     // read from Mapped File
606     TestFileStat(mf, filename, content, &stb);
607 
608     // 4. change params
609     ASSERT_TRUE(mf.ChangePath(filename1));
610     ASSERT_TRUE(mf.ChangeSize(MappedFile::DEFAULT_LENGTH));
611     ASSERT_TRUE(mf.ChangeHint(reinterpret_cast<char*>(0x80000))); // 0x80000: random address.
612     ASSERT_TRUE(mf.ChangeMode(MapMode::DEFAULT | MapMode::CREATE_IF_ABSENT));
613 
614     // 5. check status after changing
615     EXPECT_FALSE(mf.IsMapped());
616     EXPECT_FALSE(mf.IsNormed());
617 
618     // 6. remap file
619     ASSERT_EQ(mf.Map(), MAPPED_FILE_ERR_OK);
620 
621     TestFileContentEqual(mf, filename, filename1, content1, &stb);
622 }
623 
624 /*
625  * @tc.name: testReMap003
626  * @tc.desc: Test remapping via Resize().
627  */
628 HWTEST_F(UtilsMappedFileTest, testReMap003, TestSize.Level0)
629 {
630     // 1. create a new file
631     std::string filename = "test_remap.txt";
632     std::string content = "Test for default use.";
633 
634     std::string filename1 = "test_remap_1.txt";
635     std::string content1 = "Test for remapping use.";
636     ReCreateFile(filename, content);
637     ReCreateFile(filename1, content1);
638 
639     // 2. map file
640     MappedFile mf(filename);
641 
642     struct stat stb = {0};
643 
644     // 3. check status after mapping
645     // check size
646     // read from Mapped File
647     TestFileStat(mf, filename, content, &stb);
648 
649     // 4. change params
650     mf.ChangePath(filename1);
651     mf.ChangeSize(MappedFile::DEFAULT_LENGTH);
652 
653     // 5. check status after changing
654     EXPECT_FALSE(mf.IsMapped());
655     EXPECT_FALSE(mf.IsNormed());
656 
657     // 6. remap file
658     ASSERT_EQ(mf.Resize(), MAPPED_FILE_ERR_OK);
659     // 7. check status after remapping
660     TestFileContentEqual(mf, filename, filename1, content1, &stb);
661 }
662 
663 /*
664  * @tc.name: testReMap004
665  * @tc.desc: Test remapping only to extend mapped region via Resize(off_t, bool).
666  */
667 HWTEST_F(UtilsMappedFileTest, testReMap004, TestSize.Level0)
668 {
669     // 1. create a new file
670     std::string content = "Test for remapping use.";
671     std::string filename = "test_remap.txt";
672     ReCreateFile(filename, content);
673 
674     // 2. map file
675     MappedFile mf(filename);
676     struct stat stb = {0};
677 
678     // 3. check status after mapping
679     // check size
680     // read from Mapped File
681     // write to the extended region
682     TestFileStatusAndRead(mf, filename, content, &stb);
683 
684     // 4. Remap to extend region
685     ASSERT_EQ(mf.Resize(mf.Size() + 10), MAPPED_FILE_ERR_OK);
686     // 5. check status after remapping
687     EXPECT_TRUE(mf.IsMapped());
688     EXPECT_TRUE(mf.IsNormed());
689 
690     // 6. check size after remapping
691     stat(filename.c_str(), &stb);
692     EXPECT_TRUE(stb.st_size < mf.Size());
693 
694     std::string res;
695     LoadStringFromFile(filename, res);
696     EXPECT_EQ(res, content); // No changes will be sync in the original file, since mapped region
697                              // is larger than substantial size of the file
698 
699     RemoveTestFile(filename);
700 }
701 
702 /*
703  * @tc.name: testReMap005
704  * @tc.desc: Test remapping to extend mapped region as well as substantial file size via Resize(off_t, bool).
705  */
706 HWTEST_F(UtilsMappedFileTest, testReMap005, TestSize.Level0)
707 {
708     // 1. create a new file
709     std::string filename = "test_remap.txt";
710     std::string content = "Test for remapping use.";
711     ReCreateFile(filename, content);
712 
713     // 2. map file
714     MappedFile mf(filename);
715     struct stat stb = {0};
716 
717     // 3. check status after mapping
718     // check size
719     // read from Mapped File
720     // write to the extended region
721     TestFileStatusAndRead(mf, filename, content, &stb);
722 
723     // 4. remap to extend region
724     ASSERT_EQ(mf.Resize(mf.Size() + 10, true), MAPPED_FILE_ERR_OK);
725     // check status after remapping
726     EXPECT_TRUE(mf.IsMapped());
727     EXPECT_TRUE(mf.IsNormed());
728 
729     // 5. check size after remapping
730     stat(filename.c_str(), &stb);
731     EXPECT_TRUE(stb.st_size == mf.Size()); // File size will sync to that of the mapped region.
732 
733     std::string res;
734     LoadStringFromFile(filename, res);
735     EXPECT_STREQ(res.c_str(), content.append("E").c_str()); // Changes will be sync in the original file.
736 }
737 
738 /*
739  * @tc.name: testReMap006
740  * @tc.desc: Test remapping to via Resize(off_t, bool).
741  */
742 HWTEST_F(UtilsMappedFileTest, testReMap006, TestSize.Level0)
743 {
744     // 1. create a new file
745     std::string filename = "test_remap.txt";
746     std::string content = "Test for remapping use.";
747 
748     ReCreateFile(filename, content);
749 
750     // 2. map file
751     off_t size = 20;
752     MappedFile mf(filename, MapMode::DEFAULT, 0, size);
753     ASSERT_EQ(mf.Map(), MAPPED_FILE_ERR_OK);
754 
755     // 3. check status after mapping
756     ASSERT_TRUE(mf.IsMapped());
757     ASSERT_TRUE(mf.IsNormed());
758 
759     // 4. check size
760     ASSERT_TRUE(size == mf.Size());
761 
762     // 5. remap to extend region
763     ASSERT_EQ(mf.Resize(MappedFile::DEFAULT_LENGTH, true), MAPPED_FILE_ERR_OK);
764     off_t lessSize = mf.Size() - 8;
765     ASSERT_EQ(mf.Resize(lessSize, true), MAPPED_FILE_ERR_OK);
766     // 6. check status after remapping
767     EXPECT_TRUE(mf.IsMapped());
768     EXPECT_TRUE(mf.IsNormed());
769 
770     // 7. check size after remapping
771     struct stat stb = {0};
772     stat(filename.c_str(), &stb);
773     EXPECT_EQ(lessSize, mf.Size());
774 }
775 
776 /*
777  * @tc.name: testTurnNext001
778  * @tc.desc: Test TurnNext() when `IsMapped()`.
779  */
780 HWTEST_F(UtilsMappedFileTest, testTurnNext001, TestSize.Level0)
781 {
782     // 1. create a new file
783     std::string filename = "test_remap.txt";
784     std::string content = "Test for remapping use.";
785 
786     ReCreateFile(filename, content);
787 
788     struct stat stb = {0};
789     ASSERT_EQ(stat(filename.c_str(), &stb), 0);
790     off_t orig = stb.st_size; // 23 bytes
791 
792     // 2. extend its size
793     int fd = open(filename.c_str(), O_RDWR | O_CLOEXEC);
794     ASSERT_NE(fd, -1);
795     ASSERT_EQ(ftruncate(fd, MappedFile::PageSize() + MappedFile::PageSize() / 100LL), 0); // 100: ratio to a page.
796 
797     // 3. map file
798     MappedFile mf(filename, MapMode::DEFAULT, 0, orig);
799     ASSERT_EQ(mf.Map(), MAPPED_FILE_ERR_OK);
800 
801     // 4. check status after mapping
802     ASSERT_TRUE(mf.IsMapped());
803     ASSERT_TRUE(mf.IsNormed());
804 
805     // 5. turn next mapped region with the same size as the file's initial size.
806     EXPECT_EQ(mf.TurnNext(), MAPPED_FILE_ERR_OK);
807     char* cur = mf.Begin();
808     *cur = 'N';
809 
810     std::string res;
811     LoadStringFromFile(filename, res);
812     EXPECT_STREQ(res.c_str(), content.append("N").c_str());
813 
814     // 6. keep turnNext within a page
815     // this turn will reach the bottom of a page
816     TestFileRegion(mf, orig);
817 
818     // 7. this turn will trigger a remapping
819     off_t endOff = mf.EndOffset();
820     off_t curSize = mf.Size();
821     EXPECT_EQ(mf.TurnNext(), MAPPED_FILE_ERR_OK);
822     EXPECT_TRUE(mf.IsMapped());
823     EXPECT_EQ(mf.StartOffset(), endOff + 1);
824     EXPECT_EQ(mf.Size(), curSize);
825     EXPECT_EQ(mf.RegionStart(), mf.Begin());
826     EXPECT_EQ(static_cast<off_t>(mf.RegionEnd() - mf.RegionStart()) + 1LL, mf.PageSize());
827     std::cout << "==Remap A New Page==" << std::endl;
828     PrintStatus(mf);
829 
830     // 8. keep turnNext within a page
831     for (off_t cnt = 1; cnt < (MappedFile::PageSize() / 100LL / curSize); cnt++) {
832         endOff = mf.EndOffset();
833         EXPECT_EQ(mf.TurnNext(), MAPPED_FILE_ERR_OK);
834         EXPECT_EQ(mf.StartOffset(), endOff + 1);
835         EXPECT_EQ(mf.Size(), curSize);
836     }
837 
838     // 10. this turn will fail since no place remained.
839     EXPECT_NE(mf.TurnNext(), MAPPED_FILE_ERR_OK);
840 
841     RemoveTestFile(filename);
842 }
843 
844 /*
845  * @tc.name: testTurnNext002
846  * @tc.desc: Test TurnNext() when `!IsMapped()`.
847  */
848 HWTEST_F(UtilsMappedFileTest, testTurnNext002, TestSize.Level0)
849 {
850     // 1. create a new file
851     std::string filename = "test_remap.txt";
852     std::string content = "Test for remapping use.";
853 
854     ReCreateFile(filename, content);
855 
856     // 2. map file
857     MappedFile mf(filename);
858     ASSERT_EQ(mf.Map(), MAPPED_FILE_ERR_OK);
859     off_t curSize = mf.Size();
860     off_t curOff = mf.StartOffset();
861 
862     // 3. check status after mapping
863     ASSERT_TRUE(mf.IsMapped());
864     ASSERT_TRUE(mf.IsNormed());
865     // 4. recommand to unmap first before other operations on the file.
866     ASSERT_EQ(mf.Unmap(), MAPPED_FILE_ERR_OK);
867     // 5. enlarge file size to make it possible to `turnNext()`.
868     ASSERT_EQ(ftruncate(mf.GetFd(), MappedFile::PageSize() + MappedFile::PageSize() / 100LL), 0);
869     // 6. turn next page of `PageSize()` and keep the same `size_`
870     EXPECT_EQ(mf.TurnNext(), MAPPED_FILE_ERR_OK);
871     EXPECT_EQ(mf.Size(), curSize);
872     EXPECT_EQ(static_cast<off_t>(mf.StartOffset()), curOff + mf.PageSize());
873 
874     RemoveTestFile(filename);
875 }
876 
877 /*
878  * @tc.name: testTurnNext003
879  * @tc.desc: Test TurnNext() (using internal fd to `ftruncate()`).
880  */
881 HWTEST_F(UtilsMappedFileTest, testTurnNext003, TestSize.Level0)
882 {
883     // 1. create a new file
884     std::string content = "Test for remapping use.";
885     std::string filename = "test_remap.txt";
886 
887     ReCreateFile(filename, content);
888 
889     // 2. map file
890     MappedFile mf(filename);
891     ASSERT_EQ(mf.Map(), MAPPED_FILE_ERR_OK);
892 
893     // 3. check status after mapping
894     ASSERT_TRUE(mf.IsNormed());
895     ASSERT_TRUE(mf.IsMapped());
896 
897     // 4. recommand to unmap first before other operations on the file.
898     ASSERT_EQ(mf.Unmap(), MAPPED_FILE_ERR_OK);
899     // 5. enlarge file size to make it possible to `turnNext()`.
900     ASSERT_EQ(ftruncate(mf.GetFd(), MappedFile::PageSize() + MappedFile::PageSize() / 100LL), 0);
901 
902     // 6. remap
903     ASSERT_EQ(mf.Map(), MAPPED_FILE_ERR_OK);
904 
905     // 7. turn next mapped region with the same size as the file's initial size.
906     ASSERT_EQ(mf.TurnNext(), MAPPED_FILE_ERR_OK);
907     char* cur = mf.Begin();
908     *cur = 'N';
909 
910     std::string res;
911     LoadStringFromFile(filename, res);
912     EXPECT_STREQ(res.c_str(), content.append("N").c_str());
913 
914     RemoveTestFile(filename);
915 }
916 
917 /*
918  * @tc.name: testTurnNext004
919  * @tc.desc: Test TurnNext() failed.
920  */
921 HWTEST_F(UtilsMappedFileTest, testTurnNext004, TestSize.Level0)
922 {
923     // 1. create a new file
924     std::string filename = "test_remap.txt";
925     std::string content = "Test for remapping use.";
926 
927     ReCreateFile(filename, content);
928 
929     // 2. map file
930     MappedFile mf(filename);
931     ASSERT_EQ(mf.Map(), MAPPED_FILE_ERR_OK);
932 
933     // 3. check status after mapping
934     ASSERT_TRUE(mf.IsMapped());
935     ASSERT_TRUE(mf.IsNormed());
936 
937     // 4. turn next mapped region with the same size as the file's initial size.
938     EXPECT_EQ(mf.TurnNext(), ERR_INVALID_OPERATION);
939 
940     RemoveTestFile(filename);
941 }
942 
943 /*
944  * @tc.name: testTurnNext005
945  * @tc.desc: Test TurnNext() with file size less than one page.
946  */
947 HWTEST_F(UtilsMappedFileTest, testTurnNext005, TestSize.Level0)
948 {
949     // 1. create a new file
950     std::string filename = "test_remap.txt";
951     std::string content = "Test for remapping use.00";
952 
953     ReCreateFile(filename, content);
954 
955     struct stat stb = {0};
956     ASSERT_EQ(stat(filename.c_str(), &stb), 0);
957     off_t orig = stb.st_size; // 25 bytes
958 
959     // 2. extend its size
960     int fd = open(filename.c_str(), O_RDWR | O_CLOEXEC);
961     ASSERT_NE(fd, -1);
962     ASSERT_EQ(ftruncate(fd, MappedFile::PageSize() + 10), 0); // 10: remain contents less than 25bits.
963 
964     // 3. map file
965     MappedFile mf(filename, MapMode::DEFAULT, 0, orig);
966     ASSERT_EQ(mf.Map(), MAPPED_FILE_ERR_OK);
967 
968     // 4. check status after mapping
969     ASSERT_TRUE(mf.IsMapped());
970     ASSERT_TRUE(mf.IsNormed());
971 
972     // 5. turn next mapped region with the same size as the file's initial size.
973     EXPECT_EQ(mf.TurnNext(), MAPPED_FILE_ERR_OK);
974 
975     // 6. keep turnNext within a page
976     // this turn will reach the bottom of a page
977     TestFileRegion(mf, orig);
978 
979     // 7. this turn will trigger a remapping
980     off_t endOff = mf.EndOffset();
981     EXPECT_EQ(mf.TurnNext(), MAPPED_FILE_ERR_OK);
982     EXPECT_TRUE(mf.IsMapped());
983     EXPECT_EQ(mf.StartOffset(), endOff + 1);
984     EXPECT_EQ(mf.Size(), 10);
985     EXPECT_EQ(mf.RegionStart(), mf.Begin());
986     EXPECT_EQ(static_cast<off_t>(mf.RegionEnd() - mf.RegionStart()) + 1LL, mf.PageSize());
987     std::cout << "==Remap A New Page==" << std::endl;
988     PrintStatus(mf);
989 }
990 
991 /*
992  * @tc.name: testInvalidMap001
993  * @tc.desc: Test file mapping with invalid offset.
994  */
995 HWTEST_F(UtilsMappedFileTest, testInvalidMap001, TestSize.Level0)
996 {
997     // 1. create a new file
998     std::string filename = "test_invalid_1.txt";
999     std::string content = "Test for invalid use.";
1000 
1001     ReCreateFile(filename, content);
1002 
1003     // 2. map file
1004     off_t offset = 100; // Specify offset that is not multiple of page-size.
1005     MappedFile mf(filename, MapMode::DEFAULT, offset);
1006     ASSERT_NE(mf.Map(), MAPPED_FILE_ERR_OK);
1007 
1008     MappedFile mf1(filename, MapMode::DEFAULT, -1);
1009     ASSERT_NE(mf1.Map(), MAPPED_FILE_ERR_OK);
1010 
1011     // 3. check status
1012     EXPECT_FALSE(mf.IsMapped());
1013     EXPECT_FALSE(mf.IsNormed()); // mapping will fail in normalize stage.
1014     EXPECT_FALSE(mf1.IsMapped());
1015     EXPECT_FALSE(mf1.IsNormed()); // mapping will fail in normalize stage.
1016 
1017     RemoveTestFile(filename);
1018 }
1019 
1020 /*
1021  * @tc.name: testInvalidMap002
1022  * @tc.desc: Test file mapping with invalid offset excessing the substantial size of the file.
1023  */
1024 HWTEST_F(UtilsMappedFileTest, testInvalidMap002, TestSize.Level0)
1025 {
1026     // 1. create a new file
1027     std::string filename = "test_invalid_2.txt";
1028     std::string content = "Test for invalid use.";
1029 
1030     ReCreateFile(filename, content);
1031 
1032     // 2. map file
1033     off_t offset = 4 * 1024; // Specify offset excessing the substantial size of the file.
1034     MappedFile mf(filename, MapMode::DEFAULT, offset);
1035     ASSERT_NE(mf.Map(), MAPPED_FILE_ERR_OK);
1036 
1037     // 3. check status
1038     EXPECT_FALSE(mf.IsMapped());
1039     EXPECT_FALSE(mf.IsNormed()); // mapping will fail in normalize stage.
1040 
1041     RemoveTestFile(filename);
1042 }
1043 
1044 /*
1045  * @tc.name: testInvalidMap003
1046  * @tc.desc: Test mapping non-existed file without setting CREAT_IF_ABSENT.
1047  */
1048 HWTEST_F(UtilsMappedFileTest, testInvalidMap003, TestSize.Level0)
1049 {
1050     // 1. create a new file
1051     std::string filename = "test_invalid_3.txt";
1052     filename.insert(0, SUITE_PATH).insert(0, BASE_PATH);
1053     RemoveTestFile(filename);
1054 
1055     // 2. map file
1056     MappedFile mf(filename);
1057     ASSERT_NE(mf.Map(), MAPPED_FILE_ERR_OK);
1058 
1059     // 3. check status
1060     EXPECT_FALSE(mf.IsMapped());
1061     EXPECT_FALSE(mf.IsNormed()); // mapping will fail in normalize stage.
1062 
1063     RemoveTestFile(filename);
1064 }
1065 
1066 /*
1067  * @tc.name: testInvalidMap004
1068  * @tc.desc: Test mapping with invalid size.
1069  */
1070 HWTEST_F(UtilsMappedFileTest, testInvalidMap004, TestSize.Level0)
1071 {
1072     // 1. create a new file
1073     std::string filename = "test_invalid_4.txt";
1074     std::string content = "Test for invalid use.";
1075 
1076     ReCreateFile(filename, content);
1077 
1078     // 2. map file
1079     MappedFile mf(filename, MapMode::DEFAULT, 0, -2); // -2: less than DEFAULT_LENGTH(-1)
1080     ASSERT_EQ(mf.Map(), ERR_INVALID_VALUE);
1081 
1082     // 3. map again with another invalid param.
1083     MappedFile mf1(filename, MapMode::DEFAULT, 0, 0);
1084     ASSERT_EQ(mf1.Map(), ERR_INVALID_VALUE);
1085 
1086     // 4. check status
1087     EXPECT_FALSE(mf.IsMapped());
1088     EXPECT_FALSE(mf.IsNormed()); // mapping will fail in normalize stage.
1089     EXPECT_FALSE(mf1.IsMapped());
1090     EXPECT_FALSE(mf1.IsNormed()); // mapping will fail in normalize stage.
1091 
1092     RemoveTestFile(filename);
1093 }
1094 
1095 /*
1096  * @tc.name: testInvalidMap005
1097  * @tc.desc: Test mapping an already mapped file.
1098  */
1099 HWTEST_F(UtilsMappedFileTest, testInvalidMap005, TestSize.Level0)
1100 {
1101     // 1. create a new file
1102     std::string filename = "test_invalid_6.txt";
1103     std::string content = "Test for invalid use.";
1104 
1105     ReCreateFile(filename, content);
1106 
1107     // 2. map file
1108     MappedFile mf(filename);
1109     ASSERT_EQ(mf.Map(), MAPPED_FILE_ERR_OK);
1110     ASSERT_EQ(mf.Map(), ERR_INVALID_OPERATION); // Map again.
1111 
1112     // 3. check status
1113     EXPECT_TRUE(mf.IsMapped());
1114     EXPECT_TRUE(mf.IsNormed());
1115 
1116     RemoveTestFile(filename);
1117 }
1118 
1119 /*
1120  * @tc.name: testInvalidMap006
1121  * @tc.desc: Test resize with invalid params.
1122  */
1123 HWTEST_F(UtilsMappedFileTest, testInvalidMap006, TestSize.Level0)
1124 {
1125     // 1. create a new file
1126     std::string filename = "test_invalid_7.txt";
1127     std::string content = "Test for invalid use.";
1128 
1129     ReCreateFile(filename, content);
1130 
1131     // 2. map file
1132     MappedFile mf(filename);
1133     ASSERT_EQ(mf.Map(), MAPPED_FILE_ERR_OK);
1134 
1135     // 3. check status
1136     ASSERT_TRUE(mf.IsMapped());
1137     ASSERT_TRUE(mf.IsNormed());
1138 
1139     // 4. resize
1140     EXPECT_EQ(mf.Resize(0), ERR_INVALID_OPERATION);
1141     EXPECT_EQ(mf.Resize(-2), ERR_INVALID_OPERATION); // -2: less than DEFAULT_LENGTH(-1).
1142     EXPECT_EQ(mf.Resize(mf.Size()), ERR_INVALID_OPERATION);
1143 
1144     // 5. Unmap first then resize.
1145     ASSERT_EQ(mf.Unmap(), MAPPED_FILE_ERR_OK);
1146     EXPECT_EQ(mf.Resize(mf.Size() + 8), ERR_INVALID_OPERATION);
1147 
1148     RemoveTestFile(filename);
1149 }
1150 
1151 /*
1152  * @tc.name: testInvalidMap007
1153  * @tc.desc: Test resize with no param changed.
1154  */
1155 HWTEST_F(UtilsMappedFileTest, testInvalidMap007, TestSize.Level0)
1156 {
1157     // 1. create a new file
1158     std::string filename = "test_invalid_8.txt";
1159     std::string content = "Test for invalid use.";
1160 
1161     ReCreateFile(filename, content);
1162 
1163     // 2. map file
1164     MappedFile mf(filename);
1165     ASSERT_EQ(mf.Map(), MAPPED_FILE_ERR_OK);
1166 
1167     // 3. check status
1168     ASSERT_TRUE(mf.IsMapped());
1169     ASSERT_TRUE(mf.IsNormed());
1170 
1171     // 4. resize
1172     EXPECT_EQ(mf.Resize(), ERR_INVALID_OPERATION);
1173 
1174     RemoveTestFile(filename);
1175 }
1176 
1177 /*
1178  * @tc.name: testInvalidMap008
1179  * @tc.desc: Test TurnNext() with params changed.
1180  */
1181 HWTEST_F(UtilsMappedFileTest, testInvalidMap008, TestSize.Level0)
1182 {
1183     // 1. create a new file
1184     std::string filename = "test_invalid_9.txt";
1185     std::string content = "Test for invalid use.";
1186 
1187     ReCreateFile(filename, content);
1188 
1189     // 2. map file
1190     MappedFile mf(filename);
1191     ASSERT_EQ(mf.Map(), MAPPED_FILE_ERR_OK);
1192 
1193     // 3. check status
1194     ASSERT_TRUE(mf.IsMapped());
1195     ASSERT_TRUE(mf.IsNormed());
1196 
1197     // 4. Change params
1198     ASSERT_TRUE(mf.ChangeSize(mf.Size() + 1));
1199 
1200     // 5. check status
1201     ASSERT_FALSE(mf.IsMapped());
1202     ASSERT_FALSE(mf.IsNormed());
1203 
1204     // 6. turn next.
1205     EXPECT_EQ(mf.TurnNext(), ERR_INVALID_OPERATION);
1206 
1207     RemoveTestFile(filename);
1208 }
1209 
1210 /*
1211  * @tc.name: testInvalidMap009
1212  * @tc.desc: Test ChangeXX() with invalid params.
1213  */
1214 HWTEST_F(UtilsMappedFileTest, testInvalidMap009, TestSize.Level0)
1215 {
1216     // 1. create a new file
1217     std::string filename = "test_invalid_10.txt";
1218     std::string content = "Test for invalid use.";
1219 
1220     ReCreateFile(filename, content);
1221 
1222     // 2. create MappedFile
1223     MappedFile mf(filename);
1224 
1225     // 3. map file
1226     ASSERT_EQ(mf.Map(), MAPPED_FILE_ERR_OK);
1227 
1228     // 4. check status
1229     ASSERT_TRUE(mf.IsMapped());
1230     ASSERT_TRUE(mf.IsNormed());
1231 
1232     // 5. Change params
1233     ASSERT_FALSE(mf.ChangeOffset(mf.StartOffset()));
1234     ASSERT_FALSE(mf.ChangeSize(mf.Size()));
1235     ASSERT_FALSE(mf.ChangeHint(mf.GetHint()));
1236     ASSERT_FALSE(mf.ChangeMode(mf.GetMode()));
1237     ASSERT_FALSE(mf.ChangePath(mf.GetPath()));
1238 
1239     RemoveTestFile(filename);
1240 }
1241 
1242 /*
1243  * @tc.name: testAutoAdjustedMode001
1244  * @tc.desc: Test mapping file with invalid mapping mode, but can be auto adjusted.
1245  */
1246 HWTEST_F(UtilsMappedFileTest, testAutoAdjustedMode001, TestSize.Level0)
1247 {
1248     // 1. create a new file
1249     std::string filename = "test_adjmod_1.txt";
1250     std::string content = "Test for auto adj use.";
1251 
1252     ReCreateFile(filename, content);
1253 
1254     // 2. map file
1255     MapMode mode = static_cast<MapMode>(1) | static_cast<MapMode>(16) |
1256                    MapMode::PRIVATE | MapMode::READ_ONLY; // bits out of the scope will be ignored.
1257     MappedFile mf(filename, mode);
1258     ASSERT_EQ(mf.Map(), MAPPED_FILE_ERR_OK);
1259 
1260     // 3. check status
1261     EXPECT_TRUE(mf.IsMapped());
1262     EXPECT_TRUE(mf.IsNormed());
1263 
1264     // 4. check map-mode
1265     ASSERT_EQ(MapMode::PRIVATE | MapMode::READ_ONLY, mf.GetMode());
1266 
1267     RemoveTestFile(filename);
1268 }
1269 
1270 /*
1271  * @tc.name: testAutoAdjustedSize001
1272  * @tc.desc: Test file mapping with size excessing the last page of the file.
1273  */
1274 HWTEST_F(UtilsMappedFileTest, testAutoAdjustedSize001, TestSize.Level0)
1275 {
1276     // 1. create a new file
1277     std::string filename = "test_adjsize_1.txt";
1278     std::string content = "Test for auto adj use.";
1279 
1280     ReCreateFile(filename, content);
1281 
1282     // 2. map file
1283     off_t size = 5 * 1024; // Specified size excessing the last page of the file.
1284     MappedFile mf(filename, MapMode::DEFAULT, 0, size);
1285     ASSERT_EQ(mf.Map(), MAPPED_FILE_ERR_OK);
1286 
1287     // 3. check status
1288     EXPECT_TRUE(mf.IsMapped());
1289     EXPECT_TRUE(mf.IsNormed());
1290 
1291     // 4. check size
1292     struct stat stb = {0};
1293     stat(filename.c_str(), &stb);
1294     off_t max = (stb.st_size / mf.PageSize() + 1LL) * mf.PageSize() - 0LL;
1295     EXPECT_EQ(mf.Size(), max); // Size will be automatically adjusted, due to safe-concern.
1296 
1297     RemoveTestFile(filename);
1298 }
1299 
1300 /*
1301  * @tc.name: testAutoAdjustedSize002
1302  * @tc.desc: Test file mapping with size excessing the last page of the file.
1303  */
1304 HWTEST_F(UtilsMappedFileTest, testAutoAdjustedSize002, TestSize.Level0)
1305 {
1306     // 1. create a new file
1307     std::string filename = "test_adjsize_2.txt";
1308     std::string content = "Test for auto adj use.";
1309 
1310     ReCreateFile(filename, content);
1311 
1312     // 2. Extend size manually
1313     int fd = open(filename.c_str(), O_RDWR | O_CLOEXEC);
1314     if (fd != -1) {
1315         std::cout << "open success." << std::endl;
1316         ftruncate(fd, 7 * 1024);
1317 
1318         // 3. map file
1319         off_t offset = 4 * 1024;
1320         off_t size = 5 * 1024; // Specified size excessing the last page of the file.
1321         MappedFile mf(filename, MapMode::DEFAULT, offset, size);
1322         ASSERT_EQ(mf.Map(), MAPPED_FILE_ERR_OK);
1323 
1324         // 4. check status
1325         EXPECT_TRUE(mf.IsMapped());
1326         EXPECT_TRUE(mf.IsNormed());
1327 
1328         // 5. check size
1329         struct stat stb = {0};
1330         stat(filename.c_str(), &stb);
1331         off_t max = (stb.st_size / mf.PageSize() + 1LL) * mf.PageSize() - offset;
1332         EXPECT_EQ(mf.Size(), max); // Size will be automatically adjusted, due to safe-concern.
1333 
1334         close(fd);
1335     }
1336 
1337     RemoveTestFile(filename);
1338 }
1339 
1340 /*
1341  * @tc.name: testMoveMappedFile001
1342  * @tc.desc: Test move constructor.
1343  */
1344 HWTEST_F(UtilsMappedFileTest, testMoveMappedFile001, TestSize.Level0)
1345 {
1346     // 1. create a new file
1347     std::string filename = "test_move_1.txt";
1348     std::string content = "Test for move use.";
1349 
1350     ReCreateFile(filename, content);
1351 
1352     // 2. map file
1353     MappedFile mf(filename);
1354     ASSERT_EQ(mf.Map(), MAPPED_FILE_ERR_OK);
1355 
1356     off_t size = mf.Size();
1357     off_t offset = mf.StartOffset();
1358     char* data = mf.Begin();
1359     MapMode mode = mf.GetMode();
1360     const char* hint = mf.GetHint();
1361 
1362     // 3. move to a new object
1363     MappedFile mfNew(std::move(mf));
1364 
1365     // 4. check status and params after move
1366     EXPECT_FALSE(mf.IsMapped());
1367     EXPECT_FALSE(mf.IsNormed());
1368     EXPECT_EQ(mf.Begin(), nullptr);
1369     EXPECT_EQ(mf.Size(), MappedFile::DEFAULT_LENGTH);
1370     EXPECT_EQ(mf.StartOffset(), 0);
1371     EXPECT_EQ(mf.GetMode(), MapMode::DEFAULT);
1372     EXPECT_EQ(mf.GetHint(), nullptr);
1373     EXPECT_EQ(mf.GetPath(), "");
1374 
1375     EXPECT_TRUE(mfNew.IsMapped());
1376     EXPECT_TRUE(mfNew.IsNormed());
1377     EXPECT_EQ(mfNew.Begin(), data);
1378     EXPECT_EQ(mfNew.Size(), size);
1379     EXPECT_EQ(mfNew.StartOffset(), offset);
1380     EXPECT_EQ(mfNew.GetMode(), mode);
1381     EXPECT_EQ(mfNew.GetHint(), hint);
1382     EXPECT_EQ(mfNew.GetPath(), filename);
1383 
1384     // 5. read from mapped file
1385     // write to mapped file
1386     TestFileWrite(mfNew, filename, content);
1387 }
1388 
1389 /*
1390  * @tc.name: testMoveMappedFile002
1391  * @tc.desc: Test move constructor with ummapped region.
1392  */
1393 HWTEST_F(UtilsMappedFileTest, testMoveMappedFile002, TestSize.Level0)
1394 {
1395     // 1. create a new file
1396     std::string filename = "test_move_2.txt";
1397     std::string content = "Test for move use.";
1398 
1399     ReCreateFile(filename, content);
1400 
1401     // 2. map file
1402     MappedFile mf(filename);
1403     ASSERT_EQ(mf.Map(), MAPPED_FILE_ERR_OK);
1404 
1405     off_t size = mf.Size();
1406     off_t offset = mf.StartOffset();
1407     MapMode mode = mf.GetMode();
1408     const char* hint = mf.GetHint();
1409 
1410     ASSERT_EQ(mf.Unmap(), MAPPED_FILE_ERR_OK);
1411     // 3. move to a new object
1412     MappedFile mfNew(std::move(mf));
1413 
1414     // 4. check status and params after move
1415     EXPECT_FALSE(mf.IsMapped());
1416     EXPECT_FALSE(mf.IsNormed());
1417     EXPECT_EQ(mf.Begin(), nullptr);
1418     EXPECT_EQ(mf.Size(), MappedFile::DEFAULT_LENGTH);
1419     EXPECT_EQ(mf.StartOffset(), 0);
1420     EXPECT_EQ(mf.GetMode(), MapMode::DEFAULT);
1421     EXPECT_EQ(mf.GetHint(), nullptr);
1422     EXPECT_EQ(mf.GetPath(), "");
1423 
1424     EXPECT_FALSE(mfNew.IsMapped());
1425     EXPECT_TRUE(mfNew.IsNormed());
1426     EXPECT_EQ(mfNew.Begin(), nullptr);
1427     EXPECT_EQ(mfNew.Size(), size);
1428     EXPECT_EQ(mfNew.StartOffset(), offset);
1429     EXPECT_EQ(mfNew.GetMode(), mode);
1430     EXPECT_EQ(mfNew.GetHint(), hint);
1431     EXPECT_EQ(mfNew.GetPath(), filename);
1432 
1433     // 5. Map again
1434     ASSERT_EQ(mfNew.Map(), MAPPED_FILE_ERR_OK);
1435     // 6. read from mapped file
1436     // write to mapped file
1437     TestFileWrite(mfNew, filename, content);
1438 }
1439 
1440 /*
1441  * @tc.name: testMoveMappedFile003
1442  * @tc.desc: Test move assignment operator overload.
1443  */
1444 HWTEST_F(UtilsMappedFileTest, testMoveMappedFile003, TestSize.Level0)
1445 {
1446     // 1. create a new file
1447     std::string filename = "test_move_3.txt";
1448     std::string content = "Test for move use.";
1449 
1450     std::string filename1 = "test_move_4.txt";
1451     std::string content1 = "Test for move use.";
1452 
1453     ReCreateFile(filename, content);
1454     ReCreateFile(filename1, content1);
1455 
1456     // 2. map file
1457     MappedFile mf(filename);
1458     ASSERT_EQ(mf.Map(), MAPPED_FILE_ERR_OK);
1459     MappedFile mf1(filename1);
1460     ASSERT_EQ(mf1.Map(), MAPPED_FILE_ERR_OK);
1461 
1462     off_t size = mf1.Size();
1463     off_t offset = mf1.StartOffset();
1464     MapMode mode = mf1.GetMode();
1465     char* data = mf1.Begin();
1466     const char* hint = mf1.GetHint();
1467 
1468     // 3. move assignment
1469     mf = std::move(mf1);
1470 
1471     // 4. check status and params after move
1472     EXPECT_TRUE(mf.IsMapped());
1473     EXPECT_TRUE(mf.IsNormed());
1474     EXPECT_EQ(mf.Begin(), data);
1475     EXPECT_EQ(mf.Size(), size);
1476     EXPECT_EQ(mf.StartOffset(), offset);
1477     EXPECT_EQ(mf.GetMode(), mode);
1478     EXPECT_EQ(mf.GetHint(), hint);
1479     EXPECT_EQ(mf.GetPath(), filename1);
1480 
1481     // 5. read from mapped file
1482     // write to mapped file
1483     TestTwoFileWrite(mf, filename, filename1, content1);
1484 }
1485 
1486 /*
1487  * @tc.name: testMoveMappedFile004
1488  * @tc.desc: Test move assignment operator overload with ummapped region.
1489  */
1490 HWTEST_F(UtilsMappedFileTest, testMoveMappedFile004, TestSize.Level0)
1491 {
1492     // 1. create a new file
1493     std::string filename = "test_move_4.txt";
1494     std::string content = "Test for move use.";
1495     ReCreateFile(filename, content);
1496 
1497     std::string filename1 = "test_move_5.txt";
1498     std::string content1 = "Test for move use.";
1499     ReCreateFile(filename1, content1);
1500 
1501     // 2. map file
1502     MappedFile mf(filename);
1503     MappedFile mf1(filename1);
1504     ASSERT_EQ(mf.Map(), MAPPED_FILE_ERR_OK);
1505     ASSERT_EQ(mf1.Map(), MAPPED_FILE_ERR_OK);
1506 
1507     off_t size = mf1.Size();
1508     off_t offset = mf1.StartOffset();
1509     MapMode mode = mf1.GetMode();
1510     const char* hint = mf1.GetHint();
1511 
1512     // 3. ummap mf1
1513     ASSERT_EQ(mf1.Unmap(), MAPPED_FILE_ERR_OK);
1514     // 4. move assignment
1515     mf = std::move(mf1);
1516     // 5. check status and params after move
1517     EXPECT_FALSE(mf.IsMapped());
1518     EXPECT_TRUE(mf.IsNormed());
1519     EXPECT_EQ(mf.Begin(), nullptr); // since mf1 is unmapped, its `data_` are set to `nullptr`
1520     EXPECT_EQ(mf.Size(), size);
1521     EXPECT_EQ(mf.StartOffset(), offset);
1522     EXPECT_EQ(mf.GetMode(), mode);
1523     EXPECT_EQ(mf.GetHint(), hint);
1524     EXPECT_EQ(mf.GetPath(), filename1);
1525 
1526     ASSERT_EQ(mf.Map(), MAPPED_FILE_ERR_OK);
1527     // 6. read from mapped file
1528     // write to mapped file
1529     TestTwoFileWrite(mf, filename, filename1, content1);
1530 }
1531 
1532 }  // namespace
1533 }  // namespace OHOS