• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The Chromium Authors. All rights reserved.
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(const uint8_t * data,size_t size,size_t offset)30 bool CheckBufferContents(const uint8_t* data, size_t size, size_t offset) {
31   std::unique_ptr<uint8_t[]> test_data(CreateTestBuffer(size, offset));
32   return memcmp(test_data.get(), data, 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_, false)); }
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   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.data(), kFileSize, 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   map.Initialize(File(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ));
78   ASSERT_EQ(kFileSize, map.length());
79   ASSERT_TRUE(map.data() != nullptr);
80   EXPECT_TRUE(map.IsValid());
81   ASSERT_TRUE(CheckBufferContents(map.data(), kFileSize, 0));
82 }
83 
TEST_F(MemoryMappedFileTest,MapSmallFile)84 TEST_F(MemoryMappedFileTest, MapSmallFile) {
85   const size_t kFileSize = 127;
86   CreateTemporaryTestFile(kFileSize);
87   MemoryMappedFile map;
88   map.Initialize(temp_file_path());
89   ASSERT_EQ(kFileSize, map.length());
90   ASSERT_TRUE(map.data() != nullptr);
91   EXPECT_TRUE(map.IsValid());
92   ASSERT_TRUE(CheckBufferContents(map.data(), kFileSize, 0));
93 }
94 
TEST_F(MemoryMappedFileTest,MapWholeFileUsingRegion)95 TEST_F(MemoryMappedFileTest, MapWholeFileUsingRegion) {
96   const size_t kFileSize = 157 * 1024;
97   CreateTemporaryTestFile(kFileSize);
98   MemoryMappedFile map;
99 
100   File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ);
101   map.Initialize(std::move(file), MemoryMappedFile::Region::kWholeFile);
102   ASSERT_EQ(kFileSize, map.length());
103   ASSERT_TRUE(map.data() != nullptr);
104   EXPECT_TRUE(map.IsValid());
105   ASSERT_TRUE(CheckBufferContents(map.data(), kFileSize, 0));
106 }
107 
TEST_F(MemoryMappedFileTest,MapPartialRegionAtBeginning)108 TEST_F(MemoryMappedFileTest, MapPartialRegionAtBeginning) {
109   const size_t kFileSize = 157 * 1024;
110   const size_t kPartialSize = 4 * 1024 + 32;
111   CreateTemporaryTestFile(kFileSize);
112   MemoryMappedFile map;
113 
114   File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ);
115   MemoryMappedFile::Region region = {0, kPartialSize};
116   map.Initialize(std::move(file), region);
117   ASSERT_EQ(kPartialSize, map.length());
118   ASSERT_TRUE(map.data() != nullptr);
119   EXPECT_TRUE(map.IsValid());
120   ASSERT_TRUE(CheckBufferContents(map.data(), kPartialSize, 0));
121 }
122 
TEST_F(MemoryMappedFileTest,MapPartialRegionAtEnd)123 TEST_F(MemoryMappedFileTest, MapPartialRegionAtEnd) {
124   const size_t kFileSize = 157 * 1024;
125   const size_t kPartialSize = 5 * 1024 - 32;
126   const size_t kOffset = kFileSize - kPartialSize;
127   CreateTemporaryTestFile(kFileSize);
128   MemoryMappedFile map;
129 
130   File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ);
131   MemoryMappedFile::Region region = {kOffset, kPartialSize};
132   map.Initialize(std::move(file), region);
133   ASSERT_EQ(kPartialSize, map.length());
134   ASSERT_TRUE(map.data() != nullptr);
135   EXPECT_TRUE(map.IsValid());
136   ASSERT_TRUE(CheckBufferContents(map.data(), kPartialSize, kOffset));
137 }
138 
TEST_F(MemoryMappedFileTest,MapSmallPartialRegionInTheMiddle)139 TEST_F(MemoryMappedFileTest, MapSmallPartialRegionInTheMiddle) {
140   const size_t kFileSize = 157 * 1024;
141   const size_t kOffset = 1024 * 5 + 32;
142   const size_t kPartialSize = 8;
143 
144   CreateTemporaryTestFile(kFileSize);
145   MemoryMappedFile map;
146 
147   File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ);
148   MemoryMappedFile::Region region = {kOffset, kPartialSize};
149   map.Initialize(std::move(file), region);
150   ASSERT_EQ(kPartialSize, map.length());
151   ASSERT_TRUE(map.data() != nullptr);
152   EXPECT_TRUE(map.IsValid());
153   ASSERT_TRUE(CheckBufferContents(map.data(), kPartialSize, kOffset));
154 }
155 
TEST_F(MemoryMappedFileTest,MapLargePartialRegionInTheMiddle)156 TEST_F(MemoryMappedFileTest, MapLargePartialRegionInTheMiddle) {
157   const size_t kFileSize = 157 * 1024;
158   const size_t kOffset = 1024 * 5 + 32;
159   const size_t kPartialSize = 16 * 1024 - 32;
160 
161   CreateTemporaryTestFile(kFileSize);
162   MemoryMappedFile map;
163 
164   File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ);
165   MemoryMappedFile::Region region = {kOffset, kPartialSize};
166   map.Initialize(std::move(file), region);
167   ASSERT_EQ(kPartialSize, map.length());
168   ASSERT_TRUE(map.data() != nullptr);
169   EXPECT_TRUE(map.IsValid());
170   ASSERT_TRUE(CheckBufferContents(map.data(), kPartialSize, kOffset));
171 }
172 
TEST_F(MemoryMappedFileTest,WriteableFile)173 TEST_F(MemoryMappedFileTest, WriteableFile) {
174   const size_t kFileSize = 127;
175   CreateTemporaryTestFile(kFileSize);
176 
177   {
178     MemoryMappedFile map;
179     map.Initialize(temp_file_path(), MemoryMappedFile::READ_WRITE);
180     ASSERT_EQ(kFileSize, map.length());
181     ASSERT_TRUE(map.data() != nullptr);
182     EXPECT_TRUE(map.IsValid());
183     ASSERT_TRUE(CheckBufferContents(map.data(), kFileSize, 0));
184 
185     uint8_t* bytes = map.data();
186     bytes[0] = 'B';
187     bytes[1] = 'a';
188     bytes[2] = 'r';
189     bytes[kFileSize - 1] = '!';
190     EXPECT_FALSE(CheckBufferContents(map.data(), kFileSize, 0));
191     EXPECT_TRUE(CheckBufferContents(map.data() + 3, kFileSize - 4, 3));
192   }
193 
194   int64_t file_size;
195   ASSERT_TRUE(GetFileSize(temp_file_path(), &file_size));
196   EXPECT_EQ(static_cast<int64_t>(kFileSize), file_size);
197 
198   std::string contents;
199   ASSERT_TRUE(ReadFileToString(temp_file_path(), &contents));
200   EXPECT_EQ("Bar", contents.substr(0, 3));
201   EXPECT_EQ("!", contents.substr(kFileSize - 1, 1));
202 }
203 
TEST_F(MemoryMappedFileTest,ExtendableFile)204 TEST_F(MemoryMappedFileTest, ExtendableFile) {
205   const size_t kFileSize = 127;
206   const size_t kFileExtend = 100;
207   CreateTemporaryTestFile(kFileSize);
208 
209   {
210     File file(temp_file_path(),
211               File::FLAG_OPEN | File::FLAG_READ | File::FLAG_WRITE);
212     MemoryMappedFile::Region region = {0, kFileSize + kFileExtend};
213     MemoryMappedFile map;
214     map.Initialize(std::move(file), region,
215                    MemoryMappedFile::READ_WRITE_EXTEND);
216     EXPECT_EQ(kFileSize + kFileExtend, map.length());
217     ASSERT_TRUE(map.data() != nullptr);
218     EXPECT_TRUE(map.IsValid());
219     ASSERT_TRUE(CheckBufferContents(map.data(), kFileSize, 0));
220 
221     uint8_t* bytes = map.data();
222     EXPECT_EQ(0, bytes[kFileSize + 0]);
223     EXPECT_EQ(0, bytes[kFileSize + 1]);
224     EXPECT_EQ(0, bytes[kFileSize + 2]);
225     bytes[kFileSize + 0] = 'B';
226     bytes[kFileSize + 1] = 'A';
227     bytes[kFileSize + 2] = 'Z';
228     EXPECT_TRUE(CheckBufferContents(map.data(), kFileSize, 0));
229   }
230 
231   int64_t file_size;
232   ASSERT_TRUE(GetFileSize(temp_file_path(), &file_size));
233   EXPECT_LE(static_cast<int64_t>(kFileSize + 3), file_size);
234   EXPECT_GE(static_cast<int64_t>(kFileSize + kFileExtend), file_size);
235 
236   std::string contents;
237   ASSERT_TRUE(ReadFileToString(temp_file_path(), &contents));
238   EXPECT_EQ("BAZ", contents.substr(kFileSize, 3));
239 }
240 
241 }  // namespace
242 
243 }  // namespace base
244