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 "base/time/time.h"
6 #include "chrome/common/chrome_isolated_world_ids.h"
7 #include "chrome/test/base/chrome_render_view_test.h"
8 #include "components/translate/content/common/translate_messages.h"
9 #include "components/translate/content/renderer/translate_helper.h"
10 #include "components/translate/core/common/translate_constants.h"
11 #include "content/public/renderer/render_view.h"
12 #include "extensions/common/constants.h"
13 #include "testing/gmock/include/gmock/gmock.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "third_party/WebKit/public/web/WebLocalFrame.h"
17 using testing::AtLeast
;
18 using testing::Return
;
21 class TestTranslateHelper
: public translate::TranslateHelper
{
23 explicit TestTranslateHelper(content::RenderView
* render_view
)
24 : translate::TranslateHelper(
26 chrome::ISOLATED_WORLD_ID_TRANSLATE
,
28 extensions::kExtensionScheme
) {}
30 base::TimeDelta
AdjustDelay(int delayInMs
) override
{
31 // Just returns base::TimeDelta() which has initial value 0.
32 // Tasks doesn't need to be delayed in tests.
33 return base::TimeDelta();
36 void TranslatePage(const std::string
& source_lang
,
37 const std::string
& target_lang
,
38 const std::string
& translate_script
) {
39 OnTranslatePage(0, translate_script
, source_lang
, target_lang
);
42 MOCK_METHOD0(IsTranslateLibAvailable
, bool());
43 MOCK_METHOD0(IsTranslateLibReady
, bool());
44 MOCK_METHOD0(HasTranslationFinished
, bool());
45 MOCK_METHOD0(HasTranslationFailed
, bool());
46 MOCK_METHOD0(GetOriginalPageLanguage
, std::string());
47 MOCK_METHOD0(StartTranslation
, bool());
48 MOCK_METHOD1(ExecuteScript
, void(const std::string
&));
49 MOCK_METHOD2(ExecuteScriptAndGetBoolResult
, bool(const std::string
&, bool));
50 MOCK_METHOD1(ExecuteScriptAndGetStringResult
,
51 std::string(const std::string
&));
52 MOCK_METHOD1(ExecuteScriptAndGetDoubleResult
, double(const std::string
&));
55 DISALLOW_COPY_AND_ASSIGN(TestTranslateHelper
);
58 class TranslateHelperBrowserTest
: public ChromeRenderViewTest
{
60 TranslateHelperBrowserTest() : translate_helper_(NULL
) {}
63 void SetUp() override
{
64 ChromeRenderViewTest::SetUp();
65 translate_helper_
= new TestTranslateHelper(view_
);
68 void TearDown() override
{
69 delete translate_helper_
;
70 ChromeRenderViewTest::TearDown();
73 bool GetPageTranslatedMessage(std::string
* original_lang
,
74 std::string
* target_lang
,
75 translate::TranslateErrors::Type
* error
) {
76 const IPC::Message
* message
= render_thread_
->sink().
77 GetUniqueMessageMatching(ChromeViewHostMsg_PageTranslated::ID
);
80 base::Tuple
<std::string
, std::string
, translate::TranslateErrors::Type
>
82 ChromeViewHostMsg_PageTranslated::Read(message
, &translate_param
);
84 *original_lang
= base::get
<0>(translate_param
);
86 *target_lang
= base::get
<1>(translate_param
);
88 *error
= base::get
<2>(translate_param
);
92 TestTranslateHelper
* translate_helper_
;
95 DISALLOW_COPY_AND_ASSIGN(TranslateHelperBrowserTest
);
98 // Tests that the browser gets notified of the translation failure if the
99 // translate library fails/times-out during initialization.
100 TEST_F(TranslateHelperBrowserTest
, TranslateLibNeverReady
) {
101 // We make IsTranslateLibAvailable true so we don't attempt to inject the
103 EXPECT_CALL(*translate_helper_
, IsTranslateLibAvailable())
105 .WillRepeatedly(Return(true));
107 EXPECT_CALL(*translate_helper_
, IsTranslateLibReady())
108 .Times(AtLeast(5)) // See kMaxTranslateInitCheckAttempts in
109 // translate_helper.cc
110 .WillRepeatedly(Return(false));
112 translate_helper_
->TranslatePage("en", "fr", std::string());
113 base::MessageLoop::current()->RunUntilIdle();
115 translate::TranslateErrors::Type error
;
116 ASSERT_TRUE(GetPageTranslatedMessage(NULL
, NULL
, &error
));
117 EXPECT_EQ(translate::TranslateErrors::INITIALIZATION_ERROR
, error
);
120 // Tests that the browser gets notified of the translation success when the
121 // translation succeeds.
122 TEST_F(TranslateHelperBrowserTest
, TranslateSuccess
) {
123 // We make IsTranslateLibAvailable true so we don't attempt to inject the
125 EXPECT_CALL(*translate_helper_
, IsTranslateLibAvailable())
127 .WillRepeatedly(Return(true));
129 EXPECT_CALL(*translate_helper_
, IsTranslateLibReady())
130 .WillOnce(Return(false))
131 .WillOnce(Return(true));
133 EXPECT_CALL(*translate_helper_
, StartTranslation()).WillOnce(Return(true));
135 // Succeed after few checks.
136 EXPECT_CALL(*translate_helper_
, HasTranslationFailed())
137 .WillRepeatedly(Return(false));
138 EXPECT_CALL(*translate_helper_
, HasTranslationFinished())
139 .WillOnce(Return(false))
140 .WillOnce(Return(false))
141 .WillOnce(Return(true));
143 // V8 call for performance monitoring should be ignored.
144 EXPECT_CALL(*translate_helper_
,
145 ExecuteScriptAndGetDoubleResult(_
)).Times(3);
147 std::string
original_lang("en");
148 std::string
target_lang("fr");
149 translate_helper_
->TranslatePage(original_lang
, target_lang
, std::string());
150 base::MessageLoop::current()->RunUntilIdle();
152 std::string received_original_lang
;
153 std::string received_target_lang
;
154 translate::TranslateErrors::Type error
;
155 ASSERT_TRUE(GetPageTranslatedMessage(&received_original_lang
,
156 &received_target_lang
,
158 EXPECT_EQ(original_lang
, received_original_lang
);
159 EXPECT_EQ(target_lang
, received_target_lang
);
160 EXPECT_EQ(translate::TranslateErrors::NONE
, error
);
163 // Tests that the browser gets notified of the translation failure when the
164 // translation fails.
165 TEST_F(TranslateHelperBrowserTest
, TranslateFailure
) {
166 // We make IsTranslateLibAvailable true so we don't attempt to inject the
168 EXPECT_CALL(*translate_helper_
, IsTranslateLibAvailable())
170 .WillRepeatedly(Return(true));
172 EXPECT_CALL(*translate_helper_
, IsTranslateLibReady())
173 .WillOnce(Return(true));
175 EXPECT_CALL(*translate_helper_
, StartTranslation()).WillOnce(Return(true));
177 // Fail after few checks.
178 EXPECT_CALL(*translate_helper_
, HasTranslationFailed())
179 .WillOnce(Return(false))
180 .WillOnce(Return(false))
181 .WillOnce(Return(false))
182 .WillOnce(Return(true));
184 EXPECT_CALL(*translate_helper_
, HasTranslationFinished())
186 .WillRepeatedly(Return(false));
188 // V8 call for performance monitoring should be ignored.
189 EXPECT_CALL(*translate_helper_
,
190 ExecuteScriptAndGetDoubleResult(_
)).Times(2);
192 translate_helper_
->TranslatePage("en", "fr", std::string());
193 base::MessageLoop::current()->RunUntilIdle();
195 translate::TranslateErrors::Type error
;
196 ASSERT_TRUE(GetPageTranslatedMessage(NULL
, NULL
, &error
));
197 EXPECT_EQ(translate::TranslateErrors::TRANSLATION_ERROR
, error
);
200 // Tests that when the browser translate a page for which the language is
201 // undefined we query the translate element to get the language.
202 TEST_F(TranslateHelperBrowserTest
, UndefinedSourceLang
) {
203 // We make IsTranslateLibAvailable true so we don't attempt to inject the
205 EXPECT_CALL(*translate_helper_
, IsTranslateLibAvailable())
207 .WillRepeatedly(Return(true));
209 EXPECT_CALL(*translate_helper_
, IsTranslateLibReady())
210 .WillOnce(Return(true));
212 EXPECT_CALL(*translate_helper_
, GetOriginalPageLanguage())
213 .WillOnce(Return("de"));
215 EXPECT_CALL(*translate_helper_
, StartTranslation()).WillOnce(Return(true));
216 EXPECT_CALL(*translate_helper_
, HasTranslationFailed())
217 .WillOnce(Return(false));
218 EXPECT_CALL(*translate_helper_
, HasTranslationFinished())
220 .WillRepeatedly(Return(true));
222 // V8 call for performance monitoring should be ignored.
223 EXPECT_CALL(*translate_helper_
,
224 ExecuteScriptAndGetDoubleResult(_
)).Times(3);
226 translate_helper_
->TranslatePage(translate::kUnknownLanguageCode
,
229 base::MessageLoop::current()->RunUntilIdle();
231 translate::TranslateErrors::Type error
;
232 std::string original_lang
;
233 std::string target_lang
;
234 ASSERT_TRUE(GetPageTranslatedMessage(&original_lang
, &target_lang
, &error
));
235 EXPECT_EQ("de", original_lang
);
236 EXPECT_EQ("fr", target_lang
);
237 EXPECT_EQ(translate::TranslateErrors::NONE
, error
);
240 // Tests that starting a translation while a similar one is pending does not
242 TEST_F(TranslateHelperBrowserTest
, MultipleSimilarTranslations
) {
243 // We make IsTranslateLibAvailable true so we don't attempt to inject the
245 EXPECT_CALL(*translate_helper_
, IsTranslateLibAvailable())
247 .WillRepeatedly(Return(true));
249 EXPECT_CALL(*translate_helper_
, IsTranslateLibReady())
250 .WillRepeatedly(Return(true));
251 EXPECT_CALL(*translate_helper_
, StartTranslation())
252 .WillRepeatedly(Return(true));
253 EXPECT_CALL(*translate_helper_
, HasTranslationFailed())
254 .WillRepeatedly(Return(false));
255 EXPECT_CALL(*translate_helper_
, HasTranslationFinished())
256 .WillOnce(Return(true));
258 // V8 call for performance monitoring should be ignored.
259 EXPECT_CALL(*translate_helper_
,
260 ExecuteScriptAndGetDoubleResult(_
)).Times(3);
262 std::string
original_lang("en");
263 std::string
target_lang("fr");
264 translate_helper_
->TranslatePage(original_lang
, target_lang
, std::string());
265 // While this is running call again TranslatePage to make sure noting bad
267 translate_helper_
->TranslatePage(original_lang
, target_lang
, std::string());
268 base::MessageLoop::current()->RunUntilIdle();
270 std::string received_original_lang
;
271 std::string received_target_lang
;
272 translate::TranslateErrors::Type error
;
273 ASSERT_TRUE(GetPageTranslatedMessage(&received_original_lang
,
274 &received_target_lang
,
276 EXPECT_EQ(original_lang
, received_original_lang
);
277 EXPECT_EQ(target_lang
, received_target_lang
);
278 EXPECT_EQ(translate::TranslateErrors::NONE
, error
);
281 // Tests that starting a translation while a different one is pending works.
282 TEST_F(TranslateHelperBrowserTest
, MultipleDifferentTranslations
) {
283 EXPECT_CALL(*translate_helper_
, IsTranslateLibAvailable())
285 .WillRepeatedly(Return(true));
286 EXPECT_CALL(*translate_helper_
, IsTranslateLibReady())
287 .WillRepeatedly(Return(true));
288 EXPECT_CALL(*translate_helper_
, StartTranslation())
289 .WillRepeatedly(Return(true));
290 EXPECT_CALL(*translate_helper_
, HasTranslationFailed())
291 .WillRepeatedly(Return(false));
292 EXPECT_CALL(*translate_helper_
, HasTranslationFinished())
293 .WillOnce(Return(true));
295 // V8 call for performance monitoring should be ignored.
296 EXPECT_CALL(*translate_helper_
,
297 ExecuteScriptAndGetDoubleResult(_
)).Times(5);
299 std::string
original_lang("en");
300 std::string
target_lang("fr");
301 translate_helper_
->TranslatePage(original_lang
, target_lang
, std::string());
302 // While this is running call again TranslatePage with a new target lang.
303 std::string
new_target_lang("de");
304 translate_helper_
->TranslatePage(
305 original_lang
, new_target_lang
, std::string());
306 base::MessageLoop::current()->RunUntilIdle();
308 std::string received_original_lang
;
309 std::string received_target_lang
;
310 translate::TranslateErrors::Type error
;
311 ASSERT_TRUE(GetPageTranslatedMessage(&received_original_lang
,
312 &received_target_lang
,
314 EXPECT_EQ(original_lang
, received_original_lang
);
315 EXPECT_EQ(new_target_lang
, received_target_lang
);
316 EXPECT_EQ(translate::TranslateErrors::NONE
, error
);
319 // Tests that we send the right translate language message for a page and that
320 // we respect the "no translate" meta-tag.
321 TEST_F(ChromeRenderViewTest
, TranslatablePage
) {
322 // Suppress the normal delay that occurs when the page is loaded before which
323 // the renderer sends the page contents to the browser.
324 SendContentStateImmediately();
326 LoadHTML("<html><body>A random page with random content.</body></html>");
327 const IPC::Message
* message
= render_thread_
->sink().GetUniqueMessageMatching(
328 ChromeViewHostMsg_TranslateLanguageDetermined::ID
);
329 ASSERT_NE(static_cast<IPC::Message
*>(NULL
), message
);
330 ChromeViewHostMsg_TranslateLanguageDetermined::Param params
;
331 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message
, ¶ms
);
332 EXPECT_TRUE(base::get
<1>(params
)) << "Page should be translatable.";
333 render_thread_
->sink().ClearMessages();
335 // Now the page specifies the META tag to prevent translation.
336 LoadHTML("<html><head><meta name=\"google\" value=\"notranslate\"></head>"
337 "<body>A random page with random content.</body></html>");
338 message
= render_thread_
->sink().GetUniqueMessageMatching(
339 ChromeViewHostMsg_TranslateLanguageDetermined::ID
);
340 ASSERT_NE(static_cast<IPC::Message
*>(NULL
), message
);
341 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message
, ¶ms
);
342 EXPECT_FALSE(base::get
<1>(params
)) << "Page should not be translatable.";
343 render_thread_
->sink().ClearMessages();
345 // Try the alternate version of the META tag (content instead of value).
346 LoadHTML("<html><head><meta name=\"google\" content=\"notranslate\"></head>"
347 "<body>A random page with random content.</body></html>");
348 message
= render_thread_
->sink().GetUniqueMessageMatching(
349 ChromeViewHostMsg_TranslateLanguageDetermined::ID
);
350 ASSERT_NE(static_cast<IPC::Message
*>(NULL
), message
);
351 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message
, ¶ms
);
352 EXPECT_FALSE(base::get
<1>(params
)) << "Page should not be translatable.";
355 // Tests that the language meta tag takes precedence over the CLD when reporting
356 // the page's language.
357 TEST_F(ChromeRenderViewTest
, LanguageMetaTag
) {
358 // Suppress the normal delay that occurs when the page is loaded before which
359 // the renderer sends the page contents to the browser.
360 SendContentStateImmediately();
362 LoadHTML("<html><head><meta http-equiv=\"content-language\" content=\"es\">"
363 "</head><body>A random page with random content.</body></html>");
364 const IPC::Message
* message
= render_thread_
->sink().GetUniqueMessageMatching(
365 ChromeViewHostMsg_TranslateLanguageDetermined::ID
);
366 ASSERT_NE(static_cast<IPC::Message
*>(NULL
), message
);
367 ChromeViewHostMsg_TranslateLanguageDetermined::Param params
;
368 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message
, ¶ms
);
369 EXPECT_EQ("es", base::get
<0>(params
).adopted_language
);
370 render_thread_
->sink().ClearMessages();
372 // Makes sure we support multiple languages specified.
373 LoadHTML("<html><head><meta http-equiv=\"content-language\" "
374 "content=\" fr , es,en \">"
375 "</head><body>A random page with random content.</body></html>");
376 message
= render_thread_
->sink().GetUniqueMessageMatching(
377 ChromeViewHostMsg_TranslateLanguageDetermined::ID
);
378 ASSERT_NE(static_cast<IPC::Message
*>(NULL
), message
);
379 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message
, ¶ms
);
380 EXPECT_EQ("fr", base::get
<0>(params
).adopted_language
);
383 // Tests that the language meta tag works even with non-all-lower-case.
384 // http://code.google.com/p/chromium/issues/detail?id=145689
385 TEST_F(ChromeRenderViewTest
, LanguageMetaTagCase
) {
386 // Suppress the normal delay that occurs when the page is loaded before which
387 // the renderer sends the page contents to the browser.
388 SendContentStateImmediately();
390 LoadHTML("<html><head><meta http-equiv=\"Content-Language\" content=\"es\">"
391 "</head><body>A random page with random content.</body></html>");
392 const IPC::Message
* message
= render_thread_
->sink().GetUniqueMessageMatching(
393 ChromeViewHostMsg_TranslateLanguageDetermined::ID
);
394 ASSERT_NE(static_cast<IPC::Message
*>(NULL
), message
);
395 ChromeViewHostMsg_TranslateLanguageDetermined::Param params
;
396 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message
, ¶ms
);
397 EXPECT_EQ("es", base::get
<0>(params
).adopted_language
);
398 render_thread_
->sink().ClearMessages();
400 // Makes sure we support multiple languages specified.
401 LoadHTML("<html><head><meta http-equiv=\"Content-Language\" "
402 "content=\" fr , es,en \">"
403 "</head><body>A random page with random content.</body></html>");
404 message
= render_thread_
->sink().GetUniqueMessageMatching(
405 ChromeViewHostMsg_TranslateLanguageDetermined::ID
);
406 ASSERT_NE(static_cast<IPC::Message
*>(NULL
), message
);
407 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message
, ¶ms
);
408 EXPECT_EQ("fr", base::get
<0>(params
).adopted_language
);
411 // Tests that the language meta tag is converted to Chrome standard of dashes
412 // instead of underscores and proper capitalization.
413 // http://code.google.com/p/chromium/issues/detail?id=159487
414 TEST_F(ChromeRenderViewTest
, LanguageCommonMistakesAreCorrected
) {
415 // Suppress the normal delay that occurs when the page is loaded before which
416 // the renderer sends the page contents to the browser.
417 SendContentStateImmediately();
419 LoadHTML("<html><head><meta http-equiv='Content-Language' content='EN_us'>"
420 "</head><body>A random page with random content.</body></html>");
421 const IPC::Message
* message
= render_thread_
->sink().GetUniqueMessageMatching(
422 ChromeViewHostMsg_TranslateLanguageDetermined::ID
);
423 ASSERT_NE(static_cast<IPC::Message
*>(NULL
), message
);
424 ChromeViewHostMsg_TranslateLanguageDetermined::Param params
;
425 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message
, ¶ms
);
426 EXPECT_EQ("en", base::get
<0>(params
).adopted_language
);
427 render_thread_
->sink().ClearMessages();
429 LoadHTML("<html><head><meta http-equiv='Content-Language' content='ZH_tw'>"
430 "</head><body>A random page with random content.</body></html>");
431 message
= render_thread_
->sink().GetUniqueMessageMatching(
432 ChromeViewHostMsg_TranslateLanguageDetermined::ID
);
433 ASSERT_NE(static_cast<IPC::Message
*>(NULL
), message
);
434 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message
, ¶ms
);
435 EXPECT_EQ("zh-TW", base::get
<0>(params
).adopted_language
);
436 render_thread_
->sink().ClearMessages();
439 // Tests that a back navigation gets a translate language message.
440 TEST_F(ChromeRenderViewTest
, BackToTranslatablePage
) {
441 SendContentStateImmediately();
442 LoadHTML("<html><head><meta http-equiv=\"content-language\" content=\"zh\">"
443 "</head><body>This page is in Chinese.</body></html>");
444 const IPC::Message
* message
= render_thread_
->sink().GetUniqueMessageMatching(
445 ChromeViewHostMsg_TranslateLanguageDetermined::ID
);
446 ASSERT_NE(static_cast<IPC::Message
*>(NULL
), message
);
447 ChromeViewHostMsg_TranslateLanguageDetermined::Param params
;
448 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message
, ¶ms
);
449 EXPECT_EQ("zh", base::get
<0>(params
).adopted_language
);
450 render_thread_
->sink().ClearMessages();
452 content::PageState back_state
= GetCurrentPageState();
454 LoadHTML("<html><head><meta http-equiv=\"content-language\" content=\"fr\">"
455 "</head><body>This page is in French.</body></html>");
456 message
= render_thread_
->sink().GetUniqueMessageMatching(
457 ChromeViewHostMsg_TranslateLanguageDetermined::ID
);
458 ASSERT_NE(static_cast<IPC::Message
*>(NULL
), message
);
459 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message
, ¶ms
);
460 EXPECT_EQ("fr", base::get
<0>(params
).adopted_language
);
461 render_thread_
->sink().ClearMessages();
465 message
= render_thread_
->sink().GetUniqueMessageMatching(
466 ChromeViewHostMsg_TranslateLanguageDetermined::ID
);
467 ASSERT_NE(static_cast<IPC::Message
*>(NULL
), message
);
468 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message
, ¶ms
);
469 EXPECT_EQ("zh", base::get
<0>(params
).adopted_language
);
470 render_thread_
->sink().ClearMessages();