MemoryFileTest.cpp revision f447c8eb205d899085968a0a8dfae861ef56a589
1/*
2 * Copyright (C) 2016 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 <string>
18#include <vector>
19
20#include <android-base/test_utils.h>
21#include <android-base/file.h>
22#include <gtest/gtest.h>
23
24#include "Memory.h"
25
26class MemoryFileTest : public ::testing::Test {
27 protected:
28  void SetUp() override {
29    tf_ = new TemporaryFile;
30  }
31
32  void TearDown() override {
33    delete tf_;
34  }
35
36  void WriteTestData() {
37    ASSERT_TRUE(android::base::WriteStringToFd("0123456789abcdefghijklmnopqrstuvxyz", tf_->fd));
38  }
39
40  MemoryFileAtOffset memory_;
41
42  TemporaryFile* tf_ = nullptr;
43};
44
45TEST_F(MemoryFileTest, init_offset_0) {
46  WriteTestData();
47
48  ASSERT_TRUE(memory_.Init(tf_->path, 0));
49  std::vector<char> buffer(11);
50  ASSERT_TRUE(memory_.Read(0, buffer.data(), 10));
51  buffer[10] = '\0';
52  ASSERT_STREQ("0123456789", buffer.data());
53}
54
55TEST_F(MemoryFileTest, init_offset_non_zero) {
56  WriteTestData();
57
58  ASSERT_TRUE(memory_.Init(tf_->path, 10));
59  std::vector<char> buffer(11);
60  ASSERT_TRUE(memory_.Read(0, buffer.data(), 10));
61  buffer[10] = '\0';
62  ASSERT_STREQ("abcdefghij", buffer.data());
63}
64
65TEST_F(MemoryFileTest, init_offset_non_zero_larger_than_pagesize) {
66  size_t pagesize = getpagesize();
67  std::string large_string;
68  for (size_t i = 0; i < pagesize; i++) {
69    large_string += '1';
70  }
71  large_string += "012345678901234abcdefgh";
72  ASSERT_TRUE(android::base::WriteStringToFd(large_string, tf_->fd));
73
74  ASSERT_TRUE(memory_.Init(tf_->path, pagesize + 15));
75  std::vector<char> buffer(9);
76  ASSERT_TRUE(memory_.Read(0, buffer.data(), 8));
77  buffer[8] = '\0';
78  ASSERT_STREQ("abcdefgh", buffer.data());
79}
80
81TEST_F(MemoryFileTest, init_offset_pagesize_aligned) {
82  size_t pagesize = getpagesize();
83  std::string data;
84  for (size_t i = 0; i < 2 * pagesize; i++) {
85    data += static_cast<char>((i / pagesize) + '0');
86    data += static_cast<char>((i % 10) + '0');
87  }
88  ASSERT_TRUE(android::base::WriteStringToFd(data, tf_->fd));
89
90  ASSERT_TRUE(memory_.Init(tf_->path, 2 * pagesize));
91  std::vector<char> buffer(11);
92  ASSERT_TRUE(memory_.Read(0, buffer.data(), 10));
93  buffer[10] = '\0';
94  std::string expected_str;
95  for (size_t i = 0; i < 5; i++) {
96    expected_str += '1';
97    expected_str += static_cast<char>(((i + pagesize) % 10) + '0');
98  }
99  ASSERT_STREQ(expected_str.c_str(), buffer.data());
100}
101
102TEST_F(MemoryFileTest, init_offset_pagesize_aligned_plus_extra) {
103  size_t pagesize = getpagesize();
104  std::string data;
105  for (size_t i = 0; i < 2 * pagesize; i++) {
106    data += static_cast<char>((i / pagesize) + '0');
107    data += static_cast<char>((i % 10) + '0');
108  }
109  ASSERT_TRUE(android::base::WriteStringToFd(data, tf_->fd));
110
111  ASSERT_TRUE(memory_.Init(tf_->path, 2 * pagesize + 10));
112  std::vector<char> buffer(11);
113  ASSERT_TRUE(memory_.Read(0, buffer.data(), 10));
114  buffer[10] = '\0';
115  std::string expected_str;
116  for (size_t i = 0; i < 5; i++) {
117    expected_str += '1';
118    expected_str += static_cast<char>(((i + pagesize + 5) % 10) + '0');
119  }
120  ASSERT_STREQ(expected_str.c_str(), buffer.data());
121}
122
123TEST_F(MemoryFileTest, init_offset_greater_than_filesize) {
124  size_t pagesize = getpagesize();
125  std::string data;
126  uint64_t file_size = 2 * pagesize + pagesize / 2;
127  for (size_t i = 0; i < file_size; i++) {
128    data += static_cast<char>((i / pagesize) + '0');
129  }
130  ASSERT_TRUE(android::base::WriteStringToFd(data, tf_->fd));
131
132  // Check offset > file size fails and aligned_offset > file size.
133  ASSERT_FALSE(memory_.Init(tf_->path, file_size + 2 * pagesize));
134  // Check offset == filesize fails.
135  ASSERT_FALSE(memory_.Init(tf_->path, file_size));
136  // Check aligned_offset < filesize, but offset > filesize fails.
137  ASSERT_FALSE(memory_.Init(tf_->path, 2 * pagesize + pagesize / 2 + pagesize / 4));
138}
139
140TEST_F(MemoryFileTest, read_error) {
141  std::string data;
142  for (size_t i = 0; i < 5000; i++) {
143    data += static_cast<char>((i % 10) + '0');
144  }
145  ASSERT_TRUE(android::base::WriteStringToFd(data, tf_->fd));
146
147  std::vector<char> buffer(100);
148
149  // Read before init.
150  ASSERT_FALSE(memory_.Read(0, buffer.data(), 10));
151
152  ASSERT_TRUE(memory_.Init(tf_->path, 0));
153
154  ASSERT_FALSE(memory_.Read(10000, buffer.data(), 10));
155  ASSERT_FALSE(memory_.Read(5000, buffer.data(), 10));
156  ASSERT_FALSE(memory_.Read(4990, buffer.data(), 11));
157  ASSERT_TRUE(memory_.Read(4990, buffer.data(), 10));
158  ASSERT_FALSE(memory_.Read(4999, buffer.data(), 2));
159  ASSERT_TRUE(memory_.Read(4999, buffer.data(), 1));
160
161  // Check that overflow fails properly.
162  ASSERT_FALSE(memory_.Read(UINT64_MAX - 100, buffer.data(), 200));
163}
164
165TEST_F(MemoryFileTest, read_past_file_within_mapping) {
166  size_t pagesize = getpagesize();
167
168  ASSERT_TRUE(pagesize > 100);
169  std::vector<uint8_t> buffer(pagesize - 100);
170  for (size_t i = 0; i < pagesize - 100; i++) {
171    buffer[i] = static_cast<uint8_t>((i % 0x5e) + 0x20);
172  }
173  ASSERT_TRUE(android::base::WriteFully(tf_->fd, buffer.data(), buffer.size()));
174
175  ASSERT_TRUE(memory_.Init(tf_->path, 0));
176
177  for (size_t i = 0; i < 100; i++) {
178    uint8_t value;
179    ASSERT_FALSE(memory_.Read(buffer.size() + i, &value, 1)) << "Should have failed at value " << i;
180  }
181}
182
183TEST_F(MemoryFileTest, map_partial_offset_aligned) {
184  size_t pagesize = getpagesize();
185  std::vector<uint8_t> buffer(pagesize * 10);
186  for (size_t i = 0; i < pagesize * 10; i++) {
187    buffer[i] = i / pagesize + 1;
188  }
189  ASSERT_TRUE(android::base::WriteFully(tf_->fd, buffer.data(), buffer.size()));
190
191  // Map in only two pages of the data, and after the first page.
192  ASSERT_TRUE(memory_.Init(tf_->path, pagesize, pagesize * 2));
193
194  std::vector<uint8_t> read_buffer(pagesize * 2);
195  // Make sure that reading after mapped data is a failure.
196  ASSERT_FALSE(memory_.Read(pagesize * 2, read_buffer.data(), 1));
197  ASSERT_TRUE(memory_.Read(0, read_buffer.data(), pagesize * 2));
198  for (size_t i = 0; i < pagesize; i++) {
199    ASSERT_EQ(2, read_buffer[i]) << "Failed at byte " << i;
200  }
201  for (size_t i = pagesize; i < pagesize * 2; i++) {
202    ASSERT_EQ(3, read_buffer[i]) << "Failed at byte " << i;
203  }
204}
205
206TEST_F(MemoryFileTest, map_partial_offset_unaligned) {
207  size_t pagesize = getpagesize();
208  ASSERT_TRUE(pagesize > 0x100);
209  std::vector<uint8_t> buffer(pagesize * 10);
210  for (size_t i = 0; i < buffer.size(); i++) {
211    buffer[i] = i / pagesize + 1;
212  }
213  ASSERT_TRUE(android::base::WriteFully(tf_->fd, buffer.data(), buffer.size()));
214
215  // Map in only two pages of the data, and after the first page.
216  ASSERT_TRUE(memory_.Init(tf_->path, pagesize + 0x100, pagesize * 2));
217
218  std::vector<uint8_t> read_buffer(pagesize * 2);
219  // Make sure that reading after mapped data is a failure.
220  ASSERT_FALSE(memory_.Read(pagesize * 2, read_buffer.data(), 1));
221  ASSERT_TRUE(memory_.Read(0, read_buffer.data(), pagesize * 2));
222  for (size_t i = 0; i < pagesize - 0x100; i++) {
223    ASSERT_EQ(2, read_buffer[i]) << "Failed at byte " << i;
224  }
225  for (size_t i = pagesize - 0x100; i < 2 * pagesize - 0x100; i++) {
226    ASSERT_EQ(3, read_buffer[i]) << "Failed at byte " << i;
227  }
228  for (size_t i = 2 * pagesize - 0x100; i < pagesize * 2; i++) {
229    ASSERT_EQ(4, read_buffer[i]) << "Failed at byte " << i;
230  }
231}
232
233TEST_F(MemoryFileTest, map_overflow) {
234  size_t pagesize = getpagesize();
235  ASSERT_TRUE(pagesize > 0x100);
236  std::vector<uint8_t> buffer(pagesize * 10);
237  for (size_t i = 0; i < buffer.size(); i++) {
238    buffer[i] = i / pagesize + 1;
239  }
240  ASSERT_TRUE(android::base::WriteFully(tf_->fd, buffer.data(), buffer.size()));
241
242  // Map in only two pages of the data, and after the first page.
243  ASSERT_TRUE(memory_.Init(tf_->path, pagesize + 0x100, UINT64_MAX));
244
245  std::vector<uint8_t> read_buffer(pagesize * 10);
246  ASSERT_FALSE(memory_.Read(pagesize * 9 - 0x100 + 1, read_buffer.data(), 1));
247  ASSERT_TRUE(memory_.Read(0, read_buffer.data(), pagesize * 9 - 0x100));
248}
249
250TEST_F(MemoryFileTest, init_reinit) {
251  size_t pagesize = getpagesize();
252  std::vector<uint8_t> buffer(pagesize * 2);
253  for (size_t i = 0; i < buffer.size(); i++) {
254    buffer[i] = i / pagesize + 1;
255  }
256  ASSERT_TRUE(android::base::WriteFully(tf_->fd, buffer.data(), buffer.size()));
257
258  ASSERT_TRUE(memory_.Init(tf_->path, 0));
259  std::vector<uint8_t> read_buffer(buffer.size());
260  ASSERT_TRUE(memory_.Read(0, read_buffer.data(), pagesize));
261  for (size_t i = 0; i < pagesize; i++) {
262    ASSERT_EQ(1, read_buffer[i]) << "Failed at byte " << i;
263  }
264
265  // Now reinit.
266  ASSERT_TRUE(memory_.Init(tf_->path, pagesize));
267  ASSERT_TRUE(memory_.Read(0, read_buffer.data(), pagesize));
268  for (size_t i = 0; i < pagesize; i++) {
269    ASSERT_EQ(2, read_buffer[i]) << "Failed at byte " << i;
270  }
271}
272