1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <map> 6 #include <string> 7 8 #include "base/memory/scoped_ptr.h" 9 #include "chrome/common/extensions/message_bundle.h" 10 #include "chrome/renderer/extensions/extension_localization_peer.h" 11 #include "ipc/ipc_sender.h" 12 #include "ipc/ipc_sync_message.h" 13 #include "net/base/net_errors.h" 14 #include "net/url_request/url_request_status.h" 15 #include "testing/gmock/include/gmock/gmock.h" 16 #include "testing/gtest/include/gtest/gtest.h" 17 #include "webkit/child/resource_loader_bridge.h" 18 19 using testing::_; 20 using testing::DoAll; 21 using testing::Invoke; 22 using testing::StrEq; 23 using testing::Return; 24 25 static const char* const kExtensionUrl_1 = 26 "chrome-extension://some_id/popup.css"; 27 28 static const char* const kExtensionUrl_2 = 29 "chrome-extension://some_id2/popup.css"; 30 31 static const char* const kExtensionUrl_3 = 32 "chrome-extension://some_id3/popup.css"; 33 34 void MessageDeleter(IPC::Message* message) { 35 delete message; 36 } 37 38 class MockIpcMessageSender : public IPC::Sender { 39 public: 40 MockIpcMessageSender() { 41 ON_CALL(*this, Send(_)) 42 .WillByDefault(DoAll(Invoke(MessageDeleter), Return(true))); 43 } 44 45 virtual ~MockIpcMessageSender() {} 46 47 MOCK_METHOD1(Send, bool(IPC::Message* message)); 48 49 private: 50 DISALLOW_COPY_AND_ASSIGN(MockIpcMessageSender); 51 }; 52 53 class MockResourceLoaderBridgePeer 54 : public webkit_glue::ResourceLoaderBridge::Peer { 55 public: 56 MockResourceLoaderBridgePeer() {} 57 virtual ~MockResourceLoaderBridgePeer() {} 58 59 MOCK_METHOD2(OnUploadProgress, void(uint64 position, uint64 size)); 60 MOCK_METHOD4(OnReceivedRedirect, bool( 61 const GURL& new_url, 62 const webkit_glue::ResourceResponseInfo& info, 63 bool* has_new_first_party_for_cookies, 64 GURL* new_first_party_for_cookies)); 65 MOCK_METHOD1(OnReceivedResponse, void( 66 const webkit_glue::ResourceResponseInfo& info)); 67 MOCK_METHOD1(OnDownloadedData, void(int len)); 68 MOCK_METHOD3(OnReceivedData, void(const char* data, 69 int data_length, 70 int encoded_data_length)); 71 MOCK_METHOD4(OnCompletedRequest, void( 72 int error_code, 73 bool was_ignored_by_handler, 74 const std::string& security_info, 75 const base::TimeTicks& completion_time)); 76 77 private: 78 DISALLOW_COPY_AND_ASSIGN(MockResourceLoaderBridgePeer); 79 }; 80 81 class ExtensionLocalizationPeerTest : public testing::Test { 82 protected: 83 virtual void SetUp() { 84 sender_.reset(new MockIpcMessageSender()); 85 original_peer_.reset(new MockResourceLoaderBridgePeer()); 86 filter_peer_.reset( 87 ExtensionLocalizationPeer::CreateExtensionLocalizationPeer( 88 original_peer_.get(), sender_.get(), "text/css", 89 GURL(kExtensionUrl_1))); 90 } 91 92 ExtensionLocalizationPeer* CreateExtensionLocalizationPeer( 93 const std::string& mime_type, 94 const GURL& request_url) { 95 return ExtensionLocalizationPeer::CreateExtensionLocalizationPeer( 96 original_peer_.get(), sender_.get(), mime_type, request_url); 97 } 98 99 std::string GetData(ExtensionLocalizationPeer* filter_peer) { 100 EXPECT_TRUE(NULL != filter_peer); 101 return filter_peer->data_; 102 } 103 104 void SetData(ExtensionLocalizationPeer* filter_peer, 105 const std::string& data) { 106 EXPECT_TRUE(NULL != filter_peer); 107 filter_peer->data_ = data; 108 } 109 110 scoped_ptr<MockIpcMessageSender> sender_; 111 scoped_ptr<MockResourceLoaderBridgePeer> original_peer_; 112 scoped_ptr<ExtensionLocalizationPeer> filter_peer_; 113 }; 114 115 TEST_F(ExtensionLocalizationPeerTest, CreateWithWrongMimeType) { 116 filter_peer_.reset( 117 CreateExtensionLocalizationPeer("text/html", GURL(kExtensionUrl_1))); 118 EXPECT_TRUE(NULL == filter_peer_.get()); 119 } 120 121 TEST_F(ExtensionLocalizationPeerTest, CreateWithValidInput) { 122 EXPECT_TRUE(NULL != filter_peer_.get()); 123 } 124 125 TEST_F(ExtensionLocalizationPeerTest, OnReceivedData) { 126 EXPECT_TRUE(GetData(filter_peer_.get()).empty()); 127 128 const std::string data_chunk("12345"); 129 filter_peer_->OnReceivedData(data_chunk.c_str(), data_chunk.length(), -1); 130 131 EXPECT_EQ(data_chunk, GetData(filter_peer_.get())); 132 133 filter_peer_->OnReceivedData(data_chunk.c_str(), data_chunk.length(), -1); 134 EXPECT_EQ(data_chunk + data_chunk, GetData(filter_peer_.get())); 135 } 136 137 MATCHER_P(IsURLRequestEqual, status, "") { return arg.status() == status; } 138 139 TEST_F(ExtensionLocalizationPeerTest, OnCompletedRequestBadURLRequestStatus) { 140 // It will self-delete once it exits OnCompletedRequest. 141 ExtensionLocalizationPeer* filter_peer = filter_peer_.release(); 142 143 EXPECT_CALL(*original_peer_, OnReceivedResponse(_)); 144 EXPECT_CALL(*original_peer_, OnCompletedRequest( 145 net::ERR_ABORTED, false, "", base::TimeTicks())); 146 147 filter_peer->OnCompletedRequest( 148 net::ERR_FAILED, false, std::string(), base::TimeTicks()); 149 } 150 151 TEST_F(ExtensionLocalizationPeerTest, OnCompletedRequestEmptyData) { 152 // It will self-delete once it exits OnCompletedRequest. 153 ExtensionLocalizationPeer* filter_peer = filter_peer_.release(); 154 155 EXPECT_CALL(*original_peer_, OnReceivedData(_, _, _)).Times(0); 156 EXPECT_CALL(*sender_, Send(_)).Times(0); 157 158 EXPECT_CALL(*original_peer_, OnReceivedResponse(_)); 159 EXPECT_CALL(*original_peer_, OnCompletedRequest( 160 net::OK, false, "", base::TimeTicks())); 161 162 filter_peer->OnCompletedRequest( 163 net::OK, false, std::string(), base::TimeTicks()); 164 } 165 166 TEST_F(ExtensionLocalizationPeerTest, OnCompletedRequestNoCatalogs) { 167 // It will self-delete once it exits OnCompletedRequest. 168 ExtensionLocalizationPeer* filter_peer = filter_peer_.release(); 169 170 SetData(filter_peer, "some text"); 171 172 EXPECT_CALL(*sender_, Send(_)); 173 174 std::string data = GetData(filter_peer); 175 EXPECT_CALL(*original_peer_, 176 OnReceivedData(StrEq(data.data()), data.length(), -1)).Times(2); 177 178 EXPECT_CALL(*original_peer_, OnReceivedResponse(_)).Times(2); 179 EXPECT_CALL(*original_peer_, OnCompletedRequest( 180 net::OK, false, "", base::TimeTicks())).Times(2); 181 182 filter_peer->OnCompletedRequest( 183 net::OK, false, std::string(), base::TimeTicks()); 184 185 // Test if Send gets called again (it shouldn't be) when first call returned 186 // an empty dictionary. 187 filter_peer = 188 CreateExtensionLocalizationPeer("text/css", GURL(kExtensionUrl_1)); 189 SetData(filter_peer, "some text"); 190 filter_peer->OnCompletedRequest( 191 net::OK, false, std::string(), base::TimeTicks()); 192 } 193 194 TEST_F(ExtensionLocalizationPeerTest, OnCompletedRequestWithCatalogs) { 195 // It will self-delete once it exits OnCompletedRequest. 196 ExtensionLocalizationPeer* filter_peer = 197 CreateExtensionLocalizationPeer("text/css", GURL(kExtensionUrl_2)); 198 199 extensions::L10nMessagesMap messages; 200 messages.insert(std::make_pair("text", "new text")); 201 extensions::ExtensionToL10nMessagesMap& l10n_messages_map = 202 *extensions::GetExtensionToL10nMessagesMap(); 203 l10n_messages_map["some_id2"] = messages; 204 205 SetData(filter_peer, "some __MSG_text__"); 206 207 // We already have messages in memory, Send will be skipped. 208 EXPECT_CALL(*sender_, Send(_)).Times(0); 209 210 // __MSG_text__ gets replaced with "new text". 211 std::string data("some new text"); 212 EXPECT_CALL(*original_peer_, 213 OnReceivedData(StrEq(data.data()), data.length(), -1)); 214 215 EXPECT_CALL(*original_peer_, OnReceivedResponse(_)); 216 EXPECT_CALL(*original_peer_, OnCompletedRequest( 217 net::OK, false, "", base::TimeTicks())); 218 219 filter_peer->OnCompletedRequest( 220 net::OK, false, std::string(), base::TimeTicks()); 221 } 222 223 TEST_F(ExtensionLocalizationPeerTest, OnCompletedRequestReplaceMessagesFails) { 224 // It will self-delete once it exits OnCompletedRequest. 225 ExtensionLocalizationPeer* filter_peer = 226 CreateExtensionLocalizationPeer("text/css", GURL(kExtensionUrl_3)); 227 228 extensions::L10nMessagesMap messages; 229 messages.insert(std::make_pair("text", "new text")); 230 extensions::ExtensionToL10nMessagesMap& l10n_messages_map = 231 *extensions::GetExtensionToL10nMessagesMap(); 232 l10n_messages_map["some_id3"] = messages; 233 234 std::string message("some __MSG_missing_message__"); 235 SetData(filter_peer, message); 236 237 // We already have messages in memory, Send will be skipped. 238 EXPECT_CALL(*sender_, Send(_)).Times(0); 239 240 // __MSG_missing_message__ is missing, so message stays the same. 241 EXPECT_CALL(*original_peer_, 242 OnReceivedData(StrEq(message.data()), message.length(), -1)); 243 244 EXPECT_CALL(*original_peer_, OnReceivedResponse(_)); 245 EXPECT_CALL(*original_peer_, OnCompletedRequest( 246 net::OK, false, "", base::TimeTicks())); 247 248 filter_peer->OnCompletedRequest( 249 net::OK, false, std::string(), base::TimeTicks()); 250 } 251