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