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 <brillo/streams/memory_containers.h>
6
7 #include <limits>
8 #include <memory>
9
10 #include <brillo/streams/mock_stream.h>
11 #include <brillo/streams/stream_errors.h>
12 #include <gmock/gmock.h>
13 #include <gtest/gtest.h>
14
15 using testing::DoAll;
16 using testing::Invoke;
17 using testing::InSequence;
18 using testing::Return;
19 using testing::WithArgs;
20 using testing::_;
21
22 namespace brillo {
23
24 namespace {
25 class MockContiguousBuffer : public data_container::ContiguousBufferBase {
26 public:
27 MockContiguousBuffer() = default;
28
29 MOCK_METHOD2(Resize, bool(size_t, ErrorPtr*));
30 MOCK_CONST_METHOD0(GetSize, size_t());
31 MOCK_CONST_METHOD0(IsReadOnly, bool());
32
33 MOCK_CONST_METHOD2(GetReadOnlyBuffer, const void*(size_t, ErrorPtr*));
34 MOCK_METHOD2(GetBuffer, void*(size_t, ErrorPtr*));
35
36 MOCK_CONST_METHOD3(CopyMemoryBlock, void(void*, const void*, size_t));
37
38 private:
39 DISALLOW_COPY_AND_ASSIGN(MockContiguousBuffer);
40 };
41 } // anonymous namespace
42
43 class MemoryContainerTest : public testing::Test {
44 public:
IntToPtr(int addr)45 inline static void* IntToPtr(int addr) {
46 return reinterpret_cast<void*>(addr);
47 }
48
IntToConstPtr(int addr)49 inline static const void* IntToConstPtr(int addr) {
50 return reinterpret_cast<const void*>(addr);
51 }
52
53 // Dummy buffer pointer values used as external data source/destination for
54 // read/write operations.
55 void* const test_read_buffer_ = IntToPtr(12345);
56 const void* const test_write_buffer_ = IntToConstPtr(67890);
57
58 // Dummy buffer pointer values used for internal buffer owned by the
59 // memory buffer container class.
60 const void* const const_buffer_ = IntToConstPtr(123);
61 void* const buffer_ = IntToPtr(456);
62
63 MockContiguousBuffer container_;
64 };
65
TEST_F(MemoryContainerTest,Read_WithinBuffer)66 TEST_F(MemoryContainerTest, Read_WithinBuffer) {
67 {
68 InSequence s;
69 EXPECT_CALL(container_, GetSize()).WillOnce(Return(100));
70 EXPECT_CALL(container_, GetReadOnlyBuffer(10, _))
71 .WillOnce(Return(const_buffer_));
72 EXPECT_CALL(container_,
73 CopyMemoryBlock(test_read_buffer_, const_buffer_, 50)).Times(1);
74 }
75 size_t read = 0;
76 ErrorPtr error;
77 EXPECT_TRUE(container_.Read(test_read_buffer_, 50, 10, &read, &error));
78 EXPECT_EQ(50, read);
79 EXPECT_EQ(nullptr, error.get());
80 }
81
TEST_F(MemoryContainerTest,Read_PastEndOfBuffer)82 TEST_F(MemoryContainerTest, Read_PastEndOfBuffer) {
83 {
84 InSequence s;
85 EXPECT_CALL(container_, GetSize()).WillOnce(Return(100));
86 EXPECT_CALL(container_, GetReadOnlyBuffer(80, _))
87 .WillOnce(Return(const_buffer_));
88 EXPECT_CALL(container_,
89 CopyMemoryBlock(test_read_buffer_, const_buffer_, 20)).Times(1);
90 }
91 size_t read = 0;
92 EXPECT_TRUE(container_.Read(test_read_buffer_, 50, 80, &read, nullptr));
93 EXPECT_EQ(20, read);
94 }
95
TEST_F(MemoryContainerTest,Read_OutsideBuffer)96 TEST_F(MemoryContainerTest, Read_OutsideBuffer) {
97 EXPECT_CALL(container_, GetSize()).WillOnce(Return(100));
98 size_t read = 0;
99 EXPECT_TRUE(container_.Read(test_read_buffer_, 50, 100, &read, nullptr));
100 EXPECT_EQ(0, read);
101 }
102
TEST_F(MemoryContainerTest,Read_Error)103 TEST_F(MemoryContainerTest, Read_Error) {
104 auto OnReadError = [](ErrorPtr* error) {
105 Error::AddTo(error, FROM_HERE, "domain", "read_error", "read error");
106 };
107
108 {
109 InSequence s;
110 EXPECT_CALL(container_, GetSize()).WillOnce(Return(100));
111 EXPECT_CALL(container_, GetReadOnlyBuffer(0, _))
112 .WillOnce(DoAll(WithArgs<1>(Invoke(OnReadError)), Return(nullptr)));
113 }
114 size_t read = 0;
115 ErrorPtr error;
116 EXPECT_FALSE(container_.Read(test_read_buffer_, 10, 0, &read, &error));
117 EXPECT_EQ(0, read);
118 EXPECT_NE(nullptr, error.get());
119 EXPECT_EQ("domain", error->GetDomain());
120 EXPECT_EQ("read_error", error->GetCode());
121 EXPECT_EQ("read error", error->GetMessage());
122 }
123
TEST_F(MemoryContainerTest,Write_WithinBuffer)124 TEST_F(MemoryContainerTest, Write_WithinBuffer) {
125 {
126 InSequence s;
127 EXPECT_CALL(container_, GetSize()).WillOnce(Return(100));
128 EXPECT_CALL(container_, GetBuffer(10, _))
129 .WillOnce(Return(buffer_));
130 EXPECT_CALL(container_,
131 CopyMemoryBlock(buffer_, test_write_buffer_, 50)).Times(1);
132 }
133 size_t written = 0;
134 ErrorPtr error;
135 EXPECT_TRUE(container_.Write(test_write_buffer_, 50, 10, &written, &error));
136 EXPECT_EQ(50, written);
137 EXPECT_EQ(nullptr, error.get());
138 }
139
TEST_F(MemoryContainerTest,Write_PastEndOfBuffer)140 TEST_F(MemoryContainerTest, Write_PastEndOfBuffer) {
141 {
142 InSequence s;
143 EXPECT_CALL(container_, GetSize()).WillOnce(Return(100));
144 EXPECT_CALL(container_, Resize(130, _)).WillOnce(Return(true));
145 EXPECT_CALL(container_, GetBuffer(80, _))
146 .WillOnce(Return(buffer_));
147 EXPECT_CALL(container_,
148 CopyMemoryBlock(buffer_, test_write_buffer_, 50)).Times(1);
149 }
150 size_t written = 0;
151 EXPECT_TRUE(container_.Write(test_write_buffer_, 50, 80, &written, nullptr));
152 EXPECT_EQ(50, written);
153 }
154
TEST_F(MemoryContainerTest,Write_OutsideBuffer)155 TEST_F(MemoryContainerTest, Write_OutsideBuffer) {
156 {
157 InSequence s;
158 EXPECT_CALL(container_, GetSize()).WillOnce(Return(100));
159 EXPECT_CALL(container_, Resize(160, _)).WillOnce(Return(true));
160 EXPECT_CALL(container_, GetBuffer(110, _))
161 .WillOnce(Return(buffer_));
162 EXPECT_CALL(container_,
163 CopyMemoryBlock(buffer_, test_write_buffer_, 50)).Times(1);
164 }
165 size_t written = 0;
166 EXPECT_TRUE(container_.Write(test_write_buffer_, 50, 110, &written, nullptr));
167 EXPECT_EQ(50, written);
168 }
169
TEST_F(MemoryContainerTest,Write_Error_Resize)170 TEST_F(MemoryContainerTest, Write_Error_Resize) {
171 auto OnWriteError = [](ErrorPtr* error) {
172 Error::AddTo(error, FROM_HERE, "domain", "write_error", "resize error");
173 };
174
175 {
176 InSequence s;
177 EXPECT_CALL(container_, GetSize()).WillOnce(Return(100));
178 EXPECT_CALL(container_, Resize(160, _))
179 .WillOnce(DoAll(WithArgs<1>(Invoke(OnWriteError)), Return(false)));
180 }
181 size_t written = 0;
182 ErrorPtr error;
183 EXPECT_FALSE(container_.Write(test_write_buffer_, 50, 110, &written, &error));
184 EXPECT_EQ(0, written);
185 EXPECT_NE(nullptr, error.get());
186 EXPECT_EQ("domain", error->GetDomain());
187 EXPECT_EQ("write_error", error->GetCode());
188 EXPECT_EQ("resize error", error->GetMessage());
189 }
190
TEST_F(MemoryContainerTest,Write_Error)191 TEST_F(MemoryContainerTest, Write_Error) {
192 auto OnWriteError = [](ErrorPtr* error) {
193 Error::AddTo(error, FROM_HERE, "domain", "write_error", "write error");
194 };
195
196 {
197 InSequence s;
198 EXPECT_CALL(container_, GetSize()).WillOnce(Return(100));
199 EXPECT_CALL(container_, Resize(160, _)).WillOnce(Return(true));
200 EXPECT_CALL(container_, GetBuffer(110, _))
201 .WillOnce(DoAll(WithArgs<1>(Invoke(OnWriteError)), Return(nullptr)));
202 }
203 size_t written = 0;
204 ErrorPtr error;
205 EXPECT_FALSE(container_.Write(test_write_buffer_, 50, 110, &written, &error));
206 EXPECT_EQ(0, written);
207 EXPECT_NE(nullptr, error.get());
208 EXPECT_EQ("domain", error->GetDomain());
209 EXPECT_EQ("write_error", error->GetCode());
210 EXPECT_EQ("write error", error->GetMessage());
211 }
212
213 } // namespace brillo
214
215