| Index: media/blink/multibuffer_unittest.cc
|
| diff --git a/media/blink/multibuffer_unittest.cc b/media/blink/multibuffer_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..7bc20b8cad4167ab69a34f84da7b83c4f4f954aa
|
| --- /dev/null
|
| +++ b/media/blink/multibuffer_unittest.cc
|
| @@ -0,0 +1,301 @@
|
| +// Copyright 2015 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include <deque>
|
| +#include <string>
|
| +#include <vector>
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/callback_helpers.h"
|
| +#include "media/blink/multibuffer.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +const int kBlockSizeShift = 8;
|
| +const size_t kBlockSize = 1UL << kBlockSizeShift;
|
| +
|
| +namespace media {
|
| +class TestMultiBufferDataProvider;
|
| +
|
| +std::vector<TestMultiBufferDataProvider*> writers;
|
| +
|
| +class TestMultiBufferDataProvider : public media::MultiBufferDataProvider {
|
| + public:
|
| + TestMultiBufferDataProvider(MultiBufferBlockId pos) :
|
| + pos_(pos),
|
| + deferred_(false) {
|
| + writers.push_back(this);
|
| + }
|
| +
|
| + ~TestMultiBufferDataProvider() override {
|
| + for (size_t i = 0; i < writers.size(); i++) {
|
| + if (writers[i] == this) {
|
| + writers[i] = writers.back();
|
| + writers.pop_back();
|
| + return;
|
| + }
|
| + }
|
| + LOG(FATAL) << "Couldn't find myself in writers!";
|
| + }
|
| +
|
| + MultiBufferBlockId Tell() const override {
|
| + return pos_;
|
| + }
|
| +
|
| + bool Available() const override {
|
| + return !fifo_.empty();
|
| + }
|
| +
|
| + scoped_refptr<DataBuffer> Read() override {
|
| + DCHECK(Available());
|
| + scoped_refptr<DataBuffer> ret = fifo_.front();
|
| + fifo_.pop_front();
|
| + ++pos_;
|
| + return ret;
|
| + }
|
| +
|
| + void SetAvailableCallback(base::Closure cb) override {
|
| + DCHECK(!Available());
|
| + cb_ = cb;
|
| + }
|
| +
|
| + void SetDeferred(bool deferred) override {
|
| + deferred_ = deferred;
|
| + }
|
| +
|
| + bool Advance() {
|
| + // TODO(hubbe): simulate that we sometimes get data even
|
| + // after we're deferred.
|
| + // TODO(hubbe): Add EOF block.
|
| + // TODO(hubbe): Let last block be smaller.
|
| + if (deferred_) return false;
|
| +
|
| + scoped_refptr<media::DataBuffer> block = new media::DataBuffer(kBlockSize);
|
| + for (size_t x = 0; x < kBlockSize; x++) {
|
| + size_t byte_pos = (pos_.block_num() * kBlockSize) + x;
|
| + block->writable_data()[x] = (byte_pos * 15485863) >> 16;
|
| + }
|
| + block->set_data_size(kBlockSize);
|
| + fifo_.push_back(block);
|
| + cb_.Run();
|
| + return true;
|
| + }
|
| +
|
| + private:
|
| + std::deque<scoped_refptr<media::DataBuffer> > fifo_;
|
| + MultiBufferBlockId pos_;
|
| + bool deferred_;
|
| + base::Closure cb_;
|
| +};
|
| +
|
| +class TestMultiBuffer : public media::MultiBuffer {
|
| + public:
|
| + explicit TestMultiBuffer(int32_t shift) :
|
| + media::MultiBuffer(shift),
|
| + max_writers_(10000) {
|
| + }
|
| +
|
| + void SetMaxWriters(size_t max_writers) {
|
| + max_writers_ = max_writers;
|
| + }
|
| +
|
| + void CheckLRUState() {
|
| + for (DataMap::iterator i = data_.begin();
|
| + i != data_.end();
|
| + ++i) {
|
| + CHECK(i->second); // Null poineters are not allowed in data_
|
| + CHECK_NE(!!pinned_[i->first], lru_.Contains(i->first))
|
| + << " i->first = " << i->first;
|
| + }
|
| + }
|
| +
|
| + protected:
|
| + MultiBufferDataProvider* CreateWriter(MultiBufferBlockId pos) override {
|
| + CHECK_LE(writers.size(), max_writers_);
|
| + CheckLRUState();
|
| + return new TestMultiBufferDataProvider(pos);
|
| + }
|
| + private:
|
| + size_t max_writers_;
|
| +};
|
| +
|
| +}
|
| +
|
| +class MultiBufferTest : public testing::Test {
|
| + public:
|
| + MultiBufferTest() :
|
| + multibuffer_(kBlockSizeShift) {
|
| + }
|
| +
|
| + void Advance() {
|
| + CHECK(media::writers.size());
|
| + media::writers[rand() % media::writers.size()]->Advance();
|
| + multibuffer_.CheckLRUState();
|
| + }
|
| +
|
| + bool AdvanceAll() {
|
| + bool advanced = false;
|
| + for (size_t i = 0; i < media::writers.size(); i++) {
|
| + advanced |= media::writers[i]->Advance();
|
| + }
|
| + multibuffer_.CheckLRUState();
|
| + return advanced;
|
| + }
|
| +
|
| + scoped_refptr<media::UrlData> GetUrl() {
|
| + return url_index_.GetByUrl(GURL("http://x"), media::UrlData::kUnspecified);
|
| + }
|
| +
|
| + protected:
|
| + media::TestMultiBuffer multibuffer_;
|
| + media::UrlIndex url_index_;
|
| +};
|
| +
|
| +TEST_F(MultiBufferTest, ReadAll) {
|
| + multibuffer_.SetMaxWriters(1);
|
| + size_t pos = 0;
|
| + size_t end = 10000;
|
| + media::MultiBufferReader reader(&multibuffer_,
|
| + GetUrl(),
|
| + pos,
|
| + end,
|
| + 1000,
|
| + 1000,
|
| + 5000,
|
| + 2000,
|
| + base::Callback<void(int64_t, int64_t)>());
|
| + while (pos < end) {
|
| + unsigned char buffer[27];
|
| + buffer[17] = 17;
|
| + size_t to_read = std::min<size_t>(end - pos, 17);
|
| + int64 bytes_read = reader.TryRead(buffer, to_read);
|
| + if (bytes_read) {
|
| + EXPECT_EQ(buffer[17], 17);
|
| + for (size_t i = 0; i < bytes_read; i++) {
|
| + unsigned char expected = (pos * 15485863) >> 16;
|
| + EXPECT_EQ(expected, buffer[i]) << " pos = " << pos;
|
| + pos++;
|
| + }
|
| + } else {
|
| + Advance();
|
| + }
|
| + }
|
| +}
|
| +
|
| +TEST_F(MultiBufferTest, ReadAllAdvanceFirst) {
|
| + multibuffer_.SetMaxWriters(1);
|
| + size_t pos = 0;
|
| + size_t end = 10000;
|
| + media::MultiBufferReader reader(&multibuffer_,
|
| + GetUrl(),
|
| + pos,
|
| + end,
|
| + 1000,
|
| + 1000,
|
| + 5000,
|
| + 2000,
|
| + base::Callback<void(int64_t, int64_t)>());
|
| + while (pos < end) {
|
| + unsigned char buffer[27];
|
| + buffer[17] = 17;
|
| + size_t to_read = std::min<size_t>(end - pos, 17);
|
| + while (AdvanceAll());
|
| + EXPECT_TRUE(reader.TryRead(buffer, to_read));
|
| + EXPECT_EQ(buffer[17], 17);
|
| + for (size_t i = 0; i < to_read; i++) {
|
| + unsigned char expected = (pos * 15485863) >> 16;
|
| + EXPECT_EQ(expected, buffer[i]) << " pos = " << pos;
|
| + pos++;
|
| + }
|
| + }
|
| +}
|
| +
|
| +class ReadHelper {
|
| + public:
|
| + ReadHelper(scoped_refptr<media::UrlData> url,
|
| + size_t end,
|
| + size_t max_read_size,
|
| + media::MultiBuffer* multibuffer) :
|
| + pos_(0),
|
| + end_(end),
|
| + max_read_size_(max_read_size),
|
| + read_size_(0),
|
| + reader_(multibuffer,
|
| + url,
|
| + pos_,
|
| + end_,
|
| + 1000,
|
| + 1000,
|
| + 5000,
|
| + 2000,
|
| + base::Callback<void(int64_t, int64_t)>()) {
|
| + }
|
| +
|
| + bool Read() {
|
| + if (read_size_ == 0) return true;
|
| + unsigned char buffer[read_size_];
|
| + CHECK_EQ(pos_, reader_.Tell());
|
| + int64 bytes_read = reader_.TryRead(buffer, read_size_);
|
| + if (bytes_read) {
|
| + for (size_t i = 0; i < bytes_read; i++) {
|
| + unsigned char expected = (pos_ * 15485863) >> 16;
|
| + EXPECT_EQ(expected, buffer[i]) << " pos = " << pos_;
|
| + pos_++;
|
| + }
|
| + CHECK_EQ(pos_, reader_.Tell());
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + void StartRead() {
|
| + CHECK_EQ(pos_, reader_.Tell());
|
| + read_size_ = std::min(1 + rand() % (max_read_size_ - 1), end_ - pos_);
|
| + if (!Read()) {
|
| + reader_.Wait(read_size_,
|
| + base::Bind(&ReadHelper::WaitCB, base::Unretained(this)));
|
| + }
|
| + }
|
| +
|
| + void WaitCB() {
|
| + CHECK(Read());
|
| + }
|
| +
|
| + void Seek() {
|
| + pos_ = rand() % end_;
|
| + reader_.Seek(pos_);
|
| + CHECK_EQ(pos_, reader_.Tell());
|
| + }
|
| +
|
| + private:
|
| + size_t pos_;
|
| + size_t end_;
|
| + size_t max_read_size_;
|
| + size_t read_size_;
|
| + media::MultiBufferReader reader_;
|
| +};
|
| +
|
| +TEST_F(MultiBufferTest, RandomTest) {
|
| + std::vector<ReadHelper*> read_helpers;
|
| + scoped_refptr<media::UrlData> url = GetUrl();
|
| + for (size_t i = 0; i < 20; i++) {
|
| + read_helpers.push_back(new ReadHelper(url, 1000000, 1000, &multibuffer_));
|
| + }
|
| + for (int i = 0; i < 10000; i++) {
|
| + if (rand() & 1) {
|
| + if (!media::writers.empty()) Advance();
|
| + } else {
|
| + size_t j = rand() % read_helpers.size();
|
| + if (rand() % 100 < 3) {
|
| + read_helpers[j]->Seek();
|
| + multibuffer_.CheckLRUState();
|
| + }
|
| + read_helpers[j]->StartRead();
|
| + multibuffer_.CheckLRUState();
|
| + }
|
| + }
|
| + while (!read_helpers.empty()) {
|
| + delete read_helpers.back();
|
| + read_helpers.pop_back();
|
| + }
|
| +}
|
|
|