| /* | 
 |  *  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 "testing/gtest/include/gtest/gtest.h" | 
 | #include "webrtc/base/scoped_ptr.h" | 
 |  | 
 | namespace webrtc { | 
 |  | 
 | struct FreeBufferDeleter { | 
 |   inline void operator()(void* ptr) const { | 
 |     WebRtc_FreeBuffer(ptr); | 
 |   } | 
 | }; | 
 | typedef rtc::scoped_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(NULL); | 
 |   printf("seed=%u\n", seed); | 
 |   srand(seed); | 
 |   for (int i = 0; i < kNumTests; i++) { | 
 |     const int buffer_size = std::max(rand() % kMaxBufferSize, 1); | 
 |     rtc::scoped_ptr<int[]> write_data(new int[buffer_size]); | 
 |     rtc::scoped_ptr<int[]> read_data(new int[buffer_size]); | 
 |     scoped_ring_buffer buffer(WebRtc_CreateBuffer(buffer_size, sizeof(int))); | 
 |     ASSERT_TRUE(buffer.get() != NULL); | 
 |     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; | 
 |       const int num_elements = rand() % buffer_size; | 
 |       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 = NULL; | 
 |   RandomStressTest(&data_ptr); | 
 | } | 
 |  | 
 | TEST(RingBufferTest, RandomStressTestWithNullPtr) { | 
 |   RandomStressTest(NULL); | 
 | } | 
 |  | 
 | 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() != NULL); | 
 |   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(), NULL, 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) == NULL); | 
 |   EXPECT_TRUE(WebRtc_CreateBuffer(1, 0) == NULL); | 
 |   RingBuffer* buffer = WebRtc_CreateBuffer(1, 1); | 
 |   EXPECT_TRUE(buffer != NULL); | 
 |   WebRtc_FreeBuffer(buffer); | 
 | } | 
 |  | 
 | }  // namespace webrtc |