From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- .../rtc_base/copy_on_write_buffer_unittest.cc | 378 +++++++++++++++++++++ 1 file changed, 378 insertions(+) create mode 100644 third_party/libwebrtc/rtc_base/copy_on_write_buffer_unittest.cc (limited to 'third_party/libwebrtc/rtc_base/copy_on_write_buffer_unittest.cc') diff --git a/third_party/libwebrtc/rtc_base/copy_on_write_buffer_unittest.cc b/third_party/libwebrtc/rtc_base/copy_on_write_buffer_unittest.cc new file mode 100644 index 0000000000..8a9fc4e2f4 --- /dev/null +++ b/third_party/libwebrtc/rtc_base/copy_on_write_buffer_unittest.cc @@ -0,0 +1,378 @@ +/* + * Copyright 2016 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "rtc_base/copy_on_write_buffer.h" + +#include + +#include "test/gtest.h" + +namespace rtc { + +namespace { + +// clang-format off +const uint8_t kTestData[] = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf}; +// clang-format on + +} // namespace + +void EnsureBuffersShareData(const CopyOnWriteBuffer& buf1, + const CopyOnWriteBuffer& buf2) { + // Data is shared between buffers. + EXPECT_EQ(buf1.size(), buf2.size()); + EXPECT_EQ(buf1.capacity(), buf2.capacity()); + const uint8_t* data1 = buf1.data(); + const uint8_t* data2 = buf2.data(); + EXPECT_EQ(data1, data2); + EXPECT_EQ(buf1, buf2); +} + +void EnsureBuffersDontShareData(const CopyOnWriteBuffer& buf1, + const CopyOnWriteBuffer& buf2) { + // Data is not shared between buffers. + const uint8_t* data1 = buf1.cdata(); + const uint8_t* data2 = buf2.cdata(); + EXPECT_NE(data1, data2); +} + +TEST(CopyOnWriteBufferTest, TestCreateEmptyData) { + CopyOnWriteBuffer buf(static_cast(nullptr), 0); + EXPECT_EQ(buf.size(), 0u); + EXPECT_EQ(buf.capacity(), 0u); + EXPECT_EQ(buf.data(), nullptr); +} + +TEST(CopyOnWriteBufferTest, TestMoveConstruct) { + EXPECT_TRUE(std::is_nothrow_move_constructible_v); + + CopyOnWriteBuffer buf1(kTestData, 3, 10); + size_t buf1_size = buf1.size(); + size_t buf1_capacity = buf1.capacity(); + const uint8_t* buf1_data = buf1.cdata(); + + CopyOnWriteBuffer buf2(std::move(buf1)); + EXPECT_EQ(buf1.size(), 0u); + EXPECT_EQ(buf1.capacity(), 0u); + EXPECT_EQ(buf1.data(), nullptr); + EXPECT_EQ(buf2.size(), buf1_size); + EXPECT_EQ(buf2.capacity(), buf1_capacity); + EXPECT_EQ(buf2.data(), buf1_data); +} + +TEST(CopyOnWriteBufferTest, TestMoveAssign) { + CopyOnWriteBuffer buf1(kTestData, 3, 10); + size_t buf1_size = buf1.size(); + size_t buf1_capacity = buf1.capacity(); + const uint8_t* buf1_data = buf1.cdata(); + + CopyOnWriteBuffer buf2; + buf2 = std::move(buf1); + EXPECT_EQ(buf1.size(), 0u); + EXPECT_EQ(buf1.capacity(), 0u); + EXPECT_EQ(buf1.data(), nullptr); + EXPECT_EQ(buf2.size(), buf1_size); + EXPECT_EQ(buf2.capacity(), buf1_capacity); + EXPECT_EQ(buf2.data(), buf1_data); +} + +TEST(CopyOnWriteBufferTest, TestSwap) { + CopyOnWriteBuffer buf1(kTestData, 3, 10); + size_t buf1_size = buf1.size(); + size_t buf1_capacity = buf1.capacity(); + const uint8_t* buf1_data = buf1.cdata(); + + CopyOnWriteBuffer buf2(kTestData, 6, 20); + size_t buf2_size = buf2.size(); + size_t buf2_capacity = buf2.capacity(); + const uint8_t* buf2_data = buf2.cdata(); + + std::swap(buf1, buf2); + EXPECT_EQ(buf1.size(), buf2_size); + EXPECT_EQ(buf1.capacity(), buf2_capacity); + EXPECT_EQ(buf1.data(), buf2_data); + EXPECT_EQ(buf2.size(), buf1_size); + EXPECT_EQ(buf2.capacity(), buf1_capacity); + EXPECT_EQ(buf2.data(), buf1_data); +} + +TEST(CopyOnWriteBufferTest, TestAppendData) { + CopyOnWriteBuffer buf1(kTestData, 3, 10); + CopyOnWriteBuffer buf2(buf1); + + EnsureBuffersShareData(buf1, buf2); + + // AppendData copies the underlying buffer. + buf2.AppendData("foo"); + EXPECT_EQ(buf2.size(), buf1.size() + 4); // "foo" + trailing 0x00 + EXPECT_EQ(buf2.capacity(), buf1.capacity()); + EXPECT_NE(buf2.data(), buf1.data()); + + EXPECT_EQ(buf1, CopyOnWriteBuffer(kTestData, 3)); + const int8_t exp[] = {0x0, 0x1, 0x2, 'f', 'o', 'o', 0x0}; + EXPECT_EQ(buf2, CopyOnWriteBuffer(exp)); +} + +TEST(CopyOnWriteBufferTest, SetEmptyData) { + CopyOnWriteBuffer buf(10); + + buf.SetData(nullptr, 0); + + EXPECT_EQ(0u, buf.size()); +} + +TEST(CopyOnWriteBufferTest, SetDataNoMoreThanCapacityDoesntCauseReallocation) { + CopyOnWriteBuffer buf1(3, 10); + const uint8_t* const original_allocation = buf1.cdata(); + + buf1.SetData(kTestData, 10); + + EXPECT_EQ(original_allocation, buf1.cdata()); + EXPECT_EQ(buf1, CopyOnWriteBuffer(kTestData, 10)); +} + +TEST(CopyOnWriteBufferTest, SetDataMakeReferenceCopy) { + CopyOnWriteBuffer buf1(kTestData, 3, 10); + CopyOnWriteBuffer buf2; + + buf2.SetData(buf1); + + EnsureBuffersShareData(buf1, buf2); +} + +TEST(CopyOnWriteBufferTest, SetDataOnSharedKeepsOriginal) { + const uint8_t data[] = "foo"; + CopyOnWriteBuffer buf1(kTestData, 3, 10); + const uint8_t* const original_allocation = buf1.cdata(); + CopyOnWriteBuffer buf2(buf1); + + buf2.SetData(data); + + EnsureBuffersDontShareData(buf1, buf2); + EXPECT_EQ(original_allocation, buf1.cdata()); + EXPECT_EQ(buf1, CopyOnWriteBuffer(kTestData, 3)); + EXPECT_EQ(buf2, CopyOnWriteBuffer(data)); +} + +TEST(CopyOnWriteBufferTest, SetDataOnSharedKeepsCapacity) { + CopyOnWriteBuffer buf1(kTestData, 3, 10); + CopyOnWriteBuffer buf2(buf1); + EnsureBuffersShareData(buf1, buf2); + + buf2.SetData(kTestData, 2); + + EnsureBuffersDontShareData(buf1, buf2); + EXPECT_EQ(2u, buf2.size()); + EXPECT_EQ(10u, buf2.capacity()); +} + +TEST(CopyOnWriteBufferTest, TestEnsureCapacity) { + CopyOnWriteBuffer buf1(kTestData, 3, 10); + CopyOnWriteBuffer buf2(buf1); + + // Smaller than existing capacity -> no change and still same contents. + buf2.EnsureCapacity(8); + EnsureBuffersShareData(buf1, buf2); + EXPECT_EQ(buf1.size(), 3u); + EXPECT_EQ(buf1.capacity(), 10u); + EXPECT_EQ(buf2.size(), 3u); + EXPECT_EQ(buf2.capacity(), 10u); + + // Lager than existing capacity -> data is cloned. + buf2.EnsureCapacity(16); + EnsureBuffersDontShareData(buf1, buf2); + EXPECT_EQ(buf1.size(), 3u); + EXPECT_EQ(buf1.capacity(), 10u); + EXPECT_EQ(buf2.size(), 3u); + EXPECT_EQ(buf2.capacity(), 16u); + // The size and contents are still the same. + EXPECT_EQ(buf1, buf2); +} + +TEST(CopyOnWriteBufferTest, SetSizeDoesntChangeOriginal) { + CopyOnWriteBuffer buf1(kTestData, 3, 10); + const uint8_t* const original_allocation = buf1.cdata(); + CopyOnWriteBuffer buf2(buf1); + + buf2.SetSize(16); + + EnsureBuffersDontShareData(buf1, buf2); + EXPECT_EQ(original_allocation, buf1.cdata()); + EXPECT_EQ(3u, buf1.size()); + EXPECT_EQ(10u, buf1.capacity()); +} + +TEST(CopyOnWriteBufferTest, SetSizeCloneContent) { + CopyOnWriteBuffer buf1(kTestData, 3, 10); + CopyOnWriteBuffer buf2(buf1); + + buf2.SetSize(16); + + EXPECT_EQ(buf2.size(), 16u); + EXPECT_EQ(0, memcmp(buf2.data(), kTestData, 3)); +} + +TEST(CopyOnWriteBufferTest, SetSizeMayIncreaseCapacity) { + CopyOnWriteBuffer buf(kTestData, 3, 10); + + buf.SetSize(16); + + EXPECT_EQ(16u, buf.size()); + EXPECT_EQ(16u, buf.capacity()); +} + +TEST(CopyOnWriteBufferTest, SetSizeDoesntDecreaseCapacity) { + CopyOnWriteBuffer buf1(kTestData, 5, 10); + CopyOnWriteBuffer buf2(buf1); + + buf2.SetSize(2); + + EXPECT_EQ(2u, buf2.size()); + EXPECT_EQ(10u, buf2.capacity()); +} + +TEST(CopyOnWriteBufferTest, ClearDoesntChangeOriginal) { + CopyOnWriteBuffer buf1(kTestData, 3, 10); + const uint8_t* const original_allocation = buf1.cdata(); + CopyOnWriteBuffer buf2(buf1); + + buf2.Clear(); + + EnsureBuffersDontShareData(buf1, buf2); + EXPECT_EQ(3u, buf1.size()); + EXPECT_EQ(10u, buf1.capacity()); + EXPECT_EQ(original_allocation, buf1.cdata()); + EXPECT_EQ(0u, buf2.size()); +} + +TEST(CopyOnWriteBufferTest, ClearDoesntChangeCapacity) { + CopyOnWriteBuffer buf1(kTestData, 3, 10); + CopyOnWriteBuffer buf2(buf1); + + buf2.Clear(); + + EXPECT_EQ(0u, buf2.size()); + EXPECT_EQ(10u, buf2.capacity()); +} + +TEST(CopyOnWriteBufferTest, DataAccessorDoesntCloneData) { + CopyOnWriteBuffer buf1(kTestData, 3, 10); + CopyOnWriteBuffer buf2(buf1); + + EXPECT_EQ(buf1.data(), buf2.data()); +} + +TEST(CopyOnWriteBufferTest, MutableDataClonesDataWhenShared) { + CopyOnWriteBuffer buf1(kTestData, 3, 10); + CopyOnWriteBuffer buf2(buf1); + const uint8_t* cdata = buf1.data(); + + uint8_t* data1 = buf1.MutableData(); + uint8_t* data2 = buf2.MutableData(); + // buf1 was cloned above. + EXPECT_NE(data1, cdata); + // Therefore buf2 was no longer sharing data and was not cloned. + EXPECT_EQ(data2, cdata); +} + +TEST(CopyOnWriteBufferTest, SeveralReads) { + CopyOnWriteBuffer buf1(kTestData, 3, 10); + CopyOnWriteBuffer buf2(buf1); + + EnsureBuffersShareData(buf1, buf2); + for (size_t i = 0; i != 3u; ++i) { + EXPECT_EQ(buf1[i], kTestData[i]); + } + EnsureBuffersShareData(buf1, buf2); +} + +TEST(CopyOnWriteBufferTest, SeveralWrites) { + CopyOnWriteBuffer buf1(kTestData, 3, 10); + CopyOnWriteBuffer buf2(buf1); + + EnsureBuffersShareData(buf1, buf2); + for (size_t i = 0; i != 3u; ++i) { + buf1.MutableData()[i] = kTestData[i] + 1; + } + EXPECT_EQ(buf1.size(), 3u); + EXPECT_EQ(buf1.capacity(), 10u); + EXPECT_EQ(buf2.size(), 3u); + EXPECT_EQ(buf2.capacity(), 10u); + EXPECT_EQ(0, memcmp(buf2.cdata(), kTestData, 3)); +} + +TEST(CopyOnWriteBufferTest, CreateSlice) { + CopyOnWriteBuffer buf(kTestData, 10, 10); + CopyOnWriteBuffer slice = buf.Slice(3, 4); + EXPECT_EQ(slice.size(), 4u); + EXPECT_EQ(0, memcmp(buf.cdata() + 3, slice.cdata(), 4)); +} + +TEST(CopyOnWriteBufferTest, NoCopyDataOnSlice) { + CopyOnWriteBuffer buf(kTestData, 10, 10); + CopyOnWriteBuffer slice = buf.Slice(3, 4); + EXPECT_EQ(buf.cdata() + 3, slice.cdata()); +} + +TEST(CopyOnWriteBufferTest, WritingCopiesData) { + CopyOnWriteBuffer buf(kTestData, 10, 10); + CopyOnWriteBuffer slice = buf.Slice(3, 4); + slice.MutableData()[0] = 0xaa; + EXPECT_NE(buf.cdata() + 3, slice.cdata()); + EXPECT_EQ(0, memcmp(buf.cdata(), kTestData, 10)); +} + +TEST(CopyOnWriteBufferTest, WritingToBufferDoesntAffectsSlice) { + CopyOnWriteBuffer buf(kTestData, 10, 10); + CopyOnWriteBuffer slice = buf.Slice(3, 4); + buf.MutableData()[0] = 0xaa; + EXPECT_NE(buf.cdata() + 3, slice.cdata()); + EXPECT_EQ(0, memcmp(slice.cdata(), kTestData + 3, 4)); +} + +TEST(CopyOnWriteBufferTest, SliceOfASlice) { + CopyOnWriteBuffer buf(kTestData, 10, 10); + CopyOnWriteBuffer slice = buf.Slice(3, 7); + CopyOnWriteBuffer slice2 = slice.Slice(2, 3); + EXPECT_EQ(slice2.size(), 3u); + EXPECT_EQ(slice.cdata() + 2, slice2.cdata()); + EXPECT_EQ(buf.cdata() + 5, slice2.cdata()); +} + +TEST(CopyOnWriteBufferTest, SlicesAreIndependent) { + CopyOnWriteBuffer buf(kTestData, 10, 10); + CopyOnWriteBuffer slice = buf.Slice(3, 7); + CopyOnWriteBuffer slice2 = buf.Slice(3, 7); + slice2.MutableData()[0] = 0xaa; + EXPECT_EQ(buf.cdata() + 3, slice.cdata()); +} + +TEST(CopyOnWriteBufferTest, AcceptsVectorLikeTypes) { + std::vector a = {1, 2}; + std::vector b = {3, 4}; + rtc::ArrayView c(a); + rtc::ArrayView d(b); + + CopyOnWriteBuffer a_buf(a); + CopyOnWriteBuffer b_buf(b); + CopyOnWriteBuffer c_buf(c); + CopyOnWriteBuffer d_buf(d); + + CopyOnWriteBuffer all; + all.AppendData(a); + all.AppendData(b); + all.AppendData(c); + all.AppendData(d); + + EXPECT_EQ(all.size(), 8U); +} + +} // namespace rtc -- cgit v1.2.3