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