mapped_file_test.cc revision f896965072343a2d6ad64d46a61112b10b3645dd
1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "base/unix_file/mapped_file.h"
18#include "base/logging.h"
19#include "base/unix_file/fd_file.h"
20#include "base/unix_file/random_access_file_test.h"
21#include "base/unix_file/random_access_file_utils.h"
22#include "base/unix_file/string_file.h"
23#include "gtest/gtest.h"
24
25namespace unix_file {
26
27class MappedFileTest : public RandomAccessFileTest {
28 protected:
29  MappedFileTest() : kContent("some content") {
30  }
31
32  void SetUp() {
33    RandomAccessFileTest::SetUp();
34
35    good_path_ = GetTmpPath("some-file.txt");
36    int fd = TEMP_FAILURE_RETRY(open(good_path_.c_str(), O_CREAT|O_RDWR, 0666));
37    FdFile dst(fd);
38
39    StringFile src;
40    src.Assign(kContent);
41
42    ASSERT_TRUE(CopyFile(src, &dst));
43  }
44
45  void TearDown() {
46    ASSERT_EQ(unlink(good_path_.c_str()), 0);
47
48    RandomAccessFileTest::TearDown();
49  }
50
51  virtual RandomAccessFile* MakeTestFile() {
52    TEMP_FAILURE_RETRY(truncate(good_path_.c_str(), 0));
53    MappedFile* f = new MappedFile;
54    CHECK(f->Open(good_path_, MappedFile::kReadWriteMode));
55    return f;
56  }
57
58  const std::string kContent;
59  std::string good_path_;
60};
61
62TEST_F(MappedFileTest, OkayToNotUse) {
63  MappedFile file;
64  EXPECT_EQ(-1, file.Fd());
65  EXPECT_FALSE(file.IsOpened());
66  EXPECT_FALSE(file.IsMapped());
67}
68
69TEST_F(MappedFileTest, OpenClose) {
70  MappedFile file;
71  ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
72  EXPECT_GE(file.Fd(), 0);
73  EXPECT_TRUE(file.IsOpened());
74  EXPECT_EQ(kContent.size(), static_cast<uint64_t>(file.size()));
75  EXPECT_EQ(0, file.Close());
76  EXPECT_EQ(-1, file.Fd());
77  EXPECT_FALSE(file.IsOpened());
78}
79
80TEST_F(MappedFileTest, OpenFdClose) {
81  FILE* f = tmpfile();
82  ASSERT_TRUE(f != NULL);
83  MappedFile file(fileno(f));
84  EXPECT_GE(file.Fd(), 0);
85  EXPECT_TRUE(file.IsOpened());
86  EXPECT_EQ(0, file.Close());
87}
88
89TEST_F(MappedFileTest, CanUseAfterMapReadOnly) {
90  MappedFile file;
91  ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
92  EXPECT_FALSE(file.IsMapped());
93  EXPECT_TRUE(file.MapReadOnly());
94  EXPECT_TRUE(file.IsMapped());
95  EXPECT_EQ(kContent.size(), static_cast<uint64_t>(file.size()));
96  ASSERT_TRUE(file.data());
97  EXPECT_EQ(0, memcmp(kContent.c_str(), file.data(), file.size()));
98  EXPECT_EQ(0, file.Flush());
99}
100
101TEST_F(MappedFileTest, CanUseAfterMapReadWrite) {
102  MappedFile file;
103  ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode));
104  EXPECT_FALSE(file.IsMapped());
105  EXPECT_TRUE(file.MapReadWrite(1));
106  EXPECT_TRUE(file.IsMapped());
107  EXPECT_EQ(1, file.size());
108  ASSERT_TRUE(file.data());
109  EXPECT_EQ(kContent[0], *file.data());
110  EXPECT_EQ(0, file.Flush());
111}
112
113TEST_F(MappedFileTest, CanWriteNewData) {
114  const std::string new_path(GetTmpPath("new-file.txt"));
115  ASSERT_EQ(-1, unlink(new_path.c_str()));
116  ASSERT_EQ(ENOENT, errno);
117
118  MappedFile file;
119  ASSERT_TRUE(file.Open(new_path, MappedFile::kReadWriteMode));
120  EXPECT_TRUE(file.MapReadWrite(kContent.size()));
121  EXPECT_TRUE(file.IsMapped());
122  EXPECT_EQ(kContent.size(), static_cast<uint64_t>(file.size()));
123  ASSERT_TRUE(file.data());
124  memcpy(file.data(), kContent.c_str(), kContent.size());
125  EXPECT_EQ(0, file.Close());
126  EXPECT_FALSE(file.IsMapped());
127
128  FdFile new_file(TEMP_FAILURE_RETRY(open(new_path.c_str(), O_RDONLY)));
129  StringFile buffer;
130  ASSERT_TRUE(CopyFile(new_file, &buffer));
131  EXPECT_EQ(kContent, buffer.ToStringPiece());
132  EXPECT_EQ(0, unlink(new_path.c_str()));
133}
134
135TEST_F(MappedFileTest, FileMustExist) {
136  const std::string bad_path(GetTmpPath("does-not-exist.txt"));
137  MappedFile file;
138  EXPECT_FALSE(file.Open(bad_path, MappedFile::kReadOnlyMode));
139  EXPECT_EQ(-1, file.Fd());
140}
141
142TEST_F(MappedFileTest, FileMustBeWritable) {
143  MappedFile file;
144  ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
145  EXPECT_FALSE(file.MapReadWrite(10));
146}
147
148TEST_F(MappedFileTest, RemappingAllowedUntilSuccess) {
149  MappedFile file;
150  ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
151  EXPECT_FALSE(file.MapReadWrite(10));
152  EXPECT_FALSE(file.MapReadWrite(10));
153}
154
155TEST_F(MappedFileTest, ResizeMappedFile) {
156  MappedFile file;
157  ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode));
158  ASSERT_TRUE(file.MapReadWrite(10));
159  EXPECT_EQ(10, file.GetLength());
160  EXPECT_TRUE(file.Unmap());
161  EXPECT_TRUE(file.MapReadWrite(20));
162  EXPECT_EQ(20, file.GetLength());
163  EXPECT_EQ(0, file.Flush());
164  EXPECT_TRUE(file.Unmap());
165  EXPECT_EQ(0, file.Flush());
166  EXPECT_EQ(0, file.SetLength(5));
167  EXPECT_TRUE(file.MapReadOnly());
168  EXPECT_EQ(5, file.GetLength());
169}
170
171TEST_F(MappedFileTest, ReadNotMapped) {
172  TestRead();
173}
174
175TEST_F(MappedFileTest, SetLengthNotMapped) {
176  TestSetLength();
177}
178
179TEST_F(MappedFileTest, WriteNotMapped) {
180  TestWrite();
181}
182
183TEST_F(MappedFileTest, ReadMappedReadOnly) {
184  MappedFile file;
185  ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
186  ASSERT_TRUE(file.MapReadOnly());
187  TestReadContent(kContent, &file);
188}
189
190TEST_F(MappedFileTest, ReadMappedReadWrite) {
191  MappedFile file;
192  ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode));
193  ASSERT_TRUE(file.MapReadWrite(kContent.size()));
194  TestReadContent(kContent, &file);
195}
196
197TEST_F(MappedFileTest, WriteMappedReadWrite) {
198  TEMP_FAILURE_RETRY(unlink(good_path_.c_str()));
199  MappedFile file;
200  ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode));
201  ASSERT_TRUE(file.MapReadWrite(kContent.size()));
202
203  // Can't write to a negative offset.
204  EXPECT_EQ(-EINVAL, file.Write(kContent.c_str(), 0, -123));
205
206  // A zero-length write is a no-op.
207  EXPECT_EQ(0, file.Write(kContent.c_str(), 0, 0));
208  // But the file size is as given when mapped.
209  EXPECT_EQ(kContent.size(), static_cast<uint64_t>(file.GetLength()));
210
211  // Data written past the end are discarded.
212  EXPECT_EQ(kContent.size() - 1,
213            static_cast<uint64_t>(file.Write(kContent.c_str(), kContent.size(), 1)));
214  EXPECT_EQ(0, memcmp(kContent.c_str(), file.data() + 1, kContent.size() - 1));
215
216  // Data can be overwritten.
217  EXPECT_EQ(kContent.size(),
218            static_cast<uint64_t>(file.Write(kContent.c_str(), kContent.size(), 0)));
219  EXPECT_EQ(0, memcmp(kContent.c_str(), file.data(), kContent.size()));
220}
221
222#if 0  // death tests don't work on android yet
223
224class MappedFileDeathTest : public MappedFileTest {};
225
226TEST_F(MappedFileDeathTest, MustMapBeforeUse) {
227  MappedFile file;
228  EXPECT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
229  EXPECT_DEATH(file.data(), "mapped_");
230}
231
232TEST_F(MappedFileDeathTest, RemappingNotAllowedReadOnly) {
233  MappedFile file;
234  ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
235  ASSERT_TRUE(file.MapReadOnly());
236  EXPECT_DEATH(file.MapReadOnly(), "mapped_");
237}
238
239TEST_F(MappedFileDeathTest, RemappingNotAllowedReadWrite) {
240  MappedFile file;
241  ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode));
242  ASSERT_TRUE(file.MapReadWrite(10));
243  EXPECT_DEATH(file.MapReadWrite(10), "mapped_");
244}
245
246TEST_F(MappedFileDeathTest, SetLengthMappedReadWrite) {
247  MappedFile file;
248  ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadWriteMode));
249  ASSERT_TRUE(file.MapReadWrite(10));
250  EXPECT_EQ(10, file.GetLength());
251  EXPECT_DEATH(file.SetLength(0), ".*");
252}
253
254TEST_F(MappedFileDeathTest, SetLengthMappedReadOnly) {
255  MappedFile file;
256  ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
257  ASSERT_TRUE(file.MapReadOnly());
258  EXPECT_EQ(kContent.size(), file.GetLength());
259  EXPECT_DEATH(file.SetLength(0), ".*");
260}
261
262TEST_F(MappedFileDeathTest, WriteMappedReadOnly) {
263  MappedFile file;
264  ASSERT_TRUE(file.Open(good_path_, MappedFile::kReadOnlyMode));
265  ASSERT_TRUE(file.MapReadOnly());
266  char buf[10];
267  EXPECT_DEATH(file.Write(buf, 0, 0), ".*");
268}
269
270#endif
271
272}  // namespace unix_file
273