/* * Copyright (c) 2015 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 #include "testing/gtest/include/gtest/gtest.h" #include "webrtc/base/random.h" #include "webrtc/call/ringbuffer.h" namespace { template class MovableType { public: MovableType() : value_(), moved_from_(false), moved_to_(false) {} explicit MovableType(T value) : value_(value), moved_from_(false), moved_to_(false) {} MovableType(const MovableType& other) : value_(other.value_), moved_from_(false), moved_to_(false) {} MovableType(MovableType&& other) : value_(other.value_), moved_from_(false), moved_to_(true) { other.moved_from_ = true; } MovableType& operator=(const MovableType& other) { value_ = other.value_; moved_from_ = false; moved_to_ = false; return *this; } MovableType& operator=(MovableType&& other) { value_ = other.value_; moved_from_ = false; moved_to_ = true; other.moved_from_ = true; return *this; } T Value() { return value_; } bool IsMovedFrom() { return moved_from_; } bool IsMovedTo() { return moved_to_; } private: T value_; bool moved_from_; bool moved_to_; }; } // namespace namespace webrtc { // Verify that the ring buffer works as a simple queue. TEST(RingBufferTest, SimpleQueue) { size_t capacity = 100; RingBuffer q(capacity); EXPECT_TRUE(q.empty()); for (size_t i = 0; i < capacity; i++) { q.push_back(i); EXPECT_FALSE(q.empty()); } for (size_t i = 0; i < capacity; i++) { EXPECT_FALSE(q.empty()); EXPECT_EQ(i, q.front()); q.pop_front(); } EXPECT_TRUE(q.empty()); } // Do a "random" sequence of queue operations and verify that the // result is consistent with the same operation performed on a std::list. TEST(RingBufferTest, ConsistentWithStdList) { Random prng(987654321ull); size_t capacity = 10; RingBuffer q(capacity); std::list l; EXPECT_TRUE(q.empty()); for (size_t i = 0; i < 100 * capacity; i++) { bool insert = prng.Rand(); if ((insert && l.size() < capacity) || l.size() == 0) { int x = prng.Rand(); l.push_back(x); q.push_back(x); EXPECT_FALSE(q.empty()); } else { EXPECT_FALSE(q.empty()); EXPECT_EQ(l.front(), q.front()); l.pop_front(); q.pop_front(); } } while (!l.empty()) { EXPECT_FALSE(q.empty()); EXPECT_EQ(l.front(), q.front()); l.pop_front(); q.pop_front(); } EXPECT_TRUE(q.empty()); } // Test that the ringbuffer starts reusing elements from the front // when the queue becomes full. TEST(RingBufferTest, OverwriteOldElements) { size_t capacity = 100; size_t insertions = 3 * capacity + 25; RingBuffer q(capacity); EXPECT_TRUE(q.empty()); for (size_t i = 0; i < insertions; i++) { q.push_back(i); EXPECT_FALSE(q.empty()); } for (size_t i = insertions - capacity; i < insertions; i++) { EXPECT_FALSE(q.empty()); EXPECT_EQ(i, q.front()); q.pop_front(); } EXPECT_TRUE(q.empty()); } // Test that the ringbuffer uses std::move when pushing an rvalue reference. TEST(RingBufferTest, MoveSemanticsForPushBack) { size_t capacity = 100; size_t insertions = 3 * capacity + 25; RingBuffer> q(capacity); EXPECT_TRUE(q.empty()); for (size_t i = 0; i < insertions; i++) { MovableType tmp(i); EXPECT_FALSE(tmp.IsMovedFrom()); EXPECT_FALSE(tmp.IsMovedTo()); q.push_back(std::move(tmp)); EXPECT_TRUE(tmp.IsMovedFrom()); EXPECT_FALSE(tmp.IsMovedTo()); EXPECT_FALSE(q.empty()); } for (size_t i = insertions - capacity; i < insertions; i++) { EXPECT_FALSE(q.empty()); EXPECT_EQ(i, q.front().Value()); EXPECT_FALSE(q.front().IsMovedFrom()); EXPECT_TRUE(q.front().IsMovedTo()); q.pop_front(); } EXPECT_TRUE(q.empty()); } TEST(RingBufferTest, SmallCapacity) { size_t capacity = 1; RingBuffer q(capacity); EXPECT_TRUE(q.empty()); q.push_back(4711); EXPECT_FALSE(q.empty()); EXPECT_EQ(4711, q.front()); q.push_back(1024); EXPECT_FALSE(q.empty()); EXPECT_EQ(1024, q.front()); q.pop_front(); EXPECT_TRUE(q.empty()); } } // namespace webrtc