1 /*
2 * Copyright 2016 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "rtc_base/copy_on_write_buffer.h"
12
13 #include <cstdint>
14
15 #include "test/gtest.h"
16
17 namespace rtc {
18
19 namespace {
20
21 // clang-format off
22 const uint8_t kTestData[] = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
23 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
24 // clang-format on
25
26 } // namespace
27
EnsureBuffersShareData(const CopyOnWriteBuffer & buf1,const CopyOnWriteBuffer & buf2)28 void EnsureBuffersShareData(const CopyOnWriteBuffer& buf1,
29 const CopyOnWriteBuffer& buf2) {
30 // Data is shared between buffers.
31 EXPECT_EQ(buf1.size(), buf2.size());
32 EXPECT_EQ(buf1.capacity(), buf2.capacity());
33 const uint8_t* data1 = buf1.data();
34 const uint8_t* data2 = buf2.data();
35 EXPECT_EQ(data1, data2);
36 EXPECT_EQ(buf1, buf2);
37 }
38
EnsureBuffersDontShareData(const CopyOnWriteBuffer & buf1,const CopyOnWriteBuffer & buf2)39 void EnsureBuffersDontShareData(const CopyOnWriteBuffer& buf1,
40 const CopyOnWriteBuffer& buf2) {
41 // Data is not shared between buffers.
42 const uint8_t* data1 = buf1.cdata();
43 const uint8_t* data2 = buf2.cdata();
44 EXPECT_NE(data1, data2);
45 }
46
TEST(CopyOnWriteBufferTest,TestCreateEmptyData)47 TEST(CopyOnWriteBufferTest, TestCreateEmptyData) {
48 CopyOnWriteBuffer buf(static_cast<const uint8_t*>(nullptr), 0);
49 EXPECT_EQ(buf.size(), 0u);
50 EXPECT_EQ(buf.capacity(), 0u);
51 EXPECT_EQ(buf.data(), nullptr);
52 }
53
TEST(CopyOnWriteBufferTest,TestMoveConstruct)54 TEST(CopyOnWriteBufferTest, TestMoveConstruct) {
55 CopyOnWriteBuffer buf1(kTestData, 3, 10);
56 size_t buf1_size = buf1.size();
57 size_t buf1_capacity = buf1.capacity();
58 const uint8_t* buf1_data = buf1.cdata();
59
60 CopyOnWriteBuffer buf2(std::move(buf1));
61 EXPECT_EQ(buf1.size(), 0u);
62 EXPECT_EQ(buf1.capacity(), 0u);
63 EXPECT_EQ(buf1.data(), nullptr);
64 EXPECT_EQ(buf2.size(), buf1_size);
65 EXPECT_EQ(buf2.capacity(), buf1_capacity);
66 EXPECT_EQ(buf2.data(), buf1_data);
67 }
68
TEST(CopyOnWriteBufferTest,TestMoveAssign)69 TEST(CopyOnWriteBufferTest, TestMoveAssign) {
70 CopyOnWriteBuffer buf1(kTestData, 3, 10);
71 size_t buf1_size = buf1.size();
72 size_t buf1_capacity = buf1.capacity();
73 const uint8_t* buf1_data = buf1.cdata();
74
75 CopyOnWriteBuffer buf2;
76 buf2 = std::move(buf1);
77 EXPECT_EQ(buf1.size(), 0u);
78 EXPECT_EQ(buf1.capacity(), 0u);
79 EXPECT_EQ(buf1.data(), nullptr);
80 EXPECT_EQ(buf2.size(), buf1_size);
81 EXPECT_EQ(buf2.capacity(), buf1_capacity);
82 EXPECT_EQ(buf2.data(), buf1_data);
83 }
84
TEST(CopyOnWriteBufferTest,TestSwap)85 TEST(CopyOnWriteBufferTest, TestSwap) {
86 CopyOnWriteBuffer buf1(kTestData, 3, 10);
87 size_t buf1_size = buf1.size();
88 size_t buf1_capacity = buf1.capacity();
89 const uint8_t* buf1_data = buf1.cdata();
90
91 CopyOnWriteBuffer buf2(kTestData, 6, 20);
92 size_t buf2_size = buf2.size();
93 size_t buf2_capacity = buf2.capacity();
94 const uint8_t* buf2_data = buf2.cdata();
95
96 std::swap(buf1, buf2);
97 EXPECT_EQ(buf1.size(), buf2_size);
98 EXPECT_EQ(buf1.capacity(), buf2_capacity);
99 EXPECT_EQ(buf1.data(), buf2_data);
100 EXPECT_EQ(buf2.size(), buf1_size);
101 EXPECT_EQ(buf2.capacity(), buf1_capacity);
102 EXPECT_EQ(buf2.data(), buf1_data);
103 }
104
TEST(CopyOnWriteBufferTest,TestAppendData)105 TEST(CopyOnWriteBufferTest, TestAppendData) {
106 CopyOnWriteBuffer buf1(kTestData, 3, 10);
107 CopyOnWriteBuffer buf2(buf1);
108
109 EnsureBuffersShareData(buf1, buf2);
110
111 // AppendData copies the underlying buffer.
112 buf2.AppendData("foo");
113 EXPECT_EQ(buf2.size(), buf1.size() + 4); // "foo" + trailing 0x00
114 EXPECT_EQ(buf2.capacity(), buf1.capacity());
115 EXPECT_NE(buf2.data(), buf1.data());
116
117 EXPECT_EQ(buf1, CopyOnWriteBuffer(kTestData, 3));
118 const int8_t exp[] = {0x0, 0x1, 0x2, 'f', 'o', 'o', 0x0};
119 EXPECT_EQ(buf2, CopyOnWriteBuffer(exp));
120 }
121
TEST(CopyOnWriteBufferTest,SetEmptyData)122 TEST(CopyOnWriteBufferTest, SetEmptyData) {
123 CopyOnWriteBuffer buf(10);
124
125 buf.SetData<uint8_t>(nullptr, 0);
126
127 EXPECT_EQ(0u, buf.size());
128 }
129
TEST(CopyOnWriteBufferTest,SetDataNoMoreThanCapacityDoesntCauseReallocation)130 TEST(CopyOnWriteBufferTest, SetDataNoMoreThanCapacityDoesntCauseReallocation) {
131 CopyOnWriteBuffer buf1(3, 10);
132 const uint8_t* const original_allocation = buf1.cdata();
133
134 buf1.SetData(kTestData, 10);
135
136 EXPECT_EQ(original_allocation, buf1.cdata());
137 EXPECT_EQ(buf1, CopyOnWriteBuffer(kTestData, 10));
138 }
139
TEST(CopyOnWriteBufferTest,SetDataMakeReferenceCopy)140 TEST(CopyOnWriteBufferTest, SetDataMakeReferenceCopy) {
141 CopyOnWriteBuffer buf1(kTestData, 3, 10);
142 CopyOnWriteBuffer buf2;
143
144 buf2.SetData(buf1);
145
146 EnsureBuffersShareData(buf1, buf2);
147 }
148
TEST(CopyOnWriteBufferTest,SetDataOnSharedKeepsOriginal)149 TEST(CopyOnWriteBufferTest, SetDataOnSharedKeepsOriginal) {
150 const uint8_t data[] = "foo";
151 CopyOnWriteBuffer buf1(kTestData, 3, 10);
152 const uint8_t* const original_allocation = buf1.cdata();
153 CopyOnWriteBuffer buf2(buf1);
154
155 buf2.SetData(data);
156
157 EnsureBuffersDontShareData(buf1, buf2);
158 EXPECT_EQ(original_allocation, buf1.cdata());
159 EXPECT_EQ(buf1, CopyOnWriteBuffer(kTestData, 3));
160 EXPECT_EQ(buf2, CopyOnWriteBuffer(data));
161 }
162
TEST(CopyOnWriteBufferTest,SetDataOnSharedKeepsCapacity)163 TEST(CopyOnWriteBufferTest, SetDataOnSharedKeepsCapacity) {
164 CopyOnWriteBuffer buf1(kTestData, 3, 10);
165 CopyOnWriteBuffer buf2(buf1);
166 EnsureBuffersShareData(buf1, buf2);
167
168 buf2.SetData(kTestData, 2);
169
170 EnsureBuffersDontShareData(buf1, buf2);
171 EXPECT_EQ(2u, buf2.size());
172 EXPECT_EQ(10u, buf2.capacity());
173 }
174
TEST(CopyOnWriteBufferTest,TestEnsureCapacity)175 TEST(CopyOnWriteBufferTest, TestEnsureCapacity) {
176 CopyOnWriteBuffer buf1(kTestData, 3, 10);
177 CopyOnWriteBuffer buf2(buf1);
178
179 // Smaller than existing capacity -> no change and still same contents.
180 buf2.EnsureCapacity(8);
181 EnsureBuffersShareData(buf1, buf2);
182 EXPECT_EQ(buf1.size(), 3u);
183 EXPECT_EQ(buf1.capacity(), 10u);
184 EXPECT_EQ(buf2.size(), 3u);
185 EXPECT_EQ(buf2.capacity(), 10u);
186
187 // Lager than existing capacity -> data is cloned.
188 buf2.EnsureCapacity(16);
189 EnsureBuffersDontShareData(buf1, buf2);
190 EXPECT_EQ(buf1.size(), 3u);
191 EXPECT_EQ(buf1.capacity(), 10u);
192 EXPECT_EQ(buf2.size(), 3u);
193 EXPECT_EQ(buf2.capacity(), 16u);
194 // The size and contents are still the same.
195 EXPECT_EQ(buf1, buf2);
196 }
197
TEST(CopyOnWriteBufferTest,SetSizeDoesntChangeOriginal)198 TEST(CopyOnWriteBufferTest, SetSizeDoesntChangeOriginal) {
199 CopyOnWriteBuffer buf1(kTestData, 3, 10);
200 const uint8_t* const original_allocation = buf1.cdata();
201 CopyOnWriteBuffer buf2(buf1);
202
203 buf2.SetSize(16);
204
205 EnsureBuffersDontShareData(buf1, buf2);
206 EXPECT_EQ(original_allocation, buf1.cdata());
207 EXPECT_EQ(3u, buf1.size());
208 EXPECT_EQ(10u, buf1.capacity());
209 }
210
TEST(CopyOnWriteBufferTest,SetSizeCloneContent)211 TEST(CopyOnWriteBufferTest, SetSizeCloneContent) {
212 CopyOnWriteBuffer buf1(kTestData, 3, 10);
213 CopyOnWriteBuffer buf2(buf1);
214
215 buf2.SetSize(16);
216
217 EXPECT_EQ(buf2.size(), 16u);
218 EXPECT_EQ(0, memcmp(buf2.data(), kTestData, 3));
219 }
220
TEST(CopyOnWriteBufferTest,SetSizeMayIncreaseCapacity)221 TEST(CopyOnWriteBufferTest, SetSizeMayIncreaseCapacity) {
222 CopyOnWriteBuffer buf(kTestData, 3, 10);
223
224 buf.SetSize(16);
225
226 EXPECT_EQ(16u, buf.size());
227 EXPECT_EQ(16u, buf.capacity());
228 }
229
TEST(CopyOnWriteBufferTest,SetSizeDoesntDecreaseCapacity)230 TEST(CopyOnWriteBufferTest, SetSizeDoesntDecreaseCapacity) {
231 CopyOnWriteBuffer buf1(kTestData, 5, 10);
232 CopyOnWriteBuffer buf2(buf1);
233
234 buf2.SetSize(2);
235
236 EXPECT_EQ(2u, buf2.size());
237 EXPECT_EQ(10u, buf2.capacity());
238 }
239
TEST(CopyOnWriteBufferTest,ClearDoesntChangeOriginal)240 TEST(CopyOnWriteBufferTest, ClearDoesntChangeOriginal) {
241 CopyOnWriteBuffer buf1(kTestData, 3, 10);
242 const uint8_t* const original_allocation = buf1.cdata();
243 CopyOnWriteBuffer buf2(buf1);
244
245 buf2.Clear();
246
247 EnsureBuffersDontShareData(buf1, buf2);
248 EXPECT_EQ(3u, buf1.size());
249 EXPECT_EQ(10u, buf1.capacity());
250 EXPECT_EQ(original_allocation, buf1.cdata());
251 EXPECT_EQ(0u, buf2.size());
252 }
253
TEST(CopyOnWriteBufferTest,ClearDoesntChangeCapacity)254 TEST(CopyOnWriteBufferTest, ClearDoesntChangeCapacity) {
255 CopyOnWriteBuffer buf1(kTestData, 3, 10);
256 CopyOnWriteBuffer buf2(buf1);
257
258 buf2.Clear();
259
260 EXPECT_EQ(0u, buf2.size());
261 EXPECT_EQ(10u, buf2.capacity());
262 }
263
TEST(CopyOnWriteBufferTest,TestConstDataAccessor)264 TEST(CopyOnWriteBufferTest, TestConstDataAccessor) {
265 CopyOnWriteBuffer buf1(kTestData, 3, 10);
266 CopyOnWriteBuffer buf2(buf1);
267
268 // .cdata() doesn't clone data.
269 const uint8_t* cdata1 = buf1.cdata();
270 const uint8_t* cdata2 = buf2.cdata();
271 EXPECT_EQ(cdata1, cdata2);
272
273 // Non-const .data() clones data if shared.
274 const uint8_t* data1 = buf1.data();
275 const uint8_t* data2 = buf2.data();
276 EXPECT_NE(data1, data2);
277 // buf1 was cloned above.
278 EXPECT_NE(data1, cdata1);
279 // Therefore buf2 was no longer sharing data and was not cloned.
280 EXPECT_EQ(data2, cdata1);
281 }
282
TEST(CopyOnWriteBufferTest,TestBacketRead)283 TEST(CopyOnWriteBufferTest, TestBacketRead) {
284 CopyOnWriteBuffer buf1(kTestData, 3, 10);
285 CopyOnWriteBuffer buf2(buf1);
286
287 EnsureBuffersShareData(buf1, buf2);
288 // Non-const reads clone the data if shared.
289 for (size_t i = 0; i != 3u; ++i) {
290 EXPECT_EQ(buf1[i], kTestData[i]);
291 }
292 EnsureBuffersDontShareData(buf1, buf2);
293 }
294
TEST(CopyOnWriteBufferTest,TestBacketReadConst)295 TEST(CopyOnWriteBufferTest, TestBacketReadConst) {
296 CopyOnWriteBuffer buf1(kTestData, 3, 10);
297 CopyOnWriteBuffer buf2(buf1);
298
299 EnsureBuffersShareData(buf1, buf2);
300 const CopyOnWriteBuffer& cbuf1 = buf1;
301 for (size_t i = 0; i != 3u; ++i) {
302 EXPECT_EQ(cbuf1[i], kTestData[i]);
303 }
304 EnsureBuffersShareData(buf1, buf2);
305 }
306
TEST(CopyOnWriteBufferTest,TestBacketWrite)307 TEST(CopyOnWriteBufferTest, TestBacketWrite) {
308 CopyOnWriteBuffer buf1(kTestData, 3, 10);
309 CopyOnWriteBuffer buf2(buf1);
310
311 EnsureBuffersShareData(buf1, buf2);
312 for (size_t i = 0; i != 3u; ++i) {
313 buf1[i] = kTestData[i] + 1;
314 }
315 EXPECT_EQ(buf1.size(), 3u);
316 EXPECT_EQ(buf1.capacity(), 10u);
317 EXPECT_EQ(buf2.size(), 3u);
318 EXPECT_EQ(buf2.capacity(), 10u);
319 EXPECT_EQ(0, memcmp(buf2.cdata(), kTestData, 3));
320 }
321
TEST(CopyOnWriteBufferTest,CreateSlice)322 TEST(CopyOnWriteBufferTest, CreateSlice) {
323 CopyOnWriteBuffer buf(kTestData, 10, 10);
324 CopyOnWriteBuffer slice = buf.Slice(3, 4);
325 EXPECT_EQ(slice.size(), 4u);
326 EXPECT_EQ(0, memcmp(buf.cdata() + 3, slice.cdata(), 4));
327 }
328
TEST(CopyOnWriteBufferTest,NoCopyDataOnSlice)329 TEST(CopyOnWriteBufferTest, NoCopyDataOnSlice) {
330 CopyOnWriteBuffer buf(kTestData, 10, 10);
331 CopyOnWriteBuffer slice = buf.Slice(3, 4);
332 EXPECT_EQ(buf.cdata() + 3, slice.cdata());
333 }
334
TEST(CopyOnWriteBufferTest,WritingCopiesData)335 TEST(CopyOnWriteBufferTest, WritingCopiesData) {
336 CopyOnWriteBuffer buf(kTestData, 10, 10);
337 CopyOnWriteBuffer slice = buf.Slice(3, 4);
338 slice[0] = 0xaa;
339 EXPECT_NE(buf.cdata() + 3, slice.cdata());
340 EXPECT_EQ(0, memcmp(buf.cdata(), kTestData, 10));
341 }
342
TEST(CopyOnWriteBufferTest,WritingToBufferDoesntAffectsSlice)343 TEST(CopyOnWriteBufferTest, WritingToBufferDoesntAffectsSlice) {
344 CopyOnWriteBuffer buf(kTestData, 10, 10);
345 CopyOnWriteBuffer slice = buf.Slice(3, 4);
346 buf[0] = 0xaa;
347 EXPECT_NE(buf.cdata() + 3, slice.cdata());
348 EXPECT_EQ(0, memcmp(slice.cdata(), kTestData + 3, 4));
349 }
350
TEST(CopyOnWriteBufferTest,SliceOfASlice)351 TEST(CopyOnWriteBufferTest, SliceOfASlice) {
352 CopyOnWriteBuffer buf(kTestData, 10, 10);
353 CopyOnWriteBuffer slice = buf.Slice(3, 7);
354 CopyOnWriteBuffer slice2 = slice.Slice(2, 3);
355 EXPECT_EQ(slice2.size(), 3u);
356 EXPECT_EQ(slice.cdata() + 2, slice2.cdata());
357 EXPECT_EQ(buf.cdata() + 5, slice2.cdata());
358 }
359
TEST(CopyOnWriteBufferTest,SlicesAreIndependent)360 TEST(CopyOnWriteBufferTest, SlicesAreIndependent) {
361 CopyOnWriteBuffer buf(kTestData, 10, 10);
362 CopyOnWriteBuffer slice = buf.Slice(3, 7);
363 CopyOnWriteBuffer slice2 = buf.Slice(3, 7);
364 slice2[0] = 0xaa;
365 EXPECT_EQ(buf.cdata() + 3, slice.cdata());
366 }
367
368 } // namespace rtc
369