// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.


#include <set>

#include "base/utf_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/prefs/pref_change_registrar.h"
#include "chrome/browser/tab_contents/render_view_context_menu.h"
#include "chrome/browser/translate/translate_infobar_delegate.h"
#include "chrome/browser/translate/translate_manager.h"
#include "chrome/browser/translate/translate_prefs.h"
#include "chrome/browser/ui/tab_contents/test_tab_contents_wrapper.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/net/test_url_fetcher_factory.h"
#include "chrome/test/testing_browser_process.h"
#include "chrome/test/testing_profile.h"
#include "content/browser/browser_thread.h"
#include "content/browser/renderer_host/mock_render_process_host.h"
#include "content/browser/renderer_host/test_render_view_host.h"
#include "content/browser/tab_contents/navigation_controller.h"
#include "content/browser/tab_contents/test_tab_contents.h"
#include "content/common/notification_details.h"
#include "content/common/notification_observer_mock.h"
#include "content/common/notification_registrar.h"
#include "content/common/notification_type.h"
#include "content/common/view_messages.h"
#include "grit/generated_resources.h"
#include "ipc/ipc_test_sink.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "third_party/cld/languages/public/languages.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebContextMenuData.h"

using testing::_;
using testing::Pointee;
using testing::Property;
using WebKit::WebContextMenuData;

class TranslateManagerTest : public TabContentsWrapperTestHarness,
                             public NotificationObserver {
 public:
  TranslateManagerTest()
      : ui_thread_(BrowserThread::UI, &message_loop_) {
  }

  // Simluates navigating to a page and getting the page contents and language
  // for that navigation.
  void SimulateNavigation(const GURL& url,
                          const std::string& lang,
                          bool page_translatable) {
    NavigateAndCommit(url);
    SimulateOnTranslateLanguageDetermined(lang, page_translatable);
  }

  void SimulateOnTranslateLanguageDetermined(const std::string& lang,
                                             bool page_translatable) {
    rvh()->TestOnMessageReceived(ViewHostMsg_TranslateLanguageDetermined(
        0, lang, page_translatable));
  }

  bool GetTranslateMessage(int* page_id,
                           std::string* original_lang,
                           std::string* target_lang) {
    const IPC::Message* message =
        process()->sink().GetFirstMessageMatching(ViewMsg_TranslatePage::ID);
    if (!message)
      return false;
    Tuple4<int, std::string, std::string, std::string> translate_param;
    ViewMsg_TranslatePage::Read(message, &translate_param);
    if (page_id)
      *page_id = translate_param.a;
    // Ignore translate_param.b which is the script injected in the page.
    if (original_lang)
      *original_lang = translate_param.c;
    if (target_lang)
      *target_lang = translate_param.d;
    return true;
  }

  // Returns the translate infobar if there is 1 infobar and it is a translate
  // infobar.
  TranslateInfoBarDelegate* GetTranslateInfoBar() {
    return (contents()->infobar_count() == 1) ?
        contents()->GetInfoBarDelegateAt(0)->AsTranslateInfoBarDelegate() :
        NULL;
  }

  // If there is 1 infobar and it is a translate infobar, closes it and returns
  // true.  Returns false otherwise.
  bool CloseTranslateInfoBar() {
    InfoBarDelegate* infobar = GetTranslateInfoBar();
    if (!infobar)
      return false;
    infobar->InfoBarDismissed();  // Simulates closing the infobar.
    contents()->RemoveInfoBar(infobar);
    return true;
  }

  // Checks whether |infobar| has been removed and clears the removed infobar
  // list.
  bool CheckInfoBarRemovedAndReset(InfoBarDelegate* delegate) {
    bool found = removed_infobars_.count(delegate) != 0;
    removed_infobars_.clear();
    return found;
  }

  // Returns true if at least one infobar was closed.
  bool InfoBarRemoved() {
    return !removed_infobars_.empty();
  }

  // Clears the list of stored removed infobars.
  void ClearRemovedInfoBars() {
    removed_infobars_.clear();
  }

  void ExpireTranslateScriptImmediately() {
    TranslateManager::GetInstance()->set_translate_script_expiration_delay(0);
  }

  // If there is 1 infobar and it is a translate infobar, deny translation and
  // returns true.  Returns false otherwise.
  bool DenyTranslation() {
    TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
    if (!infobar)
      return false;
    infobar->TranslationDeclined();
    contents()->RemoveInfoBar(infobar);
    return true;
  }

  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details) {
    DCHECK_EQ(NotificationType::TAB_CONTENTS_INFOBAR_REMOVED, type.value);
    removed_infobars_.insert(Details<InfoBarDelegate>(details).ptr());
  }

 protected:
  virtual void SetUp() {
    URLFetcher::set_factory(&url_fetcher_factory_);

    // Access the TranslateManager singleton so it is created before we call
    // RenderViewHostTestHarness::SetUp() to match what's done in Chrome, where
    // the TranslateManager is created before the TabContents.  This matters as
    // they both register for similar events and we want the notifications to
    // happen in the same sequence (TranslateManager first, TabContents second).
    // Also clears the translate script so it is fetched everytime and sets the
    // expiration delay to a large value by default (in case it was zeroed in
    // a previous test).
    TranslateManager::GetInstance()->ClearTranslateScript();
    TranslateManager::GetInstance()->
        set_translate_script_expiration_delay(60 * 60 * 1000);

    TabContentsWrapperTestHarness::SetUp();

    notification_registrar_.Add(this,
        NotificationType::TAB_CONTENTS_INFOBAR_REMOVED,
        Source<TabContents>(contents()));
  }

  virtual void TearDown() {
    process()->sink().ClearMessages();

    notification_registrar_.Remove(this,
        NotificationType::TAB_CONTENTS_INFOBAR_REMOVED,
        Source<TabContents>(contents()));

    TabContentsWrapperTestHarness::TearDown();

    URLFetcher::set_factory(NULL);
  }

  void SimulateURLFetch(bool success) {
    TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0);
    ASSERT_TRUE(fetcher);
    net::URLRequestStatus status;
    status.set_status(success ? net::URLRequestStatus::SUCCESS :
                                net::URLRequestStatus::FAILED);
    fetcher->delegate()->OnURLFetchComplete(fetcher, fetcher->original_url(),
                                            status, success ? 200 : 500,
                                            ResponseCookies(),
                                            std::string());
  }

  void SetPrefObserverExpectation(const char* path) {
    EXPECT_CALL(
        pref_observer_,
        Observe(NotificationType(NotificationType::PREF_CHANGED),
                _,
                Property(&Details<std::string>::ptr, Pointee(path))));
  }

  NotificationObserverMock pref_observer_;

 private:
  NotificationRegistrar notification_registrar_;
  TestURLFetcherFactory url_fetcher_factory_;
  BrowserThread ui_thread_;

  // The infobars that have been removed.
  // WARNING: the pointers point to deleted objects, use only for comparison.
  std::set<InfoBarDelegate*> removed_infobars_;

  DISALLOW_COPY_AND_ASSIGN(TranslateManagerTest);
};

// An observer that keeps track of whether a navigation entry was committed.
class NavEntryCommittedObserver : public NotificationObserver {
 public:
  explicit NavEntryCommittedObserver(TabContents* tab_contents) {
    registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED,
                   Source<NavigationController>(&tab_contents->controller()));
  }

  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details) {
    DCHECK(type == NotificationType::NAV_ENTRY_COMMITTED);
    details_ =
        *(Details<NavigationController::LoadCommittedDetails>(details).ptr());
  }

  const NavigationController::LoadCommittedDetails&
      get_load_commited_details() const {
    return details_;
  }

 private:
  NavigationController::LoadCommittedDetails details_;
  NotificationRegistrar registrar_;

  DISALLOW_COPY_AND_ASSIGN(NavEntryCommittedObserver);
};

class TestRenderViewContextMenu : public RenderViewContextMenu {
 public:
  static TestRenderViewContextMenu* CreateContextMenu(
      TabContents* tab_contents) {
    ContextMenuParams params;
    params.media_type = WebKit::WebContextMenuData::MediaTypeNone;
    params.x = 0;
    params.y = 0;
    params.is_image_blocked = false;
    params.media_flags = 0;
    params.spellcheck_enabled = false;
    params.is_editable = false;
    params.page_url = tab_contents->controller().GetActiveEntry()->url();
#if defined(OS_MACOSX)
    params.writing_direction_default = 0;
    params.writing_direction_left_to_right = 0;
    params.writing_direction_right_to_left = 0;
#endif  // OS_MACOSX
    params.edit_flags = WebContextMenuData::CanTranslate;
    return new TestRenderViewContextMenu(tab_contents, params);
  }

  bool IsItemPresent(int id) {
    return menu_model_.GetIndexOfCommandId(id) != -1;
  }

  virtual void PlatformInit() { }
  virtual bool GetAcceleratorForCommandId(
      int command_id,
      ui::Accelerator* accelerator) { return false; }

 private:
  TestRenderViewContextMenu(TabContents* tab_contents,
                            const ContextMenuParams& params)
      : RenderViewContextMenu(tab_contents, params) {
  }

  DISALLOW_COPY_AND_ASSIGN(TestRenderViewContextMenu);
};

TEST_F(TranslateManagerTest, NormalTranslate) {
  // Simulate navigating to a page.
  SimulateNavigation(GURL("http://www.google.fr"), "fr", true);

  // We should have an infobar.
  TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
  ASSERT_TRUE(infobar != NULL);
  EXPECT_EQ(TranslateInfoBarDelegate::BEFORE_TRANSLATE, infobar->type());

  // Simulate clicking translate.
  process()->sink().ClearMessages();
  infobar->Translate();

  // The "Translating..." infobar should be showing.
  infobar = GetTranslateInfoBar();
  ASSERT_TRUE(infobar != NULL);
  EXPECT_EQ(TranslateInfoBarDelegate::TRANSLATING, infobar->type());

  // Simulate the translate script being retrieved (it only needs to be done
  // once in the test as it is cached).
  SimulateURLFetch(true);

  // Test that we sent the right message to the renderer.
  int page_id = 0;
  std::string original_lang, target_lang;
  EXPECT_TRUE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
  EXPECT_EQ("fr", original_lang);
  EXPECT_EQ("en", target_lang);

  // Simulate the render notifying the translation has been done.
  rvh()->TestOnMessageReceived(ViewHostMsg_PageTranslated(0, 0, "fr", "en",
      TranslateErrors::NONE));

  // The after translate infobar should be showing.
  infobar = GetTranslateInfoBar();
  ASSERT_TRUE(infobar != NULL);
  EXPECT_EQ(TranslateInfoBarDelegate::AFTER_TRANSLATE, infobar->type());

  // Simulate changing the original language, this should trigger a translation.
  process()->sink().ClearMessages();
  std::string new_original_lang = infobar->GetLanguageCodeAt(0);
  infobar->SetOriginalLanguage(0);
  EXPECT_TRUE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
  EXPECT_EQ(new_original_lang, original_lang);
  EXPECT_EQ("en", target_lang);
  // Simulate the render notifying the translation has been done.
  rvh()->TestOnMessageReceived(ViewHostMsg_PageTranslated(0, 0,
      new_original_lang, "en", TranslateErrors::NONE));
  // infobar is now invalid.
  TranslateInfoBarDelegate* new_infobar = GetTranslateInfoBar();
  ASSERT_TRUE(new_infobar != NULL);
  infobar = new_infobar;

  // Simulate changing the target language, this should trigger a translation.
  process()->sink().ClearMessages();
  std::string new_target_lang = infobar->GetLanguageCodeAt(1);
  infobar->SetTargetLanguage(1);
  EXPECT_TRUE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
  EXPECT_EQ(new_original_lang, original_lang);
  EXPECT_EQ(new_target_lang, target_lang);
  // Simulate the render notifying the translation has been done.
  rvh()->TestOnMessageReceived(ViewHostMsg_PageTranslated(0, 0,
      new_original_lang, new_target_lang, TranslateErrors::NONE));
  // infobar is now invalid.
  new_infobar = GetTranslateInfoBar();
  ASSERT_TRUE(new_infobar != NULL);
}

TEST_F(TranslateManagerTest, TranslateScriptNotAvailable) {
  // Simulate navigating to a page.
  SimulateNavigation(GURL("http://www.google.fr"), "fr", true);

  // We should have an infobar.
  TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
  ASSERT_TRUE(infobar != NULL);
  EXPECT_EQ(TranslateInfoBarDelegate::BEFORE_TRANSLATE, infobar->type());

  // Simulate clicking translate.
  process()->sink().ClearMessages();
  infobar->Translate();
  // Simulate a failure retrieving the translate script.
  SimulateURLFetch(false);

  // We should not have sent any message to translate to the renderer.
  EXPECT_FALSE(GetTranslateMessage(NULL, NULL, NULL));

  // And we should have an error infobar showing.
  infobar = GetTranslateInfoBar();
  ASSERT_TRUE(infobar != NULL);
  EXPECT_EQ(TranslateInfoBarDelegate::TRANSLATION_ERROR, infobar->type());
}

// Ensures we deal correctly with pages for which the browser does not recognize
// the language (the translate server may or not detect the language).
TEST_F(TranslateManagerTest, TranslateUnknownLanguage) {
  // Simulate navigating to a page ("und" is the string returned by the CLD for
  // languages it does not recognize).
  SimulateNavigation(GURL("http://www.google.mys"), "und", true);

  // We should not have an infobar as we don't know the language.
  ASSERT_TRUE(GetTranslateInfoBar() == NULL);

  // Translate the page anyway throught the context menu.
  scoped_ptr<TestRenderViewContextMenu> menu(
      TestRenderViewContextMenu::CreateContextMenu(contents()));
  menu->Init();
  menu->ExecuteCommand(IDC_CONTENT_CONTEXT_TRANSLATE);

  // To test that bug #49018 if fixed, make sure we deal correctly with errors.
  SimulateURLFetch(false);  // Simulate a failure to fetch the translate script.
  TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
  ASSERT_TRUE(infobar != NULL);
  EXPECT_EQ(TranslateInfoBarDelegate::TRANSLATION_ERROR, infobar->type());
  EXPECT_TRUE(infobar->IsError());
  infobar->MessageInfoBarButtonPressed();
  SimulateURLFetch(true);  // This time succeed.

  // Simulate the render notifying the translation has been done, the server
  // having detected the page was in a known and supported language.
  rvh()->TestOnMessageReceived(ViewHostMsg_PageTranslated(0, 0, "fr", "en",
      TranslateErrors::NONE));

  // The after translate infobar should be showing.
  infobar = GetTranslateInfoBar();
  ASSERT_TRUE(infobar != NULL);
  EXPECT_EQ(TranslateInfoBarDelegate::AFTER_TRANSLATE, infobar->type());
  EXPECT_EQ("fr", infobar->GetOriginalLanguageCode());
  EXPECT_EQ("en", infobar->GetTargetLanguageCode());

  // Let's run the same steps but this time the server detects the page is
  // already in English.
  SimulateNavigation(GURL("http://www.google.com"), "und", true);
  menu.reset(TestRenderViewContextMenu::CreateContextMenu(contents()));
  menu->Init();
  menu->ExecuteCommand(IDC_CONTENT_CONTEXT_TRANSLATE);
  rvh()->TestOnMessageReceived(ViewHostMsg_PageTranslated(1, 0, "en", "en",
      TranslateErrors::IDENTICAL_LANGUAGES));
  infobar = GetTranslateInfoBar();
  ASSERT_TRUE(infobar != NULL);
  EXPECT_EQ(TranslateInfoBarDelegate::TRANSLATION_ERROR, infobar->type());
  EXPECT_EQ(TranslateErrors::IDENTICAL_LANGUAGES, infobar->error());

  // Let's run the same steps again but this time the server fails to detect the
  // page's language (it returns an empty string).
  SimulateNavigation(GURL("http://www.google.com"), "und", true);
  menu.reset(TestRenderViewContextMenu::CreateContextMenu(contents()));
  menu->Init();
  menu->ExecuteCommand(IDC_CONTENT_CONTEXT_TRANSLATE);
  rvh()->TestOnMessageReceived(ViewHostMsg_PageTranslated(2, 0, "", "en",
      TranslateErrors::UNKNOWN_LANGUAGE));
  infobar = GetTranslateInfoBar();
  ASSERT_TRUE(infobar != NULL);
  EXPECT_EQ(TranslateInfoBarDelegate::TRANSLATION_ERROR, infobar->type());
  EXPECT_EQ(TranslateErrors::UNKNOWN_LANGUAGE, infobar->error());
}

// Tests that we show/don't show an info-bar for all languages the CLD can
// report.
TEST_F(TranslateManagerTest, TestAllLanguages) {
  // The index in kExpectation are the Language enum (see languages.pb.h).
  // true if we expect a translate infobar for that language.
  // Note the supported languages are in translation_manager.cc, see
  // kSupportedLanguages.
  bool kExpectations[] = {
    // 0-9
    false, true, true, true, true, true, true, true, true, true,
    // 10-19
    true, true, true, true, true, true, true, true, true, true,
    // 20-29
    true, true, true, true, true, false, false, true, true, true,
    // 30-39
    true, true, true, true, true, true, true, false, true, false,
    // 40-49
    true, false, true, false, false, true, false, true, false, false,
    // 50-59
    true, false, false, true, true, true, false, true, false, false,
    // 60-69
    false, false, true, true, false, true, true, false, true, true,
    // 70-79
    false, false, false, false, true, true, false, true, false, false,
    // 80-89
    false, false, false, false, false, false, false, false, false, false,
    // 90-99
    false, true, false, false, false, false, false, true, false, false,
    // 100-109
    false, true, false, false, false, false, false, false, false, false,
    // 110-119
    false, false, false, false, false, false, false, false, false, false,
    // 120-129
    false, false, false, false, false, false, false, false, false, false,
    // 130-139
    false, false, false, false, false, false, false, false, false, true,
    // 140-149
    false, false, false, false, false, false, false, false, false, false,
    // 150-159
    false, false, false, false, false, false, false, false, false, false,
    // 160
    false
  };

  GURL url("http://www.google.com");
  for (size_t i = 0; i < arraysize(kExpectations); ++i) {
    ASSERT_LT(i, static_cast<size_t>(NUM_LANGUAGES));

    std::string lang = LanguageCodeWithDialects(static_cast<Language>(i));
    SCOPED_TRACE(::testing::Message() << "Iteration " << i <<
        " language=" << lang);

    // We should not have a translate infobar.
    TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
    ASSERT_TRUE(infobar == NULL);

    // Simulate navigating to a page.
    NavigateAndCommit(url);
    SimulateOnTranslateLanguageDetermined(lang, true);

    // Verify we have/don't have an info-bar as expected.
    infobar = GetTranslateInfoBar();
    EXPECT_EQ(kExpectations[i], infobar != NULL);

    // Close the info-bar if applicable.
    if (infobar != NULL)
      EXPECT_TRUE(CloseTranslateInfoBar());
  }
}

// Tests auto-translate on page.
TEST_F(TranslateManagerTest, AutoTranslateOnNavigate) {
  // Simulate navigating to a page and getting its language.
  SimulateNavigation(GURL("http://www.google.fr"), "fr", true);

  // Simulate the user translating.
  TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
  ASSERT_TRUE(infobar != NULL);
  infobar->Translate();
  SimulateURLFetch(true);  // Simulate the translate script being retrieved.

  rvh()->TestOnMessageReceived(ViewHostMsg_PageTranslated(0, 0, "fr", "en",
      TranslateErrors::NONE));

  // Now navigate to a new page in the same language.
  process()->sink().ClearMessages();
  SimulateNavigation(GURL("http://news.google.fr"), "fr", true);

  // This should have automatically triggered a translation.
  int page_id = 0;
  std::string original_lang, target_lang;
  EXPECT_TRUE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
  EXPECT_EQ(1, page_id);
  EXPECT_EQ("fr", original_lang);
  EXPECT_EQ("en", target_lang);

  // Now navigate to a page in a different language.
  process()->sink().ClearMessages();
  SimulateNavigation(GURL("http://news.google.es"), "es", true);

  // This should not have triggered a translate.
  EXPECT_FALSE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
}

// Tests that multiple OnPageContents do not cause multiple infobars.
TEST_F(TranslateManagerTest, MultipleOnPageContents) {
  // Simulate navigating to a page and getting its language.
  SimulateNavigation(GURL("http://www.google.fr"), "fr", true);

  // Simulate clicking 'Nope' (don't translate).
  EXPECT_TRUE(DenyTranslation());
  EXPECT_EQ(0U, contents()->infobar_count());

  // Send a new PageContents, we should not show an infobar.
  SimulateOnTranslateLanguageDetermined("fr", true);
  EXPECT_EQ(0U, contents()->infobar_count());

  // Do the same steps but simulate closing the infobar this time.
  SimulateNavigation(GURL("http://www.youtube.fr"), "fr", true);
  EXPECT_TRUE(CloseTranslateInfoBar());
  EXPECT_EQ(0U, contents()->infobar_count());
  SimulateOnTranslateLanguageDetermined("fr", true);
  EXPECT_EQ(0U, contents()->infobar_count());
}

// Test that reloading the page brings back the infobar.
TEST_F(TranslateManagerTest, Reload) {
  // Simulate navigating to a page and getting its language.
  SimulateNavigation(GURL("http://www.google.fr"), "fr", true);

  // Close the infobar.
  EXPECT_TRUE(CloseTranslateInfoBar());

  // Reload should bring back the infobar.
  NavEntryCommittedObserver nav_observer(contents());
  Reload();

  // Ensures it is really handled a reload.
  const NavigationController::LoadCommittedDetails& nav_details =
      nav_observer.get_load_commited_details();
  EXPECT_TRUE(nav_details.entry != NULL);  // There was a navigation.
  EXPECT_EQ(NavigationType::EXISTING_PAGE, nav_details.type);

  // The TranslateManager class processes the navigation entry committed
  // notification in a posted task; process that task.
  MessageLoop::current()->RunAllPending();
  EXPECT_TRUE(GetTranslateInfoBar() != NULL);
}

// Test that reloading the page by way of typing again the URL in the
// location bar brings back the infobar.
TEST_F(TranslateManagerTest, ReloadFromLocationBar) {
  GURL url("http://www.google.fr");

  // Simulate navigating to a page and getting its language.
  SimulateNavigation(url, "fr", true);

  // Close the infobar.
  EXPECT_TRUE(CloseTranslateInfoBar());

  // Create a pending navigation and simulate a page load.  That should be the
  // equivalent of typing the URL again in the location bar.
  NavEntryCommittedObserver nav_observer(contents());
  contents()->controller().LoadURL(url, GURL(), PageTransition::TYPED);
  rvh()->SendNavigate(0, url);

  // Test that we are really getting a same page navigation, the test would be
  // useless if it was not the case.
  const NavigationController::LoadCommittedDetails& nav_details =
      nav_observer.get_load_commited_details();
  EXPECT_TRUE(nav_details.entry != NULL);  // There was a navigation.
  EXPECT_EQ(NavigationType::SAME_PAGE, nav_details.type);

  // The TranslateManager class processes the navigation entry committed
  // notification in a posted task; process that task.
  MessageLoop::current()->RunAllPending();
  EXPECT_TRUE(GetTranslateInfoBar() != NULL);
}

// Tests that a closed translate infobar does not reappear when navigating
// in-page.
TEST_F(TranslateManagerTest, CloseInfoBarInPageNavigation) {
  // Simulate navigating to a page and getting its language.
  SimulateNavigation(GURL("http://www.google.fr"), "fr", true);

  // Close the infobar.
  EXPECT_TRUE(CloseTranslateInfoBar());

  // Navigate in page, no infobar should be shown.
  SimulateNavigation(GURL("http://www.google.fr/#ref1"), "fr",
                     true);
  EXPECT_TRUE(GetTranslateInfoBar() == NULL);

  // Navigate out of page, a new infobar should show.
  SimulateNavigation(GURL("http://www.google.fr/foot"), "fr", true);
  EXPECT_TRUE(GetTranslateInfoBar() != NULL);
}

// Tests that a closed translate infobar does not reappear when navigating
// in a subframe. (http://crbug.com/48215)
TEST_F(TranslateManagerTest, CloseInfoBarInSubframeNavigation) {
  // Simulate navigating to a page and getting its language.
  SimulateNavigation(GURL("http://www.google.fr"), "fr", true);

  // Close the infobar.
  EXPECT_TRUE(CloseTranslateInfoBar());

  // Simulate a sub-frame auto-navigating.
  rvh()->SendNavigateWithTransition(1, GURL("http://pub.com"),
                                    PageTransition::AUTO_SUBFRAME);
  EXPECT_TRUE(GetTranslateInfoBar() == NULL);

  // Simulate the user navigating in a sub-frame.
  rvh()->SendNavigateWithTransition(2, GURL("http://pub.com"),
                                    PageTransition::MANUAL_SUBFRAME);
  EXPECT_TRUE(GetTranslateInfoBar() == NULL);

  // Navigate out of page, a new infobar should show.
  SimulateNavigation(GURL("http://www.google.fr/foot"), "fr", true);
  EXPECT_TRUE(GetTranslateInfoBar() != NULL);
}



// Tests that denying translation is sticky when navigating in page.
TEST_F(TranslateManagerTest, DenyTranslateInPageNavigation) {
  // Simulate navigating to a page and getting its language.
  SimulateNavigation(GURL("http://www.google.fr"), "fr", true);

  // Simulate clicking 'Nope' (don't translate).
  EXPECT_TRUE(DenyTranslation());

  // Navigate in page, no infobar should be shown.
  SimulateNavigation(GURL("http://www.google.fr/#ref1"), "fr", true);
  EXPECT_TRUE(GetTranslateInfoBar() == NULL);

  // Navigate out of page, a new infobar should show.
  SimulateNavigation(GURL("http://www.google.fr/foot"), "fr", true);
  EXPECT_TRUE(GetTranslateInfoBar() != NULL);
}

// Tests that after translating and closing the infobar, the infobar does not
// return when navigating in page.
TEST_F(TranslateManagerTest, TranslateCloseInfoBarInPageNavigation) {
  // Simulate navigating to a page and getting its language.
  SimulateNavigation(GURL("http://www.google.fr"), "fr", true);

  // Simulate the user translating.
  TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
  ASSERT_TRUE(infobar != NULL);
  infobar->Translate();
  SimulateURLFetch(true);  // Simulate the translate script being retrieved.
  rvh()->TestOnMessageReceived(ViewHostMsg_PageTranslated(0, 0, "fr", "en",
      TranslateErrors::NONE));

  // Close the infobar.
  EXPECT_TRUE(CloseTranslateInfoBar());

  // Navigate in page, no infobar should be shown.
  SimulateNavigation(GURL("http://www.google.fr/#ref1"), "fr", true);
  EXPECT_TRUE(GetTranslateInfoBar() == NULL);

  // Navigate out of page, a new infobar should show.
  // Note that we navigate to a page in a different language so we don't trigger
  // the auto-translate feature (it would translate the page automatically and
  // the before translate inforbar would not be shown).
  SimulateNavigation(GURL("http://www.google.de"), "de", true);
  EXPECT_TRUE(GetTranslateInfoBar() != NULL);
}

// Tests that the after translate the infobar still shows when navigating
// in-page.
TEST_F(TranslateManagerTest, TranslateInPageNavigation) {
  // Simulate navigating to a page and getting its language.
  SimulateNavigation(GURL("http://www.google.fr"), "fr", true);

  // Simulate the user translating.
  TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
  ASSERT_TRUE(infobar != NULL);
  infobar->Translate();
  SimulateURLFetch(true);  // Simulate the translate script being retrieved.
  rvh()->TestOnMessageReceived(ViewHostMsg_PageTranslated(0, 0, "fr", "en",
      TranslateErrors::NONE));
  // The after translate infobar is showing.
  infobar = GetTranslateInfoBar();
  ASSERT_TRUE(infobar != NULL);

  // Navigate in page, the same infobar should still be shown.
  ClearRemovedInfoBars();
  SimulateNavigation(GURL("http://www.google.fr/#ref1"), "fr",
                     true);
  EXPECT_FALSE(InfoBarRemoved());
  EXPECT_EQ(infobar, GetTranslateInfoBar());

  // Navigate out of page, a new infobar should show.
  // See note in TranslateCloseInfoBarInPageNavigation test on why it is
  // important to navigate to a page in a different language for this test.
  SimulateNavigation(GURL("http://www.google.de"), "de", true);
  // The old infobar is gone.
  EXPECT_TRUE(CheckInfoBarRemovedAndReset(infobar));
  // And there is a new one.
  EXPECT_TRUE(GetTranslateInfoBar() != NULL);
}

// Tests that no translate infobar is shown when navigating to a page in an
// unsupported language.
TEST_F(TranslateManagerTest, CLDReportsUnsupportedPageLanguage) {
  // Simulate navigating to a page and getting an unsupported language.
  SimulateNavigation(GURL("http://www.google.com"), "qbz", true);

  // No info-bar should be shown.
  EXPECT_TRUE(GetTranslateInfoBar() == NULL);
}

// Tests that we deal correctly with unsupported languages returned by the
// server.
// The translation server might return a language we don't support.
TEST_F(TranslateManagerTest, ServerReportsUnsupportedLanguage) {
  // Simulate navigating to a page and translating it.
  SimulateNavigation(GURL("http://mail.google.fr"), "fr", true);
  TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
  ASSERT_TRUE(infobar != NULL);
  process()->sink().ClearMessages();
  infobar->Translate();
  SimulateURLFetch(true);
  // Simulate the render notifying the translation has been done, but it
  // reports a language we don't support.
  rvh()->TestOnMessageReceived(ViewHostMsg_PageTranslated(0, 0, "qbz", "en",
      TranslateErrors::NONE));

  // An error infobar should be showing to report that we don't support this
  // language.
  infobar = GetTranslateInfoBar();
  ASSERT_TRUE(infobar != NULL);
  EXPECT_EQ(TranslateInfoBarDelegate::TRANSLATION_ERROR, infobar->type());

  // This infobar should have a button (so the string should not be empty).
  ASSERT_FALSE(infobar->GetMessageInfoBarButtonText().empty());

  // Pressing the button on that infobar should revert to the original language.
  process()->sink().ClearMessages();
  infobar->MessageInfoBarButtonPressed();
  const IPC::Message* message =
      process()->sink().GetFirstMessageMatching(ViewMsg_RevertTranslation::ID);
  EXPECT_TRUE(message != NULL);
  // And it should have removed the infobar.
  EXPECT_TRUE(GetTranslateInfoBar() == NULL);
}

// Tests that no translate infobar is shown when Chrome is in a language that
// the translate server does not support.
TEST_F(TranslateManagerTest, UnsupportedUILanguage) {
  TestingBrowserProcess* browser_process =
      static_cast<TestingBrowserProcess*>(g_browser_process);
  std::string original_lang = browser_process->GetApplicationLocale();
  browser_process->SetApplicationLocale("qbz");

  // Simulate navigating to a page in a language supported by the translate
  // server.
  SimulateNavigation(GURL("http://www.google.com"), "en", true);

  // No info-bar should be shown.
  EXPECT_TRUE(GetTranslateInfoBar() == NULL);

  browser_process->SetApplicationLocale(original_lang);
}

// Tests that the translate enabled preference is honored.
TEST_F(TranslateManagerTest, TranslateEnabledPref) {
  // Make sure the pref allows translate.
  PrefService* prefs = contents()->profile()->GetPrefs();
  prefs->SetBoolean(prefs::kEnableTranslate, true);

  // Simulate navigating to a page and getting its language.
  SimulateNavigation(GURL("http://www.google.fr"), "fr", true);

  // An infobar should be shown.
  TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
  EXPECT_TRUE(infobar != NULL);

  // Disable translate.
  prefs->SetBoolean(prefs::kEnableTranslate, false);

  // Navigate to a new page, that should close the previous infobar.
  GURL url("http://www.youtube.fr");
  NavigateAndCommit(url);
  infobar = GetTranslateInfoBar();
  EXPECT_TRUE(infobar == NULL);

  // Simulate getting the page contents and language, that should not trigger
  // a translate infobar.
  SimulateOnTranslateLanguageDetermined("fr", true);
  infobar = GetTranslateInfoBar();
  EXPECT_TRUE(infobar == NULL);
}

// Tests the "Never translate <language>" pref.
TEST_F(TranslateManagerTest, NeverTranslateLanguagePref) {
  // Simulate navigating to a page and getting its language.
  GURL url("http://www.google.fr");
  SimulateNavigation(url, "fr", true);

  // An infobar should be shown.
  EXPECT_TRUE(GetTranslateInfoBar() != NULL);

  // Select never translate this language.
  PrefService* prefs = contents()->profile()->GetPrefs();
  PrefChangeRegistrar registrar;
  registrar.Init(prefs);
  registrar.Add(TranslatePrefs::kPrefTranslateLanguageBlacklist,
                &pref_observer_);
  TranslatePrefs translate_prefs(prefs);
  EXPECT_FALSE(translate_prefs.IsLanguageBlacklisted("fr"));
  EXPECT_TRUE(translate_prefs.CanTranslate(prefs, "fr", url));
  SetPrefObserverExpectation(TranslatePrefs::kPrefTranslateLanguageBlacklist);
  translate_prefs.BlacklistLanguage("fr");
  EXPECT_TRUE(translate_prefs.IsLanguageBlacklisted("fr"));
  EXPECT_FALSE(translate_prefs.CanTranslate(prefs, "fr", url));

  // Close the infobar.
  EXPECT_TRUE(CloseTranslateInfoBar());

  // Navigate to a new page also in French.
  SimulateNavigation(GURL("http://wwww.youtube.fr"), "fr", true);

  // There should not be a translate infobar.
  EXPECT_TRUE(GetTranslateInfoBar() == NULL);

  // Remove the language from the blacklist.
  SetPrefObserverExpectation(TranslatePrefs::kPrefTranslateLanguageBlacklist);
  translate_prefs.RemoveLanguageFromBlacklist("fr");
  EXPECT_FALSE(translate_prefs.IsLanguageBlacklisted("fr"));
  EXPECT_TRUE(translate_prefs.CanTranslate(prefs, "fr", url));

  // Navigate to a page in French.
  SimulateNavigation(url, "fr", true);

  // There should be a translate infobar.
  EXPECT_TRUE(GetTranslateInfoBar() != NULL);
}

// Tests the "Never translate this site" pref.
TEST_F(TranslateManagerTest, NeverTranslateSitePref) {
  // Simulate navigating to a page and getting its language.
  GURL url("http://www.google.fr");
  std::string host(url.host());
  SimulateNavigation(url, "fr", true);

  // An infobar should be shown.
  EXPECT_TRUE(GetTranslateInfoBar() != NULL);

  // Select never translate this site.
  PrefService* prefs = contents()->profile()->GetPrefs();
  PrefChangeRegistrar registrar;
  registrar.Init(prefs);
  registrar.Add(TranslatePrefs::kPrefTranslateSiteBlacklist,
                &pref_observer_);
  TranslatePrefs translate_prefs(prefs);
  EXPECT_FALSE(translate_prefs.IsSiteBlacklisted(host));
  EXPECT_TRUE(translate_prefs.CanTranslate(prefs, "fr", url));
  SetPrefObserverExpectation(TranslatePrefs::kPrefTranslateSiteBlacklist);
  translate_prefs.BlacklistSite(host);
  EXPECT_TRUE(translate_prefs.IsSiteBlacklisted(host));
  EXPECT_FALSE(translate_prefs.CanTranslate(prefs, "fr", url));

  // Close the infobar.
  EXPECT_TRUE(CloseTranslateInfoBar());

  // Navigate to a new page also on the same site.
  SimulateNavigation(GURL("http://www.google.fr/hello"), "fr", true);

  // There should not be a translate infobar.
  EXPECT_TRUE(GetTranslateInfoBar() == NULL);

  // Remove the site from the blacklist.
  SetPrefObserverExpectation(TranslatePrefs::kPrefTranslateSiteBlacklist);
  translate_prefs.RemoveSiteFromBlacklist(host);
  EXPECT_FALSE(translate_prefs.IsSiteBlacklisted(host));
  EXPECT_TRUE(translate_prefs.CanTranslate(prefs, "fr", url));

  // Navigate to a page in French.
  SimulateNavigation(url, "fr", true);

  // There should be a translate infobar.
  EXPECT_TRUE(GetTranslateInfoBar() != NULL);
}

// Tests the "Always translate this language" pref.
TEST_F(TranslateManagerTest, AlwaysTranslateLanguagePref) {
  // Select always translate French to English.
  PrefService* prefs = contents()->profile()->GetPrefs();
  PrefChangeRegistrar registrar;
  registrar.Init(prefs);
  registrar.Add(TranslatePrefs::kPrefTranslateWhitelists,
                &pref_observer_);
  TranslatePrefs translate_prefs(prefs);
  SetPrefObserverExpectation(TranslatePrefs::kPrefTranslateWhitelists);
  translate_prefs.WhitelistLanguagePair("fr", "en");

  // Load a page in French.
  SimulateNavigation(GURL("http://www.google.fr"), "fr", true);

  // It should have triggered an automatic translation to English.

  // The translating infobar should be showing.
  TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
  ASSERT_TRUE(infobar != NULL);
  EXPECT_EQ(TranslateInfoBarDelegate::TRANSLATING, infobar->type());

  SimulateURLFetch(true);  // Simulate the translate script being retrieved.
  int page_id = 0;
  std::string original_lang, target_lang;
  EXPECT_TRUE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
  EXPECT_EQ("fr", original_lang);
  EXPECT_EQ("en", target_lang);
  process()->sink().ClearMessages();

  // Try another language, it should not be autotranslated.
  SimulateNavigation(GURL("http://www.google.es"), "es", true);
  EXPECT_FALSE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
  EXPECT_TRUE(GetTranslateInfoBar() != NULL);
  EXPECT_TRUE(CloseTranslateInfoBar());

  // Let's switch to incognito mode, it should not be autotranslated in that
  // case either.
  TestingProfile* test_profile =
      static_cast<TestingProfile*>(contents()->profile());
  test_profile->set_incognito(true);
  SimulateNavigation(GURL("http://www.youtube.fr"), "fr", true);
  EXPECT_FALSE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
  EXPECT_TRUE(GetTranslateInfoBar() != NULL);
  EXPECT_TRUE(CloseTranslateInfoBar());
  test_profile->set_incognito(false);  // Get back to non incognito.

  // Now revert the always translate pref and make sure we go back to expected
  // behavior, which is show a "before translate" infobar.
  SetPrefObserverExpectation(TranslatePrefs::kPrefTranslateWhitelists);
  translate_prefs.RemoveLanguagePairFromWhitelist("fr", "en");
  SimulateNavigation(GURL("http://www.google.fr"), "fr", true);
  EXPECT_FALSE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
  infobar = GetTranslateInfoBar();
  ASSERT_TRUE(infobar != NULL);
  EXPECT_EQ(TranslateInfoBarDelegate::BEFORE_TRANSLATE, infobar->type());
}

// Context menu.
TEST_F(TranslateManagerTest, ContextMenu) {
  // Blacklist www.google.fr and French for translation.
  GURL url("http://www.google.fr");
  TranslatePrefs translate_prefs(contents()->profile()->GetPrefs());
  translate_prefs.BlacklistLanguage("fr");
  translate_prefs.BlacklistSite(url.host());
  EXPECT_TRUE(translate_prefs.IsLanguageBlacklisted("fr"));
  EXPECT_TRUE(translate_prefs.IsSiteBlacklisted(url.host()));

  // Simulate navigating to a page in French. The translate menu should show but
  // should only be enabled when the page language has been received.
  NavigateAndCommit(url);
  scoped_ptr<TestRenderViewContextMenu> menu(
      TestRenderViewContextMenu::CreateContextMenu(contents()));
  menu->Init();
  EXPECT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_TRANSLATE));
  EXPECT_FALSE(menu->IsCommandIdEnabled(IDC_CONTENT_CONTEXT_TRANSLATE));

  // Simulate receiving the language.
  SimulateOnTranslateLanguageDetermined("fr", true);
  menu.reset(TestRenderViewContextMenu::CreateContextMenu(contents()));
  menu->Init();
  EXPECT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_TRANSLATE));
  EXPECT_TRUE(menu->IsCommandIdEnabled(IDC_CONTENT_CONTEXT_TRANSLATE));

  // Use the menu to translate the page.
  menu->ExecuteCommand(IDC_CONTENT_CONTEXT_TRANSLATE);

  // That should have triggered a translation.
  // The "translating..." infobar should be showing.
  TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
  ASSERT_TRUE(infobar != NULL);
  EXPECT_EQ(TranslateInfoBarDelegate::TRANSLATING, infobar->type());
  SimulateURLFetch(true);  // Simulate the translate script being retrieved.
  int page_id = 0;
  std::string original_lang, target_lang;
  EXPECT_TRUE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
  EXPECT_EQ("fr", original_lang);
  EXPECT_EQ("en", target_lang);
  process()->sink().ClearMessages();

  // This should also have reverted the blacklisting of this site and language.
  EXPECT_FALSE(translate_prefs.IsLanguageBlacklisted("fr"));
  EXPECT_FALSE(translate_prefs.IsSiteBlacklisted(url.host()));

  // Let's simulate the page being translated.
  rvh()->TestOnMessageReceived(ViewHostMsg_PageTranslated(0, 0, "fr", "en",
      TranslateErrors::NONE));

  // The translate menu should now be disabled.
  menu.reset(TestRenderViewContextMenu::CreateContextMenu(contents()));
  menu->Init();
  EXPECT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_TRANSLATE));
  EXPECT_FALSE(menu->IsCommandIdEnabled(IDC_CONTENT_CONTEXT_TRANSLATE));

  // Test that selecting translate in the context menu WHILE the page is being
  // translated does nothing (this could happen if autotranslate kicks-in and
  // the user selects the menu while the translation is being performed).
  SimulateNavigation(GURL("http://www.google.es"), "es", true);
  infobar = GetTranslateInfoBar();
  ASSERT_TRUE(infobar != NULL);
  infobar->Translate();
  EXPECT_TRUE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
  process()->sink().ClearMessages();
  menu.reset(TestRenderViewContextMenu::CreateContextMenu(contents()));
  menu->Init();
  EXPECT_TRUE(menu->IsCommandIdEnabled(IDC_CONTENT_CONTEXT_TRANSLATE));
  menu->ExecuteCommand(IDC_CONTENT_CONTEXT_TRANSLATE);
  // No message expected since the translation should have been ignored.
  EXPECT_FALSE(GetTranslateMessage(&page_id, &original_lang, &target_lang));

  // Now test that selecting translate in the context menu AFTER the page has
  // been translated does nothing.
  SimulateNavigation(GURL("http://www.google.de"), "de", true);
  infobar = GetTranslateInfoBar();
  ASSERT_TRUE(infobar != NULL);
  infobar->Translate();
  EXPECT_TRUE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
  process()->sink().ClearMessages();
  menu.reset(TestRenderViewContextMenu::CreateContextMenu(contents()));
  menu->Init();
  EXPECT_TRUE(menu->IsCommandIdEnabled(IDC_CONTENT_CONTEXT_TRANSLATE));
  rvh()->TestOnMessageReceived(ViewHostMsg_PageTranslated(0, 0, "de", "en",
      TranslateErrors::NONE));
  menu->ExecuteCommand(IDC_CONTENT_CONTEXT_TRANSLATE);
  // No message expected since the translation should have been ignored.
  EXPECT_FALSE(GetTranslateMessage(&page_id, &original_lang, &target_lang));

  // Test that the translate context menu is enabled when the page is in an
  // unknown language.
  SimulateNavigation(url, "und", true);
  menu.reset(TestRenderViewContextMenu::CreateContextMenu(contents()));
  menu->Init();
  EXPECT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_TRANSLATE));
  EXPECT_TRUE(menu->IsCommandIdEnabled(IDC_CONTENT_CONTEXT_TRANSLATE));

  // Test that the translate context menu is disabled when the page is in an
  // unsupported language.
  SimulateNavigation(url, "qbz", true);
  menu.reset(TestRenderViewContextMenu::CreateContextMenu(contents()));
  menu->Init();
  EXPECT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_TRANSLATE));
  EXPECT_FALSE(menu->IsCommandIdEnabled(IDC_CONTENT_CONTEXT_TRANSLATE));
}

// Tests that an extra always/never translate button is shown on the "before
// translate" infobar when the translation is accepted/declined 3 times,
// only when not in incognito mode.
TEST_F(TranslateManagerTest, BeforeTranslateExtraButtons) {
  TranslatePrefs translate_prefs(contents()->profile()->GetPrefs());
  translate_prefs.ResetTranslationAcceptedCount("fr");
  translate_prefs.ResetTranslationDeniedCount("fr");
  translate_prefs.ResetTranslationAcceptedCount("de");
  translate_prefs.ResetTranslationDeniedCount("de");

  // We'll do 4 times in incognito mode first to make sure the button is not
  // shown in that case, then 4 times in normal mode.
  TranslateInfoBarDelegate* infobar;
  TestingProfile* test_profile =
      static_cast<TestingProfile*>(contents()->profile());
  test_profile->set_incognito(true);
  for (int i = 0; i < 8; ++i) {
    SCOPED_TRACE(::testing::Message() << "Iteration " << i <<
        " incognito mode=" << test_profile->IsOffTheRecord());
    SimulateNavigation(GURL("http://www.google.fr"), "fr", true);
    infobar = GetTranslateInfoBar();
    ASSERT_TRUE(infobar != NULL);
    EXPECT_EQ(TranslateInfoBarDelegate::BEFORE_TRANSLATE, infobar->type());
    if (i < 7) {
      EXPECT_FALSE(infobar->ShouldShowAlwaysTranslateButton());
      infobar->Translate();
      process()->sink().ClearMessages();
    } else {
      EXPECT_TRUE(infobar->ShouldShowAlwaysTranslateButton());
    }
    if (i == 3)
      test_profile->set_incognito(false);
  }
  // Simulate the user pressing "Always translate French".
  infobar->AlwaysTranslatePageLanguage();
  EXPECT_TRUE(translate_prefs.IsLanguagePairWhitelisted("fr", "en"));
  // Simulate the translate script being retrieved (it only needs to be done
  // once in the test as it is cached).
  SimulateURLFetch(true);
  // That should have triggered a page translate.
  int page_id = 0;
  std::string original_lang, target_lang;
  EXPECT_TRUE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
  process()->sink().ClearMessages();

  // Now test that declining the translation causes a "never translate" button
  // to be shown (in non incognito mode only).
  test_profile->set_incognito(true);
  for (int i = 0; i < 8; ++i) {
    SCOPED_TRACE(::testing::Message() << "Iteration " << i <<
        " incognito mode=" << test_profile->IsOffTheRecord());
    SimulateNavigation(GURL("http://www.google.de"), "de", true);
    infobar = GetTranslateInfoBar();
    ASSERT_TRUE(infobar != NULL);
    EXPECT_EQ(TranslateInfoBarDelegate::BEFORE_TRANSLATE, infobar->type());
    if (i < 7) {
      EXPECT_FALSE(infobar->ShouldShowNeverTranslateButton());
      infobar->TranslationDeclined();
    } else {
      EXPECT_TRUE(infobar->ShouldShowNeverTranslateButton());
    }
    if (i == 3)
      test_profile->set_incognito(false);
  }
  // Simulate the user pressing "Never translate French".
  infobar->NeverTranslatePageLanguage();
  EXPECT_TRUE(translate_prefs.IsLanguageBlacklisted("de"));
  // No translation should have occured and the infobar should be gone.
  EXPECT_FALSE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
  process()->sink().ClearMessages();
  ASSERT_TRUE(GetTranslateInfoBar() == NULL);
}

// Tests that we don't show a translate infobar when a page instructs that it
// should not be translated.
TEST_F(TranslateManagerTest, NonTranslatablePage) {
  // Simulate navigating to a page.
  SimulateNavigation(GURL("http://mail.google.fr"), "fr", false);

  // We should not have an infobar.
  EXPECT_TRUE(GetTranslateInfoBar() == NULL);

  // The context menu should be disabled.
  scoped_ptr<TestRenderViewContextMenu> menu(
      TestRenderViewContextMenu::CreateContextMenu(contents()));
  menu->Init();
  EXPECT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_TRANSLATE));
  EXPECT_FALSE(menu->IsCommandIdEnabled(IDC_CONTENT_CONTEXT_TRANSLATE));
}

// Tests that the script is expired and refetched as expected.
TEST_F(TranslateManagerTest, ScriptExpires) {
  ExpireTranslateScriptImmediately();

  // Simulate navigating to a page and translating it.
  SimulateNavigation(GURL("http://www.google.fr"), "fr", true);
  TranslateInfoBarDelegate* infobar = GetTranslateInfoBar();
  ASSERT_TRUE(infobar != NULL);
  process()->sink().ClearMessages();
  infobar->Translate();
  SimulateURLFetch(true);
  rvh()->TestOnMessageReceived(ViewHostMsg_PageTranslated(0, 0, "fr", "en",
      TranslateErrors::NONE));

  // A task should have been posted to clear the script, run it.
  MessageLoop::current()->RunAllPending();

  // Do another navigation and translation.
  SimulateNavigation(GURL("http://www.google.es"), "es", true);
  infobar = GetTranslateInfoBar();
  ASSERT_TRUE(infobar != NULL);
  process()->sink().ClearMessages();
  infobar->Translate();
  // If we don't simulate the URL fetch, the TranslateManager should be waiting
  // for the script and no message should have been sent to the renderer.
  EXPECT_TRUE(
      process()->sink().GetFirstMessageMatching(ViewMsg_TranslatePage::ID) ==
      NULL);
  // Now simulate the URL fetch.
  SimulateURLFetch(true);
  // Now the message should have been sent.
  int page_id = 0;
  std::string original_lang, target_lang;
  EXPECT_TRUE(GetTranslateMessage(&page_id, &original_lang, &target_lang));
  EXPECT_EQ("es", original_lang);
  EXPECT_EQ("en", target_lang);
}