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