root/media/base/seekable_buffer_unittest.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. SetUp
  2. GetRandomInt
  3. TEST_F
  4. TEST_F
  5. TEST_F
  6. TEST_F
  7. TEST_F
  8. TEST_F
  9. TEST_F
  10. TEST_F

// Copyright (c) 2012 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 <cstdlib>

#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/time/time.h"
#include "media/base/data_buffer.h"
#include "media/base/seekable_buffer.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace media {

class SeekableBufferTest : public testing::Test {
 public:
  SeekableBufferTest() : buffer_(kBufferSize, kBufferSize) {
  }

 protected:
  static const int kDataSize = 409600;
  static const int kBufferSize = 4096;
  static const int kWriteSize = 512;

  virtual void SetUp() {
    // Note: We use srand() and rand() rather than base::RandXXX() to improve
    // unit test performance.  We don't need good random numbers, just
    // something that generates "mixed data."
    const unsigned int kKnownSeed = 0x98765432;
    srand(kKnownSeed);

    // Create random test data samples.
    for (int i = 0; i < kDataSize; i++)
      data_[i] = static_cast<char>(rand());
  }

  int GetRandomInt(int maximum) {
    return rand() % (maximum + 1);
  }

  SeekableBuffer buffer_;
  uint8 data_[kDataSize];
  uint8 write_buffer_[kDataSize];
};

TEST_F(SeekableBufferTest, RandomReadWrite) {
  int write_position = 0;
  int read_position = 0;
  while (read_position < kDataSize) {
    // Write a random amount of data.
    int write_size = GetRandomInt(kBufferSize);
    write_size = std::min(write_size, kDataSize - write_position);
    bool should_append = buffer_.Append(data_ + write_position, write_size);
    write_position += write_size;
    EXPECT_GE(write_position, read_position);
    EXPECT_EQ(write_position - read_position, buffer_.forward_bytes());
    EXPECT_EQ(should_append, buffer_.forward_bytes() < kBufferSize)
        << "Incorrect buffer full reported";

    // Peek a random amount of data.
    int copy_size = GetRandomInt(kBufferSize);
    int bytes_copied = buffer_.Peek(write_buffer_, copy_size);
    EXPECT_GE(copy_size, bytes_copied);
    EXPECT_EQ(0, memcmp(write_buffer_, data_ + read_position, bytes_copied));

    // Read a random amount of data.
    int read_size = GetRandomInt(kBufferSize);
    int bytes_read = buffer_.Read(write_buffer_, read_size);
    EXPECT_GE(read_size, bytes_read);
    EXPECT_EQ(0, memcmp(write_buffer_, data_ + read_position, bytes_read));
    read_position += bytes_read;
    EXPECT_GE(write_position, read_position);
    EXPECT_EQ(write_position - read_position, buffer_.forward_bytes());
  }
}

TEST_F(SeekableBufferTest, ReadWriteSeek) {
  const int kReadSize = kWriteSize / 4;

  for (int i = 0; i < 10; ++i) {
    // Write until buffer is full.
    for (int j = 0; j < kBufferSize; j += kWriteSize) {
      bool should_append = buffer_.Append(data_ + j, kWriteSize);
      EXPECT_EQ(j < kBufferSize - kWriteSize, should_append)
          << "Incorrect buffer full reported";
      EXPECT_EQ(j + kWriteSize, buffer_.forward_bytes());
    }

    // Simulate a read and seek pattern. Each loop reads 4 times, each time
    // reading a quarter of |kWriteSize|.
    int read_position = 0;
    int forward_bytes = kBufferSize;
    for (int j = 0; j < kBufferSize; j += kWriteSize) {
      // Read.
      EXPECT_EQ(kReadSize, buffer_.Read(write_buffer_, kReadSize));
      forward_bytes -= kReadSize;
      EXPECT_EQ(forward_bytes, buffer_.forward_bytes());
      EXPECT_EQ(0, memcmp(write_buffer_, data_ + read_position, kReadSize));
      read_position += kReadSize;

      // Seek forward.
      EXPECT_TRUE(buffer_.Seek(2 * kReadSize));
      forward_bytes -= 2 * kReadSize;
      read_position += 2 * kReadSize;
      EXPECT_EQ(forward_bytes, buffer_.forward_bytes());

      // Copy.
      EXPECT_EQ(kReadSize, buffer_.Peek(write_buffer_, kReadSize));
      EXPECT_EQ(forward_bytes, buffer_.forward_bytes());
      EXPECT_EQ(0, memcmp(write_buffer_, data_ + read_position, kReadSize));

      // Read.
      EXPECT_EQ(kReadSize, buffer_.Read(write_buffer_, kReadSize));
      forward_bytes -= kReadSize;
      EXPECT_EQ(forward_bytes, buffer_.forward_bytes());
      EXPECT_EQ(0, memcmp(write_buffer_, data_ + read_position, kReadSize));
      read_position += kReadSize;

      // Seek backward.
      EXPECT_TRUE(buffer_.Seek(-3 * static_cast<int32>(kReadSize)));
      forward_bytes += 3 * kReadSize;
      read_position -= 3 * kReadSize;
      EXPECT_EQ(forward_bytes, buffer_.forward_bytes());

      // Copy.
      EXPECT_EQ(kReadSize, buffer_.Peek(write_buffer_, kReadSize));
      EXPECT_EQ(forward_bytes, buffer_.forward_bytes());
      EXPECT_EQ(0, memcmp(write_buffer_, data_ + read_position, kReadSize));

      // Read.
      EXPECT_EQ(kReadSize, buffer_.Read(write_buffer_, kReadSize));
      forward_bytes -= kReadSize;
      EXPECT_EQ(forward_bytes, buffer_.forward_bytes());
      EXPECT_EQ(0, memcmp(write_buffer_, data_ + read_position, kReadSize));
      read_position += kReadSize;

      // Copy.
      EXPECT_EQ(kReadSize, buffer_.Peek(write_buffer_, kReadSize));
      EXPECT_EQ(forward_bytes, buffer_.forward_bytes());
      EXPECT_EQ(0, memcmp(write_buffer_, data_ + read_position, kReadSize));

      // Read.
      EXPECT_EQ(kReadSize, buffer_.Read(write_buffer_, kReadSize));
      forward_bytes -= kReadSize;
      EXPECT_EQ(forward_bytes, buffer_.forward_bytes());
      EXPECT_EQ(0, memcmp(write_buffer_, data_ + read_position, kReadSize));
      read_position += kReadSize;

      // Seek forward.
      EXPECT_TRUE(buffer_.Seek(kReadSize));
      forward_bytes -= kReadSize;
      read_position += kReadSize;
      EXPECT_EQ(forward_bytes, buffer_.forward_bytes());
    }
  }
}

TEST_F(SeekableBufferTest, BufferFull) {
  const int kMaxWriteSize = 2 * kBufferSize;

  // Write and expect the buffer to be not full.
  for (int i = 0; i < kBufferSize - kWriteSize; i += kWriteSize) {
    EXPECT_TRUE(buffer_.Append(data_ + i, kWriteSize));
    EXPECT_EQ(i + kWriteSize, buffer_.forward_bytes());
  }

  // Write until we have kMaxWriteSize bytes in the buffer. Buffer is full in
  // these writes.
  for (int i = buffer_.forward_bytes(); i < kMaxWriteSize; i += kWriteSize) {
    EXPECT_FALSE(buffer_.Append(data_ + i, kWriteSize));
    EXPECT_EQ(i + kWriteSize, buffer_.forward_bytes());
  }

  // Read until the buffer is empty.
  int read_position = 0;
  while (buffer_.forward_bytes()) {
    // Read a random amount of data.
    int read_size = GetRandomInt(kBufferSize);
    int forward_bytes = buffer_.forward_bytes();
    int bytes_read = buffer_.Read(write_buffer_, read_size);
    EXPECT_EQ(0, memcmp(write_buffer_, data_ + read_position, bytes_read));
    if (read_size > forward_bytes)
      EXPECT_EQ(forward_bytes, bytes_read);
    else
      EXPECT_EQ(read_size, bytes_read);
    read_position += bytes_read;
    EXPECT_GE(kMaxWriteSize, read_position);
    EXPECT_EQ(kMaxWriteSize - read_position, buffer_.forward_bytes());
  }

  // Expects we have no bytes left.
  EXPECT_EQ(0, buffer_.forward_bytes());
  EXPECT_EQ(0, buffer_.Read(write_buffer_, 1));
}

TEST_F(SeekableBufferTest, SeekBackward) {
  EXPECT_EQ(0, buffer_.forward_bytes());
  EXPECT_EQ(0, buffer_.backward_bytes());
  EXPECT_FALSE(buffer_.Seek(1));
  EXPECT_FALSE(buffer_.Seek(-1));

  const int kReadSize = 256;

  // Write into buffer until it's full.
  for (int i = 0; i < kBufferSize; i += kWriteSize) {
    // Write a random amount of data.
    buffer_.Append(data_ + i, kWriteSize);
  }

  // Read until buffer is empty.
  for (int i = 0; i < kBufferSize; i += kReadSize) {
    EXPECT_EQ(kReadSize, buffer_.Read(write_buffer_, kReadSize));
    EXPECT_EQ(0, memcmp(write_buffer_, data_ + i, kReadSize));
  }

  // Seek backward.
  EXPECT_TRUE(buffer_.Seek(-static_cast<int32>(kBufferSize)));
  EXPECT_FALSE(buffer_.Seek(-1));

  // Read again.
  for (int i = 0; i < kBufferSize; i += kReadSize) {
    EXPECT_EQ(kReadSize, buffer_.Read(write_buffer_, kReadSize));
    EXPECT_EQ(0, memcmp(write_buffer_, data_ + i, kReadSize));
  }
}

TEST_F(SeekableBufferTest, GetCurrentChunk) {
  const int kSeekSize = kWriteSize / 3;

  scoped_refptr<DataBuffer> buffer = DataBuffer::CopyFrom(data_, kWriteSize);

  const uint8* data;
  int size;
  EXPECT_FALSE(buffer_.GetCurrentChunk(&data, &size));

  buffer_.Append(buffer.get());
  EXPECT_TRUE(buffer_.GetCurrentChunk(&data, &size));
  EXPECT_EQ(data, buffer->data());
  EXPECT_EQ(size, buffer->data_size());

  buffer_.Seek(kSeekSize);
  EXPECT_TRUE(buffer_.GetCurrentChunk(&data, &size));
  EXPECT_EQ(data, buffer->data() + kSeekSize);
  EXPECT_EQ(size, buffer->data_size() - kSeekSize);
}

TEST_F(SeekableBufferTest, SeekForward) {
  int write_position = 0;
  int read_position = 0;
  while (read_position < kDataSize) {
    for (int i = 0; i < 10 && write_position < kDataSize; ++i) {
      // Write a random amount of data.
      int write_size = GetRandomInt(kBufferSize);
      write_size = std::min(write_size, kDataSize - write_position);

      bool should_append = buffer_.Append(data_ + write_position, write_size);
      write_position += write_size;
      EXPECT_GE(write_position, read_position);
      EXPECT_EQ(write_position - read_position, buffer_.forward_bytes());
      EXPECT_EQ(should_append, buffer_.forward_bytes() < kBufferSize)
          << "Incorrect buffer full status reported";
    }

    // Read a random amount of data.
    int seek_size = GetRandomInt(kBufferSize);
    if (buffer_.Seek(seek_size))
      read_position += seek_size;
    EXPECT_GE(write_position, read_position);
    EXPECT_EQ(write_position - read_position, buffer_.forward_bytes());

    // Read a random amount of data.
    int read_size = GetRandomInt(kBufferSize);
    int bytes_read = buffer_.Read(write_buffer_, read_size);
    EXPECT_GE(read_size, bytes_read);
    EXPECT_EQ(0, memcmp(write_buffer_, data_ + read_position, bytes_read));
    read_position += bytes_read;
    EXPECT_GE(write_position, read_position);
    EXPECT_EQ(write_position - read_position, buffer_.forward_bytes());
  }
}

TEST_F(SeekableBufferTest, AllMethods) {
  EXPECT_EQ(0, buffer_.Read(write_buffer_, 0));
  EXPECT_EQ(0, buffer_.Read(write_buffer_, 1));
  EXPECT_TRUE(buffer_.Seek(0));
  EXPECT_FALSE(buffer_.Seek(-1));
  EXPECT_FALSE(buffer_.Seek(1));
  EXPECT_EQ(0, buffer_.forward_bytes());
  EXPECT_EQ(0, buffer_.backward_bytes());
}

TEST_F(SeekableBufferTest, GetTime) {
  const int64 kNoTS = kNoTimestamp().ToInternalValue();
  const struct {
    int64 first_time_useconds;
    int64 duration_useconds;
    int consume_bytes;
    int64 expected_time;
  } tests[] = {
    { kNoTS, 1000000, 0, kNoTS },
    { kNoTS, 4000000, 0, kNoTS },
    { kNoTS, 8000000, 0, kNoTS },
    { kNoTS, 1000000, kWriteSize / 2, kNoTS },
    { kNoTS, 4000000, kWriteSize / 2, kNoTS },
    { kNoTS, 8000000, kWriteSize / 2, kNoTS },
    { kNoTS, 1000000, kWriteSize, kNoTS },
    { kNoTS, 4000000, kWriteSize, kNoTS },
    { kNoTS, 8000000, kWriteSize, kNoTS },
    { 0, 1000000, 0, 0 },
    { 0, 4000000, 0, 0 },
    { 0, 8000000, 0, 0 },
    { 0, 1000000, kWriteSize / 2, 500000 },
    { 0, 4000000, kWriteSize / 2, 2000000 },
    { 0, 8000000, kWriteSize / 2, 4000000 },
    { 0, 1000000, kWriteSize, 1000000 },
    { 0, 4000000, kWriteSize, 4000000 },
    { 0, 8000000, kWriteSize, 8000000 },
    { 5, 1000000, 0, 5 },
    { 5, 4000000, 0, 5 },
    { 5, 8000000, 0, 5 },
    { 5, 1000000, kWriteSize / 2, 500005 },
    { 5, 4000000, kWriteSize / 2, 2000005 },
    { 5, 8000000, kWriteSize / 2, 4000005 },
    { 5, 1000000, kWriteSize, 1000005 },
    { 5, 4000000, kWriteSize, 4000005 },
    { 5, 8000000, kWriteSize, 8000005 },
  };

  // current_time() must initially return kNoTimestamp().
  EXPECT_EQ(kNoTimestamp().ToInternalValue(),
            buffer_.current_time().ToInternalValue());

  scoped_refptr<DataBuffer> buffer = DataBuffer::CopyFrom(data_, kWriteSize);

  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
    buffer->set_timestamp(base::TimeDelta::FromMicroseconds(
        tests[i].first_time_useconds));
    buffer->set_duration(base::TimeDelta::FromMicroseconds(
        tests[i].duration_useconds));
    buffer_.Append(buffer.get());
    EXPECT_TRUE(buffer_.Seek(tests[i].consume_bytes));

    int64 actual = buffer_.current_time().ToInternalValue();

    EXPECT_EQ(tests[i].expected_time, actual) << "With test = { start:"
        << tests[i].first_time_useconds << ", duration:"
        << tests[i].duration_useconds << ", consumed:"
        << tests[i].consume_bytes << " }\n";

    buffer_.Clear();
  }
}

}  // namespace media

/* [<][>][^][v][top][bottom][index][help] */