blob: 15cbaa408f7649edce8df95952ac218bce0e3784 [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2019 The Chromium Authors
Robert Seseke58442762019-03-01 13:25:402// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Robert Seseke58442762019-03-01 13:25:405#include "base/containers/buffer_iterator.h"
6
7#include <string.h>
8
9#include <limits>
Arthur Sonzognie5fff99c2024-02-21 15:58:2410#include <optional>
Robert Seseke58442762019-03-01 13:25:4011#include <vector>
12
Tom Sepez7859fac52025-07-22 19:34:1613#include "base/compiler_specific.h"
danakj6d325d72024-02-13 23:42:5614#include "base/containers/span.h"
Robert Seseke58442762019-03-01 13:25:4015#include "testing/gtest/include/gtest/gtest.h"
16
17namespace base {
18namespace {
19
20struct TestStruct {
21 uint32_t one;
Peter Kastingb6079b802024-12-03 23:05:5322 uint8_t two, three, four, five;
Robert Seseke58442762019-03-01 13:25:4023};
24
25bool operator==(const TestStruct& lhs, const TestStruct& rhs) {
26 return lhs.one == rhs.one && lhs.two == rhs.two;
27}
28
29TestStruct CreateTestStruct() {
Peter Kastingb6079b802024-12-03 23:05:5330 return {0xabcdef12, 0x34, 0x56, 0x78, 0x90};
Robert Seseke58442762019-03-01 13:25:4031}
32
33TEST(BufferIteratorTest, Object) {
34 TestStruct expected = CreateTestStruct();
35
36 char buffer[sizeof(TestStruct)];
Tom Sepez7859fac52025-07-22 19:34:1637 UNSAFE_TODO(memcpy(buffer, &expected, sizeof(buffer)));
Robert Seseke58442762019-03-01 13:25:4038
39 {
40 // Read the object.
danakj6d325d72024-02-13 23:42:5641 BufferIterator<char> iterator(buffer);
Robert Seseke58442762019-03-01 13:25:4042 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.
Jose Dapena Paz81fbbbf2024-03-05 21:13:1647 BufferIterator<char> iterator(
48 span<char>(buffer).first<sizeof(buffer) - 1u>());
Robert Seseke58442762019-03-01 13:25:4049 const TestStruct* actual = iterator.Object<TestStruct>();
50 EXPECT_FALSE(actual);
51 }
52}
53
54TEST(BufferIteratorTest, MutableObject) {
55 TestStruct expected = CreateTestStruct();
56
57 char buffer[sizeof(TestStruct)];
58
danakj6d325d72024-02-13 23:42:5659 BufferIterator<char> iterator(buffer);
Robert Seseke58442762019-03-01 13:25:4060
61 {
62 // Write the object.
Peter Kastingb6079b802024-12-03 23:05:5363 *iterator.MutableObject<TestStruct>() = expected;
Robert Seseke58442762019-03-01 13:25:4064 }
65
66 // Rewind the iterator.
67 iterator.Seek(0);
68
69 {
70 // Read the object back.
71 const TestStruct* actual = iterator.Object<TestStruct>();
72 EXPECT_EQ(expected, *actual);
73 }
74}
75
David Benjaminfd7de0b2024-12-24 01:24:0176TEST(BufferIteratorTest, ObjectDoesNotFit) {
Robert Seseke58442762019-03-01 13:25:4077 char buffer[64];
David Benjaminfd7de0b2024-12-24 01:24:0178 BufferIterator<char> iterator(buffer);
Robert Seseke58442762019-03-01 13:25:4079
80 auto* pointer = iterator.Object<uint64_t>();
81 EXPECT_TRUE(pointer);
82
83 iterator.Seek(iterator.total_size() - 1);
84
85 auto* invalid_pointer = iterator.Object<uint64_t>();
86 EXPECT_FALSE(invalid_pointer);
87}
88
89TEST(BufferIteratorTest, Span) {
90 TestStruct expected = CreateTestStruct();
91
92 std::vector<char> buffer(sizeof(TestStruct) * 3);
93
94 {
95 // Load the span with data.
96 BufferIterator<char> iterator(buffer);
97 span<TestStruct> span = iterator.MutableSpan<TestStruct>(3);
98 for (auto& ts : span) {
Tom Sepez7859fac52025-07-22 19:34:1699 UNSAFE_TODO(memcpy(&ts, &expected, sizeof(expected)));
Robert Seseke58442762019-03-01 13:25:40100 }
101 }
102 {
103 // Read the data back out.
104 BufferIterator<char> iterator(buffer);
105
106 const TestStruct* actual = iterator.Object<TestStruct>();
107 EXPECT_EQ(expected, *actual);
108
109 actual = iterator.Object<TestStruct>();
110 EXPECT_EQ(expected, *actual);
111
112 actual = iterator.Object<TestStruct>();
113 EXPECT_EQ(expected, *actual);
114
115 EXPECT_EQ(iterator.total_size(), iterator.position());
116 }
117 {
118 // Cannot create spans larger than there are data for.
119 BufferIterator<char> iterator(buffer);
120 span<const TestStruct> span = iterator.Span<TestStruct>(4);
121 EXPECT_TRUE(span.empty());
122 }
123}
124
danakj216d6edf2024-03-28 22:30:30125TEST(BufferIteratorTest, FixedSpan) {
126 TestStruct expected = CreateTestStruct();
127
128 std::vector<char> buffer(sizeof(TestStruct) * 3);
129
130 {
131 // Load the span with data.
132 BufferIterator<char> iterator(buffer);
133 auto span = iterator.MutableSpan<TestStruct, 3u>();
134 static_assert(std::same_as<std::optional<base::span<TestStruct, 3u>>,
135 decltype(span)>);
136 for (auto& ts : *span) {
Tom Sepez7859fac52025-07-22 19:34:16137 UNSAFE_TODO(memcpy(&ts, &expected, sizeof(expected)));
danakj216d6edf2024-03-28 22:30:30138 }
139 }
140 {
141 // Read the data back out.
142 BufferIterator<char> iterator(buffer);
143
144 const TestStruct* actual = iterator.Object<TestStruct>();
145 EXPECT_EQ(expected, *actual);
146
147 actual = iterator.Object<TestStruct>();
148 EXPECT_EQ(expected, *actual);
149
150 actual = iterator.Object<TestStruct>();
151 EXPECT_EQ(expected, *actual);
152
153 EXPECT_EQ(iterator.total_size(), iterator.position());
154 }
155 {
156 // Cannot create spans larger than there are data for.
157 BufferIterator<char> iterator(buffer);
158 auto maybe_span = iterator.Span<TestStruct, 4u>();
159 EXPECT_FALSE(maybe_span.has_value());
160 }
161}
162
Robert Seseke58442762019-03-01 13:25:40163TEST(BufferIteratorTest, SpanOverflow) {
164 char buffer[64];
165
danakj6d325d72024-02-13 23:42:56166 BufferIterator<char> iterator(
167 // SAFETY: This intentionally makes an incorrectly-sized span. The span
168 // pointer, stored in the BufferIterator is never moved past the start in
169 // this test, as that would cause Undefined Behaviour.
170 UNSAFE_BUFFERS(span(buffer, std::numeric_limits<size_t>::max())));
danakj216d6edf2024-03-28 22:30:30171
172 constexpr size_t kInvalidU64Size =
173 (std::numeric_limits<size_t>::max() / sizeof(uint64_t)) + 1u;
Robert Seseke58442762019-03-01 13:25:40174 {
danakj216d6edf2024-03-28 22:30:30175 span<const uint64_t> empty_span = iterator.Span<uint64_t>(kInvalidU64Size);
Robert Seseke58442762019-03-01 13:25:40176 EXPECT_TRUE(empty_span.empty());
177 }
178 {
179 span<const uint64_t> empty_span =
180 iterator.Span<uint64_t>(std::numeric_limits<size_t>::max());
181 EXPECT_TRUE(empty_span.empty());
182 }
Robert Seseke58442762019-03-01 13:25:40183}
184
185TEST(BufferIteratorTest, Position) {
186 char buffer[64];
danakj6d325d72024-02-13 23:42:56187 BufferIterator<char> iterator(buffer);
Robert Seseke58442762019-03-01 13:25:40188 EXPECT_EQ(sizeof(buffer), iterator.total_size());
189
190 size_t position = iterator.position();
191 EXPECT_EQ(0u, position);
192
193 iterator.Object<uint8_t>();
194 EXPECT_EQ(sizeof(uint8_t), iterator.position() - position);
195 position = iterator.position();
196
197 iterator.Object<uint32_t>();
198 EXPECT_EQ(sizeof(uint32_t), iterator.position() - position);
199 position = iterator.position();
200
201 iterator.Seek(32);
202 EXPECT_EQ(32u, iterator.position());
203
204 EXPECT_EQ(sizeof(buffer), iterator.total_size());
205}
206
Jeremy Romane8965bd2022-10-18 00:40:18207TEST(BufferIteratorTest, CopyObject) {
208 TestStruct expected = CreateTestStruct();
209
210 constexpr int kNumCopies = 3;
211 char buffer[sizeof(TestStruct) * kNumCopies];
danakj6d325d72024-02-13 23:42:56212 for (int i = 0; i < kNumCopies; i++) {
213 as_writable_bytes(span(buffer))
214 .subspan(i * sizeof(TestStruct))
Peter Kasting448444f2024-12-13 01:25:36215 .copy_prefix_from(byte_span_from_ref(expected));
danakj6d325d72024-02-13 23:42:56216 }
Jeremy Romane8965bd2022-10-18 00:40:18217
218 BufferIterator<char> iterator(buffer);
Arthur Sonzognie5fff99c2024-02-21 15:58:24219 std::optional<TestStruct> actual;
Jeremy Romane8965bd2022-10-18 00:40:18220 for (int i = 0; i < kNumCopies; i++) {
221 actual = iterator.CopyObject<TestStruct>();
222 ASSERT_TRUE(actual.has_value());
223 EXPECT_EQ(expected, *actual);
224 }
225 actual = iterator.CopyObject<TestStruct>();
226 EXPECT_FALSE(actual.has_value());
227}
228
229TEST(BufferIteratorTest, SeekWithSizeConfines) {
230 const char buffer[] = "vindicate";
danakjfffdbb932024-06-07 17:11:41231 BufferIterator<const char> iterator(base::span_from_cstring(buffer));
Jeremy Romane8965bd2022-10-18 00:40:18232 iterator.Seek(5);
233 iterator.TruncateTo(3);
234 EXPECT_TRUE(iterator.Span<char>(4).empty());
235
236 std::string result;
Peter Kasting134ef9af2024-12-28 02:30:09237 while (const char* c = iterator.Object<char>()) {
Jeremy Romane8965bd2022-10-18 00:40:18238 result += *c;
Peter Kasting134ef9af2024-12-28 02:30:09239 }
Jeremy Romane8965bd2022-10-18 00:40:18240 EXPECT_EQ(result, "cat");
241}
242
Robert Seseke58442762019-03-01 13:25:40243} // namespace
244} // namespace base