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