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