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