| /* | 
 |  *  Copyright (c) 2012 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/modules/audio_coding/neteq/audio_vector.h" | 
 |  | 
 | #include <assert.h> | 
 | #include <stdlib.h> | 
 |  | 
 | #include <string> | 
 |  | 
 | #include "testing/gtest/include/gtest/gtest.h" | 
 | #include "webrtc/typedefs.h" | 
 |  | 
 | namespace webrtc { | 
 |  | 
 | class AudioVectorTest : public ::testing::Test { | 
 |  protected: | 
 |   virtual void SetUp() { | 
 |     // Populate test array. | 
 |     for (size_t i = 0; i < array_length(); ++i) { | 
 |       array_[i] = i; | 
 |     } | 
 |   } | 
 |  | 
 |   size_t array_length() const { | 
 |     return sizeof(array_) / sizeof(array_[0]); | 
 |   } | 
 |  | 
 |   int16_t array_[10]; | 
 | }; | 
 |  | 
 | // Create and destroy AudioVector objects, both empty and with a predefined | 
 | // length. | 
 | TEST_F(AudioVectorTest, CreateAndDestroy) { | 
 |   AudioVector vec1; | 
 |   EXPECT_TRUE(vec1.Empty()); | 
 |   EXPECT_EQ(0u, vec1.Size()); | 
 |  | 
 |   size_t initial_size = 17; | 
 |   AudioVector vec2(initial_size); | 
 |   EXPECT_FALSE(vec2.Empty()); | 
 |   EXPECT_EQ(initial_size, vec2.Size()); | 
 | } | 
 |  | 
 | // Test the subscript operator [] for getting and setting. | 
 | TEST_F(AudioVectorTest, SubscriptOperator) { | 
 |   AudioVector vec(array_length()); | 
 |   for (size_t i = 0; i < array_length(); ++i) { | 
 |     vec[i] = static_cast<int16_t>(i); | 
 |     const int16_t& value = vec[i];  // Make sure to use the const version. | 
 |     EXPECT_EQ(static_cast<int16_t>(i), value); | 
 |   } | 
 | } | 
 |  | 
 | // Test the PushBack method and the CopyFrom method. The Clear method is also | 
 | // invoked. | 
 | TEST_F(AudioVectorTest, PushBackAndCopy) { | 
 |   AudioVector vec; | 
 |   AudioVector vec_copy; | 
 |   vec.PushBack(array_, array_length()); | 
 |   vec.CopyTo(&vec_copy);  // Copy from |vec| to |vec_copy|. | 
 |   ASSERT_EQ(array_length(), vec.Size()); | 
 |   ASSERT_EQ(array_length(), vec_copy.Size()); | 
 |   for (size_t i = 0; i < array_length(); ++i) { | 
 |     EXPECT_EQ(array_[i], vec[i]); | 
 |     EXPECT_EQ(array_[i], vec_copy[i]); | 
 |   } | 
 |  | 
 |   // Clear |vec| and verify that it is empty. | 
 |   vec.Clear(); | 
 |   EXPECT_TRUE(vec.Empty()); | 
 |  | 
 |   // Now copy the empty vector and verify that the copy becomes empty too. | 
 |   vec.CopyTo(&vec_copy); | 
 |   EXPECT_TRUE(vec_copy.Empty()); | 
 | } | 
 |  | 
 | // Try to copy to a NULL pointer. Nothing should happen. | 
 | TEST_F(AudioVectorTest, CopyToNull) { | 
 |   AudioVector vec; | 
 |   AudioVector* vec_copy = NULL; | 
 |   vec.PushBack(array_, array_length()); | 
 |   vec.CopyTo(vec_copy); | 
 | } | 
 |  | 
 | // Test the PushBack method with another AudioVector as input argument. | 
 | TEST_F(AudioVectorTest, PushBackVector) { | 
 |   static const size_t kLength = 10; | 
 |   AudioVector vec1(kLength); | 
 |   AudioVector vec2(kLength); | 
 |   // Set the first vector to [0, 1, ..., kLength - 1]. | 
 |   // Set the second vector to [kLength, kLength + 1, ..., 2 * kLength - 1]. | 
 |   for (size_t i = 0; i < kLength; ++i) { | 
 |     vec1[i] = static_cast<int16_t>(i); | 
 |     vec2[i] = static_cast<int16_t>(i + kLength); | 
 |   } | 
 |   // Append vec2 to the back of vec1. | 
 |   vec1.PushBack(vec2); | 
 |   ASSERT_EQ(2 * kLength, vec1.Size()); | 
 |   for (size_t i = 0; i < 2 * kLength; ++i) { | 
 |     EXPECT_EQ(static_cast<int16_t>(i), vec1[i]); | 
 |   } | 
 | } | 
 |  | 
 | // Test the PushFront method. | 
 | TEST_F(AudioVectorTest, PushFront) { | 
 |   AudioVector vec; | 
 |   vec.PushFront(array_, array_length()); | 
 |   ASSERT_EQ(array_length(), vec.Size()); | 
 |   for (size_t i = 0; i < array_length(); ++i) { | 
 |     EXPECT_EQ(array_[i], vec[i]); | 
 |   } | 
 | } | 
 |  | 
 | // Test the PushFront method with another AudioVector as input argument. | 
 | TEST_F(AudioVectorTest, PushFrontVector) { | 
 |   static const size_t kLength = 10; | 
 |   AudioVector vec1(kLength); | 
 |   AudioVector vec2(kLength); | 
 |   // Set the first vector to [0, 1, ..., kLength - 1]. | 
 |   // Set the second vector to [kLength, kLength + 1, ..., 2 * kLength - 1]. | 
 |   for (size_t i = 0; i < kLength; ++i) { | 
 |     vec1[i] = static_cast<int16_t>(i); | 
 |     vec2[i] = static_cast<int16_t>(i + kLength); | 
 |   } | 
 |   // Prepend vec1 to the front of vec2. | 
 |   vec2.PushFront(vec1); | 
 |   ASSERT_EQ(2 * kLength, vec2.Size()); | 
 |   for (size_t i = 0; i < 2 * kLength; ++i) { | 
 |     EXPECT_EQ(static_cast<int16_t>(i), vec2[i]); | 
 |   } | 
 | } | 
 |  | 
 | // Test the PopFront method. | 
 | TEST_F(AudioVectorTest, PopFront) { | 
 |   AudioVector vec; | 
 |   vec.PushBack(array_, array_length()); | 
 |   vec.PopFront(1);  // Remove one element. | 
 |   EXPECT_EQ(array_length() - 1u, vec.Size()); | 
 |   for (size_t i = 0; i < array_length() - 1; ++i) { | 
 |     EXPECT_EQ(static_cast<int16_t>(i + 1), vec[i]); | 
 |   } | 
 |   vec.PopFront(array_length());  // Remove more elements than vector size. | 
 |   EXPECT_EQ(0u, vec.Size()); | 
 | } | 
 |  | 
 | // Test the PopBack method. | 
 | TEST_F(AudioVectorTest, PopBack) { | 
 |   AudioVector vec; | 
 |   vec.PushBack(array_, array_length()); | 
 |   vec.PopBack(1);  // Remove one element. | 
 |   EXPECT_EQ(array_length() - 1u, vec.Size()); | 
 |   for (size_t i = 0; i < array_length() - 1; ++i) { | 
 |     EXPECT_EQ(static_cast<int16_t>(i), vec[i]); | 
 |   } | 
 |   vec.PopBack(array_length());  // Remove more elements than vector size. | 
 |   EXPECT_EQ(0u, vec.Size()); | 
 | } | 
 |  | 
 | // Test the Extend method. | 
 | TEST_F(AudioVectorTest, Extend) { | 
 |   AudioVector vec; | 
 |   vec.PushBack(array_, array_length()); | 
 |   vec.Extend(5);  // Extend with 5 elements, which should all be zeros. | 
 |   ASSERT_EQ(array_length() + 5u, vec.Size()); | 
 |   // Verify that all are zero. | 
 |   for (size_t i = array_length(); i < array_length() + 5; ++i) { | 
 |     EXPECT_EQ(0, vec[i]); | 
 |   } | 
 | } | 
 |  | 
 | // Test the InsertAt method with an insert position in the middle of the vector. | 
 | TEST_F(AudioVectorTest, InsertAt) { | 
 |   AudioVector vec; | 
 |   vec.PushBack(array_, array_length()); | 
 |   static const int kNewLength = 5; | 
 |   int16_t new_array[kNewLength]; | 
 |   // Set array elements to {100, 101, 102, ... }. | 
 |   for (int i = 0; i < kNewLength; ++i) { | 
 |     new_array[i] = 100 + i; | 
 |   } | 
 |   int insert_position = 5; | 
 |   vec.InsertAt(new_array, kNewLength, insert_position); | 
 |   // Verify that the vector looks as follows: | 
 |   // {0, 1, ..., |insert_position| - 1, 100, 101, ..., 100 + kNewLength - 1, | 
 |   //  |insert_position|, |insert_position| + 1, ..., kLength - 1}. | 
 |   size_t pos = 0; | 
 |   for (int i = 0; i < insert_position; ++i) { | 
 |     EXPECT_EQ(array_[i], vec[pos]); | 
 |     ++pos; | 
 |   } | 
 |   for (int i = 0; i < kNewLength; ++i) { | 
 |     EXPECT_EQ(new_array[i], vec[pos]); | 
 |     ++pos; | 
 |   } | 
 |   for (size_t i = insert_position; i < array_length(); ++i) { | 
 |     EXPECT_EQ(array_[i], vec[pos]); | 
 |     ++pos; | 
 |   } | 
 | } | 
 |  | 
 | // Test the InsertZerosAt method with an insert position in the middle of the | 
 | // vector. Use the InsertAt method as reference. | 
 | TEST_F(AudioVectorTest, InsertZerosAt) { | 
 |   AudioVector vec; | 
 |   AudioVector vec_ref; | 
 |   vec.PushBack(array_, array_length()); | 
 |   vec_ref.PushBack(array_, array_length()); | 
 |   static const int kNewLength = 5; | 
 |   int insert_position = 5; | 
 |   vec.InsertZerosAt(kNewLength, insert_position); | 
 |   int16_t new_array[kNewLength] = {0};  // All zero elements. | 
 |   vec_ref.InsertAt(new_array, kNewLength, insert_position); | 
 |   // Verify that the vectors are identical. | 
 |   ASSERT_EQ(vec_ref.Size(), vec.Size()); | 
 |   for (size_t i = 0; i < vec.Size(); ++i) { | 
 |     EXPECT_EQ(vec_ref[i], vec[i]); | 
 |   } | 
 | } | 
 |  | 
 | // Test the InsertAt method with an insert position at the start of the vector. | 
 | TEST_F(AudioVectorTest, InsertAtBeginning) { | 
 |   AudioVector vec; | 
 |   vec.PushBack(array_, array_length()); | 
 |   static const int kNewLength = 5; | 
 |   int16_t new_array[kNewLength]; | 
 |   // Set array elements to {100, 101, 102, ... }. | 
 |   for (int i = 0; i < kNewLength; ++i) { | 
 |     new_array[i] = 100 + i; | 
 |   } | 
 |   int insert_position = 0; | 
 |   vec.InsertAt(new_array, kNewLength, insert_position); | 
 |   // Verify that the vector looks as follows: | 
 |   // {100, 101, ..., 100 + kNewLength - 1, | 
 |   //  0, 1, ..., kLength - 1}. | 
 |   size_t pos = 0; | 
 |   for (int i = 0; i < kNewLength; ++i) { | 
 |     EXPECT_EQ(new_array[i], vec[pos]); | 
 |     ++pos; | 
 |   } | 
 |   for (size_t i = insert_position; i < array_length(); ++i) { | 
 |     EXPECT_EQ(array_[i], vec[pos]); | 
 |     ++pos; | 
 |   } | 
 | } | 
 |  | 
 | // Test the InsertAt method with an insert position at the end of the vector. | 
 | TEST_F(AudioVectorTest, InsertAtEnd) { | 
 |   AudioVector vec; | 
 |   vec.PushBack(array_, array_length()); | 
 |   static const int kNewLength = 5; | 
 |   int16_t new_array[kNewLength]; | 
 |   // Set array elements to {100, 101, 102, ... }. | 
 |   for (int i = 0; i < kNewLength; ++i) { | 
 |     new_array[i] = 100 + i; | 
 |   } | 
 |   int insert_position = array_length(); | 
 |   vec.InsertAt(new_array, kNewLength, insert_position); | 
 |   // Verify that the vector looks as follows: | 
 |   // {0, 1, ..., kLength - 1, 100, 101, ..., 100 + kNewLength - 1 }. | 
 |   size_t pos = 0; | 
 |   for (size_t i = 0; i < array_length(); ++i) { | 
 |     EXPECT_EQ(array_[i], vec[pos]); | 
 |     ++pos; | 
 |   } | 
 |   for (int i = 0; i < kNewLength; ++i) { | 
 |     EXPECT_EQ(new_array[i], vec[pos]); | 
 |     ++pos; | 
 |   } | 
 | } | 
 |  | 
 | // Test the InsertAt method with an insert position beyond the end of the | 
 | // vector. Verify that a position beyond the end of the vector does not lead to | 
 | // an error. The expected outcome is the same as if the vector end was used as | 
 | // input position. That is, the input position should be capped at the maximum | 
 | // allowed value. | 
 | TEST_F(AudioVectorTest, InsertBeyondEnd) { | 
 |   AudioVector vec; | 
 |   vec.PushBack(array_, array_length()); | 
 |   static const int kNewLength = 5; | 
 |   int16_t new_array[kNewLength]; | 
 |   // Set array elements to {100, 101, 102, ... }. | 
 |   for (int i = 0; i < kNewLength; ++i) { | 
 |     new_array[i] = 100 + i; | 
 |   } | 
 |   int insert_position = array_length() + 10;  // Too large. | 
 |   vec.InsertAt(new_array, kNewLength, insert_position); | 
 |   // Verify that the vector looks as follows: | 
 |   // {0, 1, ..., kLength - 1, 100, 101, ..., 100 + kNewLength - 1 }. | 
 |   size_t pos = 0; | 
 |   for (size_t i = 0; i < array_length(); ++i) { | 
 |     EXPECT_EQ(array_[i], vec[pos]); | 
 |     ++pos; | 
 |   } | 
 |   for (int i = 0; i < kNewLength; ++i) { | 
 |     EXPECT_EQ(new_array[i], vec[pos]); | 
 |     ++pos; | 
 |   } | 
 | } | 
 |  | 
 | // Test the OverwriteAt method with a position such that all of the new values | 
 | // fit within the old vector. | 
 | TEST_F(AudioVectorTest, OverwriteAt) { | 
 |   AudioVector vec; | 
 |   vec.PushBack(array_, array_length()); | 
 |   static const int kNewLength = 5; | 
 |   int16_t new_array[kNewLength]; | 
 |   // Set array elements to {100, 101, 102, ... }. | 
 |   for (int i = 0; i < kNewLength; ++i) { | 
 |     new_array[i] = 100 + i; | 
 |   } | 
 |   size_t insert_position = 2; | 
 |   vec.OverwriteAt(new_array, kNewLength, insert_position); | 
 |   // Verify that the vector looks as follows: | 
 |   // {0, ..., |insert_position| - 1, 100, 101, ..., 100 + kNewLength - 1, | 
 |   //  |insert_position|, |insert_position| + 1, ..., kLength - 1}. | 
 |   size_t pos = 0; | 
 |   for (pos = 0; pos < insert_position; ++pos) { | 
 |     EXPECT_EQ(array_[pos], vec[pos]); | 
 |   } | 
 |   for (int i = 0; i < kNewLength; ++i) { | 
 |     EXPECT_EQ(new_array[i], vec[pos]); | 
 |     ++pos; | 
 |   } | 
 |   for (; pos < array_length(); ++pos) { | 
 |     EXPECT_EQ(array_[pos], vec[pos]); | 
 |   } | 
 | } | 
 |  | 
 | // Test the OverwriteAt method with a position such that some of the new values | 
 | // extend beyond the end of the current vector. This is valid, and the vector is | 
 | // expected to expand to accommodate the new values. | 
 | TEST_F(AudioVectorTest, OverwriteBeyondEnd) { | 
 |   AudioVector vec; | 
 |   vec.PushBack(array_, array_length()); | 
 |   static const int kNewLength = 5; | 
 |   int16_t new_array[kNewLength]; | 
 |   // Set array elements to {100, 101, 102, ... }. | 
 |   for (int i = 0; i < kNewLength; ++i) { | 
 |     new_array[i] = 100 + i; | 
 |   } | 
 |   int insert_position = array_length() - 2; | 
 |   vec.OverwriteAt(new_array, kNewLength, insert_position); | 
 |   ASSERT_EQ(array_length() - 2u + kNewLength, vec.Size()); | 
 |   // Verify that the vector looks as follows: | 
 |   // {0, ..., |insert_position| - 1, 100, 101, ..., 100 + kNewLength - 1, | 
 |   //  |insert_position|, |insert_position| + 1, ..., kLength - 1}. | 
 |   int pos = 0; | 
 |   for (pos = 0; pos < insert_position; ++pos) { | 
 |     EXPECT_EQ(array_[pos], vec[pos]); | 
 |   } | 
 |   for (int i = 0; i < kNewLength; ++i) { | 
 |     EXPECT_EQ(new_array[i], vec[pos]); | 
 |     ++pos; | 
 |   } | 
 |   // Verify that we checked to the end of |vec|. | 
 |   EXPECT_EQ(vec.Size(), static_cast<size_t>(pos)); | 
 | } | 
 |  | 
 | TEST_F(AudioVectorTest, CrossFade) { | 
 |   static const size_t kLength = 100; | 
 |   static const size_t kFadeLength = 10; | 
 |   AudioVector vec1(kLength); | 
 |   AudioVector vec2(kLength); | 
 |   // Set all vector elements to 0 in |vec1| and 100 in |vec2|. | 
 |   for (size_t i = 0; i < kLength; ++i) { | 
 |     vec1[i] = 0; | 
 |     vec2[i] = 100; | 
 |   } | 
 |   vec1.CrossFade(vec2, kFadeLength); | 
 |   ASSERT_EQ(2 * kLength - kFadeLength, vec1.Size()); | 
 |   // First part untouched. | 
 |   for (size_t i = 0; i < kLength - kFadeLength; ++i) { | 
 |     EXPECT_EQ(0, vec1[i]); | 
 |   } | 
 |   // Check mixing zone. | 
 |   for (size_t i = 0 ; i < kFadeLength; ++i) { | 
 |     EXPECT_NEAR((i + 1) * 100 / (kFadeLength + 1), | 
 |                 vec1[kLength - kFadeLength + i], 1); | 
 |   } | 
 |   // Second part untouched. | 
 |   for (size_t i = kLength; i < vec1.Size(); ++i) { | 
 |     EXPECT_EQ(100, vec1[i]); | 
 |   } | 
 | } | 
 |  | 
 | }  // namespace webrtc |