// Copyright 2016 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 "media/filters/memory_data_source.h"

#include <memory>

#include "base/bind.h"
#include "base/macros.h"
#include "base/rand_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace media {

class MemoryDataSourceTest : public ::testing::Test {
 public:
  MemoryDataSourceTest() {}

 protected:
  void Initialize(size_t size) {
    data_.assign(size, 0);
    base::RandBytes(data_.data(), size);
    memory_data_source_.reset(new MemoryDataSource(data_.data(), size));
    EXPECT_EQ(size, GetSize());
  }

  // Reads |size| bytes starting from |position|, expects |expected_read_size|
  // bytes to be read and checks the read data. Expects error when
  // |expected_read_size| is DataSource::kReadError.
  void ReadAndExpect(int64_t position, int size, int expected_read_size) {
    std::vector<uint8_t> data(size < 0 ? 0 : size, 0);

    EXPECT_CALL(*this, ReadCB(expected_read_size));
    memory_data_source_->Read(
        position, size, data.data(),
        base::Bind(&MemoryDataSourceTest::ReadCB, base::Unretained(this)));

    if (expected_read_size != DataSource::kReadError) {
      EXPECT_EQ(
          0, memcmp(data_.data() + position, data.data(), expected_read_size));
    }
  }

  size_t GetSize() {
    int64_t size = 0;
    EXPECT_TRUE(memory_data_source_->GetSize(&size));
    EXPECT_GE(size, 0);
    return size;
  }

  void Stop() { memory_data_source_->Stop(); }

  MOCK_METHOD1(ReadCB, void(int size));

 private:
  std::vector<uint8_t> data_;
  std::unique_ptr<MemoryDataSource> memory_data_source_;

  DISALLOW_COPY_AND_ASSIGN(MemoryDataSourceTest);
};

TEST_F(MemoryDataSourceTest, EmptySource) {
  Initialize(0);
  ReadAndExpect(0, 0, 0);
}

TEST_F(MemoryDataSourceTest, ReadData) {
  Initialize(128);
  ReadAndExpect(0, 0, 0);
  ReadAndExpect(0, 128, 128);
  ReadAndExpect(12, 64, 64);
  ReadAndExpect(128, 0, 0);
}

TEST_F(MemoryDataSourceTest, ReadData_InvalidPosition) {
  Initialize(128);
  ReadAndExpect(-7, 64, DataSource::kReadError);
  ReadAndExpect(129, 64, DataSource::kReadError);
}

TEST_F(MemoryDataSourceTest, ReadData_InvalidSize) {
  Initialize(128);
  ReadAndExpect(0, -12, DataSource::kReadError);
}

TEST_F(MemoryDataSourceTest, ReadData_PartialRead) {
  Initialize(128);
  ReadAndExpect(0, 129, 128);
  ReadAndExpect(96, 100, 32);
}

// All ReadData() will fail after Stop().
TEST_F(MemoryDataSourceTest, Stop) {
  Initialize(128);
  ReadAndExpect(12, 64, 64);
  Stop();
  ReadAndExpect(12, 64, DataSource::kReadError);
}

// ReadData() doesn't affect GetSize().
TEST_F(MemoryDataSourceTest, GetSize) {
  Initialize(128);
  ReadAndExpect(12, 64, 64);
  EXPECT_EQ(128u, GetSize());
  ReadAndExpect(-7, 64, DataSource::kReadError);
  EXPECT_EQ(128u, GetSize());
}

}  // namespace media
