| Index: net/filter/brotli_source_stream_unittest.cc
|
| diff --git a/net/filter/brotli_source_stream_unittest.cc b/net/filter/brotli_source_stream_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..363c554719008296673e89fce3531083f18e2863
|
| --- /dev/null
|
| +++ b/net/filter/brotli_source_stream_unittest.cc
|
| @@ -0,0 +1,258 @@
|
| +// 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 <string>
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/bit_cast.h"
|
| +#include "base/callback.h"
|
| +#include "base/files/file_util.h"
|
| +#include "base/path_service.h"
|
| +#include "base/run_loop.h"
|
| +#include "net/base/io_buffer.h"
|
| +#include "net/base/test_completion_callback.h"
|
| +#include "net/filter/brotli_source_stream.h"
|
| +#include "net/filter/mock_source_stream.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +#include "testing/platform_test.h"
|
| +
|
| +namespace net {
|
| +
|
| +namespace {
|
| +
|
| +const size_t kDefaultBufferSize = 4096;
|
| +const size_t kSmallBufferSize = 128;
|
| +
|
| +} // namespace
|
| +
|
| +class BrotliSourceStreamTest : public PlatformTest {
|
| + protected:
|
| + void SetUp() override {
|
| + PlatformTest::SetUp();
|
| +
|
| + // Get the path of data directory.
|
| + base::FilePath data_dir;
|
| + PathService::Get(base::DIR_SOURCE_ROOT, &data_dir);
|
| + data_dir = data_dir.AppendASCII("net");
|
| + data_dir = data_dir.AppendASCII("data");
|
| + data_dir = data_dir.AppendASCII("filter_unittests");
|
| +
|
| + // Read data from the original file into buffer.
|
| + base::FilePath file_path;
|
| + file_path = data_dir.AppendASCII("google.txt");
|
| + ASSERT_TRUE(base::ReadFileToString(file_path, &source_data_));
|
| + ASSERT_GE(kDefaultBufferSize, source_data_.size());
|
| +
|
| + // Read data from the encoded file into buffer.
|
| + base::FilePath encoded_file_path;
|
| + encoded_file_path = data_dir.AppendASCII("google.br");
|
| + ASSERT_TRUE(base::ReadFileToString(encoded_file_path, &encoded_buffer_));
|
| + ASSERT_GE(kDefaultBufferSize, encoded_buffer_.size());
|
| +
|
| + std::unique_ptr<MockSourceStream> source(new MockSourceStream);
|
| + source_ = source.get();
|
| + brotli_stream_ = CreateBrotliSourceStream(std::move(source));
|
| + }
|
| +
|
| + int ReadStream(const TestCompletionCallback& callback) {
|
| + return brotli_stream_->Read(out_buffer(), out_data_size(),
|
| + callback.callback());
|
| + }
|
| +
|
| + IOBuffer* out_buffer() { return out_buffer_.get(); }
|
| + char* out_data() { return out_buffer_->data(); }
|
| + size_t out_data_size() { return out_buffer_->size(); }
|
| +
|
| + std::string source_data() { return source_data_; }
|
| +
|
| + size_t source_data_len() { return source_data_.length(); }
|
| +
|
| + char* encoded_buffer() { return &encoded_buffer_[0]; }
|
| +
|
| + size_t encoded_len() { return encoded_buffer_.length(); }
|
| +
|
| + MockSourceStream* source() { return source_; }
|
| + SourceStream* brotli_stream() { return brotli_stream_.get(); }
|
| + scoped_refptr<IOBufferWithSize> out_buffer_;
|
| +
|
| + private:
|
| + MockSourceStream* source_;
|
| + std::unique_ptr<SourceStream> brotli_stream_;
|
| + std::unique_ptr<base::RunLoop> loop_;
|
| +
|
| + std::string source_data_;
|
| + std::string encoded_buffer_;
|
| +};
|
| +
|
| +// Basic scenario: decoding brotli data with big enough buffer.
|
| +TEST_F(BrotliSourceStreamTest, DecodeBrotliOneBlockSync) {
|
| + source()->AddReadResult(encoded_buffer(), encoded_len(), OK, true);
|
| + out_buffer_ = new IOBufferWithSize(kDefaultBufferSize);
|
| + TestCompletionCallback callback;
|
| + int bytes_read = ReadStream(callback);
|
| +
|
| + EXPECT_EQ(static_cast<int>(source_data_len()), bytes_read);
|
| + EXPECT_EQ(0, memcmp(out_data(), source_data().c_str(), source_data_len()));
|
| + EXPECT_EQ("BROTLI", brotli_stream()->OrderedTypeStringList());
|
| +}
|
| +
|
| +// Basic scenario: decoding brotli data with big enough buffer.
|
| +TEST_F(BrotliSourceStreamTest, DecodeBrotliTwoBlockSync) {
|
| + source()->AddReadResult(encoded_buffer(), 10, OK, true);
|
| + source()->AddReadResult(encoded_buffer() + 10, encoded_len() - 10, OK, true);
|
| + out_buffer_ = new IOBufferWithSize(kDefaultBufferSize);
|
| + TestCompletionCallback callback;
|
| + int bytes_read = ReadStream(callback);
|
| + EXPECT_EQ(static_cast<int>(source_data_len()), bytes_read);
|
| + EXPECT_EQ(0, memcmp(out_data(), source_data().c_str(), source_data_len()));
|
| + EXPECT_EQ("BROTLI", brotli_stream()->OrderedTypeStringList());
|
| +}
|
| +
|
| +// Basic scenario: decoding brotli data with big enough buffer.
|
| +TEST_F(BrotliSourceStreamTest, DecodeBrotliOneBlockAsync) {
|
| + source()->AddReadResult(encoded_buffer(), encoded_len(), OK, false);
|
| + out_buffer_ = new IOBufferWithSize(kDefaultBufferSize);
|
| + TestCompletionCallback callback;
|
| + int bytes_read = ReadStream(callback);
|
| +
|
| + EXPECT_EQ(ERR_IO_PENDING, bytes_read);
|
| + source()->CompleteNextRead();
|
| + int rv = callback.WaitForResult();
|
| + EXPECT_EQ(static_cast<int>(source_data_len()), rv);
|
| + EXPECT_EQ(0, memcmp(out_data(), source_data().c_str(), source_data_len()));
|
| + EXPECT_EQ("BROTLI", brotli_stream()->OrderedTypeStringList());
|
| +}
|
| +
|
| +// Tests we can call filter repeatedly to get all the data decoded.
|
| +// To do that, we create a filter with a small buffer that can not hold all
|
| +// the input data.
|
| +TEST_F(BrotliSourceStreamTest, DecodeWithSmallBufferSync) {
|
| + source()->AddReadResult(encoded_buffer(), encoded_len(), OK, true);
|
| + out_buffer_ = new IOBufferWithSize(kSmallBufferSize);
|
| +
|
| + scoped_refptr<IOBuffer> buffer = new IOBufferWithSize(source_data_len());
|
| + size_t total_bytes_read = 0;
|
| + int bytes_read = 0;
|
| + TestCompletionCallback callback;
|
| + do {
|
| + bytes_read = ReadStream(callback);
|
| + EXPECT_GE(kSmallBufferSize, static_cast<size_t>(bytes_read));
|
| + memcpy(buffer->data() + total_bytes_read, out_data(), bytes_read);
|
| + total_bytes_read += bytes_read;
|
| + } while (bytes_read > 0);
|
| + EXPECT_EQ(source_data_len(), total_bytes_read);
|
| + EXPECT_EQ(0, memcmp(buffer->data(), source_data().c_str(), total_bytes_read));
|
| + EXPECT_EQ("BROTLI", brotli_stream()->OrderedTypeStringList());
|
| +}
|
| +
|
| +// Tests we can call filter repeatedly to get all the data decoded.
|
| +// To do that, we create a filter with a small buffer that can not hold all
|
| +// the input data.
|
| +TEST_F(BrotliSourceStreamTest, DecodeWithSmallBufferAsync) {
|
| + source()->AddReadResult(encoded_buffer(), encoded_len(), OK, false);
|
| + out_buffer_ = new IOBufferWithSize(kSmallBufferSize);
|
| +
|
| + scoped_refptr<IOBuffer> buffer = new IOBufferWithSize(source_data_len());
|
| + size_t total_bytes_read = 0;
|
| + int bytes_read = 0;
|
| + do {
|
| + TestCompletionCallback callback;
|
| + bytes_read = ReadStream(callback);
|
| + if (bytes_read == ERR_IO_PENDING) {
|
| + source()->CompleteNextRead();
|
| + bytes_read = callback.WaitForResult();
|
| + }
|
| + EXPECT_GE(static_cast<int>(kSmallBufferSize), bytes_read);
|
| + memcpy(buffer->data() + total_bytes_read, out_data(), bytes_read);
|
| + total_bytes_read += bytes_read;
|
| + } while (bytes_read > 0);
|
| + EXPECT_EQ(source_data_len(), total_bytes_read);
|
| + EXPECT_EQ(0, memcmp(buffer->data(), source_data().c_str(), total_bytes_read));
|
| + EXPECT_EQ("BROTLI", brotli_stream()->OrderedTypeStringList());
|
| +}
|
| +
|
| +// Tests we can still decode with just 1 byte buffer in the filter.
|
| +// The purpose of this test: sometimes the filter will consume input without
|
| +// generating output. Verify filter can handle it correctly.
|
| +TEST_F(BrotliSourceStreamTest, DecodeWithOneByteBuffer) {
|
| + source()->AddReadResult(encoded_buffer(), encoded_len(), OK, true);
|
| + out_buffer_ = new IOBufferWithSize(1);
|
| + scoped_refptr<IOBuffer> buffer = new IOBufferWithSize(source_data_len());
|
| + size_t total_bytes_read = 0;
|
| + int bytes_read = 0;
|
| + do {
|
| + TestCompletionCallback callback;
|
| + bytes_read = ReadStream(callback);
|
| + EXPECT_NE(ERR_IO_PENDING, bytes_read);
|
| + EXPECT_GE(1, bytes_read);
|
| + memcpy(buffer->data() + total_bytes_read, out_data(), bytes_read);
|
| + total_bytes_read += bytes_read;
|
| + } while (bytes_read > 0);
|
| + EXPECT_EQ(source_data_len(), total_bytes_read);
|
| + EXPECT_EQ(0,
|
| + memcmp(buffer->data(), source_data().c_str(), source_data_len()));
|
| + EXPECT_EQ("BROTLI", brotli_stream()->OrderedTypeStringList());
|
| +}
|
| +
|
| +// Decoding deflate stream with corrupted data.
|
| +TEST_F(BrotliSourceStreamTest, DecodeCorruptedData) {
|
| + char corrupt_data[kDefaultBufferSize];
|
| + int corrupt_data_len = encoded_len();
|
| + memcpy(corrupt_data, encoded_buffer(), encoded_len());
|
| + int pos = corrupt_data_len / 2;
|
| + corrupt_data[pos] = !corrupt_data[pos];
|
| +
|
| + source()->AddReadResult(corrupt_data, corrupt_data_len, OK, true);
|
| + out_buffer_ = new IOBufferWithSize(kDefaultBufferSize);
|
| + int error = OK;
|
| + do {
|
| + TestCompletionCallback callback;
|
| + error = ReadStream(callback);
|
| + EXPECT_NE(ERR_IO_PENDING, error);
|
| + } while (error > 0);
|
| + // Expect failures
|
| + EXPECT_EQ(ERR_CONTENT_DECODING_FAILED, error);
|
| + EXPECT_EQ("BROTLI", brotli_stream()->OrderedTypeStringList());
|
| +}
|
| +
|
| +// Decoding deflate stream with missing data.
|
| +TEST_F(BrotliSourceStreamTest, DecodeMissingData) {
|
| + char corrupt_data[kDefaultBufferSize];
|
| + int corrupt_data_len = encoded_len();
|
| + memcpy(corrupt_data, encoded_buffer(), encoded_len());
|
| +
|
| + int pos = corrupt_data_len / 2;
|
| + int len = corrupt_data_len - pos - 1;
|
| + memmove(&corrupt_data[pos], &corrupt_data[pos + 1], len);
|
| + --corrupt_data_len;
|
| +
|
| + // Decode the corrupted data with filter
|
| + source()->AddReadResult(corrupt_data, corrupt_data_len, OK, true);
|
| + out_buffer_ = new IOBufferWithSize(kDefaultBufferSize);
|
| + int error = OK;
|
| + do {
|
| + TestCompletionCallback callback;
|
| + error = ReadStream(callback);
|
| + EXPECT_NE(ERR_IO_PENDING, error);
|
| + } while (error > 0);
|
| + // Expect failures
|
| + EXPECT_EQ(ERR_CONTENT_DECODING_FAILED, error);
|
| + EXPECT_EQ("BROTLI", brotli_stream()->OrderedTypeStringList());
|
| +}
|
| +
|
| +// Decoding brotli stream with empty output data.
|
| +TEST_F(BrotliSourceStreamTest, DecodeEmptyData) {
|
| + char data[1] = {6}; // WBITS = 16, ISLAST = 1, ISLASTEMPTY = 1
|
| + int data_len = 1;
|
| +
|
| + // Decode the corrupted data with filter
|
| + source()->AddReadResult(data, data_len, OK, true);
|
| + out_buffer_ = new IOBufferWithSize(kDefaultBufferSize);
|
| + TestCompletionCallback callback;
|
| + int bytes_read = ReadStream(callback);
|
| + EXPECT_EQ(OK, bytes_read);
|
| + EXPECT_EQ("BROTLI", brotli_stream()->OrderedTypeStringList());
|
| +}
|
| +
|
| +} // namespace net
|
|
|