1 // Copyright (c) 2012 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.
5 #include "chrome/common/chrome_constants.h"
6 #include "chrome/common/render_messages.h"
7 #include "chrome/renderer/translate_helper.h"
8 #include "chrome/test/base/chrome_render_view_test.h"
9 #include "content/public/renderer/render_view.h"
10 #include "testing/gmock/include/gmock/gmock.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12 #include "third_party/WebKit/Source/WebKit/chromium/public/WebHistoryItem.h"
14 using testing::AtLeast
;
15 using testing::Return
;
17 class TestTranslateHelper
: public TranslateHelper
{
19 explicit TestTranslateHelper(content::RenderView
* render_view
)
20 : TranslateHelper(render_view
) {
23 virtual bool DontDelayTasks() { return true; }
25 void TranslatePage(int page_id
,
26 const std::string
& source_lang
,
27 const std::string
& target_lang
,
28 const std::string
& translate_script
) {
29 OnTranslatePage(page_id
, translate_script
, source_lang
, target_lang
);
32 MOCK_METHOD0(IsTranslateLibAvailable
, bool());
33 MOCK_METHOD0(IsTranslateLibReady
, bool());
34 MOCK_METHOD0(HasTranslationFinished
, bool());
35 MOCK_METHOD0(HasTranslationFailed
, bool());
36 MOCK_METHOD0(GetOriginalPageLanguage
, std::string());
37 MOCK_METHOD0(StartTranslation
, bool());
40 DISALLOW_COPY_AND_ASSIGN(TestTranslateHelper
);
43 class TranslateHelperTest
: public ChromeRenderViewTest
{
45 TranslateHelperTest() : translate_helper_(NULL
) {}
48 virtual void SetUp() {
49 ChromeRenderViewTest::SetUp();
50 translate_helper_
= new TestTranslateHelper(view_
);
53 virtual void TearDown() {
54 delete translate_helper_
;
55 ChromeRenderViewTest::TearDown();
58 bool GetPageTranslatedMessage(int* page_id
,
59 std::string
* original_lang
,
60 std::string
* target_lang
,
61 TranslateErrors::Type
* error
) {
62 const IPC::Message
* message
= render_thread_
->sink().
63 GetUniqueMessageMatching(ChromeViewHostMsg_PageTranslated::ID
);
66 Tuple4
<int, std::string
, std::string
, TranslateErrors::Type
>
68 ChromeViewHostMsg_PageTranslated::Read(message
, &translate_param
);
70 *page_id
= translate_param
.a
;
72 *original_lang
= translate_param
.b
;
74 *target_lang
= translate_param
.c
;
76 *error
= translate_param
.d
;
80 TestTranslateHelper
* translate_helper_
;
83 // Tests that the browser gets notified of the translation failure if the
84 // translate library fails/times-out during initialization.
85 TEST_F(TranslateHelperTest
, TranslateLibNeverReady
) {
86 // We make IsTranslateLibAvailable true so we don't attempt to inject the
88 EXPECT_CALL(*translate_helper_
, IsTranslateLibAvailable())
90 .WillRepeatedly(Return(true));
92 EXPECT_CALL(*translate_helper_
, IsTranslateLibReady())
93 .Times(AtLeast(5)) // See kMaxTranslateInitCheckAttempts in
94 // translate_helper.cc
95 .WillRepeatedly(Return(false));
97 translate_helper_
->TranslatePage(
98 view_
->GetPageId(), "en", "fr", std::string());
99 MessageLoop::current()->RunAllPending();
102 TranslateErrors::Type error
;
103 ASSERT_TRUE(GetPageTranslatedMessage(&page_id
, NULL
, NULL
, &error
));
104 EXPECT_EQ(view_
->GetPageId(), page_id
);
105 EXPECT_EQ(TranslateErrors::INITIALIZATION_ERROR
, error
);
108 // Tests that the browser gets notified of the translation success when the
109 // translation succeeds.
110 TEST_F(TranslateHelperTest
, TranslateSuccess
) {
111 // We make IsTranslateLibAvailable true so we don't attempt to inject the
113 EXPECT_CALL(*translate_helper_
, IsTranslateLibAvailable())
115 .WillRepeatedly(Return(true));
117 EXPECT_CALL(*translate_helper_
, IsTranslateLibReady())
118 .WillOnce(Return(false))
119 .WillOnce(Return(true));
121 EXPECT_CALL(*translate_helper_
, StartTranslation()).WillOnce(Return(true));
123 // Succeed after few checks.
124 EXPECT_CALL(*translate_helper_
, HasTranslationFailed())
125 .WillRepeatedly(Return(false));
126 EXPECT_CALL(*translate_helper_
, HasTranslationFinished())
127 .WillOnce(Return(false))
128 .WillOnce(Return(false))
129 .WillOnce(Return(true));
131 std::string
original_lang("en");
132 std::string
target_lang("fr");
133 translate_helper_
->TranslatePage(
134 view_
->GetPageId(), original_lang
, target_lang
, std::string());
135 MessageLoop::current()->RunAllPending();
138 std::string received_original_lang
;
139 std::string received_target_lang
;
140 TranslateErrors::Type error
;
141 ASSERT_TRUE(GetPageTranslatedMessage(&page_id
,
142 &received_original_lang
,
143 &received_target_lang
,
145 EXPECT_EQ(view_
->GetPageId(), page_id
);
146 EXPECT_EQ(original_lang
, received_original_lang
);
147 EXPECT_EQ(target_lang
, received_target_lang
);
148 EXPECT_EQ(TranslateErrors::NONE
, error
);
151 // Tests that the browser gets notified of the translation failure when the
152 // translation fails.
153 TEST_F(TranslateHelperTest
, TranslateFailure
) {
154 // We make IsTranslateLibAvailable true so we don't attempt to inject the
156 EXPECT_CALL(*translate_helper_
, IsTranslateLibAvailable())
158 .WillRepeatedly(Return(true));
160 EXPECT_CALL(*translate_helper_
, IsTranslateLibReady())
161 .WillOnce(Return(true));
163 EXPECT_CALL(*translate_helper_
, StartTranslation()).WillOnce(Return(true));
165 // Fail after few checks.
166 EXPECT_CALL(*translate_helper_
, HasTranslationFailed())
167 .WillOnce(Return(false))
168 .WillOnce(Return(false))
169 .WillOnce(Return(false))
170 .WillOnce(Return(true));
172 EXPECT_CALL(*translate_helper_
, HasTranslationFinished())
174 .WillRepeatedly(Return(false));
176 translate_helper_
->TranslatePage(
177 view_
->GetPageId(), "en", "fr", std::string());
178 MessageLoop::current()->RunAllPending();
181 TranslateErrors::Type error
;
182 ASSERT_TRUE(GetPageTranslatedMessage(&page_id
, NULL
, NULL
, &error
));
183 EXPECT_EQ(view_
->GetPageId(), page_id
);
184 EXPECT_EQ(TranslateErrors::TRANSLATION_ERROR
, error
);
187 // Tests that when the browser translate a page for which the language is
188 // undefined we query the translate element to get the language.
189 TEST_F(TranslateHelperTest
, UndefinedSourceLang
) {
190 // We make IsTranslateLibAvailable true so we don't attempt to inject the
192 EXPECT_CALL(*translate_helper_
, IsTranslateLibAvailable())
194 .WillRepeatedly(Return(true));
196 EXPECT_CALL(*translate_helper_
, IsTranslateLibReady())
197 .WillOnce(Return(true));
199 EXPECT_CALL(*translate_helper_
, GetOriginalPageLanguage())
200 .WillOnce(Return("de"));
202 EXPECT_CALL(*translate_helper_
, StartTranslation()).WillOnce(Return(true));
203 EXPECT_CALL(*translate_helper_
, HasTranslationFailed())
204 .WillOnce(Return(false));
205 EXPECT_CALL(*translate_helper_
, HasTranslationFinished())
207 .WillRepeatedly(Return(true));
209 translate_helper_
->TranslatePage(view_
->GetPageId(),
210 chrome::kUnknownLanguageCode
, "fr",
212 MessageLoop::current()->RunAllPending();
215 TranslateErrors::Type error
;
216 std::string original_lang
;
217 std::string target_lang
;
218 ASSERT_TRUE(GetPageTranslatedMessage(&page_id
, &original_lang
, &target_lang
,
220 EXPECT_EQ(view_
->GetPageId(), page_id
);
221 EXPECT_EQ("de", original_lang
);
222 EXPECT_EQ("fr", target_lang
);
223 EXPECT_EQ(TranslateErrors::NONE
, error
);
226 // Tests that starting a translation while a similar one is pending does not
228 TEST_F(TranslateHelperTest
, MultipleSimilarTranslations
) {
229 // We make IsTranslateLibAvailable true so we don't attempt to inject the
231 EXPECT_CALL(*translate_helper_
, IsTranslateLibAvailable())
233 .WillRepeatedly(Return(true));
235 EXPECT_CALL(*translate_helper_
, IsTranslateLibReady())
236 .WillRepeatedly(Return(true));
237 EXPECT_CALL(*translate_helper_
, StartTranslation())
238 .WillRepeatedly(Return(true));
239 EXPECT_CALL(*translate_helper_
, HasTranslationFailed())
240 .WillRepeatedly(Return(false));
241 EXPECT_CALL(*translate_helper_
, HasTranslationFinished())
242 .WillOnce(Return(true));
244 std::string
original_lang("en");
245 std::string
target_lang("fr");
246 translate_helper_
->TranslatePage(
247 view_
->GetPageId(), original_lang
, target_lang
, std::string());
248 // While this is running call again TranslatePage to make sure noting bad
250 translate_helper_
->TranslatePage(
251 view_
->GetPageId(), original_lang
, target_lang
, std::string());
252 MessageLoop::current()->RunAllPending();
255 std::string received_original_lang
;
256 std::string received_target_lang
;
257 TranslateErrors::Type error
;
258 ASSERT_TRUE(GetPageTranslatedMessage(&page_id
,
259 &received_original_lang
,
260 &received_target_lang
,
262 EXPECT_EQ(view_
->GetPageId(), page_id
);
263 EXPECT_EQ(original_lang
, received_original_lang
);
264 EXPECT_EQ(target_lang
, received_target_lang
);
265 EXPECT_EQ(TranslateErrors::NONE
, error
);
268 // Tests that starting a translation while a different one is pending works.
269 TEST_F(TranslateHelperTest
, MultipleDifferentTranslations
) {
270 EXPECT_CALL(*translate_helper_
, IsTranslateLibAvailable())
272 .WillRepeatedly(Return(true));
273 EXPECT_CALL(*translate_helper_
, IsTranslateLibReady())
274 .WillRepeatedly(Return(true));
275 EXPECT_CALL(*translate_helper_
, StartTranslation())
276 .WillRepeatedly(Return(true));
277 EXPECT_CALL(*translate_helper_
, HasTranslationFailed())
278 .WillRepeatedly(Return(false));
279 EXPECT_CALL(*translate_helper_
, HasTranslationFinished())
280 .WillOnce(Return(true));
282 std::string
original_lang("en");
283 std::string
target_lang("fr");
284 translate_helper_
->TranslatePage(
285 view_
->GetPageId(), original_lang
, target_lang
, std::string());
286 // While this is running call again TranslatePage with a new target lang.
287 std::string
new_target_lang("de");
288 translate_helper_
->TranslatePage(
289 view_
->GetPageId(), original_lang
, new_target_lang
, std::string());
290 MessageLoop::current()->RunAllPending();
293 std::string received_original_lang
;
294 std::string received_target_lang
;
295 TranslateErrors::Type error
;
296 ASSERT_TRUE(GetPageTranslatedMessage(&page_id
,
297 &received_original_lang
,
298 &received_target_lang
,
300 EXPECT_EQ(view_
->GetPageId(), page_id
);
301 EXPECT_EQ(original_lang
, received_original_lang
);
302 EXPECT_EQ(new_target_lang
, received_target_lang
);
303 EXPECT_EQ(TranslateErrors::NONE
, error
);
306 // Tests that we send the right translate language message for a page and that
307 // we respect the "no translate" meta-tag.
308 TEST_F(ChromeRenderViewTest
, TranslatablePage
) {
309 // Suppress the normal delay that occurs when the page is loaded before which
310 // the renderer sends the page contents to the browser.
311 SendContentStateImmediately();
313 LoadHTML("<html><body>A random page with random content.</body></html>");
314 const IPC::Message
* message
= render_thread_
->sink().GetUniqueMessageMatching(
315 ChromeViewHostMsg_TranslateLanguageDetermined::ID
);
316 ASSERT_NE(static_cast<IPC::Message
*>(NULL
), message
);
317 ChromeViewHostMsg_TranslateLanguageDetermined::Param params
;
318 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message
, ¶ms
);
319 EXPECT_TRUE(params
.b
) << "Page should be translatable.";
320 render_thread_
->sink().ClearMessages();
322 // Now the page specifies the META tag to prevent translation.
323 LoadHTML("<html><head><meta name=\"google\" value=\"notranslate\"></head>"
324 "<body>A random page with random content.</body></html>");
325 message
= render_thread_
->sink().GetUniqueMessageMatching(
326 ChromeViewHostMsg_TranslateLanguageDetermined::ID
);
327 ASSERT_NE(static_cast<IPC::Message
*>(NULL
), message
);
328 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message
, ¶ms
);
329 EXPECT_FALSE(params
.b
) << "Page should not be translatable.";
330 render_thread_
->sink().ClearMessages();
332 // Try the alternate version of the META tag (content instead of value).
333 LoadHTML("<html><head><meta name=\"google\" content=\"notranslate\"></head>"
334 "<body>A random page with random content.</body></html>");
335 message
= render_thread_
->sink().GetUniqueMessageMatching(
336 ChromeViewHostMsg_TranslateLanguageDetermined::ID
);
337 ASSERT_NE(static_cast<IPC::Message
*>(NULL
), message
);
338 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message
, ¶ms
);
339 EXPECT_FALSE(params
.b
) << "Page should not be translatable.";
342 // Tests that the language meta tag takes precedence over the CLD when reporting
343 // the page's language.
344 TEST_F(ChromeRenderViewTest
, LanguageMetaTag
) {
345 // Suppress the normal delay that occurs when the page is loaded before which
346 // the renderer sends the page contents to the browser.
347 SendContentStateImmediately();
349 LoadHTML("<html><head><meta http-equiv=\"content-language\" content=\"es\">"
350 "</head><body>A random page with random content.</body></html>");
351 const IPC::Message
* message
= render_thread_
->sink().GetUniqueMessageMatching(
352 ChromeViewHostMsg_TranslateLanguageDetermined::ID
);
353 ASSERT_NE(static_cast<IPC::Message
*>(NULL
), message
);
354 ChromeViewHostMsg_TranslateLanguageDetermined::Param params
;
355 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message
, ¶ms
);
356 EXPECT_EQ("es", params
.a
);
357 render_thread_
->sink().ClearMessages();
359 // Makes sure we support multiple languages specified.
360 LoadHTML("<html><head><meta http-equiv=\"content-language\" "
361 "content=\" fr , es,en \">"
362 "</head><body>A random page with random content.</body></html>");
363 message
= render_thread_
->sink().GetUniqueMessageMatching(
364 ChromeViewHostMsg_TranslateLanguageDetermined::ID
);
365 ASSERT_NE(static_cast<IPC::Message
*>(NULL
), message
);
366 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message
, ¶ms
);
367 EXPECT_EQ("fr", params
.a
);
370 // Tests that a back navigation gets a translate language message.
371 TEST_F(ChromeRenderViewTest
, BackToTranslatablePage
) {
372 SendContentStateImmediately();
373 LoadHTML("<html><head><meta http-equiv=\"content-language\" content=\"zh\">"
374 "</head><body>This page is in Chinese.</body></html>");
375 const IPC::Message
* message
= render_thread_
->sink().GetUniqueMessageMatching(
376 ChromeViewHostMsg_TranslateLanguageDetermined::ID
);
377 ASSERT_NE(static_cast<IPC::Message
*>(NULL
), message
);
378 ChromeViewHostMsg_TranslateLanguageDetermined::Param params
;
379 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message
, ¶ms
);
380 EXPECT_EQ("zh", params
.a
);
381 render_thread_
->sink().ClearMessages();
383 LoadHTML("<html><head><meta http-equiv=\"content-language\" content=\"fr\">"
384 "</head><body>This page is in French.</body></html>");
385 message
= render_thread_
->sink().GetUniqueMessageMatching(
386 ChromeViewHostMsg_TranslateLanguageDetermined::ID
);
387 ASSERT_NE(static_cast<IPC::Message
*>(NULL
), message
);
388 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message
, ¶ms
);
389 EXPECT_EQ("fr", params
.a
);
390 render_thread_
->sink().ClearMessages();
392 GoBack(GetMainFrame()->previousHistoryItem());
394 message
= render_thread_
->sink().GetUniqueMessageMatching(
395 ChromeViewHostMsg_TranslateLanguageDetermined::ID
);
396 ASSERT_NE(static_cast<IPC::Message
*>(NULL
), message
);
397 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message
, ¶ms
);
398 EXPECT_EQ("zh", params
.a
);
399 render_thread_
->sink().ClearMessages();