/* * Copyright (c) 2013 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 "common_audio/ring_buffer.h" #include #include #include #include #include "test/gtest.h" namespace webrtc { struct FreeBufferDeleter { inline void operator()(void* ptr) const { WebRtc_FreeBuffer(ptr); } }; typedef std::unique_ptr scoped_ring_buffer; static void AssertElementEq(int expected, int actual) { ASSERT_EQ(expected, actual); } static int SetIncrementingData(int* data, int num_elements, int starting_value) { for (int i = 0; i < num_elements; i++) { data[i] = starting_value++; } return starting_value; } static int CheckIncrementingData(int* data, int num_elements, int starting_value) { for (int i = 0; i < num_elements; i++) { AssertElementEq(starting_value++, data[i]); } return starting_value; } // We use ASSERTs in this test to avoid obscuring the seed in the case of a // failure. static void RandomStressTest(int** data_ptr) { const int kNumTests = 10; const int kNumOps = 1000; const int kMaxBufferSize = 1000; unsigned int seed = time(nullptr); printf("seed=%u\n", seed); srand(seed); for (int i = 0; i < kNumTests; i++) { // rand_r is not supported on many platforms, so rand is used. const int buffer_size = std::max(rand() % kMaxBufferSize, 1); // NOLINT std::unique_ptr write_data(new int[buffer_size]); std::unique_ptr read_data(new int[buffer_size]); scoped_ring_buffer buffer(WebRtc_CreateBuffer(buffer_size, sizeof(int))); ASSERT_TRUE(buffer.get() != nullptr); WebRtc_InitBuffer(buffer.get()); int buffer_consumed = 0; int write_element = 0; int read_element = 0; for (int j = 0; j < kNumOps; j++) { const bool write = rand() % 2 == 0 ? true : false; // NOLINT const int num_elements = rand() % buffer_size; // NOLINT if (write) { const int buffer_available = buffer_size - buffer_consumed; ASSERT_EQ(static_cast(buffer_available), WebRtc_available_write(buffer.get())); const int expected_elements = std::min(num_elements, buffer_available); write_element = SetIncrementingData(write_data.get(), expected_elements, write_element); ASSERT_EQ( static_cast(expected_elements), WebRtc_WriteBuffer(buffer.get(), write_data.get(), num_elements)); buffer_consumed = std::min(buffer_consumed + expected_elements, buffer_size); } else { const int expected_elements = std::min(num_elements, buffer_consumed); ASSERT_EQ(static_cast(buffer_consumed), WebRtc_available_read(buffer.get())); ASSERT_EQ( static_cast(expected_elements), WebRtc_ReadBuffer(buffer.get(), reinterpret_cast(data_ptr), read_data.get(), num_elements)); int* check_ptr = read_data.get(); if (data_ptr) { check_ptr = *data_ptr; } read_element = CheckIncrementingData(check_ptr, expected_elements, read_element); buffer_consumed = std::max(buffer_consumed - expected_elements, 0); } } } } TEST(RingBufferTest, RandomStressTest) { int* data_ptr = nullptr; RandomStressTest(&data_ptr); } TEST(RingBufferTest, RandomStressTestWithNullPtr) { RandomStressTest(nullptr); } TEST(RingBufferTest, PassingNulltoReadBufferForcesMemcpy) { const size_t kDataSize = 2; int write_data[kDataSize]; int read_data[kDataSize]; int* data_ptr; scoped_ring_buffer buffer(WebRtc_CreateBuffer(kDataSize, sizeof(int))); ASSERT_TRUE(buffer.get() != nullptr); WebRtc_InitBuffer(buffer.get()); SetIncrementingData(write_data, kDataSize, 0); EXPECT_EQ(kDataSize, WebRtc_WriteBuffer(buffer.get(), write_data, kDataSize)); SetIncrementingData(read_data, kDataSize, kDataSize); EXPECT_EQ(kDataSize, WebRtc_ReadBuffer(buffer.get(), reinterpret_cast(&data_ptr), read_data, kDataSize)); // Copying was not necessary, so `read_data` has not been updated. CheckIncrementingData(data_ptr, kDataSize, 0); CheckIncrementingData(read_data, kDataSize, kDataSize); EXPECT_EQ(kDataSize, WebRtc_WriteBuffer(buffer.get(), write_data, kDataSize)); EXPECT_EQ(kDataSize, WebRtc_ReadBuffer(buffer.get(), nullptr, read_data, kDataSize)); // Passing null forces a memcpy, so `read_data` is now updated. CheckIncrementingData(read_data, kDataSize, 0); } TEST(RingBufferTest, CreateHandlesErrors) { EXPECT_TRUE(WebRtc_CreateBuffer(0, 1) == nullptr); EXPECT_TRUE(WebRtc_CreateBuffer(1, 0) == nullptr); RingBuffer* buffer = WebRtc_CreateBuffer(1, 1); EXPECT_TRUE(buffer != nullptr); WebRtc_FreeBuffer(buffer); } } // namespace webrtc