- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / renderer / translate / translate_helper_browsertest.cc
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.
4
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/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"
14
15 using testing::AtLeast;
16 using testing::Return;
17 using testing::_;
18
19 class TestTranslateHelper : public TranslateHelper {
20  public:
21   explicit TestTranslateHelper(content::RenderView* render_view)
22       : TranslateHelper(render_view) {
23   }
24
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();
29   }
30
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);
36   }
37
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&));
49
50  private:
51   DISALLOW_COPY_AND_ASSIGN(TestTranslateHelper);
52 };
53
54 class TranslateHelperBrowserTest : public ChromeRenderViewTest {
55  public:
56   TranslateHelperBrowserTest() : translate_helper_(NULL) {}
57
58  protected:
59   virtual void SetUp() OVERRIDE {
60     ChromeRenderViewTest::SetUp();
61     translate_helper_ = new TestTranslateHelper(view_);
62   }
63
64   virtual void TearDown() OVERRIDE {
65     delete translate_helper_;
66     ChromeRenderViewTest::TearDown();
67   }
68
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);
75     if (!message)
76       return false;
77     Tuple4<int, std::string, std::string, TranslateErrors::Type>
78         translate_param;
79     ChromeViewHostMsg_PageTranslated::Read(message, &translate_param);
80     if (page_id)
81       *page_id = translate_param.a;
82     if (original_lang)
83       *original_lang = translate_param.b;
84     if (target_lang)
85       *target_lang = translate_param.c;
86     if (error)
87       *error = translate_param.d;
88     return true;
89   }
90
91   TestTranslateHelper* translate_helper_;
92
93  private:
94   DISALLOW_COPY_AND_ASSIGN(TranslateHelperBrowserTest);
95 };
96
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
101   // library.
102   EXPECT_CALL(*translate_helper_, IsTranslateLibAvailable())
103       .Times(AtLeast(1))
104       .WillRepeatedly(Return(true));
105
106   EXPECT_CALL(*translate_helper_, IsTranslateLibReady())
107       .Times(AtLeast(5))  // See kMaxTranslateInitCheckAttempts in
108                           // translate_helper.cc
109       .WillRepeatedly(Return(false));
110
111   translate_helper_->TranslatePage(
112       view_->GetPageId(), "en", "fr", std::string());
113   base::MessageLoop::current()->RunUntilIdle();
114
115   int page_id;
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);
120 }
121
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
126   // library.
127   EXPECT_CALL(*translate_helper_, IsTranslateLibAvailable())
128       .Times(AtLeast(1))
129       .WillRepeatedly(Return(true));
130
131   EXPECT_CALL(*translate_helper_, IsTranslateLibReady())
132       .WillOnce(Return(false))
133       .WillOnce(Return(true));
134
135   EXPECT_CALL(*translate_helper_, StartTranslation()).WillOnce(Return(true));
136
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));
144
145   // V8 call for performance monitoring should be ignored.
146   EXPECT_CALL(*translate_helper_,
147               ExecuteScriptAndGetDoubleResult(_)).Times(3);
148
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();
154
155   int page_id;
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,
162                                        &error));
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);
167 }
168
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
173   // library.
174   EXPECT_CALL(*translate_helper_, IsTranslateLibAvailable())
175       .Times(AtLeast(1))
176       .WillRepeatedly(Return(true));
177
178   EXPECT_CALL(*translate_helper_, IsTranslateLibReady())
179       .WillOnce(Return(true));
180
181   EXPECT_CALL(*translate_helper_, StartTranslation()).WillOnce(Return(true));
182
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));
189
190   EXPECT_CALL(*translate_helper_, HasTranslationFinished())
191       .Times(AtLeast(1))
192       .WillRepeatedly(Return(false));
193
194   // V8 call for performance monitoring should be ignored.
195   EXPECT_CALL(*translate_helper_,
196               ExecuteScriptAndGetDoubleResult(_)).Times(2);
197
198   translate_helper_->TranslatePage(
199       view_->GetPageId(), "en", "fr", std::string());
200   base::MessageLoop::current()->RunUntilIdle();
201
202   int page_id;
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);
207 }
208
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
213   // library.
214   EXPECT_CALL(*translate_helper_, IsTranslateLibAvailable())
215       .Times(AtLeast(1))
216       .WillRepeatedly(Return(true));
217
218   EXPECT_CALL(*translate_helper_, IsTranslateLibReady())
219       .WillOnce(Return(true));
220
221   EXPECT_CALL(*translate_helper_, GetOriginalPageLanguage())
222       .WillOnce(Return("de"));
223
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())
228       .Times(AtLeast(1))
229       .WillRepeatedly(Return(true));
230
231   // V8 call for performance monitoring should be ignored.
232   EXPECT_CALL(*translate_helper_,
233               ExecuteScriptAndGetDoubleResult(_)).Times(3);
234
235   translate_helper_->TranslatePage(view_->GetPageId(),
236                                    translate::kUnknownLanguageCode, "fr",
237                                    std::string());
238   base::MessageLoop::current()->RunUntilIdle();
239
240   int page_id;
241   TranslateErrors::Type error;
242   std::string original_lang;
243   std::string target_lang;
244   ASSERT_TRUE(GetPageTranslatedMessage(&page_id, &original_lang, &target_lang,
245                                        &error));
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);
250 }
251
252 // Tests that starting a translation while a similar one is pending does not
253 // break anything.
254 TEST_F(TranslateHelperBrowserTest, MultipleSimilarTranslations) {
255   // We make IsTranslateLibAvailable true so we don't attempt to inject the
256   // library.
257   EXPECT_CALL(*translate_helper_, IsTranslateLibAvailable())
258       .Times(AtLeast(1))
259       .WillRepeatedly(Return(true));
260
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));
269
270   // V8 call for performance monitoring should be ignored.
271   EXPECT_CALL(*translate_helper_,
272               ExecuteScriptAndGetDoubleResult(_)).Times(3);
273
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
279   // happens.
280   translate_helper_->TranslatePage(
281       view_->GetPageId(), original_lang, target_lang, std::string());
282   base::MessageLoop::current()->RunUntilIdle();
283
284   int page_id;
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,
291                                        &error));
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);
296 }
297
298 // Tests that starting a translation while a different one is pending works.
299 TEST_F(TranslateHelperBrowserTest, MultipleDifferentTranslations) {
300   EXPECT_CALL(*translate_helper_, IsTranslateLibAvailable())
301       .Times(AtLeast(1))
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));
311
312   // V8 call for performance monitoring should be ignored.
313   EXPECT_CALL(*translate_helper_,
314               ExecuteScriptAndGetDoubleResult(_)).Times(5);
315
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();
325
326   int page_id;
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,
333                                        &error));
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);
338 }
339
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();
346
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, &params);
353   EXPECT_TRUE(params.b) << "Page should be translatable.";
354   render_thread_->sink().ClearMessages();
355
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, &params);
363   EXPECT_FALSE(params.b) << "Page should not be translatable.";
364   render_thread_->sink().ClearMessages();
365
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, &params);
373   EXPECT_FALSE(params.b) << "Page should not be translatable.";
374 }
375
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();
382
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, &params);
390   EXPECT_EQ("es", params.a.adopted_language);
391   render_thread_->sink().ClearMessages();
392
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, &params);
401   EXPECT_EQ("fr", params.a.adopted_language);
402 }
403
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();
410
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, &params);
418   EXPECT_EQ("es", params.a.adopted_language);
419   render_thread_->sink().ClearMessages();
420
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, &params);
429   EXPECT_EQ("fr", params.a.adopted_language);
430 }
431
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();
439
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, &params);
447   EXPECT_EQ("en-US", params.a.adopted_language);
448   render_thread_->sink().ClearMessages();
449 }
450
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, &params);
461   EXPECT_EQ("zh", params.a.adopted_language);
462   render_thread_->sink().ClearMessages();
463
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, &params);
470   EXPECT_EQ("fr", params.a.adopted_language);
471   render_thread_->sink().ClearMessages();
472
473   GoBack(GetMainFrame()->previousHistoryItem());
474
475   message = render_thread_->sink().GetUniqueMessageMatching(
476       ChromeViewHostMsg_TranslateLanguageDetermined::ID);
477   ASSERT_NE(static_cast<IPC::Message*>(NULL), message);
478   ChromeViewHostMsg_TranslateLanguageDetermined::Read(message, &params);
479   EXPECT_EQ("zh", params.a.adopted_language);
480   render_thread_->sink().ClearMessages();
481 }