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
6#include <set>
7
8#include "base/utf_string_conversions.h"
9#include "chrome/app/chrome_command_ids.h"
10#include "chrome/browser/prefs/pref_service.h"
11#include "chrome/browser/prefs/pref_change_registrar.h"
12#include "chrome/browser/tab_contents/render_view_context_menu.h"
13#include "chrome/browser/translate/translate_infobar_delegate.h"
14#include "chrome/browser/translate/translate_manager.h"
15#include "chrome/browser/translate/translate_prefs.h"
16#include "chrome/browser/ui/tab_contents/test_tab_contents_wrapper.h"
17#include "chrome/common/pref_names.h"
18#include "chrome/common/render_messages.h"
19#include "chrome/common/net/test_url_fetcher_factory.h"
20#include "chrome/test/testing_browser_process.h"
21#include "chrome/test/testing_profile.h"
22#include "content/browser/browser_thread.h"
23#include "content/browser/renderer_host/mock_render_process_host.h"
24#include "content/browser/renderer_host/test_render_view_host.h"
25#include "content/browser/tab_contents/navigation_controller.h"
26#include "content/browser/tab_contents/test_tab_contents.h"
27#include "content/common/notification_details.h"
28#include "content/common/notification_observer_mock.h"
29#include "content/common/notification_registrar.h"
30#include "content/common/notification_type.h"
31#include "content/common/view_messages.h"
32#include "grit/generated_resources.h"
33#include "ipc/ipc_test_sink.h"
34#include "testing/gmock/include/gmock/gmock.h"
35#include "third_party/cld/languages/public/languages.h"
36#include "third_party/WebKit/Source/WebKit/chromium/public/WebContextMenuData.h"
37
38using testing::_;
39using testing::Pointee;
40using testing::Property;
41using WebKit::WebContextMenuData;
42
43class TranslateManagerTest : public TabContentsWrapperTestHarness,
44                             public NotificationObserver {
45 public:
46  TranslateManagerTest()
47      : ui_thread_(BrowserThread::UI, &message_loop_) {
48  }
49
50  // Simluates navigating to a page and getting the page contents and language
51  // for that navigation.
52  void SimulateNavigation(const GURL& url,
53                          const std::string& lang,
54                          bool page_translatable) {
55    NavigateAndCommit(url);
56    SimulateOnTranslateLanguageDetermined(lang, page_translatable);
57  }
58
59  void SimulateOnTranslateLanguageDetermined(const std::string& lang,
60                                             bool page_translatable) {
61    rvh()->TestOnMessageReceived(ViewHostMsg_TranslateLanguageDetermined(
62        0, lang, page_translatable));
63  }
64
65  bool GetTranslateMessage(int* page_id,
66                           std::string* original_lang,
67                           std::string* target_lang) {
68    const IPC::Message* message =
69        process()->sink().GetFirstMessageMatching(ViewMsg_TranslatePage::ID);
70    if (!message)
71      return false;
72    Tuple4<int, std::string, std::string, std::string> translate_param;
73    ViewMsg_TranslatePage::Read(message, &translate_param);
74    if (page_id)
75      *page_id = translate_param.a;
76    // Ignore translate_param.b which is the script injected in the page.
77    if (original_lang)
78      *original_lang = translate_param.c;
79    if (target_lang)
80      *target_lang = translate_param.d;
81    return true;
82  }
83
84  // Returns the translate infobar if there is 1 infobar and it is a translate
85  // infobar.
86  TranslateInfoBarDelegate* GetTranslateInfoBar() {
87    return (contents()->infobar_count() == 1) ?
88        contents()->GetInfoBarDelegateAt(0)->AsTranslateInfoBarDelegate() :
89        NULL;
90  }
91
92  // If there is 1 infobar and it is a translate infobar, closes it and returns
93  // true.  Returns false otherwise.
94  bool CloseTranslateInfoBar() {
95    InfoBarDelegate* infobar = GetTranslateInfoBar();
96    if (!infobar)
97      return false;
98    infobar->InfoBarDismissed();  // Simulates closing the infobar.
99    contents()->RemoveInfoBar(infobar);
100    return true;
101  }
102
103  // Checks whether |infobar| has been removed and clears the removed infobar
104  // list.
105  bool CheckInfoBarRemovedAndReset(InfoBarDelegate* delegate) {
106    bool found = removed_infobars_.count(delegate) != 0;
107    removed_infobars_.clear();
108    return found;
109  }
110
111  // Returns true if at least one infobar was closed.
112  bool InfoBarRemoved() {
113    return !removed_infobars_.empty();
114  }
115
116  // Clears the list of stored removed infobars.
117  void ClearRemovedInfoBars() {
118    removed_infobars_.clear();
119  }
120
121  void ExpireTranslateScriptImmediately() {
122    TranslateManager::GetInstance()->set_translate_script_expiration_delay(0);
123  }
124
125  // If there is 1 infobar and it is a translate infobar, deny translation and
126  // returns true.  Returns false otherwise.
127  bool DenyTranslation() {
128    TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
129    if (!infobar)
130      return false;
131    infobar->TranslationDeclined();
132    contents()->RemoveInfoBar(infobar);
133    return true;
134  }
135
136  virtual void Observe(NotificationType type,
137                       const NotificationSource& source,
138                       const NotificationDetails& details) {
139    DCHECK_EQ(NotificationType::TAB_CONTENTS_INFOBAR_REMOVED, type.value);
140    removed_infobars_.insert(Details<InfoBarDelegate>(details).ptr());
141  }
142
143 protected:
144  virtual void SetUp() {
145    URLFetcher::set_factory(&url_fetcher_factory_);
146
147    // Access the TranslateManager singleton so it is created before we call
148    // RenderViewHostTestHarness::SetUp() to match what's done in Chrome, where
149    // the TranslateManager is created before the TabContents.  This matters as
150    // they both register for similar events and we want the notifications to
151    // happen in the same sequence (TranslateManager first, TabContents second).
152    // Also clears the translate script so it is fetched everytime and sets the
153    // expiration delay to a large value by default (in case it was zeroed in
154    // a previous test).
155    TranslateManager::GetInstance()->ClearTranslateScript();
156    TranslateManager::GetInstance()->
157        set_translate_script_expiration_delay(60 * 60 * 1000);
158
159    TabContentsWrapperTestHarness::SetUp();
160
161    notification_registrar_.Add(this,
162        NotificationType::TAB_CONTENTS_INFOBAR_REMOVED,
163        Source<TabContents>(contents()));
164  }
165
166  virtual void TearDown() {
167    process()->sink().ClearMessages();
168
169    notification_registrar_.Remove(this,
170        NotificationType::TAB_CONTENTS_INFOBAR_REMOVED,
171        Source<TabContents>(contents()));
172
173    TabContentsWrapperTestHarness::TearDown();
174
175    URLFetcher::set_factory(NULL);
176  }
177
178  void SimulateURLFetch(bool success) {
179    TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0);
180    ASSERT_TRUE(fetcher);
181    net::URLRequestStatus status;
182    status.set_status(success ? net::URLRequestStatus::SUCCESS :
183                                net::URLRequestStatus::FAILED);
184    fetcher->delegate()->OnURLFetchComplete(fetcher, fetcher->original_url(),
185                                            status, success ? 200 : 500,
186                                            ResponseCookies(),
187                                            std::string());
188  }
189
190  void SetPrefObserverExpectation(const char* path) {
191    EXPECT_CALL(
192        pref_observer_,
193        Observe(NotificationType(NotificationType::PREF_CHANGED),
194                _,
195                Property(&Details<std::string>::ptr, Pointee(path))));
196  }
197
198  NotificationObserverMock pref_observer_;
199
200 private:
201  NotificationRegistrar notification_registrar_;
202  TestURLFetcherFactory url_fetcher_factory_;
203  BrowserThread ui_thread_;
204
205  // The infobars that have been removed.
206  // WARNING: the pointers point to deleted objects, use only for comparison.
207  std::set<InfoBarDelegate*> removed_infobars_;
208
209  DISALLOW_COPY_AND_ASSIGN(TranslateManagerTest);
210};
211
212// An observer that keeps track of whether a navigation entry was committed.
213class NavEntryCommittedObserver : public NotificationObserver {
214 public:
215  explicit NavEntryCommittedObserver(TabContents* tab_contents) {
216    registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED,
217                   Source<NavigationController>(&tab_contents->controller()));
218  }
219
220  virtual void Observe(NotificationType type,
221                       const NotificationSource& source,
222                       const NotificationDetails& details) {
223    DCHECK(type == NotificationType::NAV_ENTRY_COMMITTED);
224    details_ =
225        *(Details<NavigationController::LoadCommittedDetails>(details).ptr());
226  }
227
228  const NavigationController::LoadCommittedDetails&
229      get_load_commited_details() const {
230    return details_;
231  }
232
233 private:
234  NavigationController::LoadCommittedDetails details_;
235  NotificationRegistrar registrar_;
236
237  DISALLOW_COPY_AND_ASSIGN(NavEntryCommittedObserver);
238};
239
240class TestRenderViewContextMenu : public RenderViewContextMenu {
241 public:
242  static TestRenderViewContextMenu* CreateContextMenu(
243      TabContents* tab_contents) {
244    ContextMenuParams params;
245    params.media_type = WebKit::WebContextMenuData::MediaTypeNone;
246    params.x = 0;
247    params.y = 0;
248    params.is_image_blocked = false;
249    params.media_flags = 0;
250    params.spellcheck_enabled = false;
251    params.is_editable = false;
252    params.page_url = tab_contents->controller().GetActiveEntry()->url();
253#if defined(OS_MACOSX)
254    params.writing_direction_default = 0;
255    params.writing_direction_left_to_right = 0;
256    params.writing_direction_right_to_left = 0;
257#endif  // OS_MACOSX
258    params.edit_flags = WebContextMenuData::CanTranslate;
259    return new TestRenderViewContextMenu(tab_contents, params);
260  }
261
262  bool IsItemPresent(int id) {
263    return menu_model_.GetIndexOfCommandId(id) != -1;
264  }
265
266  virtual void PlatformInit() { }
267  virtual bool GetAcceleratorForCommandId(
268      int command_id,
269      ui::Accelerator* accelerator) { return false; }
270
271 private:
272  TestRenderViewContextMenu(TabContents* tab_contents,
273                            const ContextMenuParams& params)
274      : RenderViewContextMenu(tab_contents, params) {
275  }
276
277  DISALLOW_COPY_AND_ASSIGN(TestRenderViewContextMenu);
278};
279
280TEST_F(TranslateManagerTest, NormalTranslate) {
281  // Simulate navigating to a page.
282  SimulateNavigation(GURL("http://www.google.fr"), "fr", true);
283
284  // We should have an infobar.
285  TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
286  ASSERT_TRUE(infobar != NULL);
287  EXPECT_EQ(TranslateInfoBarDelegate::BEFORE_TRANSLATE, infobar->type());
288
289  // Simulate clicking translate.
290  process()->sink().ClearMessages();
291  infobar->Translate();
292
293  // The "Translating..." infobar should be showing.
294  infobar = GetTranslateInfoBar();
295  ASSERT_TRUE(infobar != NULL);
296  EXPECT_EQ(TranslateInfoBarDelegate::TRANSLATING, infobar->type());
297
298  // Simulate the translate script being retrieved (it only needs to be done
299  // once in the test as it is cached).
300  SimulateURLFetch(true);
301
302  // Test that we sent the right message to the renderer.
303  int page_id = 0;
304  std::string original_lang, target_lang;
305  EXPECT_TRUE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
306  EXPECT_EQ("fr", original_lang);
307  EXPECT_EQ("en", target_lang);
308
309  // Simulate the render notifying the translation has been done.
310  rvh()->TestOnMessageReceived(ViewHostMsg_PageTranslated(0, 0, "fr", "en",
311      TranslateErrors::NONE));
312
313  // The after translate infobar should be showing.
314  infobar = GetTranslateInfoBar();
315  ASSERT_TRUE(infobar != NULL);
316  EXPECT_EQ(TranslateInfoBarDelegate::AFTER_TRANSLATE, infobar->type());
317
318  // Simulate changing the original language, this should trigger a translation.
319  process()->sink().ClearMessages();
320  std::string new_original_lang = infobar->GetLanguageCodeAt(0);
321  infobar->SetOriginalLanguage(0);
322  EXPECT_TRUE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
323  EXPECT_EQ(new_original_lang, original_lang);
324  EXPECT_EQ("en", target_lang);
325  // Simulate the render notifying the translation has been done.
326  rvh()->TestOnMessageReceived(ViewHostMsg_PageTranslated(0, 0,
327      new_original_lang, "en", TranslateErrors::NONE));
328  // infobar is now invalid.
329  TranslateInfoBarDelegate* new_infobar = GetTranslateInfoBar();
330  ASSERT_TRUE(new_infobar != NULL);
331  infobar = new_infobar;
332
333  // Simulate changing the target language, this should trigger a translation.
334  process()->sink().ClearMessages();
335  std::string new_target_lang = infobar->GetLanguageCodeAt(1);
336  infobar->SetTargetLanguage(1);
337  EXPECT_TRUE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
338  EXPECT_EQ(new_original_lang, original_lang);
339  EXPECT_EQ(new_target_lang, target_lang);
340  // Simulate the render notifying the translation has been done.
341  rvh()->TestOnMessageReceived(ViewHostMsg_PageTranslated(0, 0,
342      new_original_lang, new_target_lang, TranslateErrors::NONE));
343  // infobar is now invalid.
344  new_infobar = GetTranslateInfoBar();
345  ASSERT_TRUE(new_infobar != NULL);
346}
347
348TEST_F(TranslateManagerTest, TranslateScriptNotAvailable) {
349  // Simulate navigating to a page.
350  SimulateNavigation(GURL("http://www.google.fr"), "fr", true);
351
352  // We should have an infobar.
353  TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
354  ASSERT_TRUE(infobar != NULL);
355  EXPECT_EQ(TranslateInfoBarDelegate::BEFORE_TRANSLATE, infobar->type());
356
357  // Simulate clicking translate.
358  process()->sink().ClearMessages();
359  infobar->Translate();
360  // Simulate a failure retrieving the translate script.
361  SimulateURLFetch(false);
362
363  // We should not have sent any message to translate to the renderer.
364  EXPECT_FALSE(GetTranslateMessage(NULL, NULL, NULL));
365
366  // And we should have an error infobar showing.
367  infobar = GetTranslateInfoBar();
368  ASSERT_TRUE(infobar != NULL);
369  EXPECT_EQ(TranslateInfoBarDelegate::TRANSLATION_ERROR, infobar->type());
370}
371
372// Ensures we deal correctly with pages for which the browser does not recognize
373// the language (the translate server may or not detect the language).
374TEST_F(TranslateManagerTest, TranslateUnknownLanguage) {
375  // Simulate navigating to a page ("und" is the string returned by the CLD for
376  // languages it does not recognize).
377  SimulateNavigation(GURL("http://www.google.mys"), "und", true);
378
379  // We should not have an infobar as we don't know the language.
380  ASSERT_TRUE(GetTranslateInfoBar() == NULL);
381
382  // Translate the page anyway throught the context menu.
383  scoped_ptr<TestRenderViewContextMenu> menu(
384      TestRenderViewContextMenu::CreateContextMenu(contents()));
385  menu->Init();
386  menu->ExecuteCommand(IDC_CONTENT_CONTEXT_TRANSLATE);
387
388  // To test that bug #49018 if fixed, make sure we deal correctly with errors.
389  SimulateURLFetch(false);  // Simulate a failure to fetch the translate script.
390  TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
391  ASSERT_TRUE(infobar != NULL);
392  EXPECT_EQ(TranslateInfoBarDelegate::TRANSLATION_ERROR, infobar->type());
393  EXPECT_TRUE(infobar->IsError());
394  infobar->MessageInfoBarButtonPressed();
395  SimulateURLFetch(true);  // This time succeed.
396
397  // Simulate the render notifying the translation has been done, the server
398  // having detected the page was in a known and supported language.
399  rvh()->TestOnMessageReceived(ViewHostMsg_PageTranslated(0, 0, "fr", "en",
400      TranslateErrors::NONE));
401
402  // The after translate infobar should be showing.
403  infobar = GetTranslateInfoBar();
404  ASSERT_TRUE(infobar != NULL);
405  EXPECT_EQ(TranslateInfoBarDelegate::AFTER_TRANSLATE, infobar->type());
406  EXPECT_EQ("fr", infobar->GetOriginalLanguageCode());
407  EXPECT_EQ("en", infobar->GetTargetLanguageCode());
408
409  // Let's run the same steps but this time the server detects the page is
410  // already in English.
411  SimulateNavigation(GURL("http://www.google.com"), "und", true);
412  menu.reset(TestRenderViewContextMenu::CreateContextMenu(contents()));
413  menu->Init();
414  menu->ExecuteCommand(IDC_CONTENT_CONTEXT_TRANSLATE);
415  rvh()->TestOnMessageReceived(ViewHostMsg_PageTranslated(1, 0, "en", "en",
416      TranslateErrors::IDENTICAL_LANGUAGES));
417  infobar = GetTranslateInfoBar();
418  ASSERT_TRUE(infobar != NULL);
419  EXPECT_EQ(TranslateInfoBarDelegate::TRANSLATION_ERROR, infobar->type());
420  EXPECT_EQ(TranslateErrors::IDENTICAL_LANGUAGES, infobar->error());
421
422  // Let's run the same steps again but this time the server fails to detect the
423  // page's language (it returns an empty string).
424  SimulateNavigation(GURL("http://www.google.com"), "und", true);
425  menu.reset(TestRenderViewContextMenu::CreateContextMenu(contents()));
426  menu->Init();
427  menu->ExecuteCommand(IDC_CONTENT_CONTEXT_TRANSLATE);
428  rvh()->TestOnMessageReceived(ViewHostMsg_PageTranslated(2, 0, "", "en",
429      TranslateErrors::UNKNOWN_LANGUAGE));
430  infobar = GetTranslateInfoBar();
431  ASSERT_TRUE(infobar != NULL);
432  EXPECT_EQ(TranslateInfoBarDelegate::TRANSLATION_ERROR, infobar->type());
433  EXPECT_EQ(TranslateErrors::UNKNOWN_LANGUAGE, infobar->error());
434}
435
436// Tests that we show/don't show an info-bar for all languages the CLD can
437// report.
438TEST_F(TranslateManagerTest, TestAllLanguages) {
439  // The index in kExpectation are the Language enum (see languages.pb.h).
440  // true if we expect a translate infobar for that language.
441  // Note the supported languages are in translation_manager.cc, see
442  // kSupportedLanguages.
443  bool kExpectations[] = {
444    // 0-9
445    false, true, true, true, true, true, true, true, true, true,
446    // 10-19
447    true, true, true, true, true, true, true, true, true, true,
448    // 20-29
449    true, true, true, true, true, false, false, true, true, true,
450    // 30-39
451    true, true, true, true, true, true, true, false, true, false,
452    // 40-49
453    true, false, true, false, false, true, false, true, false, false,
454    // 50-59
455    true, false, false, true, true, true, false, true, false, false,
456    // 60-69
457    false, false, true, true, false, true, true, false, true, true,
458    // 70-79
459    false, false, false, false, true, true, false, true, false, false,
460    // 80-89
461    false, false, false, false, false, false, false, false, false, false,
462    // 90-99
463    false, true, false, false, false, false, false, true, false, false,
464    // 100-109
465    false, true, false, false, false, false, false, false, false, false,
466    // 110-119
467    false, false, false, false, false, false, false, false, false, false,
468    // 120-129
469    false, false, false, false, false, false, false, false, false, false,
470    // 130-139
471    false, false, false, false, false, false, false, false, false, true,
472    // 140-149
473    false, false, false, false, false, false, false, false, false, false,
474    // 150-159
475    false, false, false, false, false, false, false, false, false, false,
476    // 160
477    false
478  };
479
480  GURL url("http://www.google.com");
481  for (size_t i = 0; i < arraysize(kExpectations); ++i) {
482    ASSERT_LT(i, static_cast<size_t>(NUM_LANGUAGES));
483
484    std::string lang = LanguageCodeWithDialects(static_cast<Language>(i));
485    SCOPED_TRACE(::testing::Message() << "Iteration " << i <<
486        " language=" << lang);
487
488    // We should not have a translate infobar.
489    TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
490    ASSERT_TRUE(infobar == NULL);
491
492    // Simulate navigating to a page.
493    NavigateAndCommit(url);
494    SimulateOnTranslateLanguageDetermined(lang, true);
495
496    // Verify we have/don't have an info-bar as expected.
497    infobar = GetTranslateInfoBar();
498    EXPECT_EQ(kExpectations[i], infobar != NULL);
499
500    // Close the info-bar if applicable.
501    if (infobar != NULL)
502      EXPECT_TRUE(CloseTranslateInfoBar());
503  }
504}
505
506// Tests auto-translate on page.
507TEST_F(TranslateManagerTest, AutoTranslateOnNavigate) {
508  // Simulate navigating to a page and getting its language.
509  SimulateNavigation(GURL("http://www.google.fr"), "fr", true);
510
511  // Simulate the user translating.
512  TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
513  ASSERT_TRUE(infobar != NULL);
514  infobar->Translate();
515  SimulateURLFetch(true);  // Simulate the translate script being retrieved.
516
517  rvh()->TestOnMessageReceived(ViewHostMsg_PageTranslated(0, 0, "fr", "en",
518      TranslateErrors::NONE));
519
520  // Now navigate to a new page in the same language.
521  process()->sink().ClearMessages();
522  SimulateNavigation(GURL("http://news.google.fr"), "fr", true);
523
524  // This should have automatically triggered a translation.
525  int page_id = 0;
526  std::string original_lang, target_lang;
527  EXPECT_TRUE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
528  EXPECT_EQ(1, page_id);
529  EXPECT_EQ("fr", original_lang);
530  EXPECT_EQ("en", target_lang);
531
532  // Now navigate to a page in a different language.
533  process()->sink().ClearMessages();
534  SimulateNavigation(GURL("http://news.google.es"), "es", true);
535
536  // This should not have triggered a translate.
537  EXPECT_FALSE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
538}
539
540// Tests that multiple OnPageContents do not cause multiple infobars.
541TEST_F(TranslateManagerTest, MultipleOnPageContents) {
542  // Simulate navigating to a page and getting its language.
543  SimulateNavigation(GURL("http://www.google.fr"), "fr", true);
544
545  // Simulate clicking 'Nope' (don't translate).
546  EXPECT_TRUE(DenyTranslation());
547  EXPECT_EQ(0U, contents()->infobar_count());
548
549  // Send a new PageContents, we should not show an infobar.
550  SimulateOnTranslateLanguageDetermined("fr", true);
551  EXPECT_EQ(0U, contents()->infobar_count());
552
553  // Do the same steps but simulate closing the infobar this time.
554  SimulateNavigation(GURL("http://www.youtube.fr"), "fr", true);
555  EXPECT_TRUE(CloseTranslateInfoBar());
556  EXPECT_EQ(0U, contents()->infobar_count());
557  SimulateOnTranslateLanguageDetermined("fr", true);
558  EXPECT_EQ(0U, contents()->infobar_count());
559}
560
561// Test that reloading the page brings back the infobar.
562TEST_F(TranslateManagerTest, Reload) {
563  // Simulate navigating to a page and getting its language.
564  SimulateNavigation(GURL("http://www.google.fr"), "fr", true);
565
566  // Close the infobar.
567  EXPECT_TRUE(CloseTranslateInfoBar());
568
569  // Reload should bring back the infobar.
570  NavEntryCommittedObserver nav_observer(contents());
571  Reload();
572
573  // Ensures it is really handled a reload.
574  const NavigationController::LoadCommittedDetails& nav_details =
575      nav_observer.get_load_commited_details();
576  EXPECT_TRUE(nav_details.entry != NULL);  // There was a navigation.
577  EXPECT_EQ(NavigationType::EXISTING_PAGE, nav_details.type);
578
579  // The TranslateManager class processes the navigation entry committed
580  // notification in a posted task; process that task.
581  MessageLoop::current()->RunAllPending();
582  EXPECT_TRUE(GetTranslateInfoBar() != NULL);
583}
584
585// Test that reloading the page by way of typing again the URL in the
586// location bar brings back the infobar.
587TEST_F(TranslateManagerTest, ReloadFromLocationBar) {
588  GURL url("http://www.google.fr");
589
590  // Simulate navigating to a page and getting its language.
591  SimulateNavigation(url, "fr", true);
592
593  // Close the infobar.
594  EXPECT_TRUE(CloseTranslateInfoBar());
595
596  // Create a pending navigation and simulate a page load.  That should be the
597  // equivalent of typing the URL again in the location bar.
598  NavEntryCommittedObserver nav_observer(contents());
599  contents()->controller().LoadURL(url, GURL(), PageTransition::TYPED);
600  rvh()->SendNavigate(0, url);
601
602  // Test that we are really getting a same page navigation, the test would be
603  // useless if it was not the case.
604  const NavigationController::LoadCommittedDetails& nav_details =
605      nav_observer.get_load_commited_details();
606  EXPECT_TRUE(nav_details.entry != NULL);  // There was a navigation.
607  EXPECT_EQ(NavigationType::SAME_PAGE, nav_details.type);
608
609  // The TranslateManager class processes the navigation entry committed
610  // notification in a posted task; process that task.
611  MessageLoop::current()->RunAllPending();
612  EXPECT_TRUE(GetTranslateInfoBar() != NULL);
613}
614
615// Tests that a closed translate infobar does not reappear when navigating
616// in-page.
617TEST_F(TranslateManagerTest, CloseInfoBarInPageNavigation) {
618  // Simulate navigating to a page and getting its language.
619  SimulateNavigation(GURL("http://www.google.fr"), "fr", true);
620
621  // Close the infobar.
622  EXPECT_TRUE(CloseTranslateInfoBar());
623
624  // Navigate in page, no infobar should be shown.
625  SimulateNavigation(GURL("http://www.google.fr/#ref1"), "fr",
626                     true);
627  EXPECT_TRUE(GetTranslateInfoBar() == NULL);
628
629  // Navigate out of page, a new infobar should show.
630  SimulateNavigation(GURL("http://www.google.fr/foot"), "fr", true);
631  EXPECT_TRUE(GetTranslateInfoBar() != NULL);
632}
633
634// Tests that a closed translate infobar does not reappear when navigating
635// in a subframe. (http://crbug.com/48215)
636TEST_F(TranslateManagerTest, CloseInfoBarInSubframeNavigation) {
637  // Simulate navigating to a page and getting its language.
638  SimulateNavigation(GURL("http://www.google.fr"), "fr", true);
639
640  // Close the infobar.
641  EXPECT_TRUE(CloseTranslateInfoBar());
642
643  // Simulate a sub-frame auto-navigating.
644  rvh()->SendNavigateWithTransition(1, GURL("http://pub.com"),
645                                    PageTransition::AUTO_SUBFRAME);
646  EXPECT_TRUE(GetTranslateInfoBar() == NULL);
647
648  // Simulate the user navigating in a sub-frame.
649  rvh()->SendNavigateWithTransition(2, GURL("http://pub.com"),
650                                    PageTransition::MANUAL_SUBFRAME);
651  EXPECT_TRUE(GetTranslateInfoBar() == NULL);
652
653  // Navigate out of page, a new infobar should show.
654  SimulateNavigation(GURL("http://www.google.fr/foot"), "fr", true);
655  EXPECT_TRUE(GetTranslateInfoBar() != NULL);
656}
657
658
659
660// Tests that denying translation is sticky when navigating in page.
661TEST_F(TranslateManagerTest, DenyTranslateInPageNavigation) {
662  // Simulate navigating to a page and getting its language.
663  SimulateNavigation(GURL("http://www.google.fr"), "fr", true);
664
665  // Simulate clicking 'Nope' (don't translate).
666  EXPECT_TRUE(DenyTranslation());
667
668  // Navigate in page, no infobar should be shown.
669  SimulateNavigation(GURL("http://www.google.fr/#ref1"), "fr", true);
670  EXPECT_TRUE(GetTranslateInfoBar() == NULL);
671
672  // Navigate out of page, a new infobar should show.
673  SimulateNavigation(GURL("http://www.google.fr/foot"), "fr", true);
674  EXPECT_TRUE(GetTranslateInfoBar() != NULL);
675}
676
677// Tests that after translating and closing the infobar, the infobar does not
678// return when navigating in page.
679TEST_F(TranslateManagerTest, TranslateCloseInfoBarInPageNavigation) {
680  // Simulate navigating to a page and getting its language.
681  SimulateNavigation(GURL("http://www.google.fr"), "fr", true);
682
683  // Simulate the user translating.
684  TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
685  ASSERT_TRUE(infobar != NULL);
686  infobar->Translate();
687  SimulateURLFetch(true);  // Simulate the translate script being retrieved.
688  rvh()->TestOnMessageReceived(ViewHostMsg_PageTranslated(0, 0, "fr", "en",
689      TranslateErrors::NONE));
690
691  // Close the infobar.
692  EXPECT_TRUE(CloseTranslateInfoBar());
693
694  // Navigate in page, no infobar should be shown.
695  SimulateNavigation(GURL("http://www.google.fr/#ref1"), "fr", true);
696  EXPECT_TRUE(GetTranslateInfoBar() == NULL);
697
698  // Navigate out of page, a new infobar should show.
699  // Note that we navigate to a page in a different language so we don't trigger
700  // the auto-translate feature (it would translate the page automatically and
701  // the before translate inforbar would not be shown).
702  SimulateNavigation(GURL("http://www.google.de"), "de", true);
703  EXPECT_TRUE(GetTranslateInfoBar() != NULL);
704}
705
706// Tests that the after translate the infobar still shows when navigating
707// in-page.
708TEST_F(TranslateManagerTest, TranslateInPageNavigation) {
709  // Simulate navigating to a page and getting its language.
710  SimulateNavigation(GURL("http://www.google.fr"), "fr", true);
711
712  // Simulate the user translating.
713  TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
714  ASSERT_TRUE(infobar != NULL);
715  infobar->Translate();
716  SimulateURLFetch(true);  // Simulate the translate script being retrieved.
717  rvh()->TestOnMessageReceived(ViewHostMsg_PageTranslated(0, 0, "fr", "en",
718      TranslateErrors::NONE));
719  // The after translate infobar is showing.
720  infobar = GetTranslateInfoBar();
721  ASSERT_TRUE(infobar != NULL);
722
723  // Navigate in page, the same infobar should still be shown.
724  ClearRemovedInfoBars();
725  SimulateNavigation(GURL("http://www.google.fr/#ref1"), "fr",
726                     true);
727  EXPECT_FALSE(InfoBarRemoved());
728  EXPECT_EQ(infobar, GetTranslateInfoBar());
729
730  // Navigate out of page, a new infobar should show.
731  // See note in TranslateCloseInfoBarInPageNavigation test on why it is
732  // important to navigate to a page in a different language for this test.
733  SimulateNavigation(GURL("http://www.google.de"), "de", true);
734  // The old infobar is gone.
735  EXPECT_TRUE(CheckInfoBarRemovedAndReset(infobar));
736  // And there is a new one.
737  EXPECT_TRUE(GetTranslateInfoBar() != NULL);
738}
739
740// Tests that no translate infobar is shown when navigating to a page in an
741// unsupported language.
742TEST_F(TranslateManagerTest, CLDReportsUnsupportedPageLanguage) {
743  // Simulate navigating to a page and getting an unsupported language.
744  SimulateNavigation(GURL("http://www.google.com"), "qbz", true);
745
746  // No info-bar should be shown.
747  EXPECT_TRUE(GetTranslateInfoBar() == NULL);
748}
749
750// Tests that we deal correctly with unsupported languages returned by the
751// server.
752// The translation server might return a language we don't support.
753TEST_F(TranslateManagerTest, ServerReportsUnsupportedLanguage) {
754  // Simulate navigating to a page and translating it.
755  SimulateNavigation(GURL("http://mail.google.fr"), "fr", true);
756  TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
757  ASSERT_TRUE(infobar != NULL);
758  process()->sink().ClearMessages();
759  infobar->Translate();
760  SimulateURLFetch(true);
761  // Simulate the render notifying the translation has been done, but it
762  // reports a language we don't support.
763  rvh()->TestOnMessageReceived(ViewHostMsg_PageTranslated(0, 0, "qbz", "en",
764      TranslateErrors::NONE));
765
766  // An error infobar should be showing to report that we don't support this
767  // language.
768  infobar = GetTranslateInfoBar();
769  ASSERT_TRUE(infobar != NULL);
770  EXPECT_EQ(TranslateInfoBarDelegate::TRANSLATION_ERROR, infobar->type());
771
772  // This infobar should have a button (so the string should not be empty).
773  ASSERT_FALSE(infobar->GetMessageInfoBarButtonText().empty());
774
775  // Pressing the button on that infobar should revert to the original language.
776  process()->sink().ClearMessages();
777  infobar->MessageInfoBarButtonPressed();
778  const IPC::Message* message =
779      process()->sink().GetFirstMessageMatching(ViewMsg_RevertTranslation::ID);
780  EXPECT_TRUE(message != NULL);
781  // And it should have removed the infobar.
782  EXPECT_TRUE(GetTranslateInfoBar() == NULL);
783}
784
785// Tests that no translate infobar is shown when Chrome is in a language that
786// the translate server does not support.
787TEST_F(TranslateManagerTest, UnsupportedUILanguage) {
788  TestingBrowserProcess* browser_process =
789      static_cast<TestingBrowserProcess*>(g_browser_process);
790  std::string original_lang = browser_process->GetApplicationLocale();
791  browser_process->SetApplicationLocale("qbz");
792
793  // Simulate navigating to a page in a language supported by the translate
794  // server.
795  SimulateNavigation(GURL("http://www.google.com"), "en", true);
796
797  // No info-bar should be shown.
798  EXPECT_TRUE(GetTranslateInfoBar() == NULL);
799
800  browser_process->SetApplicationLocale(original_lang);
801}
802
803// Tests that the translate enabled preference is honored.
804TEST_F(TranslateManagerTest, TranslateEnabledPref) {
805  // Make sure the pref allows translate.
806  PrefService* prefs = contents()->profile()->GetPrefs();
807  prefs->SetBoolean(prefs::kEnableTranslate, true);
808
809  // Simulate navigating to a page and getting its language.
810  SimulateNavigation(GURL("http://www.google.fr"), "fr", true);
811
812  // An infobar should be shown.
813  TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
814  EXPECT_TRUE(infobar != NULL);
815
816  // Disable translate.
817  prefs->SetBoolean(prefs::kEnableTranslate, false);
818
819  // Navigate to a new page, that should close the previous infobar.
820  GURL url("http://www.youtube.fr");
821  NavigateAndCommit(url);
822  infobar = GetTranslateInfoBar();
823  EXPECT_TRUE(infobar == NULL);
824
825  // Simulate getting the page contents and language, that should not trigger
826  // a translate infobar.
827  SimulateOnTranslateLanguageDetermined("fr", true);
828  infobar = GetTranslateInfoBar();
829  EXPECT_TRUE(infobar == NULL);
830}
831
832// Tests the "Never translate <language>" pref.
833TEST_F(TranslateManagerTest, NeverTranslateLanguagePref) {
834  // Simulate navigating to a page and getting its language.
835  GURL url("http://www.google.fr");
836  SimulateNavigation(url, "fr", true);
837
838  // An infobar should be shown.
839  EXPECT_TRUE(GetTranslateInfoBar() != NULL);
840
841  // Select never translate this language.
842  PrefService* prefs = contents()->profile()->GetPrefs();
843  PrefChangeRegistrar registrar;
844  registrar.Init(prefs);
845  registrar.Add(TranslatePrefs::kPrefTranslateLanguageBlacklist,
846                &pref_observer_);
847  TranslatePrefs translate_prefs(prefs);
848  EXPECT_FALSE(translate_prefs.IsLanguageBlacklisted("fr"));
849  EXPECT_TRUE(translate_prefs.CanTranslate(prefs, "fr", url));
850  SetPrefObserverExpectation(TranslatePrefs::kPrefTranslateLanguageBlacklist);
851  translate_prefs.BlacklistLanguage("fr");
852  EXPECT_TRUE(translate_prefs.IsLanguageBlacklisted("fr"));
853  EXPECT_FALSE(translate_prefs.CanTranslate(prefs, "fr", url));
854
855  // Close the infobar.
856  EXPECT_TRUE(CloseTranslateInfoBar());
857
858  // Navigate to a new page also in French.
859  SimulateNavigation(GURL("http://wwww.youtube.fr"), "fr", true);
860
861  // There should not be a translate infobar.
862  EXPECT_TRUE(GetTranslateInfoBar() == NULL);
863
864  // Remove the language from the blacklist.
865  SetPrefObserverExpectation(TranslatePrefs::kPrefTranslateLanguageBlacklist);
866  translate_prefs.RemoveLanguageFromBlacklist("fr");
867  EXPECT_FALSE(translate_prefs.IsLanguageBlacklisted("fr"));
868  EXPECT_TRUE(translate_prefs.CanTranslate(prefs, "fr", url));
869
870  // Navigate to a page in French.
871  SimulateNavigation(url, "fr", true);
872
873  // There should be a translate infobar.
874  EXPECT_TRUE(GetTranslateInfoBar() != NULL);
875}
876
877// Tests the "Never translate this site" pref.
878TEST_F(TranslateManagerTest, NeverTranslateSitePref) {
879  // Simulate navigating to a page and getting its language.
880  GURL url("http://www.google.fr");
881  std::string host(url.host());
882  SimulateNavigation(url, "fr", true);
883
884  // An infobar should be shown.
885  EXPECT_TRUE(GetTranslateInfoBar() != NULL);
886
887  // Select never translate this site.
888  PrefService* prefs = contents()->profile()->GetPrefs();
889  PrefChangeRegistrar registrar;
890  registrar.Init(prefs);
891  registrar.Add(TranslatePrefs::kPrefTranslateSiteBlacklist,
892                &pref_observer_);
893  TranslatePrefs translate_prefs(prefs);
894  EXPECT_FALSE(translate_prefs.IsSiteBlacklisted(host));
895  EXPECT_TRUE(translate_prefs.CanTranslate(prefs, "fr", url));
896  SetPrefObserverExpectation(TranslatePrefs::kPrefTranslateSiteBlacklist);
897  translate_prefs.BlacklistSite(host);
898  EXPECT_TRUE(translate_prefs.IsSiteBlacklisted(host));
899  EXPECT_FALSE(translate_prefs.CanTranslate(prefs, "fr", url));
900
901  // Close the infobar.
902  EXPECT_TRUE(CloseTranslateInfoBar());
903
904  // Navigate to a new page also on the same site.
905  SimulateNavigation(GURL("http://www.google.fr/hello"), "fr", true);
906
907  // There should not be a translate infobar.
908  EXPECT_TRUE(GetTranslateInfoBar() == NULL);
909
910  // Remove the site from the blacklist.
911  SetPrefObserverExpectation(TranslatePrefs::kPrefTranslateSiteBlacklist);
912  translate_prefs.RemoveSiteFromBlacklist(host);
913  EXPECT_FALSE(translate_prefs.IsSiteBlacklisted(host));
914  EXPECT_TRUE(translate_prefs.CanTranslate(prefs, "fr", url));
915
916  // Navigate to a page in French.
917  SimulateNavigation(url, "fr", true);
918
919  // There should be a translate infobar.
920  EXPECT_TRUE(GetTranslateInfoBar() != NULL);
921}
922
923// Tests the "Always translate this language" pref.
924TEST_F(TranslateManagerTest, AlwaysTranslateLanguagePref) {
925  // Select always translate French to English.
926  PrefService* prefs = contents()->profile()->GetPrefs();
927  PrefChangeRegistrar registrar;
928  registrar.Init(prefs);
929  registrar.Add(TranslatePrefs::kPrefTranslateWhitelists,
930                &pref_observer_);
931  TranslatePrefs translate_prefs(prefs);
932  SetPrefObserverExpectation(TranslatePrefs::kPrefTranslateWhitelists);
933  translate_prefs.WhitelistLanguagePair("fr", "en");
934
935  // Load a page in French.
936  SimulateNavigation(GURL("http://www.google.fr"), "fr", true);
937
938  // It should have triggered an automatic translation to English.
939
940  // The translating infobar should be showing.
941  TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
942  ASSERT_TRUE(infobar != NULL);
943  EXPECT_EQ(TranslateInfoBarDelegate::TRANSLATING, infobar->type());
944
945  SimulateURLFetch(true);  // Simulate the translate script being retrieved.
946  int page_id = 0;
947  std::string original_lang, target_lang;
948  EXPECT_TRUE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
949  EXPECT_EQ("fr", original_lang);
950  EXPECT_EQ("en", target_lang);
951  process()->sink().ClearMessages();
952
953  // Try another language, it should not be autotranslated.
954  SimulateNavigation(GURL("http://www.google.es"), "es", true);
955  EXPECT_FALSE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
956  EXPECT_TRUE(GetTranslateInfoBar() != NULL);
957  EXPECT_TRUE(CloseTranslateInfoBar());
958
959  // Let's switch to incognito mode, it should not be autotranslated in that
960  // case either.
961  TestingProfile* test_profile =
962      static_cast<TestingProfile*>(contents()->profile());
963  test_profile->set_incognito(true);
964  SimulateNavigation(GURL("http://www.youtube.fr"), "fr", true);
965  EXPECT_FALSE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
966  EXPECT_TRUE(GetTranslateInfoBar() != NULL);
967  EXPECT_TRUE(CloseTranslateInfoBar());
968  test_profile->set_incognito(false);  // Get back to non incognito.
969
970  // Now revert the always translate pref and make sure we go back to expected
971  // behavior, which is show a "before translate" infobar.
972  SetPrefObserverExpectation(TranslatePrefs::kPrefTranslateWhitelists);
973  translate_prefs.RemoveLanguagePairFromWhitelist("fr", "en");
974  SimulateNavigation(GURL("http://www.google.fr"), "fr", true);
975  EXPECT_FALSE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
976  infobar = GetTranslateInfoBar();
977  ASSERT_TRUE(infobar != NULL);
978  EXPECT_EQ(TranslateInfoBarDelegate::BEFORE_TRANSLATE, infobar->type());
979}
980
981// Context menu.
982TEST_F(TranslateManagerTest, ContextMenu) {
983  // Blacklist www.google.fr and French for translation.
984  GURL url("http://www.google.fr");
985  TranslatePrefs translate_prefs(contents()->profile()->GetPrefs());
986  translate_prefs.BlacklistLanguage("fr");
987  translate_prefs.BlacklistSite(url.host());
988  EXPECT_TRUE(translate_prefs.IsLanguageBlacklisted("fr"));
989  EXPECT_TRUE(translate_prefs.IsSiteBlacklisted(url.host()));
990
991  // Simulate navigating to a page in French. The translate menu should show but
992  // should only be enabled when the page language has been received.
993  NavigateAndCommit(url);
994  scoped_ptr<TestRenderViewContextMenu> menu(
995      TestRenderViewContextMenu::CreateContextMenu(contents()));
996  menu->Init();
997  EXPECT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_TRANSLATE));
998  EXPECT_FALSE(menu->IsCommandIdEnabled(IDC_CONTENT_CONTEXT_TRANSLATE));
999
1000  // Simulate receiving the language.
1001  SimulateOnTranslateLanguageDetermined("fr", true);
1002  menu.reset(TestRenderViewContextMenu::CreateContextMenu(contents()));
1003  menu->Init();
1004  EXPECT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_TRANSLATE));
1005  EXPECT_TRUE(menu->IsCommandIdEnabled(IDC_CONTENT_CONTEXT_TRANSLATE));
1006
1007  // Use the menu to translate the page.
1008  menu->ExecuteCommand(IDC_CONTENT_CONTEXT_TRANSLATE);
1009
1010  // That should have triggered a translation.
1011  // The "translating..." infobar should be showing.
1012  TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
1013  ASSERT_TRUE(infobar != NULL);
1014  EXPECT_EQ(TranslateInfoBarDelegate::TRANSLATING, infobar->type());
1015  SimulateURLFetch(true);  // Simulate the translate script being retrieved.
1016  int page_id = 0;
1017  std::string original_lang, target_lang;
1018  EXPECT_TRUE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
1019  EXPECT_EQ("fr", original_lang);
1020  EXPECT_EQ("en", target_lang);
1021  process()->sink().ClearMessages();
1022
1023  // This should also have reverted the blacklisting of this site and language.
1024  EXPECT_FALSE(translate_prefs.IsLanguageBlacklisted("fr"));
1025  EXPECT_FALSE(translate_prefs.IsSiteBlacklisted(url.host()));
1026
1027  // Let's simulate the page being translated.
1028  rvh()->TestOnMessageReceived(ViewHostMsg_PageTranslated(0, 0, "fr", "en",
1029      TranslateErrors::NONE));
1030
1031  // The translate menu should now be disabled.
1032  menu.reset(TestRenderViewContextMenu::CreateContextMenu(contents()));
1033  menu->Init();
1034  EXPECT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_TRANSLATE));
1035  EXPECT_FALSE(menu->IsCommandIdEnabled(IDC_CONTENT_CONTEXT_TRANSLATE));
1036
1037  // Test that selecting translate in the context menu WHILE the page is being
1038  // translated does nothing (this could happen if autotranslate kicks-in and
1039  // the user selects the menu while the translation is being performed).
1040  SimulateNavigation(GURL("http://www.google.es"), "es", true);
1041  infobar = GetTranslateInfoBar();
1042  ASSERT_TRUE(infobar != NULL);
1043  infobar->Translate();
1044  EXPECT_TRUE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
1045  process()->sink().ClearMessages();
1046  menu.reset(TestRenderViewContextMenu::CreateContextMenu(contents()));
1047  menu->Init();
1048  EXPECT_TRUE(menu->IsCommandIdEnabled(IDC_CONTENT_CONTEXT_TRANSLATE));
1049  menu->ExecuteCommand(IDC_CONTENT_CONTEXT_TRANSLATE);
1050  // No message expected since the translation should have been ignored.
1051  EXPECT_FALSE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
1052
1053  // Now test that selecting translate in the context menu AFTER the page has
1054  // been translated does nothing.
1055  SimulateNavigation(GURL("http://www.google.de"), "de", true);
1056  infobar = GetTranslateInfoBar();
1057  ASSERT_TRUE(infobar != NULL);
1058  infobar->Translate();
1059  EXPECT_TRUE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
1060  process()->sink().ClearMessages();
1061  menu.reset(TestRenderViewContextMenu::CreateContextMenu(contents()));
1062  menu->Init();
1063  EXPECT_TRUE(menu->IsCommandIdEnabled(IDC_CONTENT_CONTEXT_TRANSLATE));
1064  rvh()->TestOnMessageReceived(ViewHostMsg_PageTranslated(0, 0, "de", "en",
1065      TranslateErrors::NONE));
1066  menu->ExecuteCommand(IDC_CONTENT_CONTEXT_TRANSLATE);
1067  // No message expected since the translation should have been ignored.
1068  EXPECT_FALSE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
1069
1070  // Test that the translate context menu is enabled when the page is in an
1071  // unknown language.
1072  SimulateNavigation(url, "und", true);
1073  menu.reset(TestRenderViewContextMenu::CreateContextMenu(contents()));
1074  menu->Init();
1075  EXPECT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_TRANSLATE));
1076  EXPECT_TRUE(menu->IsCommandIdEnabled(IDC_CONTENT_CONTEXT_TRANSLATE));
1077
1078  // Test that the translate context menu is disabled when the page is in an
1079  // unsupported language.
1080  SimulateNavigation(url, "qbz", true);
1081  menu.reset(TestRenderViewContextMenu::CreateContextMenu(contents()));
1082  menu->Init();
1083  EXPECT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_TRANSLATE));
1084  EXPECT_FALSE(menu->IsCommandIdEnabled(IDC_CONTENT_CONTEXT_TRANSLATE));
1085}
1086
1087// Tests that an extra always/never translate button is shown on the "before
1088// translate" infobar when the translation is accepted/declined 3 times,
1089// only when not in incognito mode.
1090TEST_F(TranslateManagerTest, BeforeTranslateExtraButtons) {
1091  TranslatePrefs translate_prefs(contents()->profile()->GetPrefs());
1092  translate_prefs.ResetTranslationAcceptedCount("fr");
1093  translate_prefs.ResetTranslationDeniedCount("fr");
1094  translate_prefs.ResetTranslationAcceptedCount("de");
1095  translate_prefs.ResetTranslationDeniedCount("de");
1096
1097  // We'll do 4 times in incognito mode first to make sure the button is not
1098  // shown in that case, then 4 times in normal mode.
1099  TranslateInfoBarDelegate* infobar;
1100  TestingProfile* test_profile =
1101      static_cast<TestingProfile*>(contents()->profile());
1102  test_profile->set_incognito(true);
1103  for (int i = 0; i < 8; ++i) {
1104    SCOPED_TRACE(::testing::Message() << "Iteration " << i <<
1105        " incognito mode=" << test_profile->IsOffTheRecord());
1106    SimulateNavigation(GURL("http://www.google.fr"), "fr", true);
1107    infobar = GetTranslateInfoBar();
1108    ASSERT_TRUE(infobar != NULL);
1109    EXPECT_EQ(TranslateInfoBarDelegate::BEFORE_TRANSLATE, infobar->type());
1110    if (i < 7) {
1111      EXPECT_FALSE(infobar->ShouldShowAlwaysTranslateButton());
1112      infobar->Translate();
1113      process()->sink().ClearMessages();
1114    } else {
1115      EXPECT_TRUE(infobar->ShouldShowAlwaysTranslateButton());
1116    }
1117    if (i == 3)
1118      test_profile->set_incognito(false);
1119  }
1120  // Simulate the user pressing "Always translate French".
1121  infobar->AlwaysTranslatePageLanguage();
1122  EXPECT_TRUE(translate_prefs.IsLanguagePairWhitelisted("fr", "en"));
1123  // Simulate the translate script being retrieved (it only needs to be done
1124  // once in the test as it is cached).
1125  SimulateURLFetch(true);
1126  // That should have triggered a page translate.
1127  int page_id = 0;
1128  std::string original_lang, target_lang;
1129  EXPECT_TRUE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
1130  process()->sink().ClearMessages();
1131
1132  // Now test that declining the translation causes a "never translate" button
1133  // to be shown (in non incognito mode only).
1134  test_profile->set_incognito(true);
1135  for (int i = 0; i < 8; ++i) {
1136    SCOPED_TRACE(::testing::Message() << "Iteration " << i <<
1137        " incognito mode=" << test_profile->IsOffTheRecord());
1138    SimulateNavigation(GURL("http://www.google.de"), "de", true);
1139    infobar = GetTranslateInfoBar();
1140    ASSERT_TRUE(infobar != NULL);
1141    EXPECT_EQ(TranslateInfoBarDelegate::BEFORE_TRANSLATE, infobar->type());
1142    if (i < 7) {
1143      EXPECT_FALSE(infobar->ShouldShowNeverTranslateButton());
1144      infobar->TranslationDeclined();
1145    } else {
1146      EXPECT_TRUE(infobar->ShouldShowNeverTranslateButton());
1147    }
1148    if (i == 3)
1149      test_profile->set_incognito(false);
1150  }
1151  // Simulate the user pressing "Never translate French".
1152  infobar->NeverTranslatePageLanguage();
1153  EXPECT_TRUE(translate_prefs.IsLanguageBlacklisted("de"));
1154  // No translation should have occured and the infobar should be gone.
1155  EXPECT_FALSE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
1156  process()->sink().ClearMessages();
1157  ASSERT_TRUE(GetTranslateInfoBar() == NULL);
1158}
1159
1160// Tests that we don't show a translate infobar when a page instructs that it
1161// should not be translated.
1162TEST_F(TranslateManagerTest, NonTranslatablePage) {
1163  // Simulate navigating to a page.
1164  SimulateNavigation(GURL("http://mail.google.fr"), "fr", false);
1165
1166  // We should not have an infobar.
1167  EXPECT_TRUE(GetTranslateInfoBar() == NULL);
1168
1169  // The context menu should be disabled.
1170  scoped_ptr<TestRenderViewContextMenu> menu(
1171      TestRenderViewContextMenu::CreateContextMenu(contents()));
1172  menu->Init();
1173  EXPECT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_TRANSLATE));
1174  EXPECT_FALSE(menu->IsCommandIdEnabled(IDC_CONTENT_CONTEXT_TRANSLATE));
1175}
1176
1177// Tests that the script is expired and refetched as expected.
1178TEST_F(TranslateManagerTest, ScriptExpires) {
1179  ExpireTranslateScriptImmediately();
1180
1181  // Simulate navigating to a page and translating it.
1182  SimulateNavigation(GURL("http://www.google.fr"), "fr", true);
1183  TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
1184  ASSERT_TRUE(infobar != NULL);
1185  process()->sink().ClearMessages();
1186  infobar->Translate();
1187  SimulateURLFetch(true);
1188  rvh()->TestOnMessageReceived(ViewHostMsg_PageTranslated(0, 0, "fr", "en",
1189      TranslateErrors::NONE));
1190
1191  // A task should have been posted to clear the script, run it.
1192  MessageLoop::current()->RunAllPending();
1193
1194  // Do another navigation and translation.
1195  SimulateNavigation(GURL("http://www.google.es"), "es", true);
1196  infobar = GetTranslateInfoBar();
1197  ASSERT_TRUE(infobar != NULL);
1198  process()->sink().ClearMessages();
1199  infobar->Translate();
1200  // If we don't simulate the URL fetch, the TranslateManager should be waiting
1201  // for the script and no message should have been sent to the renderer.
1202  EXPECT_TRUE(
1203      process()->sink().GetFirstMessageMatching(ViewMsg_TranslatePage::ID) ==
1204      NULL);
1205  // Now simulate the URL fetch.
1206  SimulateURLFetch(true);
1207  // Now the message should have been sent.
1208  int page_id = 0;
1209  std::string original_lang, target_lang;
1210  EXPECT_TRUE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
1211  EXPECT_EQ("es", original_lang);
1212  EXPECT_EQ("en", target_lang);
1213}
1214