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/render_messages.h"
7 #include "chrome/renderer/translate/translate_helper.h"
8 #include "chrome/test/base/chrome_render_view_test.h"
9 #include "components/translate/core/common/translate_constants.h"
10 #include "content/public/renderer/render_view.h"
11 #include "testing/gmock/include/gmock/gmock.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "third_party/WebKit/public/web/WebHistoryItem.h"
15 using testing::AtLeast
;
16 using testing::Return
;
19 class TestTranslateHelper
: public TranslateHelper
{
21 explicit TestTranslateHelper(content::RenderView
* render_view
)
22 : TranslateHelper(render_view
) {
25 virtual base::TimeDelta
AdjustDelay(int delayInMs
) OVERRIDE
{
26 // Just returns base::TimeDelta() which has initial value 0.
27 // Tasks doesn't need to be delayed in tests.
28 return base::TimeDelta();
31 void TranslatePage(int page_id
,
32 const std::string
& source_lang
,
33 const std::string
& target_lang
,
34 const std::string
& translate_script
) {
35 OnTranslatePage(page_id
, translate_script
, source_lang
, target_lang
);
38 MOCK_METHOD0(IsTranslateLibAvailable
, bool());
39 MOCK_METHOD0(IsTranslateLibReady
, bool());
40 MOCK_METHOD0(HasTranslationFinished
, bool());
41 MOCK_METHOD0(HasTranslationFailed
, bool());
42 MOCK_METHOD0(GetOriginalPageLanguage
, std::string());
43 MOCK_METHOD0(StartTranslation
, bool());
44 MOCK_METHOD1(ExecuteScript
, void(const std::string
&));
45 MOCK_METHOD2(ExecuteScriptAndGetBoolResult
, bool(const std::string
&, bool));
46 MOCK_METHOD1(ExecuteScriptAndGetStringResult
,
47 std::string(const std::string
&));
48 MOCK_METHOD1(ExecuteScriptAndGetDoubleResult
, double(const std::string
&));
51 DISALLOW_COPY_AND_ASSIGN(TestTranslateHelper
);
54 class TranslateHelperBrowserTest
: public ChromeRenderViewTest
{
56 TranslateHelperBrowserTest() : translate_helper_(NULL
) {}
59 virtual void SetUp() OVERRIDE
{
60 ChromeRenderViewTest::SetUp();
61 translate_helper_
= new TestTranslateHelper(view_
);
64 virtual void TearDown() OVERRIDE
{
65 delete translate_helper_
;
66 ChromeRenderViewTest::TearDown();
69 bool GetPageTranslatedMessage(int* page_id
,
70 std::string
* original_lang
,
71 std::string
* target_lang
,
72 TranslateErrors::Type
* error
) {
73 const IPC::Message
* message
= render_thread_
->sink().
74 GetUniqueMessageMatching(ChromeViewHostMsg_PageTranslated::ID
);
77 Tuple4
<int, std::string
, std::string
, TranslateErrors::Type
>
79 ChromeViewHostMsg_PageTranslated::Read(message
, &translate_param
);
81 *page_id
= translate_param
.a
;
83 *original_lang
= translate_param
.b
;
85 *target_lang
= translate_param
.c
;
87 *error
= translate_param
.d
;
91 TestTranslateHelper
* translate_helper_
;
94 DISALLOW_COPY_AND_ASSIGN(TranslateHelperBrowserTest
);
97 // Tests that the browser gets notified of the translation failure if the
98 // translate library fails/times-out during initialization.
99 TEST_F(TranslateHelperBrowserTest
, TranslateLibNeverReady
) {
100 // We make IsTranslateLibAvailable true so we don't attempt to inject the
102 EXPECT_CALL(*translate_helper_
, IsTranslateLibAvailable())
104 .WillRepeatedly(Return(true));
106 EXPECT_CALL(*translate_helper_
, IsTranslateLibReady())
107 .Times(AtLeast(5)) // See kMaxTranslateInitCheckAttempts in
108 // translate_helper.cc
109 .WillRepeatedly(Return(false));
111 translate_helper_
->TranslatePage(
112 view_
->GetPageId(), "en", "fr", std::string());
113 base::MessageLoop::current()->RunUntilIdle();
116 TranslateErrors::Type error
;
117 ASSERT_TRUE(GetPageTranslatedMessage(&page_id
, NULL
, NULL
, &error
));
118 EXPECT_EQ(view_
->GetPageId(), page_id
);
119 EXPECT_EQ(TranslateErrors::INITIALIZATION_ERROR
, error
);
122 // Tests that the browser gets notified of the translation success when the
123 // translation succeeds.
124 TEST_F(TranslateHelperBrowserTest
, TranslateSuccess
) {
125 // We make IsTranslateLibAvailable true so we don't attempt to inject the
127 EXPECT_CALL(*translate_helper_
, IsTranslateLibAvailable())
129 .WillRepeatedly(Return(true));
131 EXPECT_CALL(*translate_helper_
, IsTranslateLibReady())
132 .WillOnce(Return(false))
133 .WillOnce(Return(true));
135 EXPECT_CALL(*translate_helper_
, StartTranslation()).WillOnce(Return(true));
137 // Succeed after few checks.
138 EXPECT_CALL(*translate_helper_
, HasTranslationFailed())
139 .WillRepeatedly(Return(false));
140 EXPECT_CALL(*translate_helper_
, HasTranslationFinished())
141 .WillOnce(Return(false))
142 .WillOnce(Return(false))
143 .WillOnce(Return(true));
145 // V8 call for performance monitoring should be ignored.
146 EXPECT_CALL(*translate_helper_
,
147 ExecuteScriptAndGetDoubleResult(_
)).Times(3);
149 std::string
original_lang("en");
150 std::string
target_lang("fr");
151 translate_helper_
->TranslatePage(
152 view_
->GetPageId(), original_lang
, target_lang
, std::string());
153 base::MessageLoop::current()->RunUntilIdle();
156 std::string received_original_lang
;
157 std::string received_target_lang
;
158 TranslateErrors::Type error
;
159 ASSERT_TRUE(GetPageTranslatedMessage(&page_id
,
160 &received_original_lang
,
161 &received_target_lang
,
163 EXPECT_EQ(view_
->GetPageId(), page_id
);
164 EXPECT_EQ(original_lang
, received_original_lang
);
165 EXPECT_EQ(target_lang
, received_target_lang
);
166 EXPECT_EQ(TranslateErrors::NONE
, error
);
169 // Tests that the browser gets notified of the translation failure when the
170 // translation fails.
171 TEST_F(TranslateHelperBrowserTest
, TranslateFailure
) {
172 // We make IsTranslateLibAvailable true so we don't attempt to inject the
174 EXPECT_CALL(*translate_helper_
, IsTranslateLibAvailable())
176 .WillRepeatedly(Return(true));
178 EXPECT_CALL(*translate_helper_
, IsTranslateLibReady())
179 .WillOnce(Return(true));
181 EXPECT_CALL(*translate_helper_
, StartTranslation()).WillOnce(Return(true));
183 // Fail after few checks.
184 EXPECT_CALL(*translate_helper_
, HasTranslationFailed())
185 .WillOnce(Return(false))
186 .WillOnce(Return(false))
187 .WillOnce(Return(false))
188 .WillOnce(Return(true));
190 EXPECT_CALL(*translate_helper_
, HasTranslationFinished())
192 .WillRepeatedly(Return(false));
194 // V8 call for performance monitoring should be ignored.
195 EXPECT_CALL(*translate_helper_
,
196 ExecuteScriptAndGetDoubleResult(_
)).Times(2);
198 translate_helper_
->TranslatePage(
199 view_
->GetPageId(), "en", "fr", std::string());
200 base::MessageLoop::current()->RunUntilIdle();
203 TranslateErrors::Type error
;
204 ASSERT_TRUE(GetPageTranslatedMessage(&page_id
, NULL
, NULL
, &error
));
205 EXPECT_EQ(view_
->GetPageId(), page_id
);
206 EXPECT_EQ(TranslateErrors::TRANSLATION_ERROR
, error
);
209 // Tests that when the browser translate a page for which the language is
210 // undefined we query the translate element to get the language.
211 TEST_F(TranslateHelperBrowserTest
, UndefinedSourceLang
) {
212 // We make IsTranslateLibAvailable true so we don't attempt to inject the
214 EXPECT_CALL(*translate_helper_
, IsTranslateLibAvailable())
216 .WillRepeatedly(Return(true));
218 EXPECT_CALL(*translate_helper_
, IsTranslateLibReady())
219 .WillOnce(Return(true));
221 EXPECT_CALL(*translate_helper_
, GetOriginalPageLanguage())
222 .WillOnce(Return("de"));
224 EXPECT_CALL(*translate_helper_
, StartTranslation()).WillOnce(Return(true));
225 EXPECT_CALL(*translate_helper_
, HasTranslationFailed())
226 .WillOnce(Return(false));
227 EXPECT_CALL(*translate_helper_
, HasTranslationFinished())
229 .WillRepeatedly(Return(true));
231 // V8 call for performance monitoring should be ignored.
232 EXPECT_CALL(*translate_helper_
,
233 ExecuteScriptAndGetDoubleResult(_
)).Times(3);
235 translate_helper_
->TranslatePage(view_
->GetPageId(),
236 translate::kUnknownLanguageCode
, "fr",
238 base::MessageLoop::current()->RunUntilIdle();
241 TranslateErrors::Type error
;
242 std::string original_lang
;
243 std::string target_lang
;
244 ASSERT_TRUE(GetPageTranslatedMessage(&page_id
, &original_lang
, &target_lang
,
246 EXPECT_EQ(view_
->GetPageId(), page_id
);
247 EXPECT_EQ("de", original_lang
);
248 EXPECT_EQ("fr", target_lang
);
249 EXPECT_EQ(TranslateErrors::NONE
, error
);
252 // Tests that starting a translation while a similar one is pending does not
254 TEST_F(TranslateHelperBrowserTest
, MultipleSimilarTranslations
) {
255 // We make IsTranslateLibAvailable true so we don't attempt to inject the
257 EXPECT_CALL(*translate_helper_
, IsTranslateLibAvailable())
259 .WillRepeatedly(Return(true));
261 EXPECT_CALL(*translate_helper_
, IsTranslateLibReady())
262 .WillRepeatedly(Return(true));
263 EXPECT_CALL(*translate_helper_
, StartTranslation())
264 .WillRepeatedly(Return(true));
265 EXPECT_CALL(*translate_helper_
, HasTranslationFailed())
266 .WillRepeatedly(Return(false));
267 EXPECT_CALL(*translate_helper_
, HasTranslationFinished())
268 .WillOnce(Return(true));
270 // V8 call for performance monitoring should be ignored.
271 EXPECT_CALL(*translate_helper_
,
272 ExecuteScriptAndGetDoubleResult(_
)).Times(3);
274 std::string
original_lang("en");
275 std::string
target_lang("fr");
276 translate_helper_
->TranslatePage(
277 view_
->GetPageId(), original_lang
, target_lang
, std::string());
278 // While this is running call again TranslatePage to make sure noting bad
280 translate_helper_
->TranslatePage(
281 view_
->GetPageId(), original_lang
, target_lang
, std::string());
282 base::MessageLoop::current()->RunUntilIdle();
285 std::string received_original_lang
;
286 std::string received_target_lang
;
287 TranslateErrors::Type error
;
288 ASSERT_TRUE(GetPageTranslatedMessage(&page_id
,
289 &received_original_lang
,
290 &received_target_lang
,
292 EXPECT_EQ(view_
->GetPageId(), page_id
);
293 EXPECT_EQ(original_lang
, received_original_lang
);
294 EXPECT_EQ(target_lang
, received_target_lang
);
295 EXPECT_EQ(TranslateErrors::NONE
, error
);
298 // Tests that starting a translation while a different one is pending works.
299 TEST_F(TranslateHelperBrowserTest
, MultipleDifferentTranslations
) {
300 EXPECT_CALL(*translate_helper_
, IsTranslateLibAvailable())
302 .WillRepeatedly(Return(true));
303 EXPECT_CALL(*translate_helper_
, IsTranslateLibReady())
304 .WillRepeatedly(Return(true));
305 EXPECT_CALL(*translate_helper_
, StartTranslation())
306 .WillRepeatedly(Return(true));
307 EXPECT_CALL(*translate_helper_
, HasTranslationFailed())
308 .WillRepeatedly(Return(false));
309 EXPECT_CALL(*translate_helper_
, HasTranslationFinished())
310 .WillOnce(Return(true));
312 // V8 call for performance monitoring should be ignored.
313 EXPECT_CALL(*translate_helper_
,
314 ExecuteScriptAndGetDoubleResult(_
)).Times(5);
316 std::string
original_lang("en");
317 std::string
target_lang("fr");
318 translate_helper_
->TranslatePage(
319 view_
->GetPageId(), original_lang
, target_lang
, std::string());
320 // While this is running call again TranslatePage with a new target lang.
321 std::string
new_target_lang("de");
322 translate_helper_
->TranslatePage(
323 view_
->GetPageId(), original_lang
, new_target_lang
, std::string());
324 base::MessageLoop::current()->RunUntilIdle();
327 std::string received_original_lang
;
328 std::string received_target_lang
;
329 TranslateErrors::Type error
;
330 ASSERT_TRUE(GetPageTranslatedMessage(&page_id
,
331 &received_original_lang
,
332 &received_target_lang
,
334 EXPECT_EQ(view_
->GetPageId(), page_id
);
335 EXPECT_EQ(original_lang
, received_original_lang
);
336 EXPECT_EQ(new_target_lang
, received_target_lang
);
337 EXPECT_EQ(TranslateErrors::NONE
, error
);
340 // Tests that we send the right translate language message for a page and that
341 // we respect the "no translate" meta-tag.
342 TEST_F(ChromeRenderViewTest
, TranslatablePage
) {
343 // Suppress the normal delay that occurs when the page is loaded before which
344 // the renderer sends the page contents to the browser.
345 SendContentStateImmediately();
347 LoadHTML("<html><body>A random page with random content.</body></html>");
348 const IPC::Message
* message
= render_thread_
->sink().GetUniqueMessageMatching(
349 ChromeViewHostMsg_TranslateLanguageDetermined::ID
);
350 ASSERT_NE(static_cast<IPC::Message
*>(NULL
), message
);
351 ChromeViewHostMsg_TranslateLanguageDetermined::Param params
;
352 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message
, ¶ms
);
353 EXPECT_TRUE(params
.b
) << "Page should be translatable.";
354 render_thread_
->sink().ClearMessages();
356 // Now the page specifies the META tag to prevent translation.
357 LoadHTML("<html><head><meta name=\"google\" value=\"notranslate\"></head>"
358 "<body>A random page with random content.</body></html>");
359 message
= render_thread_
->sink().GetUniqueMessageMatching(
360 ChromeViewHostMsg_TranslateLanguageDetermined::ID
);
361 ASSERT_NE(static_cast<IPC::Message
*>(NULL
), message
);
362 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message
, ¶ms
);
363 EXPECT_FALSE(params
.b
) << "Page should not be translatable.";
364 render_thread_
->sink().ClearMessages();
366 // Try the alternate version of the META tag (content instead of value).
367 LoadHTML("<html><head><meta name=\"google\" content=\"notranslate\"></head>"
368 "<body>A random page with random content.</body></html>");
369 message
= render_thread_
->sink().GetUniqueMessageMatching(
370 ChromeViewHostMsg_TranslateLanguageDetermined::ID
);
371 ASSERT_NE(static_cast<IPC::Message
*>(NULL
), message
);
372 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message
, ¶ms
);
373 EXPECT_FALSE(params
.b
) << "Page should not be translatable.";
376 // Tests that the language meta tag takes precedence over the CLD when reporting
377 // the page's language.
378 TEST_F(ChromeRenderViewTest
, LanguageMetaTag
) {
379 // Suppress the normal delay that occurs when the page is loaded before which
380 // the renderer sends the page contents to the browser.
381 SendContentStateImmediately();
383 LoadHTML("<html><head><meta http-equiv=\"content-language\" content=\"es\">"
384 "</head><body>A random page with random content.</body></html>");
385 const IPC::Message
* message
= render_thread_
->sink().GetUniqueMessageMatching(
386 ChromeViewHostMsg_TranslateLanguageDetermined::ID
);
387 ASSERT_NE(static_cast<IPC::Message
*>(NULL
), message
);
388 ChromeViewHostMsg_TranslateLanguageDetermined::Param params
;
389 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message
, ¶ms
);
390 EXPECT_EQ("es", params
.a
.adopted_language
);
391 render_thread_
->sink().ClearMessages();
393 // Makes sure we support multiple languages specified.
394 LoadHTML("<html><head><meta http-equiv=\"content-language\" "
395 "content=\" fr , es,en \">"
396 "</head><body>A random page with random content.</body></html>");
397 message
= render_thread_
->sink().GetUniqueMessageMatching(
398 ChromeViewHostMsg_TranslateLanguageDetermined::ID
);
399 ASSERT_NE(static_cast<IPC::Message
*>(NULL
), message
);
400 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message
, ¶ms
);
401 EXPECT_EQ("fr", params
.a
.adopted_language
);
404 // Tests that the language meta tag works even with non-all-lower-case.
405 // http://code.google.com/p/chromium/issues/detail?id=145689
406 TEST_F(ChromeRenderViewTest
, LanguageMetaTagCase
) {
407 // Suppress the normal delay that occurs when the page is loaded before which
408 // the renderer sends the page contents to the browser.
409 SendContentStateImmediately();
411 LoadHTML("<html><head><meta http-equiv=\"Content-Language\" content=\"es\">"
412 "</head><body>A random page with random content.</body></html>");
413 const IPC::Message
* message
= render_thread_
->sink().GetUniqueMessageMatching(
414 ChromeViewHostMsg_TranslateLanguageDetermined::ID
);
415 ASSERT_NE(static_cast<IPC::Message
*>(NULL
), message
);
416 ChromeViewHostMsg_TranslateLanguageDetermined::Param params
;
417 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message
, ¶ms
);
418 EXPECT_EQ("es", params
.a
.adopted_language
);
419 render_thread_
->sink().ClearMessages();
421 // Makes sure we support multiple languages specified.
422 LoadHTML("<html><head><meta http-equiv=\"Content-Language\" "
423 "content=\" fr , es,en \">"
424 "</head><body>A random page with random content.</body></html>");
425 message
= render_thread_
->sink().GetUniqueMessageMatching(
426 ChromeViewHostMsg_TranslateLanguageDetermined::ID
);
427 ASSERT_NE(static_cast<IPC::Message
*>(NULL
), message
);
428 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message
, ¶ms
);
429 EXPECT_EQ("fr", params
.a
.adopted_language
);
432 // Tests that the language meta tag is converted to Chrome standard of dashes
433 // instead of underscores and proper capitalization.
434 // http://code.google.com/p/chromium/issues/detail?id=159487
435 TEST_F(ChromeRenderViewTest
, LanguageCommonMistakesAreCorrected
) {
436 // Suppress the normal delay that occurs when the page is loaded before which
437 // the renderer sends the page contents to the browser.
438 SendContentStateImmediately();
440 LoadHTML("<html><head><meta http-equiv='Content-Language' content='EN_us'>"
441 "</head><body>A random page with random content.</body></html>");
442 const IPC::Message
* message
= render_thread_
->sink().GetUniqueMessageMatching(
443 ChromeViewHostMsg_TranslateLanguageDetermined::ID
);
444 ASSERT_NE(static_cast<IPC::Message
*>(NULL
), message
);
445 ChromeViewHostMsg_TranslateLanguageDetermined::Param params
;
446 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message
, ¶ms
);
447 EXPECT_EQ("en-US", params
.a
.adopted_language
);
448 render_thread_
->sink().ClearMessages();
451 // Tests that a back navigation gets a translate language message.
452 TEST_F(ChromeRenderViewTest
, BackToTranslatablePage
) {
453 SendContentStateImmediately();
454 LoadHTML("<html><head><meta http-equiv=\"content-language\" content=\"zh\">"
455 "</head><body>This page is in Chinese.</body></html>");
456 const IPC::Message
* message
= render_thread_
->sink().GetUniqueMessageMatching(
457 ChromeViewHostMsg_TranslateLanguageDetermined::ID
);
458 ASSERT_NE(static_cast<IPC::Message
*>(NULL
), message
);
459 ChromeViewHostMsg_TranslateLanguageDetermined::Param params
;
460 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message
, ¶ms
);
461 EXPECT_EQ("zh", params
.a
.adopted_language
);
462 render_thread_
->sink().ClearMessages();
464 LoadHTML("<html><head><meta http-equiv=\"content-language\" content=\"fr\">"
465 "</head><body>This page is in French.</body></html>");
466 message
= render_thread_
->sink().GetUniqueMessageMatching(
467 ChromeViewHostMsg_TranslateLanguageDetermined::ID
);
468 ASSERT_NE(static_cast<IPC::Message
*>(NULL
), message
);
469 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message
, ¶ms
);
470 EXPECT_EQ("fr", params
.a
.adopted_language
);
471 render_thread_
->sink().ClearMessages();
473 GoBack(GetMainFrame()->previousHistoryItem());
475 message
= render_thread_
->sink().GetUniqueMessageMatching(
476 ChromeViewHostMsg_TranslateLanguageDetermined::ID
);
477 ASSERT_NE(static_cast<IPC::Message
*>(NULL
), message
);
478 ChromeViewHostMsg_TranslateLanguageDetermined::Read(message
, ¶ms
);
479 EXPECT_EQ("zh", params
.a
.adopted_language
);
480 render_thread_
->sink().ClearMessages();