1 // Copyright (c) 2011 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/extension_message_bundle.h"
10 #include "chrome/common/extensions/extension_localization_peer.h"
11 #include "ipc/ipc_message.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/glue/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
MessageDeleter(IPC::Message * message)34 void MessageDeleter(IPC::Message* message) {
35 delete static_cast<IPC::SyncMessage*>(message)->GetReplyDeserializer();
36 delete message;
37 }
38
39 class MockIpcMessageSender : public IPC::Message::Sender {
40 public:
MockIpcMessageSender()41 MockIpcMessageSender() {
42 ON_CALL(*this, Send(_))
43 .WillByDefault(DoAll(Invoke(MessageDeleter), Return(true)));
44 }
45
~MockIpcMessageSender()46 virtual ~MockIpcMessageSender() {}
47
48 MOCK_METHOD1(Send, bool(IPC::Message* message));
49
50 private:
51 DISALLOW_COPY_AND_ASSIGN(MockIpcMessageSender);
52 };
53
54 class MockResourceLoaderBridgePeer
55 : public webkit_glue::ResourceLoaderBridge::Peer {
56 public:
MockResourceLoaderBridgePeer()57 MockResourceLoaderBridgePeer() {}
~MockResourceLoaderBridgePeer()58 virtual ~MockResourceLoaderBridgePeer() {}
59
60 MOCK_METHOD2(OnUploadProgress, void(uint64 position, uint64 size));
61 MOCK_METHOD4(OnReceivedRedirect, bool(
62 const GURL& new_url,
63 const webkit_glue::ResourceResponseInfo& info,
64 bool* has_new_first_party_for_cookies,
65 GURL* new_first_party_for_cookies));
66 MOCK_METHOD1(OnReceivedResponse, void(
67 const webkit_glue::ResourceResponseInfo& info));
68 MOCK_METHOD1(OnDownloadedData, void(int len));
69 MOCK_METHOD3(OnReceivedData, void(const char* data,
70 int data_length,
71 int encoded_data_length));
72 MOCK_METHOD3(OnCompletedRequest, void(
73 const net::URLRequestStatus& status,
74 const std::string& security_info,
75 const base::Time& completion_time));
76
77 private:
78 DISALLOW_COPY_AND_ASSIGN(MockResourceLoaderBridgePeer);
79 };
80
81 class ExtensionLocalizationPeerTest : public testing::Test {
82 protected:
SetUp()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
CreateExtensionLocalizationPeer(const std::string & mime_type,const GURL & request_url)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
GetData(ExtensionLocalizationPeer * filter_peer)99 std::string GetData(ExtensionLocalizationPeer* filter_peer) {
100 EXPECT_TRUE(NULL != filter_peer);
101 return filter_peer->data_;
102 }
103
SetData(ExtensionLocalizationPeer * filter_peer,const std::string & data)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
TEST_F(ExtensionLocalizationPeerTest,CreateWithWrongMimeType)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
TEST_F(ExtensionLocalizationPeerTest,CreateWithValidInput)121 TEST_F(ExtensionLocalizationPeerTest, CreateWithValidInput) {
122 EXPECT_TRUE(NULL != filter_peer_.get());
123 }
124
TEST_F(ExtensionLocalizationPeerTest,OnReceivedData)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
TEST_F(ExtensionLocalizationPeerTest,OnCompletedRequestBadURLRequestStatus)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 IsURLRequestEqual(net::URLRequestStatus::CANCELED), "", base::Time()));
146
147 net::URLRequestStatus status;
148 status.set_status(net::URLRequestStatus::FAILED);
149 filter_peer->OnCompletedRequest(status, "", base::Time());
150 }
151
TEST_F(ExtensionLocalizationPeerTest,OnCompletedRequestEmptyData)152 TEST_F(ExtensionLocalizationPeerTest, OnCompletedRequestEmptyData) {
153 // It will self-delete once it exits OnCompletedRequest.
154 ExtensionLocalizationPeer* filter_peer = filter_peer_.release();
155
156 EXPECT_CALL(*original_peer_, OnReceivedData(_, _, _)).Times(0);
157 EXPECT_CALL(*sender_, Send(_)).Times(0);
158
159 EXPECT_CALL(*original_peer_, OnReceivedResponse(_));
160 EXPECT_CALL(*original_peer_, OnCompletedRequest(
161 IsURLRequestEqual(net::URLRequestStatus::SUCCESS), "", base::Time()));
162
163 net::URLRequestStatus status;
164 status.set_status(net::URLRequestStatus::SUCCESS);
165 filter_peer->OnCompletedRequest(status, "", base::Time());
166 }
167
TEST_F(ExtensionLocalizationPeerTest,OnCompletedRequestNoCatalogs)168 TEST_F(ExtensionLocalizationPeerTest, OnCompletedRequestNoCatalogs) {
169 // It will self-delete once it exits OnCompletedRequest.
170 ExtensionLocalizationPeer* filter_peer = filter_peer_.release();
171
172 SetData(filter_peer, "some text");
173
174 EXPECT_CALL(*sender_, Send(_));
175
176 std::string data = GetData(filter_peer);
177 EXPECT_CALL(*original_peer_,
178 OnReceivedData(StrEq(data.data()), data.length(), -1)).Times(2);
179
180 EXPECT_CALL(*original_peer_, OnReceivedResponse(_)).Times(2);
181 EXPECT_CALL(*original_peer_, OnCompletedRequest(
182 IsURLRequestEqual(
183 net::URLRequestStatus::SUCCESS), "", base::Time())).Times(2);
184
185 net::URLRequestStatus status;
186 status.set_status(net::URLRequestStatus::SUCCESS);
187 filter_peer->OnCompletedRequest(status, "", base::Time());
188
189 // Test if Send gets called again (it shouldn't be) when first call returned
190 // an empty dictionary.
191 filter_peer =
192 CreateExtensionLocalizationPeer("text/css", GURL(kExtensionUrl_1));
193 SetData(filter_peer, "some text");
194 filter_peer->OnCompletedRequest(status, "", base::Time());
195 }
196
TEST_F(ExtensionLocalizationPeerTest,OnCompletedRequestWithCatalogs)197 TEST_F(ExtensionLocalizationPeerTest, OnCompletedRequestWithCatalogs) {
198 // It will self-delete once it exits OnCompletedRequest.
199 ExtensionLocalizationPeer* filter_peer =
200 CreateExtensionLocalizationPeer("text/css", GURL(kExtensionUrl_2));
201
202 L10nMessagesMap messages;
203 messages.insert(std::make_pair("text", "new text"));
204 ExtensionToL10nMessagesMap& l10n_messages_map =
205 *GetExtensionToL10nMessagesMap();
206 l10n_messages_map["some_id2"] = messages;
207
208 SetData(filter_peer, "some __MSG_text__");
209
210 // We already have messages in memory, Send will be skipped.
211 EXPECT_CALL(*sender_, Send(_)).Times(0);
212
213 // __MSG_text__ gets replaced with "new text".
214 std::string data("some new text");
215 EXPECT_CALL(*original_peer_,
216 OnReceivedData(StrEq(data.data()), data.length(), -1));
217
218 EXPECT_CALL(*original_peer_, OnReceivedResponse(_));
219 EXPECT_CALL(*original_peer_, OnCompletedRequest(
220 IsURLRequestEqual(net::URLRequestStatus::SUCCESS), "", base::Time()));
221
222 net::URLRequestStatus status;
223 status.set_status(net::URLRequestStatus::SUCCESS);
224 filter_peer->OnCompletedRequest(status, "", base::Time());
225 }
226
TEST_F(ExtensionLocalizationPeerTest,OnCompletedRequestReplaceMessagesFails)227 TEST_F(ExtensionLocalizationPeerTest, OnCompletedRequestReplaceMessagesFails) {
228 // It will self-delete once it exits OnCompletedRequest.
229 ExtensionLocalizationPeer* filter_peer =
230 CreateExtensionLocalizationPeer("text/css", GURL(kExtensionUrl_3));
231
232 L10nMessagesMap messages;
233 messages.insert(std::make_pair("text", "new text"));
234 ExtensionToL10nMessagesMap& l10n_messages_map =
235 *GetExtensionToL10nMessagesMap();
236 l10n_messages_map["some_id3"] = messages;
237
238 std::string message("some __MSG_missing_message__");
239 SetData(filter_peer, message);
240
241 // We already have messages in memory, Send will be skipped.
242 EXPECT_CALL(*sender_, Send(_)).Times(0);
243
244 // __MSG_missing_message__ is missing, so message stays the same.
245 EXPECT_CALL(*original_peer_,
246 OnReceivedData(StrEq(message.data()), message.length(), -1));
247
248 EXPECT_CALL(*original_peer_, OnReceivedResponse(_));
249 EXPECT_CALL(*original_peer_, OnCompletedRequest(
250 IsURLRequestEqual(net::URLRequestStatus::SUCCESS), "", base::Time()));
251
252 net::URLRequestStatus status;
253 status.set_status(net::URLRequestStatus::SUCCESS);
254 filter_peer->OnCompletedRequest(status, "", base::Time());
255 }
256