| /* |
| * 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 "webrtc/common_audio/ring_buffer.h" |
| |
| #include <stdlib.h> |
| #include <time.h> |
| |
| #include <algorithm> |
| #include <memory> |
| |
| #include "webrtc/test/gtest.h" |
| |
| namespace webrtc { |
| |
| struct FreeBufferDeleter { |
| inline void operator()(void* ptr) const { |
| WebRtc_FreeBuffer(ptr); |
| } |
| }; |
| typedef std::unique_ptr<RingBuffer, FreeBufferDeleter> 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<int[]> write_data(new int[buffer_size]); |
| std::unique_ptr<int[]> 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<size_t>(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<size_t>(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<size_t>(buffer_consumed), |
| WebRtc_available_read(buffer.get())); |
| ASSERT_EQ(static_cast<size_t>(expected_elements), |
| WebRtc_ReadBuffer(buffer.get(), |
| reinterpret_cast<void**>(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<void**>(&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 |