• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // 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 
5 #include "bsdiff/extents_file.h"
6 
7 #include <gmock/gmock.h>
8 #include <gtest/gtest.h>
9 #include <string>
10 #include <vector>
11 
12 #include "bsdiff/file_interface.h"
13 
14 using std::vector;
15 using testing::AnyNumber;
16 using testing::InSequence;
17 using testing::Return;
18 using testing::StrictMock;
19 using testing::_;
20 
21 namespace bsdiff {
22 
23 // Mock class for the underlying file interface.
24 class 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());
30   MOCK_METHOD1(GetSize, bool(uint64_t*));
31 };
32 
ACTION(SucceedIO)33 ACTION(SucceedIO) {
34   // Check that arg1 (count) can be converted
35   *arg2 = arg1;
36   return true;
37 }
38 
ACTION_P(SucceedPartialIO,bytes)39 ACTION_P(SucceedPartialIO, bytes) {
40   // Check that arg1 (count) can be converted
41   *arg2 = bytes;
42   return true;
43 }
44 
45 class ExtentsFileTest : public testing::Test {
46  protected:
SetUp()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 
TEST_F(ExtentsFileTest,DestructorCloses)60 TEST_F(ExtentsFileTest, DestructorCloses) {
61   ExtentsFile file(std::move(mock_file_ptr_), {});
62 }
63 
TEST_F(ExtentsFileTest,CloseIsForwarded)64 TEST_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 
TEST_F(ExtentsFileTest,GetSizeSumExtents)70 TEST_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 
TEST_F(ExtentsFileTest,SeekToRightOffsets)78 TEST_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 
TEST_F(ExtentsFileTest,ReadAcrossAllExtents)109 TEST_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 
TEST_F(ExtentsFileTest,MultiReadAcrossAllExtents)130 TEST_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 
TEST_F(ExtentsFileTest,ReadSmallChunks)156 TEST_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 
TEST_F(ExtentsFileTest,ReadFailureFails)172 TEST_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 
181   size_t bytes_read = 0;
182   EXPECT_TRUE(file.Read(nullptr, 100, &bytes_read));
183   EXPECT_EQ(1U, bytes_read);
184 }
185 
TEST_F(ExtentsFileTest,ReadFails)186 TEST_F(ExtentsFileTest, ReadFails) {
187   ExtentsFile file(std::move(mock_file_ptr_), {ex_t{10, 1}, ex_t{20, 10}});
188   EXPECT_CALL(*mock_file_, Seek(10)).WillOnce(Return(true));
189   EXPECT_CALL(*mock_file_, Read(_, 1, _)).WillOnce(Return(false));
190   size_t bytes_read;
191   EXPECT_FALSE(file.Read(nullptr, 1, &bytes_read));
192 }
193 
TEST_F(ExtentsFileTest,ReadPartialReadsAndEOF)194 TEST_F(ExtentsFileTest, ReadPartialReadsAndEOF) {
195   ExtentsFile file(std::move(mock_file_ptr_), {ex_t{10, 1}, ex_t{20, 10}});
196   EXPECT_CALL(*mock_file_, Seek(_))
197       .Times(AnyNumber())
198       .WillRepeatedly(Return(true));
199   char* buf = reinterpret_cast<char*>(0x1234);
200   InSequence s;
201   EXPECT_CALL(*mock_file_, Read(buf, 1, _)).WillOnce(SucceedIO());
202   EXPECT_CALL(*mock_file_, Read(buf + 1, _, _)).WillOnce(SucceedPartialIO(3));
203   EXPECT_CALL(*mock_file_, Read(buf + 4, _, _)).WillOnce(SucceedPartialIO(0));
204 
205   size_t bytes_read = 0;
206   EXPECT_TRUE(file.Read(buf, 100, &bytes_read));
207   EXPECT_EQ(4U, bytes_read);
208 }
209 
210 }  // namespace bsdiff
211