1 // Copyright 2019 The Chromium Authors
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 "base/containers/buffer_iterator.h"
6
7 #include <string.h>
8
9 #include <limits>
10 #include <vector>
11
12 #include "testing/gtest/include/gtest/gtest.h"
13
14 namespace base {
15 namespace {
16
17 struct TestStruct {
18 uint32_t one;
19 uint8_t two;
20 };
21
operator ==(const TestStruct & lhs,const TestStruct & rhs)22 bool operator==(const TestStruct& lhs, const TestStruct& rhs) {
23 return lhs.one == rhs.one && lhs.two == rhs.two;
24 }
25
CreateTestStruct()26 TestStruct CreateTestStruct() {
27 TestStruct expected;
28 expected.one = 0xabcdef12;
29 expected.two = 0x34;
30 return expected;
31 }
32
TEST(BufferIteratorTest,Object)33 TEST(BufferIteratorTest, Object) {
34 TestStruct expected = CreateTestStruct();
35
36 char buffer[sizeof(TestStruct)];
37 memcpy(buffer, &expected, sizeof(buffer));
38
39 {
40 // Read the object.
41 BufferIterator<char> iterator(buffer, sizeof(buffer));
42 const TestStruct* actual = iterator.Object<TestStruct>();
43 EXPECT_EQ(expected, *actual);
44 }
45 {
46 // Iterator's view of the data is not large enough to read the object.
47 BufferIterator<char> iterator(buffer, sizeof(buffer) - 1);
48 const TestStruct* actual = iterator.Object<TestStruct>();
49 EXPECT_FALSE(actual);
50 }
51 }
52
TEST(BufferIteratorTest,MutableObject)53 TEST(BufferIteratorTest, MutableObject) {
54 TestStruct expected = CreateTestStruct();
55
56 char buffer[sizeof(TestStruct)];
57
58 BufferIterator<char> iterator(buffer, sizeof(buffer));
59
60 {
61 // Write the object.
62 TestStruct* actual = iterator.MutableObject<TestStruct>();
63 actual->one = expected.one;
64 actual->two = expected.two;
65 }
66
67 // Rewind the iterator.
68 iterator.Seek(0);
69
70 {
71 // Read the object back.
72 const TestStruct* actual = iterator.Object<TestStruct>();
73 EXPECT_EQ(expected, *actual);
74 }
75 }
76
TEST(BufferIteratorTest,ObjectSizeOverflow)77 TEST(BufferIteratorTest, ObjectSizeOverflow) {
78 char buffer[64];
79 BufferIterator<char> iterator(buffer, std::numeric_limits<size_t>::max());
80
81 auto* pointer = iterator.Object<uint64_t>();
82 EXPECT_TRUE(pointer);
83
84 iterator.Seek(iterator.total_size() - 1);
85
86 auto* invalid_pointer = iterator.Object<uint64_t>();
87 EXPECT_FALSE(invalid_pointer);
88 }
89
TEST(BufferIteratorTest,Span)90 TEST(BufferIteratorTest, Span) {
91 TestStruct expected = CreateTestStruct();
92
93 std::vector<char> buffer(sizeof(TestStruct) * 3);
94
95 {
96 // Load the span with data.
97 BufferIterator<char> iterator(buffer);
98 span<TestStruct> span = iterator.MutableSpan<TestStruct>(3);
99 for (auto& ts : span) {
100 memcpy(&ts, &expected, sizeof(expected));
101 }
102 }
103 {
104 // Read the data back out.
105 BufferIterator<char> iterator(buffer);
106
107 const TestStruct* actual = iterator.Object<TestStruct>();
108 EXPECT_EQ(expected, *actual);
109
110 actual = iterator.Object<TestStruct>();
111 EXPECT_EQ(expected, *actual);
112
113 actual = iterator.Object<TestStruct>();
114 EXPECT_EQ(expected, *actual);
115
116 EXPECT_EQ(iterator.total_size(), iterator.position());
117 }
118 {
119 // Cannot create spans larger than there are data for.
120 BufferIterator<char> iterator(buffer);
121 span<const TestStruct> span = iterator.Span<TestStruct>(4);
122 EXPECT_TRUE(span.empty());
123 }
124 }
125
TEST(BufferIteratorTest,SpanOverflow)126 TEST(BufferIteratorTest, SpanOverflow) {
127 char buffer[64];
128
129 BufferIterator<char> iterator(buffer, std::numeric_limits<size_t>::max());
130 {
131 span<const uint64_t> empty_span = iterator.Span<uint64_t>(
132 (std::numeric_limits<size_t>::max() / sizeof(uint64_t)) + 1);
133 EXPECT_TRUE(empty_span.empty());
134 }
135 {
136 span<const uint64_t> empty_span =
137 iterator.Span<uint64_t>(std::numeric_limits<size_t>::max());
138 EXPECT_TRUE(empty_span.empty());
139 }
140 {
141 iterator.Seek(iterator.total_size() - 7);
142 span<const uint64_t> empty_span = iterator.Span<uint64_t>(1);
143 EXPECT_TRUE(empty_span.empty());
144 }
145 }
146
TEST(BufferIteratorTest,Position)147 TEST(BufferIteratorTest, Position) {
148 char buffer[64];
149 BufferIterator<char> iterator(buffer, sizeof(buffer));
150 EXPECT_EQ(sizeof(buffer), iterator.total_size());
151
152 size_t position = iterator.position();
153 EXPECT_EQ(0u, position);
154
155 iterator.Object<uint8_t>();
156 EXPECT_EQ(sizeof(uint8_t), iterator.position() - position);
157 position = iterator.position();
158
159 iterator.Object<uint32_t>();
160 EXPECT_EQ(sizeof(uint32_t), iterator.position() - position);
161 position = iterator.position();
162
163 iterator.Seek(32);
164 EXPECT_EQ(32u, iterator.position());
165
166 EXPECT_EQ(sizeof(buffer), iterator.total_size());
167 }
168
TEST(BufferIteratorTest,CopyObject)169 TEST(BufferIteratorTest, CopyObject) {
170 TestStruct expected = CreateTestStruct();
171
172 constexpr int kNumCopies = 3;
173 char buffer[sizeof(TestStruct) * kNumCopies];
174 for (int i = 0; i < kNumCopies; i++)
175 memcpy(buffer + i * sizeof(TestStruct), &expected, sizeof(TestStruct));
176
177 BufferIterator<char> iterator(buffer);
178 absl::optional<TestStruct> actual;
179 for (int i = 0; i < kNumCopies; i++) {
180 actual = iterator.CopyObject<TestStruct>();
181 ASSERT_TRUE(actual.has_value());
182 EXPECT_EQ(expected, *actual);
183 }
184 actual = iterator.CopyObject<TestStruct>();
185 EXPECT_FALSE(actual.has_value());
186 }
187
TEST(BufferIteratorTest,SeekWithSizeConfines)188 TEST(BufferIteratorTest, SeekWithSizeConfines) {
189 const char buffer[] = "vindicate";
190 BufferIterator<const char> iterator(buffer);
191 iterator.Seek(5);
192 iterator.TruncateTo(3);
193 EXPECT_TRUE(iterator.Span<char>(4).empty());
194
195 std::string result;
196 while (const char* c = iterator.Object<char>())
197 result += *c;
198 EXPECT_EQ(result, "cat");
199 }
200
201 } // namespace
202 } // namespace base
203