| Index: net/filter/sdch_stream_source_unittest.cc
|
| diff --git a/net/filter/sdch_stream_source_unittest.cc b/net/filter/sdch_stream_source_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..bd37aefffc9b184ea4a4983ce8dee00e11cd6ac5
|
| --- /dev/null
|
| +++ b/net/filter/sdch_stream_source_unittest.cc
|
| @@ -0,0 +1,241 @@
|
| +// 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/callback.h"
|
| +#include "net/base/io_buffer.h"
|
| +#include "net/filter/mock_stream_source.h"
|
| +#include "net/filter/sdch_stream_source.h"
|
| +#include "net/filter/sdch_stream_source_delegate.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +namespace {
|
| +
|
| +using net::Error;
|
| +using net::MockStreamSource;
|
| +using net::SdchStreamSource;
|
| +
|
| +const size_t kBufferSize = 4096;
|
| +const char* kDictionaryError = "dictionary error";
|
| +const char* kDecodingError = "decoding error";
|
| +
|
| +static const char kTestVcdiffDictionary[] =
|
| + "DictionaryFor"
|
| + "SdchCompression1SdchCompression2SdchCompression3SdchCompression\n";
|
| +static const char kTestData[] =
|
| + "0000000000000000000000000000000000000000000000"
|
| + "0000000000000000000000000000TestData "
|
| + "SdchCompression1SdchCompression2SdchCompression3SdchCompression"
|
| + "00000000000000000000000000000000000000000000000000000000000000000000000000"
|
| + "000000000000000000000000000000000000000\n";
|
| +static const char kSdchCompressedTestData[] =
|
| + "\326\303\304\0\0\001M\0\201S\202\004\0\201E\006\001"
|
| + "00000000000000000000000000000000000000000000000000000000000000000000000000"
|
| + "TestData 00000000000000000000000000000000000000000000000000000000000000000"
|
| + "000000000000000000000000000000000000000000000000\n\001S\023\077\001r\r";
|
| +
|
| +class SdchStreamSourceTest : public ::testing::Test,
|
| + public net::SdchStreamSourceDelegate {
|
| + public:
|
| + SdchStreamSourceTest()
|
| + : dictionary_error_handled_(false), decoding_error_handled_(false) {}
|
| +
|
| + void SetUp() override {
|
| + ::testing::Test::SetUp();
|
| +
|
| + out_buffer_ = new net::IOBuffer(kBufferSize);
|
| +
|
| + scoped_ptr<MockStreamSource> source(new MockStreamSource);
|
| + source_ = source.get();
|
| + sdch_stream_.reset(new SdchStreamSource(std::move(source), this));
|
| + }
|
| +
|
| + net::IOBuffer* out_buffer() { return out_buffer_.get(); }
|
| + char* out_data() { return out_buffer_->data(); }
|
| + size_t out_buffer_size() { return kBufferSize; }
|
| +
|
| + Error last_error() { return last_error_; }
|
| + size_t last_bytes_read() { return last_bytes_read_; }
|
| +
|
| + MockStreamSource* source() { return source_; }
|
| + SdchStreamSource* sdch_stream() { return sdch_stream_.get(); }
|
| +
|
| + bool dictionary_error_handled() { return dictionary_error_handled_; }
|
| + bool decoding_error_handled() { return decoding_error_handled_; }
|
| + std::string last_get_dictionary_id() { return last_get_dictionary_id_; }
|
| +
|
| + net::StreamSource::OnReadCompleteCallback callback() {
|
| + return base::Bind(&SdchStreamSourceTest::OnReadComplete,
|
| + base::Unretained(this));
|
| + }
|
| +
|
| + void OnReadComplete(Error error, size_t bytes_read) {
|
| + last_error_ = error;
|
| + last_bytes_read_ = bytes_read;
|
| + }
|
| +
|
| + void ReadStream() {
|
| + last_error_ = sdch_stream()->Read(out_buffer(), out_buffer_size(),
|
| + &last_bytes_read_, callback());
|
| + }
|
| +
|
| + void SetTestDictionary(const std::string& dictionary_id,
|
| + const std::string& dictionary_text) {
|
| + test_dictionary_id_ = dictionary_id;
|
| + test_dictionary_text_ = dictionary_text;
|
| + }
|
| +
|
| + void AppendDictionaryIdTo(std::string* resp, std::string* server_id) {
|
| + std::string client_id;
|
| + net::SdchManager::GenerateHash(kTestVcdiffDictionary, &client_id,
|
| + server_id);
|
| + SetTestDictionary(*server_id, kTestVcdiffDictionary);
|
| + char response[server_id->size() + 1];
|
| + memcpy(response, server_id->data(), server_id->size());
|
| + response[server_id->size()] = '\0';
|
| + resp->append(response, server_id->size() + 1);
|
| + }
|
| +
|
| + // SdchStreamSourceDelegate implementation.
|
| + bool HandleDictionaryError(SdchStreamSource* source) override {
|
| + dictionary_error_handled_ = true;
|
| + sdch_stream()->ReplaceOutput(kDictionaryError, strlen(kDictionaryError));
|
| + return true;
|
| + }
|
| +
|
| + bool HandleDecodingError(SdchStreamSource* source) override {
|
| + decoding_error_handled_ = true;
|
| + sdch_stream()->ReplaceOutput(kDecodingError, strlen(kDictionaryError));
|
| + return true;
|
| + }
|
| +
|
| + bool GetDictionary(const std::string& server_id,
|
| + const std::string** text) override {
|
| + last_get_dictionary_id_ = server_id;
|
| + if (server_id == test_dictionary_id_) {
|
| + *text = &test_dictionary_text_;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + void NotifyStreamDone() override {}
|
| +
|
| + private:
|
| + // Owned by sdch_stream_.
|
| + MockStreamSource* source_;
|
| + scoped_ptr<SdchStreamSource> sdch_stream_;
|
| +
|
| + scoped_refptr<net::IOBuffer> out_buffer_;
|
| +
|
| + std::string test_dictionary_id_;
|
| + std::string test_dictionary_text_;
|
| +
|
| + size_t last_bytes_read_;
|
| + Error last_error_;
|
| + std::string last_get_dictionary_id_;
|
| + bool dictionary_error_handled_;
|
| + bool decoding_error_handled_;
|
| +};
|
| +
|
| +TEST_F(SdchStreamSourceTest, EmptyStream) {
|
| + source()->AddReadResult("", 0, net::OK, true);
|
| + ReadStream();
|
| + EXPECT_EQ(net::OK, last_error());
|
| + EXPECT_EQ(0U, last_bytes_read());
|
| +}
|
| +
|
| +// Ensure that GetDictionary() is not called at all if the SDCH dictionary ID is
|
| +// malformed.
|
| +TEST_F(SdchStreamSourceTest, BogusDictionaryId) {
|
| + char id[] = {0x1f, '0', '0', '0', '0', '0', '0', '0', 0x0};
|
| + source()->AddReadResult(id, sizeof(id), net::OK, true);
|
| + SetTestDictionary(id, "...");
|
| + ReadStream();
|
| + EXPECT_TRUE(dictionary_error_handled());
|
| + EXPECT_EQ("", last_get_dictionary_id());
|
| + EXPECT_EQ(net::OK, last_error());
|
| + EXPECT_EQ(strlen(kDictionaryError), last_bytes_read());
|
| + EXPECT_EQ(0, memcmp(kDictionaryError, out_data(), last_bytes_read()));
|
| +}
|
| +
|
| +// Ensure that the stream's dictionary error handler is called if GetDictionary
|
| +// returns no dictionary.
|
| +TEST_F(SdchStreamSourceTest, NoDictionaryError) {
|
| + char id[] = "00000000";
|
| + source()->AddReadResult(id, sizeof(id), net::OK, true);
|
| + ReadStream();
|
| + EXPECT_TRUE(dictionary_error_handled());
|
| + EXPECT_EQ(id, last_get_dictionary_id());
|
| +}
|
| +
|
| +TEST_F(SdchStreamSourceTest, DictionaryLoaded) {
|
| + std::string response;
|
| + std::string server_id;
|
| + AppendDictionaryIdTo(&response, &server_id);
|
| + source()->AddReadResult(response.data(), response.size(), net::OK, true);
|
| + ReadStream();
|
| + EXPECT_FALSE(dictionary_error_handled());
|
| + EXPECT_EQ(server_id, last_get_dictionary_id());
|
| +}
|
| +
|
| +TEST_F(SdchStreamSourceTest, DecompressOneBlockSync) {
|
| + std::string response;
|
| + std::string server_id;
|
| + AppendDictionaryIdTo(&response, &server_id);
|
| + source()->AddReadResult(response.data(), response.size(), net::OK, true);
|
| + source()->AddReadResult(kSdchCompressedTestData,
|
| + sizeof(kSdchCompressedTestData) - 1, net::OK, true);
|
| + ReadStream();
|
| + EXPECT_FALSE(dictionary_error_handled());
|
| + EXPECT_FALSE(decoding_error_handled());
|
| + EXPECT_EQ(server_id, last_get_dictionary_id());
|
| + EXPECT_EQ(net::OK, last_error());
|
| + EXPECT_EQ(sizeof(kTestData) - 1, last_bytes_read());
|
| + EXPECT_EQ(0, memcmp(kTestData, out_data(), last_bytes_read()));
|
| +}
|
| +
|
| +TEST_F(SdchStreamSourceTest, DecompressTwoBlocksSync) {
|
| + std::string response;
|
| + std::string server_id;
|
| + AppendDictionaryIdTo(&response, &server_id);
|
| + source()->AddReadResult(response.data(), response.size(), net::OK, true);
|
| + source()->AddReadResult(kSdchCompressedTestData, 32, net::OK, true);
|
| + source()->AddReadResult(kSdchCompressedTestData + 32,
|
| + sizeof(kSdchCompressedTestData) - 1 - 32, net::OK,
|
| + true);
|
| + ReadStream();
|
| + EXPECT_FALSE(dictionary_error_handled());
|
| + EXPECT_FALSE(decoding_error_handled());
|
| + EXPECT_EQ(server_id, last_get_dictionary_id());
|
| + EXPECT_EQ(net::OK, last_error());
|
| + EXPECT_EQ(sizeof(kTestData) - 1, last_bytes_read());
|
| + EXPECT_EQ(0, memcmp(kTestData, out_data(), last_bytes_read()));
|
| +}
|
| +
|
| +TEST_F(SdchStreamSourceTest, DecompressOneBlockAsync) {
|
| + std::string response;
|
| + std::string server_id;
|
| + AppendDictionaryIdTo(&response, &server_id);
|
| + source()->AddReadResult(response.data(), response.size(), net::OK, false);
|
| + source()->AddReadResult(kSdchCompressedTestData,
|
| + sizeof(kSdchCompressedTestData) - 1, net::OK, false);
|
| + ReadStream();
|
| + EXPECT_EQ(net::ERR_IO_PENDING, last_error());
|
| + source()->CompleteNextRead();
|
| + // The callback hasn't been called yet, because the first read didn't return
|
| + // any bytes that could be decoded to produce output.
|
| + EXPECT_EQ(net::ERR_IO_PENDING, last_error());
|
| + source()->CompleteNextRead();
|
| + EXPECT_FALSE(dictionary_error_handled());
|
| + EXPECT_FALSE(decoding_error_handled());
|
| + EXPECT_EQ(server_id, last_get_dictionary_id());
|
| + EXPECT_EQ(net::OK, last_error());
|
| + EXPECT_EQ(sizeof(kTestData) - 1, last_bytes_read());
|
| + EXPECT_EQ(0, memcmp(kTestData, out_data(), last_bytes_read()));
|
| +}
|
| +
|
| +} // namespace
|
|
|