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