root/chrome/browser/google/google_url_tracker_unittest.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. notified
  2. clear_notified
  3. observe_nav_start_
  4. TestGoogleURLTrackerNavigationHelper
  5. SetGoogleURLTracker
  6. SetListeningForNavigationStart
  7. IsListeningForNavigationStart
  8. SetListeningForNavigationCommit
  9. IsListeningForNavigationCommit
  10. SetListeningForTabDestruction
  11. IsListeningForTabDestruction
  12. fetched_google_url
  13. set_google_url
  14. google_url
  15. observer_notified
  16. clear_observer_notified
  17. OnInfoBarClosed
  18. SetUp
  19. TearDown
  20. GetFetcher
  21. MockSearchDomainCheckResponse
  22. RequestServerCheck
  23. FinishSleep
  24. NotifyIPAddressChanged
  25. SetLastPromptedGoogleURL
  26. GetLastPromptedGoogleURL
  27. SetNavigationPending
  28. CommitNonSearch
  29. CommitSearch
  30. CloseTab
  31. GetMapEntry
  32. GetInfoBarDelegate
  33. ExpectDefaultURLs
  34. ExpectListeningForCommit
  35. CreateTestInfoBar
  36. Create
  37. infobar_service_
  38. Update
  39. Close
  40. TEST_F
  41. TEST_F
  42. TEST_F
  43. TEST_F
  44. TEST_F
  45. TEST_F
  46. TEST_F
  47. TEST_F
  48. TEST_F
  49. TEST_F
  50. TEST_F
  51. TEST_F
  52. TEST_F
  53. TEST_F
  54. TEST_F
  55. TEST_F
  56. TEST_F
  57. TEST_F
  58. TEST_F
  59. TEST_F
  60. TEST_F
  61. TEST_F

// Copyright (c) 2012 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 "chrome/browser/google/google_url_tracker.h"

#include <set>
#include <string>

#include "base/message_loop/message_loop.h"
#include "base/prefs/pref_service.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/google/google_url_tracker_factory.h"
#include "chrome/browser/google/google_url_tracker_infobar_delegate.h"
#include "chrome/browser/google/google_url_tracker_navigation_helper.h"
#include "chrome/browser/infobars/infobar.h"
#include "chrome/browser/infobars/infobar_delegate.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_profile.h"
#include "content/public/browser/notification_service.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "net/url_request/url_fetcher.h"
#include "testing/gtest/include/gtest/gtest.h"

class GoogleURLTrackerTest;

namespace {

// TestInfoBarDelegate --------------------------------------------------------

class TestInfoBarDelegate : public GoogleURLTrackerInfoBarDelegate {
 public:
  // Creates a test infobar and delegate and returns the infobar.  Unlike the
  // parent class, this does not add the infobar to |infobar_service|, since
  // that "pointer" is really just a magic number.  Thus there is no
  // InfoBarService ownership of the returned object; and since the caller
  // doesn't own the returned object, we rely on |test_harness| cleaning this up
  // eventually in GoogleURLTrackerTest::OnInfoBarClosed() to avoid leaks.
  static InfoBar* Create(GoogleURLTrackerTest* test_harness,
                         InfoBarService* infobar_service,
                         GoogleURLTracker* google_url_tracker,
                         const GURL& search_url);

 private:
  TestInfoBarDelegate(GoogleURLTrackerTest* test_harness,
                      InfoBarService* infobar_service,
                      GoogleURLTracker* google_url_tracker,
                      const GURL& search_url);
  virtual ~TestInfoBarDelegate();

  // GoogleURLTrackerInfoBarDelegate:
  virtual void Update(const GURL& search_url) OVERRIDE;
  virtual void Close(bool redo_search) OVERRIDE;

  GoogleURLTrackerTest* test_harness_;
  InfoBarService* infobar_service_;

  DISALLOW_COPY_AND_ASSIGN(TestInfoBarDelegate);
};

// The member function definitions come after the declaration of
// GoogleURLTrackerTest, so they can call members on it.


// TestNotificationObserver ---------------------------------------------------

class TestNotificationObserver : public content::NotificationObserver {
 public:
  TestNotificationObserver();
  virtual ~TestNotificationObserver();

  virtual void Observe(int type,
                       const content::NotificationSource& source,
                       const content::NotificationDetails& details) OVERRIDE;
  bool notified() const { return notified_; }
  void clear_notified() { notified_ = false; }

 private:
  bool notified_;
};

TestNotificationObserver::TestNotificationObserver() : notified_(false) {
}

TestNotificationObserver::~TestNotificationObserver() {
}

void TestNotificationObserver::Observe(
    int type,
    const content::NotificationSource& source,
    const content::NotificationDetails& details) {
  notified_ = true;
}


// TestGoogleURLTrackerNavigationHelper -------------------------------------

class TestGoogleURLTrackerNavigationHelper
    : public GoogleURLTrackerNavigationHelper {
 public:
  TestGoogleURLTrackerNavigationHelper();
  virtual ~TestGoogleURLTrackerNavigationHelper();

  virtual void SetGoogleURLTracker(GoogleURLTracker* tracker) OVERRIDE;
  virtual void SetListeningForNavigationStart(bool listen) OVERRIDE;
  virtual bool IsListeningForNavigationStart() OVERRIDE;
  virtual void SetListeningForNavigationCommit(
      const content::NavigationController* nav_controller,
      bool listen) OVERRIDE;
  virtual bool IsListeningForNavigationCommit(
      const content::NavigationController* nav_controller) OVERRIDE;
  virtual void SetListeningForTabDestruction(
      const content::NavigationController* nav_controller,
      bool listen) OVERRIDE;
  virtual bool IsListeningForTabDestruction(
      const content::NavigationController* nav_controller) OVERRIDE;

 private:
  GoogleURLTracker* tracker_;
  bool observe_nav_start_;
  std::set<const content::NavigationController*>
      nav_controller_commit_listeners_;
  std::set<const content::NavigationController*>
      nav_controller_tab_close_listeners_;
};

TestGoogleURLTrackerNavigationHelper::TestGoogleURLTrackerNavigationHelper()
    : tracker_(NULL),
      observe_nav_start_(false) {
}

TestGoogleURLTrackerNavigationHelper::
    ~TestGoogleURLTrackerNavigationHelper() {
}

void TestGoogleURLTrackerNavigationHelper::SetGoogleURLTracker(
    GoogleURLTracker* tracker) {
  tracker_ = tracker;
}

void TestGoogleURLTrackerNavigationHelper::SetListeningForNavigationStart(
    bool listen) {
  observe_nav_start_ = listen;
}

bool TestGoogleURLTrackerNavigationHelper::IsListeningForNavigationStart() {
  return observe_nav_start_;
}

void TestGoogleURLTrackerNavigationHelper::SetListeningForNavigationCommit(
    const content::NavigationController* nav_controller,
    bool listen) {
  if (listen)
    nav_controller_commit_listeners_.insert(nav_controller);
  else
    nav_controller_commit_listeners_.erase(nav_controller);
}

bool TestGoogleURLTrackerNavigationHelper::IsListeningForNavigationCommit(
    const content::NavigationController* nav_controller) {
  return nav_controller_commit_listeners_.count(nav_controller) > 0;
}

void TestGoogleURLTrackerNavigationHelper::SetListeningForTabDestruction(
    const content::NavigationController* nav_controller,
    bool listen) {
  if (listen)
    nav_controller_tab_close_listeners_.insert(nav_controller);
  else
    nav_controller_tab_close_listeners_.erase(nav_controller);
}

bool TestGoogleURLTrackerNavigationHelper::IsListeningForTabDestruction(
    const content::NavigationController* nav_controller) {
  return nav_controller_tab_close_listeners_.count(nav_controller) > 0;
}

}  // namespace


// GoogleURLTrackerTest -------------------------------------------------------

// Ths class exercises GoogleURLTracker.  In order to avoid instantiating more
// of the Chrome infrastructure than necessary, the GoogleURLTracker functions
// are carefully written so that many of the functions which take
// NavigationController* or InfoBarService* do not actually dereference the
// objects, merely use them for comparisons and lookups, e.g. in |entry_map_|.
// This then allows the test code here to not create any of these objects, and
// instead supply "pointers" that are actually reinterpret_cast<>()ed magic
// numbers.  Then we write the necessary stubs/hooks, here and in
// TestInfoBarDelegate above, to make everything continue to work.
//
// Technically, the C++98 spec defines the result of casting
// T* -> intptr_t -> T* to be an identity, but intptr_t -> T* -> intptr_t (what
// we use here) is "implementation-defined".  Since I've never seen a compiler
// break this, though, and the result would simply be a failing test rather than
// a bug in Chrome, we'll use it anyway.
class GoogleURLTrackerTest : public testing::Test {
 public:
  // Called by TestInfoBarDelegate::Close().
  void OnInfoBarClosed(scoped_ptr<InfoBar> infobar,
                       InfoBarService* infobar_service);

 protected:
  GoogleURLTrackerTest();
  virtual ~GoogleURLTrackerTest();

  // testing::Test
  virtual void SetUp() OVERRIDE;
  virtual void TearDown() OVERRIDE;

  net::TestURLFetcher* GetFetcher();
  void MockSearchDomainCheckResponse(const std::string& domain);
  void RequestServerCheck();
  void FinishSleep();
  void NotifyIPAddressChanged();
  GURL fetched_google_url() const {
    return google_url_tracker_->fetched_google_url();
  }
  void set_google_url(const GURL& url) {
    google_url_tracker_->google_url_ = url;
  }
  GURL google_url() const { return google_url_tracker_->google_url(); }
  void SetLastPromptedGoogleURL(const GURL& url);
  GURL GetLastPromptedGoogleURL();
  void SetNavigationPending(intptr_t unique_id, bool is_search);
  void CommitNonSearch(intptr_t unique_id);
  void CommitSearch(intptr_t unique_id, const GURL& search_url);
  void CloseTab(intptr_t unique_id);
  GoogleURLTrackerMapEntry* GetMapEntry(intptr_t unique_id);
  GoogleURLTrackerInfoBarDelegate* GetInfoBarDelegate(intptr_t unique_id);
  void ExpectDefaultURLs() const;
  void ExpectListeningForCommit(intptr_t unique_id, bool listening);
  bool observer_notified() const { return observer_.notified(); }
  void clear_observer_notified() { observer_.clear_notified(); }

 private:
  // Since |infobar_service| is really a magic number rather than an actual
  // object, we don't add the created infobar to it.  Instead we will simulate
  // any helper<->infobar interaction necessary.  The returned object will be
  // cleaned up in OnInfoBarClosed().
  InfoBar* CreateTestInfoBar(InfoBarService* infobar_service,
                             GoogleURLTracker* google_url_tracker,
                             const GURL& search_url);

  // These are required by the TestURLFetchers GoogleURLTracker will create (see
  // test_url_fetcher_factory.h).
  content::TestBrowserThreadBundle thread_bundle_;
  // Creating this allows us to call
  // net::NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests().
  scoped_ptr<net::NetworkChangeNotifier> network_change_notifier_;
  net::TestURLFetcherFactory fetcher_factory_;
  content::NotificationRegistrar registrar_;
  TestNotificationObserver observer_;
  GoogleURLTrackerNavigationHelper* nav_helper_;
  TestingProfile profile_;
  scoped_ptr<GoogleURLTracker> google_url_tracker_;
  // This tracks the different "tabs" a test has "opened", so we can close them
  // properly before shutting down |google_url_tracker_|, which expects that.
  std::set<int> unique_ids_seen_;
};

void GoogleURLTrackerTest::OnInfoBarClosed(scoped_ptr<InfoBar> infobar,
                                           InfoBarService* infobar_service) {
  // First, simulate the InfoBarService firing INFOBAR_REMOVED.
  InfoBar::RemovedDetails removed_details(infobar.get(), false);
  GoogleURLTracker::EntryMap::const_iterator i =
      google_url_tracker_->entry_map_.find(infobar_service);
  ASSERT_FALSE(i == google_url_tracker_->entry_map_.end());
  GoogleURLTrackerMapEntry* map_entry = i->second;
  ASSERT_EQ(infobar->delegate(), map_entry->infobar_delegate());
  map_entry->Observe(
      chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED,
      content::Source<InfoBarService>(infobar_service),
      content::Details<InfoBar::RemovedDetails>(&removed_details));

  // Second, simulate the infobar container closing the infobar in response.
  // This happens automatically as |infobar| goes out of scope.
}

GoogleURLTrackerTest::GoogleURLTrackerTest()
    : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {
  GoogleURLTrackerFactory::GetInstance()->
      RegisterUserPrefsOnBrowserContextForTest(&profile_);
}

GoogleURLTrackerTest::~GoogleURLTrackerTest() {
}

void GoogleURLTrackerTest::SetUp() {
  network_change_notifier_.reset(net::NetworkChangeNotifier::CreateMock());
  // Ownership is passed to google_url_tracker_, but a weak pointer is kept;
  // this is safe since GoogleURLTracker keeps the observer for its lifetime.
  nav_helper_ = new TestGoogleURLTrackerNavigationHelper();
  scoped_ptr<GoogleURLTrackerNavigationHelper> nav_helper(nav_helper_);
  google_url_tracker_.reset(
      new GoogleURLTracker(&profile_, nav_helper.Pass(),
                           GoogleURLTracker::UNIT_TEST_MODE));
  google_url_tracker_->infobar_creator_ = base::Bind(
      &GoogleURLTrackerTest::CreateTestInfoBar, base::Unretained(this));
}

void GoogleURLTrackerTest::TearDown() {
  while (!unique_ids_seen_.empty())
    CloseTab(*unique_ids_seen_.begin());

  nav_helper_ = NULL;
  google_url_tracker_.reset();
  network_change_notifier_.reset();
}

net::TestURLFetcher* GoogleURLTrackerTest::GetFetcher() {
  // This will return the last fetcher created.  If no fetchers have been
  // created, we'll pass GetFetcherByID() "-1", and it will return NULL.
  return fetcher_factory_.GetFetcherByID(google_url_tracker_->fetcher_id_ - 1);
}

void GoogleURLTrackerTest::MockSearchDomainCheckResponse(
    const std::string& domain) {
  net::TestURLFetcher* fetcher = GetFetcher();
  if (!fetcher)
    return;
  fetcher_factory_.RemoveFetcherFromMap(fetcher->id());
  fetcher->set_url(GURL(GoogleURLTracker::kSearchDomainCheckURL));
  fetcher->set_response_code(200);
  fetcher->SetResponseString(domain);
  fetcher->delegate()->OnURLFetchComplete(fetcher);
  // At this point, |fetcher| is deleted.
}

void GoogleURLTrackerTest::RequestServerCheck() {
  if (!registrar_.IsRegistered(&observer_,
                               chrome::NOTIFICATION_GOOGLE_URL_UPDATED,
                               content::Source<Profile>(&profile_))) {
    registrar_.Add(&observer_, chrome::NOTIFICATION_GOOGLE_URL_UPDATED,
                   content::Source<Profile>(&profile_));
  }
  google_url_tracker_->SetNeedToFetch();
}

void GoogleURLTrackerTest::FinishSleep() {
  google_url_tracker_->FinishSleep();
}

void GoogleURLTrackerTest::NotifyIPAddressChanged() {
  net::NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
  // For thread safety, the NCN queues tasks to do the actual notifications, so
  // we need to spin the message loop so the tracker will actually be notified.
  base::MessageLoop::current()->RunUntilIdle();
}

void GoogleURLTrackerTest::SetLastPromptedGoogleURL(const GURL& url) {
  profile_.GetPrefs()->SetString(prefs::kLastPromptedGoogleURL, url.spec());
}

GURL GoogleURLTrackerTest::GetLastPromptedGoogleURL() {
  return GURL(profile_.GetPrefs()->GetString(prefs::kLastPromptedGoogleURL));
}

void GoogleURLTrackerTest::SetNavigationPending(intptr_t unique_id,
                                                bool is_search) {
  if (is_search) {
    google_url_tracker_->SearchCommitted();
    // Note that the call above might not have actually registered a listener
    // for navigation starts if the searchdomaincheck response was bogus.
  }
  unique_ids_seen_.insert(unique_id);
  if (nav_helper_->IsListeningForNavigationStart()) {
    google_url_tracker_->OnNavigationPending(
        reinterpret_cast<content::NavigationController*>(unique_id),
        reinterpret_cast<InfoBarService*>(unique_id), unique_id);
  }
}

void GoogleURLTrackerTest::CommitNonSearch(intptr_t unique_id) {
  GoogleURLTrackerMapEntry* map_entry = GetMapEntry(unique_id);
  if (!map_entry)
    return;

  ExpectListeningForCommit(unique_id, false);

  // The infobar should be showing; otherwise the pending non-search should
  // have closed it.
  ASSERT_TRUE(map_entry->has_infobar_delegate());

  // The pending_id should have been reset to 0 when the non-search became
  // pending.
  EXPECT_EQ(0, map_entry->infobar_delegate()->pending_id());

  // Committing the navigation would close the infobar.
  map_entry->infobar_delegate()->Close(false);
}

void GoogleURLTrackerTest::CommitSearch(intptr_t unique_id,
                                        const GURL& search_url) {
  DCHECK(search_url.is_valid());
  if (nav_helper_->IsListeningForNavigationCommit(
      reinterpret_cast<content::NavigationController*>(unique_id))) {
    google_url_tracker_->OnNavigationCommitted(
        reinterpret_cast<InfoBarService*>(unique_id), search_url);
  }
}

void GoogleURLTrackerTest::CloseTab(intptr_t unique_id) {
  unique_ids_seen_.erase(unique_id);
  content::NavigationController* nav_controller =
      reinterpret_cast<content::NavigationController*>(unique_id);
  if (nav_helper_->IsListeningForTabDestruction(nav_controller)) {
    google_url_tracker_->OnTabClosed(nav_controller);
  } else {
    // Closing a tab with an infobar showing would close the infobar.
    GoogleURLTrackerInfoBarDelegate* delegate = GetInfoBarDelegate(unique_id);
    if (delegate)
      delegate->Close(false);
  }
}

GoogleURLTrackerMapEntry* GoogleURLTrackerTest::GetMapEntry(
    intptr_t unique_id) {
  GoogleURLTracker::EntryMap::const_iterator i =
      google_url_tracker_->entry_map_.find(
          reinterpret_cast<InfoBarService*>(unique_id));
  return (i == google_url_tracker_->entry_map_.end()) ? NULL : i->second;
}

GoogleURLTrackerInfoBarDelegate* GoogleURLTrackerTest::GetInfoBarDelegate(
    intptr_t unique_id) {
  GoogleURLTrackerMapEntry* map_entry = GetMapEntry(unique_id);
  return map_entry ? map_entry->infobar_delegate() : NULL;
}

void GoogleURLTrackerTest::ExpectDefaultURLs() const {
  EXPECT_EQ(GURL(GoogleURLTracker::kDefaultGoogleHomepage), google_url());
  EXPECT_EQ(GURL(), fetched_google_url());
}

void GoogleURLTrackerTest::ExpectListeningForCommit(intptr_t unique_id,
                                                    bool listening) {
  GoogleURLTrackerMapEntry* map_entry = GetMapEntry(unique_id);
  if (map_entry) {
    EXPECT_EQ(listening, nav_helper_->IsListeningForNavigationCommit(
        map_entry->navigation_controller()));
  } else {
    EXPECT_FALSE(listening);
  }
}

InfoBar* GoogleURLTrackerTest::CreateTestInfoBar(
    InfoBarService* infobar_service,
    GoogleURLTracker* google_url_tracker,
    const GURL& search_url) {
  return TestInfoBarDelegate::Create(this, infobar_service, google_url_tracker,
                                     search_url);
}


// TestInfoBarDelegate --------------------------------------------------------

namespace {

// static
InfoBar* TestInfoBarDelegate::Create(GoogleURLTrackerTest* test_harness,
                                     InfoBarService* infobar_service,
                                     GoogleURLTracker* google_url_tracker,
                                     const GURL& search_url) {
  return ConfirmInfoBarDelegate::CreateInfoBar(
      scoped_ptr<ConfirmInfoBarDelegate>(new TestInfoBarDelegate(
          test_harness, infobar_service, google_url_tracker,
          search_url))).release();
}

TestInfoBarDelegate::TestInfoBarDelegate(GoogleURLTrackerTest* test_harness,
                                         InfoBarService* infobar_service,
                                         GoogleURLTracker* google_url_tracker,
                                         const GURL& search_url)
  : GoogleURLTrackerInfoBarDelegate(google_url_tracker, search_url),
    test_harness_(test_harness),
    infobar_service_(infobar_service) {
}

TestInfoBarDelegate::~TestInfoBarDelegate() {
}

void TestInfoBarDelegate::Update(const GURL& search_url) {
  set_search_url(search_url);
  set_pending_id(0);
}

void TestInfoBarDelegate::Close(bool redo_search) {
  test_harness_->OnInfoBarClosed(scoped_ptr<InfoBar>(infobar()),
                                 infobar_service_);
  // WARNING: At this point |this| has been deleted!
}

}  // namespace


// Tests ----------------------------------------------------------------------

TEST_F(GoogleURLTrackerTest, DontFetchWhenNoOneRequestsCheck) {
  ExpectDefaultURLs();
  FinishSleep();
  // No one called RequestServerCheck() so nothing should have happened.
  EXPECT_FALSE(GetFetcher());
  MockSearchDomainCheckResponse("http://www.google.co.uk/");
  ExpectDefaultURLs();
  EXPECT_FALSE(observer_notified());
}

TEST_F(GoogleURLTrackerTest, UpdateOnFirstRun) {
  RequestServerCheck();
  EXPECT_FALSE(GetFetcher());
  ExpectDefaultURLs();
  EXPECT_FALSE(observer_notified());

  FinishSleep();
  MockSearchDomainCheckResponse("http://www.google.co.uk/");
  EXPECT_EQ(GURL("http://www.google.co.uk/"), fetched_google_url());
  // GoogleURL should be updated, becase there was no last prompted URL.
  EXPECT_EQ(GURL("http://www.google.co.uk/"), google_url());
  EXPECT_TRUE(observer_notified());
}

TEST_F(GoogleURLTrackerTest, DontUpdateWhenUnchanged) {
  SetLastPromptedGoogleURL(GURL("http://www.google.co.uk/"));

  RequestServerCheck();
  EXPECT_FALSE(GetFetcher());
  ExpectDefaultURLs();
  EXPECT_FALSE(observer_notified());

  FinishSleep();
  MockSearchDomainCheckResponse("http://www.google.co.uk/");
  EXPECT_EQ(GURL("http://www.google.co.uk/"), fetched_google_url());
  // GoogleURL should not be updated, because the fetched and prompted URLs
  // match.
  EXPECT_EQ(GURL(GoogleURLTracker::kDefaultGoogleHomepage), google_url());
  EXPECT_FALSE(observer_notified());
}

TEST_F(GoogleURLTrackerTest, DontPromptOnBadReplies) {
  SetLastPromptedGoogleURL(GURL("http://www.google.co.uk/"));

  RequestServerCheck();
  EXPECT_FALSE(GetFetcher());
  ExpectDefaultURLs();
  EXPECT_FALSE(observer_notified());

  // Old-style domain string.
  FinishSleep();
  MockSearchDomainCheckResponse(".google.co.in");
  EXPECT_EQ(GURL(), fetched_google_url());
  EXPECT_EQ(GURL(GoogleURLTracker::kDefaultGoogleHomepage), google_url());
  EXPECT_FALSE(observer_notified());
  SetNavigationPending(1, true);
  CommitSearch(1, GURL("http://www.google.co.uk/search?q=test"));
  EXPECT_TRUE(GetMapEntry(1) == NULL);

  // Bad subdomain.
  NotifyIPAddressChanged();
  MockSearchDomainCheckResponse("http://mail.google.com/");
  EXPECT_EQ(GURL(), fetched_google_url());
  EXPECT_EQ(GURL(GoogleURLTracker::kDefaultGoogleHomepage), google_url());
  EXPECT_FALSE(observer_notified());
  SetNavigationPending(1, true);
  CommitSearch(1, GURL("http://www.google.co.uk/search?q=test"));
  EXPECT_TRUE(GetMapEntry(1) == NULL);

  // Non-empty path.
  NotifyIPAddressChanged();
  MockSearchDomainCheckResponse("http://www.google.com/search");
  EXPECT_EQ(GURL(), fetched_google_url());
  EXPECT_EQ(GURL(GoogleURLTracker::kDefaultGoogleHomepage), google_url());
  EXPECT_FALSE(observer_notified());
  SetNavigationPending(1, true);
  CommitSearch(1, GURL("http://www.google.co.uk/search?q=test"));
  EXPECT_TRUE(GetMapEntry(1) == NULL);

  // Non-empty query.
  NotifyIPAddressChanged();
  MockSearchDomainCheckResponse("http://www.google.com/?q=foo");
  EXPECT_EQ(GURL(), fetched_google_url());
  EXPECT_EQ(GURL(GoogleURLTracker::kDefaultGoogleHomepage), google_url());
  EXPECT_FALSE(observer_notified());
  SetNavigationPending(1, true);
  CommitSearch(1, GURL("http://www.google.co.uk/search?q=test"));
  EXPECT_TRUE(GetMapEntry(1) == NULL);

  // Non-empty ref.
  NotifyIPAddressChanged();
  MockSearchDomainCheckResponse("http://www.google.com/#anchor");
  EXPECT_EQ(GURL(), fetched_google_url());
  EXPECT_EQ(GURL(GoogleURLTracker::kDefaultGoogleHomepage), google_url());
  EXPECT_FALSE(observer_notified());
  SetNavigationPending(1, true);
  CommitSearch(1, GURL("http://www.google.co.uk/search?q=test"));
  EXPECT_TRUE(GetMapEntry(1) == NULL);

  // Complete garbage.
  NotifyIPAddressChanged();
  MockSearchDomainCheckResponse("HJ)*qF)_*&@f1");
  EXPECT_EQ(GURL(), fetched_google_url());
  EXPECT_EQ(GURL(GoogleURLTracker::kDefaultGoogleHomepage), google_url());
  EXPECT_FALSE(observer_notified());
  SetNavigationPending(1, true);
  CommitSearch(1, GURL("http://www.google.co.uk/search?q=test"));
  EXPECT_TRUE(GetMapEntry(1) == NULL);
}

TEST_F(GoogleURLTrackerTest, UpdatePromptedURLOnReturnToPreviousLocation) {
  SetLastPromptedGoogleURL(GURL("http://www.google.co.jp/"));
  set_google_url(GURL("http://www.google.co.uk/"));
  RequestServerCheck();
  FinishSleep();
  MockSearchDomainCheckResponse("http://www.google.co.uk/");
  EXPECT_EQ(GURL("http://www.google.co.uk/"), fetched_google_url());
  EXPECT_EQ(GURL("http://www.google.co.uk/"), google_url());
  EXPECT_EQ(GURL("http://www.google.co.uk/"), GetLastPromptedGoogleURL());
  EXPECT_FALSE(observer_notified());
}

TEST_F(GoogleURLTrackerTest, SilentlyAcceptSchemeChange) {
  // We should auto-accept changes to the current Google URL that merely change
  // the scheme, regardless of what the last prompted URL was.
  SetLastPromptedGoogleURL(GURL("http://www.google.co.jp/"));
  set_google_url(GURL("http://www.google.co.uk/"));
  RequestServerCheck();
  FinishSleep();
  MockSearchDomainCheckResponse("https://www.google.co.uk/");
  EXPECT_EQ(GURL("https://www.google.co.uk/"), fetched_google_url());
  EXPECT_EQ(GURL("https://www.google.co.uk/"), google_url());
  EXPECT_EQ(GURL("https://www.google.co.uk/"), GetLastPromptedGoogleURL());
  EXPECT_TRUE(observer_notified());

  NotifyIPAddressChanged();
  MockSearchDomainCheckResponse("http://www.google.co.uk/");
  EXPECT_EQ(GURL("http://www.google.co.uk/"), fetched_google_url());
  EXPECT_EQ(GURL("http://www.google.co.uk/"), google_url());
  EXPECT_EQ(GURL("http://www.google.co.uk/"), GetLastPromptedGoogleURL());
  EXPECT_TRUE(observer_notified());
}

TEST_F(GoogleURLTrackerTest, RefetchOnIPAddressChange) {
  RequestServerCheck();
  FinishSleep();
  MockSearchDomainCheckResponse("http://www.google.co.uk/");
  EXPECT_EQ(GURL("http://www.google.co.uk/"), fetched_google_url());
  EXPECT_EQ(GURL("http://www.google.co.uk/"), google_url());
  EXPECT_TRUE(observer_notified());
  clear_observer_notified();

  NotifyIPAddressChanged();
  MockSearchDomainCheckResponse("http://www.google.co.in/");
  EXPECT_EQ(GURL("http://www.google.co.in/"), fetched_google_url());
  // Just fetching a new URL shouldn't reset things without a prompt.
  EXPECT_EQ(GURL("http://www.google.co.uk/"), google_url());
  EXPECT_FALSE(observer_notified());
}

TEST_F(GoogleURLTrackerTest, DontRefetchWhenNoOneRequestsCheck) {
  FinishSleep();
  NotifyIPAddressChanged();
  // No one called RequestServerCheck() so nothing should have happened.
  EXPECT_FALSE(GetFetcher());
  MockSearchDomainCheckResponse("http://www.google.co.uk/");
  ExpectDefaultURLs();
  EXPECT_FALSE(observer_notified());
}

TEST_F(GoogleURLTrackerTest, FetchOnLateRequest) {
  FinishSleep();
  NotifyIPAddressChanged();
  MockSearchDomainCheckResponse("http://www.google.co.jp/");

  RequestServerCheck();
  // The first request for a check should trigger a fetch if it hasn't happened
  // already.
  MockSearchDomainCheckResponse("http://www.google.co.uk/");
  EXPECT_EQ(GURL("http://www.google.co.uk/"), fetched_google_url());
  EXPECT_EQ(GURL("http://www.google.co.uk/"), google_url());
  EXPECT_TRUE(observer_notified());
}

TEST_F(GoogleURLTrackerTest, DontFetchTwiceOnLateRequests) {
  FinishSleep();
  NotifyIPAddressChanged();
  MockSearchDomainCheckResponse("http://www.google.co.jp/");

  RequestServerCheck();
  // The first request for a check should trigger a fetch if it hasn't happened
  // already.
  MockSearchDomainCheckResponse("http://www.google.co.uk/");
  EXPECT_EQ(GURL("http://www.google.co.uk/"), fetched_google_url());
  EXPECT_EQ(GURL("http://www.google.co.uk/"), google_url());
  EXPECT_TRUE(observer_notified());
  clear_observer_notified();

  RequestServerCheck();
  // The second request should be ignored.
  EXPECT_FALSE(GetFetcher());
  MockSearchDomainCheckResponse("http://www.google.co.in/");
  EXPECT_EQ(GURL("http://www.google.co.uk/"), fetched_google_url());
  EXPECT_EQ(GURL("http://www.google.co.uk/"), google_url());
  EXPECT_FALSE(observer_notified());
}

TEST_F(GoogleURLTrackerTest, SearchingDoesNothingIfNoNeedToPrompt) {
  RequestServerCheck();
  FinishSleep();
  MockSearchDomainCheckResponse("http://www.google.co.uk/");
  EXPECT_EQ(GURL("http://www.google.co.uk/"), fetched_google_url());
  EXPECT_EQ(GURL("http://www.google.co.uk/"), google_url());
  EXPECT_EQ(GURL("http://www.google.co.uk/"), GetLastPromptedGoogleURL());
  EXPECT_TRUE(observer_notified());
  clear_observer_notified();

  SetNavigationPending(1, true);
  CommitSearch(1, GURL("http://www.google.co.uk/search?q=test"));
  EXPECT_TRUE(GetMapEntry(1) == NULL);
  EXPECT_EQ(GURL("http://www.google.co.uk/"), fetched_google_url());
  EXPECT_EQ(GURL("http://www.google.co.uk/"), google_url());
  EXPECT_EQ(GURL("http://www.google.co.uk/"), GetLastPromptedGoogleURL());
  EXPECT_FALSE(observer_notified());
}

TEST_F(GoogleURLTrackerTest, TabClosedOnPendingSearch) {
  SetLastPromptedGoogleURL(GURL("http://www.google.co.uk/"));
  RequestServerCheck();
  FinishSleep();
  MockSearchDomainCheckResponse("http://www.google.co.jp/");
  EXPECT_EQ(GURL(GoogleURLTracker::kDefaultGoogleHomepage), google_url());
  EXPECT_EQ(GURL("http://www.google.co.jp/"), fetched_google_url());
  EXPECT_EQ(GURL("http://www.google.co.uk/"), GetLastPromptedGoogleURL());
  EXPECT_FALSE(observer_notified());

  SetNavigationPending(1, true);
  GoogleURLTrackerMapEntry* map_entry = GetMapEntry(1);
  ASSERT_FALSE(map_entry == NULL);
  EXPECT_FALSE(map_entry->has_infobar_delegate());
  EXPECT_EQ(GURL(GoogleURLTracker::kDefaultGoogleHomepage), google_url());
  EXPECT_EQ(GURL("http://www.google.co.uk/"), GetLastPromptedGoogleURL());
  EXPECT_FALSE(observer_notified());

  CloseTab(1);
  EXPECT_TRUE(GetMapEntry(1) == NULL);
  EXPECT_EQ(GURL(GoogleURLTracker::kDefaultGoogleHomepage), google_url());
  EXPECT_EQ(GURL("http://www.google.co.uk/"), GetLastPromptedGoogleURL());
  EXPECT_FALSE(observer_notified());
}

TEST_F(GoogleURLTrackerTest, TabClosedOnCommittedSearch) {
  SetLastPromptedGoogleURL(GURL("http://www.google.co.uk/"));
  RequestServerCheck();
  FinishSleep();
  MockSearchDomainCheckResponse("http://www.google.co.jp/");

  SetNavigationPending(1, true);
  CommitSearch(1, GURL("http://www.google.co.uk/search?q=test"));
  EXPECT_FALSE(GetInfoBarDelegate(1) == NULL);

  CloseTab(1);
  EXPECT_TRUE(GetMapEntry(1) == NULL);
  EXPECT_EQ(GURL(GoogleURLTracker::kDefaultGoogleHomepage), google_url());
  EXPECT_EQ(GURL("http://www.google.co.uk/"), GetLastPromptedGoogleURL());
  EXPECT_FALSE(observer_notified());
}

TEST_F(GoogleURLTrackerTest, InfoBarClosed) {
  SetLastPromptedGoogleURL(GURL("http://www.google.co.uk/"));
  RequestServerCheck();
  FinishSleep();
  MockSearchDomainCheckResponse("http://www.google.co.jp/");

  SetNavigationPending(1, true);
  CommitSearch(1, GURL("http://www.google.co.uk/search?q=test"));
  GoogleURLTrackerInfoBarDelegate* infobar = GetInfoBarDelegate(1);
  ASSERT_FALSE(infobar == NULL);

  infobar->Close(false);
  EXPECT_TRUE(GetMapEntry(1) == NULL);
  EXPECT_EQ(GURL(GoogleURLTracker::kDefaultGoogleHomepage), google_url());
  EXPECT_EQ(GURL("http://www.google.co.uk/"), GetLastPromptedGoogleURL());
  EXPECT_FALSE(observer_notified());
}

TEST_F(GoogleURLTrackerTest, InfoBarRefused) {
  SetLastPromptedGoogleURL(GURL("http://www.google.co.uk/"));
  RequestServerCheck();
  FinishSleep();
  MockSearchDomainCheckResponse("http://www.google.co.jp/");

  SetNavigationPending(1, true);
  CommitSearch(1, GURL("http://www.google.co.uk/search?q=test"));
  GoogleURLTrackerInfoBarDelegate* infobar = GetInfoBarDelegate(1);
  ASSERT_FALSE(infobar == NULL);

  infobar->Cancel();
  EXPECT_TRUE(GetMapEntry(1) == NULL);
  EXPECT_EQ(GURL(GoogleURLTracker::kDefaultGoogleHomepage), google_url());
  EXPECT_EQ(GURL("http://www.google.co.jp/"), GetLastPromptedGoogleURL());
  EXPECT_FALSE(observer_notified());
}

TEST_F(GoogleURLTrackerTest, InfoBarAccepted) {
  SetLastPromptedGoogleURL(GURL("http://www.google.co.uk/"));
  RequestServerCheck();
  FinishSleep();
  MockSearchDomainCheckResponse("http://www.google.co.jp/");

  SetNavigationPending(1, true);
  CommitSearch(1, GURL("http://www.google.co.uk/search?q=test"));
  GoogleURLTrackerInfoBarDelegate* infobar = GetInfoBarDelegate(1);
  ASSERT_FALSE(infobar == NULL);

  infobar->Accept();
  EXPECT_TRUE(GetMapEntry(1) == NULL);
  EXPECT_EQ(GURL("http://www.google.co.jp/"), google_url());
  EXPECT_EQ(GURL("http://www.google.co.jp/"), GetLastPromptedGoogleURL());
  EXPECT_TRUE(observer_notified());
}

TEST_F(GoogleURLTrackerTest, FetchesCanAutomaticallyCloseInfoBars) {
  RequestServerCheck();
  FinishSleep();
  MockSearchDomainCheckResponse(google_url().spec());

  // Re-fetching the accepted URL after showing an infobar for another URL
  // should close the infobar.
  NotifyIPAddressChanged();
  MockSearchDomainCheckResponse("http://www.google.co.uk/");
  SetNavigationPending(1, true);
  CommitSearch(1, GURL("http://www.google.com/search?q=test"));
  EXPECT_FALSE(GetInfoBarDelegate(1) == NULL);
  NotifyIPAddressChanged();
  MockSearchDomainCheckResponse(google_url().spec());
  EXPECT_EQ(google_url(), GetLastPromptedGoogleURL());
  EXPECT_TRUE(GetMapEntry(1) == NULL);

  // As should fetching a URL that differs from the accepted only by the scheme.
  NotifyIPAddressChanged();
  MockSearchDomainCheckResponse("http://www.google.co.uk/");
  SetNavigationPending(1, true);
  CommitSearch(1, GURL("http://www.google.com/search?q=test"));
  EXPECT_FALSE(GetInfoBarDelegate(1) == NULL);
  NotifyIPAddressChanged();
  url_canon::Replacements<char> replacements;
  const std::string& scheme("https");
  replacements.SetScheme(scheme.data(),
                         url_parse::Component(0, scheme.length()));
  GURL new_google_url(google_url().ReplaceComponents(replacements));
  MockSearchDomainCheckResponse(new_google_url.spec());
  EXPECT_EQ(new_google_url, GetLastPromptedGoogleURL());
  EXPECT_TRUE(GetMapEntry(1) == NULL);

  // As should re-fetching the last prompted URL.
  SetLastPromptedGoogleURL(GURL("http://www.google.co.uk/"));
  NotifyIPAddressChanged();
  MockSearchDomainCheckResponse("http://www.google.co.jp/");
  SetNavigationPending(1, true);
  CommitSearch(1, GURL("http://www.google.com/search?q=test"));
  EXPECT_FALSE(GetInfoBarDelegate(1) == NULL);
  NotifyIPAddressChanged();
  MockSearchDomainCheckResponse("http://www.google.co.uk/");
  EXPECT_EQ(new_google_url, google_url());
  EXPECT_EQ(GURL("http://www.google.co.uk/"), GetLastPromptedGoogleURL());
  EXPECT_TRUE(GetMapEntry(1) == NULL);

  // And one that differs from the last prompted URL only by the scheme.
  NotifyIPAddressChanged();
  MockSearchDomainCheckResponse("http://www.google.co.jp/");
  SetNavigationPending(1, true);
  CommitSearch(1, GURL("http://www.google.com/search?q=test"));
  EXPECT_FALSE(GetInfoBarDelegate(1) == NULL);
  NotifyIPAddressChanged();
  MockSearchDomainCheckResponse("https://www.google.co.uk/");
  EXPECT_EQ(new_google_url, google_url());
  EXPECT_EQ(GURL("https://www.google.co.uk/"), GetLastPromptedGoogleURL());
  EXPECT_TRUE(GetMapEntry(1) == NULL);

  // And fetching a different URL entirely.
  NotifyIPAddressChanged();
  MockSearchDomainCheckResponse("http://www.google.co.jp/");
  SetNavigationPending(1, true);
  CommitSearch(1, GURL("http://www.google.com/search?q=test"));
  EXPECT_FALSE(GetInfoBarDelegate(1) == NULL);
  NotifyIPAddressChanged();
  MockSearchDomainCheckResponse("https://www.google.co.in/");
  EXPECT_EQ(new_google_url, google_url());
  EXPECT_EQ(GURL("https://www.google.co.uk/"), GetLastPromptedGoogleURL());
  EXPECT_TRUE(GetMapEntry(1) == NULL);
}

TEST_F(GoogleURLTrackerTest, ResetInfoBarGoogleURLs) {
  RequestServerCheck();
  FinishSleep();
  MockSearchDomainCheckResponse(google_url().spec());

  NotifyIPAddressChanged();
  MockSearchDomainCheckResponse("http://www.google.co.uk/");
  SetNavigationPending(1, true);
  CommitSearch(1, GURL("http://www.google.com/search?q=test"));
  GoogleURLTrackerInfoBarDelegate* delegate = GetInfoBarDelegate(1);
  ASSERT_FALSE(delegate == NULL);
  EXPECT_EQ(GURL("http://www.google.co.uk/"), fetched_google_url());

  // If while an infobar is showing we fetch a new URL that differs from the
  // infobar's only by scheme, the infobar should stay showing.
  NotifyIPAddressChanged();
  MockSearchDomainCheckResponse("https://www.google.co.uk/");
  EXPECT_EQ(delegate, GetInfoBarDelegate(1));
  EXPECT_EQ(GURL("https://www.google.co.uk/"), fetched_google_url());
}

TEST_F(GoogleURLTrackerTest, NavigationsAfterPendingSearch) {
  SetLastPromptedGoogleURL(GURL("http://www.google.co.uk/"));
  RequestServerCheck();
  FinishSleep();
  MockSearchDomainCheckResponse("http://www.google.co.jp/");

  // A pending non-search after a pending search should delete the map entry.
  SetNavigationPending(1, true);
  GoogleURLTrackerMapEntry* map_entry = GetMapEntry(1);
  ASSERT_FALSE(map_entry == NULL);
  EXPECT_FALSE(map_entry->has_infobar_delegate());
  SetNavigationPending(1, false);
  EXPECT_TRUE(GetMapEntry(1) == NULL);

  // A pending search after a pending search should leave the map entry alive.
  SetNavigationPending(1, true);
  map_entry = GetMapEntry(1);
  ASSERT_FALSE(map_entry == NULL);
  EXPECT_FALSE(map_entry->has_infobar_delegate());
  SetNavigationPending(1, true);
  ASSERT_EQ(map_entry, GetMapEntry(1));
  EXPECT_FALSE(map_entry->has_infobar_delegate());
  ASSERT_NO_FATAL_FAILURE(ExpectListeningForCommit(1, true));

  // Committing this search should show an infobar.
  CommitSearch(1, GURL("http://www.google.co.uk/search?q=test2"));
  EXPECT_TRUE(map_entry->has_infobar_delegate());
  EXPECT_EQ(GURL(GoogleURLTracker::kDefaultGoogleHomepage), google_url());
  EXPECT_EQ(GURL("http://www.google.co.uk/"), GetLastPromptedGoogleURL());
  EXPECT_FALSE(observer_notified());
  ASSERT_NO_FATAL_FAILURE(ExpectListeningForCommit(1, false));
}

TEST_F(GoogleURLTrackerTest, NavigationsAfterCommittedSearch) {
  SetLastPromptedGoogleURL(GURL("http://www.google.co.uk/"));
  RequestServerCheck();
  FinishSleep();
  MockSearchDomainCheckResponse("http://www.google.co.jp/");
  SetNavigationPending(1, true);
  CommitSearch(1, GURL("http://www.google.co.uk/search?q=test"));
  GoogleURLTrackerInfoBarDelegate* delegate = GetInfoBarDelegate(1);
  ASSERT_FALSE(delegate == NULL);
  ASSERT_NO_FATAL_FAILURE(ExpectListeningForCommit(1, false));

  // A pending non-search on a visible infobar should basically do nothing.
  SetNavigationPending(1, false);
  ASSERT_EQ(delegate, GetInfoBarDelegate(1));
  EXPECT_EQ(0, delegate->pending_id());
  ASSERT_NO_FATAL_FAILURE(ExpectListeningForCommit(1, false));

  // As should another pending non-search after the first.
  SetNavigationPending(1, false);
  ASSERT_EQ(delegate, GetInfoBarDelegate(1));
  EXPECT_EQ(0, delegate->pending_id());
  ASSERT_NO_FATAL_FAILURE(ExpectListeningForCommit(1, false));

  // Committing this non-search should close the infobar.  The control flow in
  // these tests is not really comparable to in the real browser, but at least a
  // few sanity-checks will be performed.
  ASSERT_NO_FATAL_FAILURE(CommitNonSearch(1));
  EXPECT_TRUE(GetMapEntry(1) == NULL);

  // A pending search on a visible infobar should cause the infobar to listen
  // for the search to commit.
  SetNavigationPending(1, true);
  CommitSearch(1, GURL("http://www.google.co.uk/search?q=test"));
  delegate = GetInfoBarDelegate(1);
  ASSERT_FALSE(delegate == NULL);
  SetNavigationPending(1, true);
  ASSERT_EQ(delegate, GetInfoBarDelegate(1));
  EXPECT_EQ(1, delegate->pending_id());
  ASSERT_NO_FATAL_FAILURE(ExpectListeningForCommit(1, true));

  // But a non-search after this should cancel that state.
  SetNavigationPending(1, false);
  ASSERT_EQ(delegate, GetInfoBarDelegate(1));
  EXPECT_EQ(0, delegate->pending_id());
  ASSERT_NO_FATAL_FAILURE(ExpectListeningForCommit(1, false));

  // Another pending search after the non-search should put us back into
  // "waiting for commit" mode.
  SetNavigationPending(1, true);
  ASSERT_EQ(delegate, GetInfoBarDelegate(1));
  EXPECT_EQ(1, delegate->pending_id());
  ASSERT_NO_FATAL_FAILURE(ExpectListeningForCommit(1, true));

  // A second pending search after the first should not really change anything.
  SetNavigationPending(1, true);
  ASSERT_EQ(delegate, GetInfoBarDelegate(1));
  EXPECT_EQ(1, delegate->pending_id());
  ASSERT_NO_FATAL_FAILURE(ExpectListeningForCommit(1, true));

  // Committing this search should change the visible infobar's search_url.
  CommitSearch(1, GURL("http://www.google.co.uk/search?q=test2"));
  ASSERT_EQ(delegate, GetInfoBarDelegate(1));
  EXPECT_EQ(GURL("http://www.google.co.uk/search?q=test2"),
            delegate->search_url());
  EXPECT_EQ(0, delegate->pending_id());
  ASSERT_NO_FATAL_FAILURE(ExpectListeningForCommit(1, false));
  EXPECT_EQ(GURL(GoogleURLTracker::kDefaultGoogleHomepage), google_url());
  EXPECT_EQ(GURL("http://www.google.co.uk/"), GetLastPromptedGoogleURL());
  EXPECT_FALSE(observer_notified());
}

TEST_F(GoogleURLTrackerTest, MultipleMapEntries) {
  SetLastPromptedGoogleURL(GURL("http://www.google.co.uk/"));
  RequestServerCheck();
  FinishSleep();
  MockSearchDomainCheckResponse("http://www.google.co.jp/");

  SetNavigationPending(1, true);
  GoogleURLTrackerMapEntry* map_entry = GetMapEntry(1);
  ASSERT_FALSE(map_entry == NULL);
  EXPECT_FALSE(map_entry->has_infobar_delegate());

  SetNavigationPending(2, true);
  CommitSearch(2, GURL("http://www.google.co.uk/search?q=test2"));
  GoogleURLTrackerInfoBarDelegate* delegate2 = GetInfoBarDelegate(2);
  ASSERT_FALSE(delegate2 == NULL);
  EXPECT_EQ(GURL("http://www.google.co.uk/search?q=test2"),
            delegate2->search_url());

  SetNavigationPending(3, true);
  GoogleURLTrackerMapEntry* map_entry3 = GetMapEntry(3);
  ASSERT_FALSE(map_entry3 == NULL);
  EXPECT_FALSE(map_entry3->has_infobar_delegate());

  SetNavigationPending(4, true);
  CommitSearch(4, GURL("http://www.google.co.uk/search?q=test4"));
  GoogleURLTrackerInfoBarDelegate* delegate4 = GetInfoBarDelegate(4);
  ASSERT_FALSE(delegate4 == NULL);
  EXPECT_EQ(GURL("http://www.google.co.uk/search?q=test4"),
            delegate4->search_url());

  CommitSearch(1, GURL("http://www.google.co.uk/search?q=test"));
  EXPECT_TRUE(map_entry->has_infobar_delegate());

  delegate2->Close(false);
  EXPECT_TRUE(GetMapEntry(2) == NULL);
  EXPECT_FALSE(observer_notified());

  delegate4->Accept();
  EXPECT_TRUE(GetMapEntry(1) == NULL);
  EXPECT_TRUE(GetMapEntry(3) == NULL);
  EXPECT_TRUE(GetMapEntry(4) == NULL);
  EXPECT_EQ(GURL("http://www.google.co.jp/"), google_url());
  EXPECT_EQ(GURL("http://www.google.co.jp/"), GetLastPromptedGoogleURL());
  EXPECT_TRUE(observer_notified());
}

TEST_F(GoogleURLTrackerTest, IgnoreIrrelevantNavigation) {
  SetLastPromptedGoogleURL(GURL("http://www.google.co.uk/"));
  RequestServerCheck();
  FinishSleep();
  MockSearchDomainCheckResponse("http://www.google.co.jp/");

  // This tests a particularly gnarly sequence of events that used to cause us
  // to erroneously listen for a non-search navigation to commit.
  SetNavigationPending(1, true);
  CommitSearch(1, GURL("http://www.google.co.uk/search?q=test"));
  SetNavigationPending(2, true);
  CommitSearch(2, GURL("http://www.google.co.uk/search?q=test2"));
  EXPECT_FALSE(GetInfoBarDelegate(1) == NULL);
  GoogleURLTrackerInfoBarDelegate* delegate2 = GetInfoBarDelegate(2);
  ASSERT_FALSE(delegate2 == NULL);
  SetNavigationPending(1, true);
  ASSERT_NO_FATAL_FAILURE(ExpectListeningForCommit(1, true));
  delegate2->Close(false);
  SetNavigationPending(1, false);
  ASSERT_NO_FATAL_FAILURE(ExpectListeningForCommit(1, false));
}

/* [<][>][^][v][top][bottom][index][help] */