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