| // Copyright (c) 2011 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 <map> |
| #include <string> |
| |
| #include "base/memory/scoped_ptr.h" |
| #include "chrome/common/extensions/extension_message_bundle.h" |
| #include "chrome/common/extensions/extension_localization_peer.h" |
| #include "ipc/ipc_message.h" |
| #include "ipc/ipc_sync_message.h" |
| #include "net/base/net_errors.h" |
| #include "net/url_request/url_request_status.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "webkit/glue/resource_loader_bridge.h" |
| |
| using testing::_; |
| using testing::DoAll; |
| using testing::Invoke; |
| using testing::StrEq; |
| using testing::Return; |
| |
| static const char* const kExtensionUrl_1 = |
| "chrome-extension://some_id/popup.css"; |
| |
| static const char* const kExtensionUrl_2 = |
| "chrome-extension://some_id2/popup.css"; |
| |
| static const char* const kExtensionUrl_3 = |
| "chrome-extension://some_id3/popup.css"; |
| |
| void MessageDeleter(IPC::Message* message) { |
| delete static_cast<IPC::SyncMessage*>(message)->GetReplyDeserializer(); |
| delete message; |
| } |
| |
| class MockIpcMessageSender : public IPC::Message::Sender { |
| public: |
| MockIpcMessageSender() { |
| ON_CALL(*this, Send(_)) |
| .WillByDefault(DoAll(Invoke(MessageDeleter), Return(true))); |
| } |
| |
| virtual ~MockIpcMessageSender() {} |
| |
| MOCK_METHOD1(Send, bool(IPC::Message* message)); |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(MockIpcMessageSender); |
| }; |
| |
| class MockResourceLoaderBridgePeer |
| : public webkit_glue::ResourceLoaderBridge::Peer { |
| public: |
| MockResourceLoaderBridgePeer() {} |
| virtual ~MockResourceLoaderBridgePeer() {} |
| |
| MOCK_METHOD2(OnUploadProgress, void(uint64 position, uint64 size)); |
| MOCK_METHOD4(OnReceivedRedirect, bool( |
| const GURL& new_url, |
| const webkit_glue::ResourceResponseInfo& info, |
| bool* has_new_first_party_for_cookies, |
| GURL* new_first_party_for_cookies)); |
| MOCK_METHOD1(OnReceivedResponse, void( |
| const webkit_glue::ResourceResponseInfo& info)); |
| MOCK_METHOD1(OnDownloadedData, void(int len)); |
| MOCK_METHOD3(OnReceivedData, void(const char* data, |
| int data_length, |
| int encoded_data_length)); |
| MOCK_METHOD3(OnCompletedRequest, void( |
| const net::URLRequestStatus& status, |
| const std::string& security_info, |
| const base::Time& completion_time)); |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(MockResourceLoaderBridgePeer); |
| }; |
| |
| class ExtensionLocalizationPeerTest : public testing::Test { |
| protected: |
| virtual void SetUp() { |
| sender_.reset(new MockIpcMessageSender()); |
| original_peer_.reset(new MockResourceLoaderBridgePeer()); |
| filter_peer_.reset( |
| ExtensionLocalizationPeer::CreateExtensionLocalizationPeer( |
| original_peer_.get(), sender_.get(), "text/css", |
| GURL(kExtensionUrl_1))); |
| } |
| |
| ExtensionLocalizationPeer* CreateExtensionLocalizationPeer( |
| const std::string& mime_type, |
| const GURL& request_url) { |
| return ExtensionLocalizationPeer::CreateExtensionLocalizationPeer( |
| original_peer_.get(), sender_.get(), mime_type, request_url); |
| } |
| |
| std::string GetData(ExtensionLocalizationPeer* filter_peer) { |
| EXPECT_TRUE(NULL != filter_peer); |
| return filter_peer->data_; |
| } |
| |
| void SetData(ExtensionLocalizationPeer* filter_peer, |
| const std::string& data) { |
| EXPECT_TRUE(NULL != filter_peer); |
| filter_peer->data_ = data; |
| } |
| |
| scoped_ptr<MockIpcMessageSender> sender_; |
| scoped_ptr<MockResourceLoaderBridgePeer> original_peer_; |
| scoped_ptr<ExtensionLocalizationPeer> filter_peer_; |
| }; |
| |
| TEST_F(ExtensionLocalizationPeerTest, CreateWithWrongMimeType) { |
| filter_peer_.reset( |
| CreateExtensionLocalizationPeer("text/html", GURL(kExtensionUrl_1))); |
| EXPECT_TRUE(NULL == filter_peer_.get()); |
| } |
| |
| TEST_F(ExtensionLocalizationPeerTest, CreateWithValidInput) { |
| EXPECT_TRUE(NULL != filter_peer_.get()); |
| } |
| |
| TEST_F(ExtensionLocalizationPeerTest, OnReceivedData) { |
| EXPECT_TRUE(GetData(filter_peer_.get()).empty()); |
| |
| const std::string data_chunk("12345"); |
| filter_peer_->OnReceivedData(data_chunk.c_str(), data_chunk.length(), -1); |
| |
| EXPECT_EQ(data_chunk, GetData(filter_peer_.get())); |
| |
| filter_peer_->OnReceivedData(data_chunk.c_str(), data_chunk.length(), -1); |
| EXPECT_EQ(data_chunk + data_chunk, GetData(filter_peer_.get())); |
| } |
| |
| MATCHER_P(IsURLRequestEqual, status, "") { return arg.status() == status; } |
| |
| TEST_F(ExtensionLocalizationPeerTest, OnCompletedRequestBadURLRequestStatus) { |
| // It will self-delete once it exits OnCompletedRequest. |
| ExtensionLocalizationPeer* filter_peer = filter_peer_.release(); |
| |
| EXPECT_CALL(*original_peer_, OnReceivedResponse(_)); |
| EXPECT_CALL(*original_peer_, OnCompletedRequest( |
| IsURLRequestEqual(net::URLRequestStatus::CANCELED), "", base::Time())); |
| |
| net::URLRequestStatus status; |
| status.set_status(net::URLRequestStatus::FAILED); |
| filter_peer->OnCompletedRequest(status, "", base::Time()); |
| } |
| |
| TEST_F(ExtensionLocalizationPeerTest, OnCompletedRequestEmptyData) { |
| // It will self-delete once it exits OnCompletedRequest. |
| ExtensionLocalizationPeer* filter_peer = filter_peer_.release(); |
| |
| EXPECT_CALL(*original_peer_, OnReceivedData(_, _, _)).Times(0); |
| EXPECT_CALL(*sender_, Send(_)).Times(0); |
| |
| EXPECT_CALL(*original_peer_, OnReceivedResponse(_)); |
| EXPECT_CALL(*original_peer_, OnCompletedRequest( |
| IsURLRequestEqual(net::URLRequestStatus::SUCCESS), "", base::Time())); |
| |
| net::URLRequestStatus status; |
| status.set_status(net::URLRequestStatus::SUCCESS); |
| filter_peer->OnCompletedRequest(status, "", base::Time()); |
| } |
| |
| TEST_F(ExtensionLocalizationPeerTest, OnCompletedRequestNoCatalogs) { |
| // It will self-delete once it exits OnCompletedRequest. |
| ExtensionLocalizationPeer* filter_peer = filter_peer_.release(); |
| |
| SetData(filter_peer, "some text"); |
| |
| EXPECT_CALL(*sender_, Send(_)); |
| |
| std::string data = GetData(filter_peer); |
| EXPECT_CALL(*original_peer_, |
| OnReceivedData(StrEq(data.data()), data.length(), -1)).Times(2); |
| |
| EXPECT_CALL(*original_peer_, OnReceivedResponse(_)).Times(2); |
| EXPECT_CALL(*original_peer_, OnCompletedRequest( |
| IsURLRequestEqual( |
| net::URLRequestStatus::SUCCESS), "", base::Time())).Times(2); |
| |
| net::URLRequestStatus status; |
| status.set_status(net::URLRequestStatus::SUCCESS); |
| filter_peer->OnCompletedRequest(status, "", base::Time()); |
| |
| // Test if Send gets called again (it shouldn't be) when first call returned |
| // an empty dictionary. |
| filter_peer = |
| CreateExtensionLocalizationPeer("text/css", GURL(kExtensionUrl_1)); |
| SetData(filter_peer, "some text"); |
| filter_peer->OnCompletedRequest(status, "", base::Time()); |
| } |
| |
| TEST_F(ExtensionLocalizationPeerTest, OnCompletedRequestWithCatalogs) { |
| // It will self-delete once it exits OnCompletedRequest. |
| ExtensionLocalizationPeer* filter_peer = |
| CreateExtensionLocalizationPeer("text/css", GURL(kExtensionUrl_2)); |
| |
| L10nMessagesMap messages; |
| messages.insert(std::make_pair("text", "new text")); |
| ExtensionToL10nMessagesMap& l10n_messages_map = |
| *GetExtensionToL10nMessagesMap(); |
| l10n_messages_map["some_id2"] = messages; |
| |
| SetData(filter_peer, "some __MSG_text__"); |
| |
| // We already have messages in memory, Send will be skipped. |
| EXPECT_CALL(*sender_, Send(_)).Times(0); |
| |
| // __MSG_text__ gets replaced with "new text". |
| std::string data("some new text"); |
| EXPECT_CALL(*original_peer_, |
| OnReceivedData(StrEq(data.data()), data.length(), -1)); |
| |
| EXPECT_CALL(*original_peer_, OnReceivedResponse(_)); |
| EXPECT_CALL(*original_peer_, OnCompletedRequest( |
| IsURLRequestEqual(net::URLRequestStatus::SUCCESS), "", base::Time())); |
| |
| net::URLRequestStatus status; |
| status.set_status(net::URLRequestStatus::SUCCESS); |
| filter_peer->OnCompletedRequest(status, "", base::Time()); |
| } |
| |
| TEST_F(ExtensionLocalizationPeerTest, OnCompletedRequestReplaceMessagesFails) { |
| // It will self-delete once it exits OnCompletedRequest. |
| ExtensionLocalizationPeer* filter_peer = |
| CreateExtensionLocalizationPeer("text/css", GURL(kExtensionUrl_3)); |
| |
| L10nMessagesMap messages; |
| messages.insert(std::make_pair("text", "new text")); |
| ExtensionToL10nMessagesMap& l10n_messages_map = |
| *GetExtensionToL10nMessagesMap(); |
| l10n_messages_map["some_id3"] = messages; |
| |
| std::string message("some __MSG_missing_message__"); |
| SetData(filter_peer, message); |
| |
| // We already have messages in memory, Send will be skipped. |
| EXPECT_CALL(*sender_, Send(_)).Times(0); |
| |
| // __MSG_missing_message__ is missing, so message stays the same. |
| EXPECT_CALL(*original_peer_, |
| OnReceivedData(StrEq(message.data()), message.length(), -1)); |
| |
| EXPECT_CALL(*original_peer_, OnReceivedResponse(_)); |
| EXPECT_CALL(*original_peer_, OnCompletedRequest( |
| IsURLRequestEqual(net::URLRequestStatus::SUCCESS), "", base::Time())); |
| |
| net::URLRequestStatus status; |
| status.set_status(net::URLRequestStatus::SUCCESS); |
| filter_peer->OnCompletedRequest(status, "", base::Time()); |
| } |