xref: /aosp_15_r20/external/cronet/base/files/memory_mapped_file_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2014 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/files/memory_mapped_file.h"
6 
7 #include <stddef.h>
8 #include <stdint.h>
9 
10 #include <utility>
11 
12 #include "base/files/file_path.h"
13 #include "base/files/file_util.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "testing/platform_test.h"
16 
17 namespace base {
18 
19 namespace {
20 
21 // Create a temporary buffer and fill it with a watermark sequence.
CreateTestBuffer(size_t size,size_t offset)22 std::unique_ptr<uint8_t[]> CreateTestBuffer(size_t size, size_t offset) {
23   std::unique_ptr<uint8_t[]> buf(new uint8_t[size]);
24   for (size_t i = 0; i < size; ++i)
25     buf.get()[i] = static_cast<uint8_t>((offset + i) % 253);
26   return buf;
27 }
28 
29 // Check that the watermark sequence is consistent with the |offset| provided.
CheckBufferContents(span<const uint8_t> bytes,size_t offset)30 bool CheckBufferContents(span<const uint8_t> bytes, size_t offset) {
31   std::unique_ptr<uint8_t[]> test_data(CreateTestBuffer(bytes.size(), offset));
32   return memcmp(test_data.get(), bytes.data(), bytes.size()) == 0;
33 }
34 
35 class MemoryMappedFileTest : public PlatformTest {
36  protected:
SetUp()37   void SetUp() override {
38     PlatformTest::SetUp();
39     CreateTemporaryFile(&temp_file_path_);
40   }
41 
TearDown()42   void TearDown() override { EXPECT_TRUE(DeleteFile(temp_file_path_)); }
43 
CreateTemporaryTestFile(size_t size)44   void CreateTemporaryTestFile(size_t size) {
45     File file(temp_file_path_,
46               File::FLAG_CREATE_ALWAYS | File::FLAG_READ | File::FLAG_WRITE);
47     EXPECT_TRUE(file.IsValid());
48 
49     std::unique_ptr<uint8_t[]> test_data(CreateTestBuffer(size, 0));
50     size_t bytes_written =
51         file.Write(0, reinterpret_cast<char*>(test_data.get()), size);
52     EXPECT_EQ(size, bytes_written);
53     file.Close();
54   }
55 
temp_file_path() const56   const FilePath temp_file_path() const { return temp_file_path_; }
57 
58  private:
59   FilePath temp_file_path_;
60 };
61 
TEST_F(MemoryMappedFileTest,MapWholeFileByPath)62 TEST_F(MemoryMappedFileTest, MapWholeFileByPath) {
63   const size_t kFileSize = 68 * 1024;
64   CreateTemporaryTestFile(kFileSize);
65   MemoryMappedFile map;
66   ASSERT_TRUE(map.Initialize(temp_file_path()));
67   ASSERT_EQ(kFileSize, map.length());
68   ASSERT_TRUE(map.data() != nullptr);
69   EXPECT_TRUE(map.IsValid());
70   ASSERT_TRUE(CheckBufferContents(map.bytes(), 0));
71 }
72 
TEST_F(MemoryMappedFileTest,MapWholeFileByFD)73 TEST_F(MemoryMappedFileTest, MapWholeFileByFD) {
74   const size_t kFileSize = 68 * 1024;
75   CreateTemporaryTestFile(kFileSize);
76   MemoryMappedFile map;
77   ASSERT_TRUE(map.Initialize(
78       File(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ)));
79   ASSERT_EQ(kFileSize, map.length());
80   ASSERT_TRUE(map.data() != nullptr);
81   EXPECT_TRUE(map.IsValid());
82   ASSERT_TRUE(CheckBufferContents(map.bytes(), 0));
83 }
84 
TEST_F(MemoryMappedFileTest,MapSmallFile)85 TEST_F(MemoryMappedFileTest, MapSmallFile) {
86   const size_t kFileSize = 127;
87   CreateTemporaryTestFile(kFileSize);
88   MemoryMappedFile map;
89   ASSERT_TRUE(map.Initialize(temp_file_path()));
90   ASSERT_EQ(kFileSize, map.length());
91   ASSERT_TRUE(map.data() != nullptr);
92   EXPECT_TRUE(map.IsValid());
93   ASSERT_TRUE(CheckBufferContents(map.bytes(), 0));
94 }
95 
TEST_F(MemoryMappedFileTest,MapWholeFileUsingRegion)96 TEST_F(MemoryMappedFileTest, MapWholeFileUsingRegion) {
97   const size_t kFileSize = 157 * 1024;
98   CreateTemporaryTestFile(kFileSize);
99   MemoryMappedFile map;
100 
101   File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ);
102   ASSERT_TRUE(
103       map.Initialize(std::move(file), MemoryMappedFile::Region::kWholeFile));
104   ASSERT_EQ(kFileSize, map.length());
105   ASSERT_TRUE(map.data() != nullptr);
106   EXPECT_TRUE(map.IsValid());
107   ASSERT_TRUE(CheckBufferContents(map.bytes(), 0));
108 }
109 
TEST_F(MemoryMappedFileTest,MapPartialRegionAtBeginning)110 TEST_F(MemoryMappedFileTest, MapPartialRegionAtBeginning) {
111   const size_t kFileSize = 157 * 1024;
112   const size_t kPartialSize = 4 * 1024 + 32;
113   CreateTemporaryTestFile(kFileSize);
114   MemoryMappedFile map;
115 
116   File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ);
117   MemoryMappedFile::Region region = {0, kPartialSize};
118   ASSERT_TRUE(map.Initialize(std::move(file), region));
119   ASSERT_EQ(kPartialSize, map.length());
120   ASSERT_TRUE(map.data() != nullptr);
121   EXPECT_TRUE(map.IsValid());
122   ASSERT_TRUE(CheckBufferContents(map.bytes().first(kPartialSize), 0));
123 }
124 
TEST_F(MemoryMappedFileTest,MapPartialRegionAtEnd)125 TEST_F(MemoryMappedFileTest, MapPartialRegionAtEnd) {
126   const size_t kFileSize = 157 * 1024;
127   const size_t kPartialSize = 5 * 1024 - 32;
128   const size_t kOffset = kFileSize - kPartialSize;
129   CreateTemporaryTestFile(kFileSize);
130   MemoryMappedFile map;
131 
132   File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ);
133   MemoryMappedFile::Region region = {kOffset, kPartialSize};
134   ASSERT_TRUE(map.Initialize(std::move(file), region));
135   ASSERT_EQ(kPartialSize, map.length());
136   ASSERT_TRUE(map.data() != nullptr);
137   EXPECT_TRUE(map.IsValid());
138   ASSERT_TRUE(CheckBufferContents(map.bytes().first(kPartialSize), kOffset));
139 }
140 
TEST_F(MemoryMappedFileTest,MapSmallPartialRegionInTheMiddle)141 TEST_F(MemoryMappedFileTest, MapSmallPartialRegionInTheMiddle) {
142   const size_t kFileSize = 157 * 1024;
143   const size_t kOffset = 1024 * 5 + 32;
144   const size_t kPartialSize = 8;
145 
146   CreateTemporaryTestFile(kFileSize);
147   MemoryMappedFile map;
148 
149   File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ);
150   MemoryMappedFile::Region region = {kOffset, kPartialSize};
151   ASSERT_TRUE(map.Initialize(std::move(file), region));
152   ASSERT_EQ(kPartialSize, map.length());
153   ASSERT_TRUE(map.data() != nullptr);
154   EXPECT_TRUE(map.IsValid());
155   ASSERT_TRUE(CheckBufferContents(map.bytes().first(kPartialSize), kOffset));
156 }
157 
TEST_F(MemoryMappedFileTest,MapLargePartialRegionInTheMiddle)158 TEST_F(MemoryMappedFileTest, MapLargePartialRegionInTheMiddle) {
159   const size_t kFileSize = 157 * 1024;
160   const size_t kOffset = 1024 * 5 + 32;
161   const size_t kPartialSize = 16 * 1024 - 32;
162 
163   CreateTemporaryTestFile(kFileSize);
164   MemoryMappedFile map;
165 
166   File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ);
167   MemoryMappedFile::Region region = {kOffset, kPartialSize};
168   ASSERT_TRUE(map.Initialize(std::move(file), region));
169   ASSERT_EQ(kPartialSize, map.length());
170   ASSERT_TRUE(map.data() != nullptr);
171   EXPECT_TRUE(map.IsValid());
172   ASSERT_TRUE(CheckBufferContents(map.bytes().first(kPartialSize), kOffset));
173 }
174 
TEST_F(MemoryMappedFileTest,WriteableFile)175 TEST_F(MemoryMappedFileTest, WriteableFile) {
176   const size_t kFileSize = 127;
177   CreateTemporaryTestFile(kFileSize);
178 
179   {
180     MemoryMappedFile map;
181     ASSERT_TRUE(map.Initialize(temp_file_path(), MemoryMappedFile::READ_WRITE));
182     ASSERT_EQ(kFileSize, map.length());
183     ASSERT_TRUE(map.data() != nullptr);
184     EXPECT_TRUE(map.IsValid());
185     ASSERT_TRUE(CheckBufferContents(map.bytes(), 0));
186 
187     span<uint8_t> bytes = map.mutable_bytes();
188     bytes[0] = 'B';
189     bytes[1] = 'a';
190     bytes[2] = 'r';
191     bytes[kFileSize - 1] = '!';
192     EXPECT_FALSE(CheckBufferContents(map.bytes(), 0));
193     EXPECT_TRUE(
194         CheckBufferContents(map.bytes().first(kFileSize - 1).subspan(3), 3));
195   }
196 
197   int64_t file_size;
198   ASSERT_TRUE(GetFileSize(temp_file_path(), &file_size));
199   EXPECT_EQ(static_cast<int64_t>(kFileSize), file_size);
200 
201   std::string contents;
202   ASSERT_TRUE(ReadFileToString(temp_file_path(), &contents));
203   EXPECT_EQ("Bar", contents.substr(0, 3));
204   EXPECT_EQ("!", contents.substr(kFileSize - 1, 1));
205 }
206 
TEST_F(MemoryMappedFileTest,CopyOnWrite)207 TEST_F(MemoryMappedFileTest, CopyOnWrite) {
208   const size_t kFileSize = 127;
209   CreateTemporaryTestFile(kFileSize);
210 
211   {
212     MemoryMappedFile map;
213     ASSERT_TRUE(
214         map.Initialize(temp_file_path(), MemoryMappedFile::READ_WRITE_COPY));
215     ASSERT_EQ(kFileSize, map.length());
216     ASSERT_TRUE(map.data() != nullptr);
217     EXPECT_TRUE(map.IsValid());
218     ASSERT_TRUE(CheckBufferContents(map.bytes(), 0));
219 
220     span<uint8_t> bytes = map.mutable_bytes();
221     bytes[0] = 'B';
222     bytes[1] = 'a';
223     bytes[2] = 'r';
224     bytes[kFileSize - 1] = '!';
225     EXPECT_FALSE(CheckBufferContents(map.bytes(), 0));
226     EXPECT_TRUE(
227         CheckBufferContents(map.bytes().first(kFileSize - 1).subspan(3), 3));
228   }
229 
230   int64_t file_size;
231   ASSERT_TRUE(GetFileSize(temp_file_path(), &file_size));
232   EXPECT_EQ(static_cast<int64_t>(kFileSize), file_size);
233 
234   // Although the buffer has been modified in memory, the file is unchanged.
235   std::string contents;
236   ASSERT_TRUE(ReadFileToString(temp_file_path(), &contents));
237   EXPECT_TRUE(CheckBufferContents(as_bytes(span(contents)), 0));
238 }
239 
TEST_F(MemoryMappedFileTest,ExtendableFile)240 TEST_F(MemoryMappedFileTest, ExtendableFile) {
241   const size_t kFileSize = 127;
242   const size_t kFileExtend = 100;
243   CreateTemporaryTestFile(kFileSize);
244 
245   {
246     File file(temp_file_path(),
247               File::FLAG_OPEN | File::FLAG_READ | File::FLAG_WRITE);
248     MemoryMappedFile::Region region = {0, kFileSize + kFileExtend};
249     MemoryMappedFile map;
250     ASSERT_TRUE(map.Initialize(std::move(file), region,
251                                MemoryMappedFile::READ_WRITE_EXTEND));
252     EXPECT_EQ(kFileSize + kFileExtend, map.length());
253     ASSERT_TRUE(map.data() != nullptr);
254     EXPECT_TRUE(map.IsValid());
255     ASSERT_TRUE(CheckBufferContents(map.bytes().first(kFileSize), 0));
256 
257     span<uint8_t> bytes = map.mutable_bytes();
258     EXPECT_EQ(0, bytes[kFileSize + 0]);
259     EXPECT_EQ(0, bytes[kFileSize + 1]);
260     EXPECT_EQ(0, bytes[kFileSize + 2]);
261     bytes[kFileSize + 0] = 'B';
262     bytes[kFileSize + 1] = 'A';
263     bytes[kFileSize + 2] = 'Z';
264     EXPECT_TRUE(CheckBufferContents(map.bytes().first(kFileSize), 0));
265   }
266 
267   int64_t file_size;
268   ASSERT_TRUE(GetFileSize(temp_file_path(), &file_size));
269   EXPECT_LE(static_cast<int64_t>(kFileSize + 3), file_size);
270   EXPECT_GE(static_cast<int64_t>(kFileSize + kFileExtend), file_size);
271 
272   std::string contents;
273   ASSERT_TRUE(ReadFileToString(temp_file_path(), &contents));
274   EXPECT_EQ("BAZ", contents.substr(kFileSize, 3));
275 }
276 
277 }  // namespace
278 
279 }  // namespace base
280