blob: 38f288ad010cba46851e9a949d4cb3d3e86b8c84 [file] [log] [blame]
Alex Deymo03f1deb2015-10-13 02:15:31 -07001// Copyright 2015 The Chromium OS 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
Alex Deymoddf9db52017-03-02 16:10:41 -08005#include "bsdiff/extents_file.h"
Alex Deymo03f1deb2015-10-13 02:15:31 -07006
Alex Deymo03f1deb2015-10-13 02:15:31 -07007#include <gmock/gmock.h>
Alex Deymodcd423b2017-09-13 20:54:24 +02008#include <gtest/gtest.h>
Alex Deymo03f1deb2015-10-13 02:15:31 -07009#include <string>
10#include <vector>
11
Alex Deymoddf9db52017-03-02 16:10:41 -080012#include "bsdiff/file_interface.h"
Alex Deymo03f1deb2015-10-13 02:15:31 -070013
Alex Deymo03f1deb2015-10-13 02:15:31 -070014using std::vector;
15using testing::AnyNumber;
Alex Deymo03f1deb2015-10-13 02:15:31 -070016using testing::InSequence;
Alex Deymodcd423b2017-09-13 20:54:24 +020017using testing::Return;
18using testing::StrictMock;
Alex Deymo03f1deb2015-10-13 02:15:31 -070019using testing::_;
20
21namespace bsdiff {
22
23// Mock class for the underlying file interface.
24class MockFile : public FileInterface {
25 public:
26 MOCK_METHOD3(Read, bool(void*, size_t, size_t*));
27 MOCK_METHOD3(Write, bool(const void*, size_t, size_t*));
28 MOCK_METHOD1(Seek, bool(off_t));
29 MOCK_METHOD0(Close, bool());
Alex Deymodaf35162015-10-14 20:43:15 -070030 MOCK_METHOD1(GetSize, bool(uint64_t*));
Alex Deymo03f1deb2015-10-13 02:15:31 -070031};
32
33ACTION(SucceedIO) {
34 // Check that arg1 (count) can be converted
35 *arg2 = arg1;
36 return true;
37}
38
39ACTION_P(SucceedPartialIO, bytes) {
40 // Check that arg1 (count) can be converted
41 *arg2 = bytes;
42 return true;
43}
44
45class ExtentsFileTest : public testing::Test {
46 protected:
47 void SetUp() {
48 mock_file_ = new StrictMock<MockFile>();
49 mock_file_ptr_.reset(mock_file_);
50 // The destructor of the ExtentsFile will call Close once.
51 EXPECT_CALL(*mock_file_, Close()).WillOnce(Return(true));
52 }
53
54 // Pointer to the underlying File owned by the ExtentsFile under test. This
55 // pointer is invalidated whenever the ExtentsFile is destroyed.
56 StrictMock<MockFile>* mock_file_;
57 std::unique_ptr<FileInterface> mock_file_ptr_;
58};
59
60TEST_F(ExtentsFileTest, DestructorCloses) {
61 ExtentsFile file(std::move(mock_file_ptr_), {});
62}
63
64TEST_F(ExtentsFileTest, CloseIsForwarded) {
65 ExtentsFile file(std::move(mock_file_ptr_), {});
66 EXPECT_TRUE(file.Close());
67 EXPECT_CALL(*mock_file_, Close()).WillOnce(Return(false));
68}
69
Alex Deymodaf35162015-10-14 20:43:15 -070070TEST_F(ExtentsFileTest, GetSizeSumExtents) {
71 ExtentsFile file(std::move(mock_file_ptr_),
72 {ex_t{10, 5}, ex_t{20, 5}, {25, 2}});
73 uint64_t size;
74 EXPECT_TRUE(file.GetSize(&size));
75 EXPECT_EQ(12U, size);
76}
77
Alex Deymo03f1deb2015-10-13 02:15:31 -070078TEST_F(ExtentsFileTest, SeekToRightOffsets) {
79 ExtentsFile file(std::move(mock_file_ptr_),
80 {ex_t{10, 5}, ex_t{20, 5}, {25, 2}});
81 vector<std::pair<off_t, off_t>> tests = {
82 // Seek to the beginning of the file.
83 {0, 10},
84 // Seek to the middle of a extent.
85 {3, 13},
86 {11, 26},
87 // Seek to the extent boundary.
88 {5, 20}, // Seeks to the first byte in the second extent.
89 {10, 25},
90 };
91 for (const auto& offset_pair : tests) {
92 // We use a failing Read() call to trigger the actual seek call to the
93 // underlying file.
94 EXPECT_CALL(*mock_file_, Seek(offset_pair.second)).WillOnce(Return(true));
95 EXPECT_CALL(*mock_file_, Read(_, _, _)).WillOnce(Return(false));
96
97 EXPECT_TRUE(file.Seek(offset_pair.first));
98 size_t bytes_read;
99 EXPECT_FALSE(file.Read(nullptr, 1, &bytes_read));
100 }
101
102 // Seeking to the end of the file is ok, but not past it.
103 EXPECT_TRUE(file.Seek(12));
104 EXPECT_FALSE(file.Seek(13));
105
106 EXPECT_FALSE(file.Seek(-1));
107}
108
109TEST_F(ExtentsFileTest, ReadAcrossAllExtents) {
110 ExtentsFile file(std::move(mock_file_ptr_),
111 {ex_t{10, 5}, ex_t{20, 7}, {27, 3}});
112 InSequence s;
113 char* buf = reinterpret_cast<char*>(0x1234);
114
115 EXPECT_CALL(*mock_file_, Seek(10)).WillOnce(Return(true));
116 EXPECT_CALL(*mock_file_, Read(buf, 5, _)).WillOnce(SucceedIO());
117 EXPECT_CALL(*mock_file_, Seek(20)).WillOnce(Return(true));
118 EXPECT_CALL(*mock_file_, Read(buf + 5, 7, _)).WillOnce(SucceedIO());
119 EXPECT_CALL(*mock_file_, Seek(27)).WillOnce(Return(true));
120 EXPECT_CALL(*mock_file_, Read(buf + 12, 3, _)).WillOnce(SucceedIO());
121
122 // FileExtents::Read() should read everything in one shot, by reading all
123 // the little chunks. Note that it doesn't attempt to read past the end of the
124 // FileExtents.
125 size_t bytes_read = 0;
126 EXPECT_TRUE(file.Read(buf, 100, &bytes_read));
127 EXPECT_EQ(15U, bytes_read);
128}
129
Sen Jiangf822e6c2015-11-24 13:44:00 -0800130TEST_F(ExtentsFileTest, MultiReadAcrossAllExtents) {
131 ExtentsFile file(std::move(mock_file_ptr_),
132 {ex_t{10, 5}, ex_t{20, 7}, {27, 3}});
133 InSequence s;
134 char* buf = reinterpret_cast<char*>(0x1234);
135
136 EXPECT_CALL(*mock_file_, Seek(10)).WillOnce(Return(true));
137 EXPECT_CALL(*mock_file_, Read(buf, 2, _)).WillOnce(SucceedIO());
138 EXPECT_CALL(*mock_file_, Seek(12)).WillOnce(Return(true));
139 EXPECT_CALL(*mock_file_, Read(buf, 3, _)).WillOnce(SucceedIO());
140 EXPECT_CALL(*mock_file_, Seek(20)).WillOnce(Return(true));
141 EXPECT_CALL(*mock_file_, Read(buf + 3, 5, _)).WillOnce(SucceedIO());
142 EXPECT_CALL(*mock_file_, Seek(25)).WillOnce(Return(true));
143 EXPECT_CALL(*mock_file_, Read(buf, 2, _)).WillOnce(SucceedIO());
144 EXPECT_CALL(*mock_file_, Seek(27)).WillOnce(Return(true));
145 EXPECT_CALL(*mock_file_, Read(buf + 2, 3, _)).WillOnce(SucceedIO());
146
147 size_t bytes_read = 0;
148 EXPECT_TRUE(file.Read(buf, 2, &bytes_read));
149 EXPECT_EQ(2U, bytes_read);
150 EXPECT_TRUE(file.Read(buf, 8, &bytes_read));
151 EXPECT_EQ(8U, bytes_read);
152 EXPECT_TRUE(file.Read(buf, 100, &bytes_read));
153 EXPECT_EQ(5U, bytes_read);
154}
155
Alex Deymo03f1deb2015-10-13 02:15:31 -0700156TEST_F(ExtentsFileTest, ReadSmallChunks) {
157 ExtentsFile file(std::move(mock_file_ptr_), {ex_t{10, 1}, ex_t{20, 10}});
158 InSequence s;
159 char* buf = reinterpret_cast<char*>(0x1234);
160
161 EXPECT_CALL(*mock_file_, Seek(10)).WillOnce(Return(true));
162 EXPECT_CALL(*mock_file_, Read(buf, 1, _)).WillOnce(SucceedIO());
163 EXPECT_CALL(*mock_file_, Seek(20)).WillOnce(Return(true));
164 // We expect to read only part of the second extent.
165 EXPECT_CALL(*mock_file_, Read(buf + 1, 1, _)).WillOnce(SucceedIO());
166
167 size_t bytes_read = 0;
168 EXPECT_TRUE(file.Read(buf, 2, &bytes_read));
169 EXPECT_EQ(2U, bytes_read);
170}
171
172TEST_F(ExtentsFileTest, ReadFailureFails) {
173 ExtentsFile file(std::move(mock_file_ptr_), {ex_t{10, 1}, ex_t{20, 10}});
174 EXPECT_CALL(*mock_file_, Seek(_))
175 .Times(AnyNumber())
176 .WillRepeatedly(Return(true));
177 EXPECT_CALL(*mock_file_, Read(_, 1, _)).WillOnce(SucceedIO());
178 // A second read that fails will succeed if there was partial data read.
179 EXPECT_CALL(*mock_file_, Read(_, 10, _)).WillOnce(Return(false));
180
Amin Hassania65cff92020-03-23 11:37:24 -0700181 char* buf = reinterpret_cast<char*>(0x1234);
Alex Deymo03f1deb2015-10-13 02:15:31 -0700182 size_t bytes_read = 0;
Amin Hassania65cff92020-03-23 11:37:24 -0700183 EXPECT_TRUE(file.Read(buf, 100, &bytes_read));
Alex Deymo03f1deb2015-10-13 02:15:31 -0700184 EXPECT_EQ(1U, bytes_read);
185}
186
187TEST_F(ExtentsFileTest, ReadFails) {
188 ExtentsFile file(std::move(mock_file_ptr_), {ex_t{10, 1}, ex_t{20, 10}});
189 EXPECT_CALL(*mock_file_, Seek(10)).WillOnce(Return(true));
190 EXPECT_CALL(*mock_file_, Read(_, 1, _)).WillOnce(Return(false));
191 size_t bytes_read;
192 EXPECT_FALSE(file.Read(nullptr, 1, &bytes_read));
193}
194
195TEST_F(ExtentsFileTest, ReadPartialReadsAndEOF) {
196 ExtentsFile file(std::move(mock_file_ptr_), {ex_t{10, 1}, ex_t{20, 10}});
197 EXPECT_CALL(*mock_file_, Seek(_))
198 .Times(AnyNumber())
199 .WillRepeatedly(Return(true));
200 char* buf = reinterpret_cast<char*>(0x1234);
201 InSequence s;
202 EXPECT_CALL(*mock_file_, Read(buf, 1, _)).WillOnce(SucceedIO());
203 EXPECT_CALL(*mock_file_, Read(buf + 1, _, _)).WillOnce(SucceedPartialIO(3));
204 EXPECT_CALL(*mock_file_, Read(buf + 4, _, _)).WillOnce(SucceedPartialIO(0));
205
206 size_t bytes_read = 0;
207 EXPECT_TRUE(file.Read(buf, 100, &bytes_read));
208 EXPECT_EQ(4U, bytes_read);
209}
210
211} // namespace bsdiff