summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorbrettw@google.com <brettw@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-08-19 17:38:12 +0000
committerbrettw@google.com <brettw@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-08-19 17:38:12 +0000
commit6cf85906b0504908e3fd0fafa46be78903bfd6b9 (patch)
tree564d578de2118da6012571178e9f557da2e164a5 /chrome
parentdfcb522ab183af2bfd6924e32bf43a8bd173097c (diff)
downloadchromium_src-6cf85906b0504908e3fd0fafa46be78903bfd6b9.zip
chromium_src-6cf85906b0504908e3fd0fafa46be78903bfd6b9.tar.gz
chromium_src-6cf85906b0504908e3fd0fafa46be78903bfd6b9.tar.bz2
Cleans up notifications for the NavigationController. There were several
notifications before and some of them were very unclear and misused (STATE_CHANGED). This one, and PRUNED were called unnecessarily in some cases as well. I replaced STATE_CHANGED and INDEX_CHANGED with ENTRY_COMMITTED which is more clear and covers (I think!) all the cases that the callers care about. I added a simple notification testing helper class, and used in the navigation controller unit tests to make sure we get the proper notifications. I had to change NotificationSource/Details to have a = and copy constructor so I can track them easily in my helper. I don't see why this would be bad. BUG=1325636,1321376,1325779 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@1039 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/alternate_nav_url_fetcher.cc6
-rw-r--r--chrome/browser/jsmessage_box_handler.cc6
-rw-r--r--chrome/browser/navigation_controller.cc33
-rw-r--r--chrome/browser/navigation_controller.h5
-rw-r--r--chrome/browser/navigation_controller_base.cc25
-rw-r--r--chrome/browser/navigation_controller_base.h2
-rw-r--r--chrome/browser/navigation_controller_unittest.cc136
-rw-r--r--chrome/browser/session_service.cc6
-rw-r--r--chrome/browser/ssl_manager.cc6
-rw-r--r--chrome/browser/ssl_policy.cc1
-rw-r--r--chrome/browser/views/location_bar_view.cc6
-rw-r--r--chrome/common/notification_details.h5
-rw-r--r--chrome/common/notification_source.h5
-rw-r--r--chrome/common/notification_types.h36
-rw-r--r--chrome/test/test_notification_tracker.cc105
-rw-r--r--chrome/test/test_notification_tracker.h105
-rw-r--r--chrome/test/unit/unittests.vcproj16
17 files changed, 418 insertions, 86 deletions
diff --git a/chrome/browser/alternate_nav_url_fetcher.cc b/chrome/browser/alternate_nav_url_fetcher.cc
index a791106..e86105b 100644
--- a/chrome/browser/alternate_nav_url_fetcher.cc
+++ b/chrome/browser/alternate_nav_url_fetcher.cc
@@ -41,14 +41,14 @@ AlternateNavURLFetcher::AlternateNavURLFetcher(
state_(NOT_STARTED),
navigated_to_entry_(false) {
NotificationService::current()->AddObserver(this,
- NOTIFY_NAV_STATE_CHANGED, NotificationService::AllSources());
+ NOTIFY_NAV_ENTRY_PENDING, NotificationService::AllSources());
}
AlternateNavURLFetcher::~AlternateNavURLFetcher() {
if (state_ == NOT_STARTED) {
// Never caught the NavigationController notification.
NotificationService::current()->RemoveObserver(this,
- NOTIFY_NAV_STATE_CHANGED, NotificationService::AllSources());
+ NOTIFY_NAV_ENTRY_PENDING, NotificationService::AllSources());
} // Otherwise, Observe() removed the observer already.
}
@@ -69,7 +69,7 @@ void AlternateNavURLFetcher::Observe(NotificationType type,
controller_->SetAlternateNavURLFetcher(this);
NotificationService::current()->RemoveObserver(this,
- NOTIFY_NAV_STATE_CHANGED, NotificationService::AllSources());
+ NOTIFY_NAV_ENTRY_PENDING, NotificationService::AllSources());
DCHECK_EQ(NOT_STARTED, state_);
state_ = IN_PROGRESS;
diff --git a/chrome/browser/jsmessage_box_handler.cc b/chrome/browser/jsmessage_box_handler.cc
index 09b9757..549981a 100644
--- a/chrome/browser/jsmessage_box_handler.cc
+++ b/chrome/browser/jsmessage_box_handler.cc
@@ -63,7 +63,7 @@ void JavascriptMessageBoxHandler::RunJavascriptMessageBox(
JavascriptMessageBoxHandler::~JavascriptMessageBoxHandler() {
NotificationService::current()->
- RemoveObserver(this, NOTIFY_NAV_STATE_CHANGED,
+ RemoveObserver(this, NOTIFY_NAV_ENTRY_COMMITTED,
NotificationService::AllSources());
NotificationService::current()->
RemoveObserver(this, NOTIFY_TAB_CONTENTS_DESTROYED,
@@ -188,7 +188,7 @@ void JavascriptMessageBoxHandler::Observe(NotificationType type,
if (!web_contents_)
return;
- if (type == NOTIFY_NAV_STATE_CHANGED &&
+ if (type == NOTIFY_NAV_ENTRY_COMMITTED &&
Source<NavigationController>(source).ptr() == web_contents_->controller())
web_contents_gone = true;
@@ -230,7 +230,7 @@ JavascriptMessageBoxHandler::JavascriptMessageBoxHandler(
// Make sure we get navigation notifications so we know when our parent
// contents will disappear or navigate to a different page.
NotificationService::current()->
- AddObserver(this, NOTIFY_NAV_STATE_CHANGED,
+ AddObserver(this, NOTIFY_NAV_ENTRY_COMMITTED,
NotificationService::AllSources());
NotificationService::current()->
AddObserver(this, NOTIFY_TAB_CONTENTS_DESTROYED,
diff --git a/chrome/browser/navigation_controller.cc b/chrome/browser/navigation_controller.cc
index 91b404a4..5100922 100644
--- a/chrome/browser/navigation_controller.cc
+++ b/chrome/browser/navigation_controller.cc
@@ -349,13 +349,6 @@ const SkBitmap& NavigationController::GetLazyFavIcon() const {
}
}
-void NavigationController::EntryUpdated(NavigationEntry* entry) {
- if (entry == GetActiveEntry()) {
- // Someone has modified our active navigation entry.
- NotifyNavigationStateChanged();
- }
-}
-
void NavigationController::SetAlternateNavURLFetcher(
AlternateNavURLFetcher* alternate_nav_url_fetcher) {
DCHECK(!alternate_nav_url_fetcher_.get());
@@ -423,17 +416,10 @@ void NavigationController::DiscardPendingEntry() {
DCHECK(from_contents != active_contents_);
ScheduleTabContentsCollection(from_contents->type());
}
-
- // Note: this may be redundant in some cases. we may want to optimize away
- // the redundant notifications.
- NotifyNavigationStateChanged();
}
void NavigationController::InsertEntry(NavigationEntry* entry) {
NavigationControllerBase::InsertEntry(entry);
- NotificationService::current()->Notify(NOTIFY_NAV_INDEX_CHANGED,
- Source<NavigationController>(this),
- NotificationService::NoDetails());
active_contents_->NotifyDidNavigate(NAVIGATION_NEW, 0);
}
@@ -473,19 +459,16 @@ void NavigationController::NavigateToPendingEntry(bool reload) {
from_contents->delegate()->ReplaceContents(from_contents, contents);
}
- if (contents->Navigate(*pending_entry_, reload)) {
- // Note: this is redundant if navigation completed synchronously because
- // DidNavigateToEntry call this as well.
- NotifyNavigationStateChanged();
- } else {
+ if (!contents->Navigate(*pending_entry_, reload))
DiscardPendingEntry();
- }
}
-void NavigationController::NotifyNavigationStateChanged() {
+void NavigationController::NotifyNavigationEntryCommitted() {
// Reset the Alternate Nav URL Fetcher if we're loading some page it doesn't
// care about. We must do this before calling Notify() below as that may
// result in the creation of a new fetcher.
+ //
+ // TODO(brettw) bug 1324500: this logic should be moved out of the controller!
const NavigationEntry* const entry = GetActiveEntry();
if (!entry ||
(entry->unique_id() != alternate_nav_url_fetcher_entry_unique_id_)) {
@@ -500,7 +483,7 @@ void NavigationController::NotifyNavigationStateChanged() {
active_contents_->NotifyNavigationStateChanged(
TabContents::INVALIDATE_EVERYTHING);
- NotificationService::current()->Notify(NOTIFY_NAV_STATE_CHANGED,
+ NotificationService::current()->Notify(NOTIFY_NAV_ENTRY_COMMITTED,
Source<NavigationController>(this),
NotificationService::NoDetails());
}
@@ -520,12 +503,6 @@ void NavigationController::IndexOfActiveEntryChanged(
nav_type = NAVIGATION_REPLACE;
}
active_contents_->NotifyDidNavigate(nav_type, relative_navigation_offset);
- if (GetCurrentEntryIndex() != -1) {
- NotificationService::current()->Notify(
- NOTIFY_NAV_INDEX_CHANGED,
- Source<NavigationController>(this),
- NotificationService::NoDetails());
- }
}
TabContents* NavigationController::GetTabContentsCreateIfNecessary(
diff --git a/chrome/browser/navigation_controller.h b/chrome/browser/navigation_controller.h
index 136540e..4378b04 100644
--- a/chrome/browser/navigation_controller.h
+++ b/chrome/browser/navigation_controller.h
@@ -133,9 +133,6 @@ class NavigationController : public NavigationControllerBase {
const std::wstring& GetLazyTitle() const;
const SkBitmap& GetLazyFavIcon() const;
- // Called when |entry| has been updated outside its NavigationController.
- void EntryUpdated(NavigationEntry* entry);
-
void SetAlternateNavURLFetcher(
AlternateNavURLFetcher* alternate_nav_url_fetcher);
@@ -200,7 +197,7 @@ class NavigationController : public NavigationControllerBase {
virtual int GetMaxPageID() const;
virtual void NavigateToPendingEntry(bool reload);
- virtual void NotifyNavigationStateChanged();
+ virtual void NotifyNavigationEntryCommitted();
// Lets the history database know navigation entries have been removed.
virtual void NotifyPrunedEntries();
diff --git a/chrome/browser/navigation_controller_base.cc b/chrome/browser/navigation_controller_base.cc
index f2b921d..e086e82 100644
--- a/chrome/browser/navigation_controller_base.cc
+++ b/chrome/browser/navigation_controller_base.cc
@@ -33,6 +33,8 @@
#include "base/logging.h"
#include "chrome/browser/navigation_entry.h"
+#include "chrome/common/notification_service.h"
+#include "chrome/common/notification_types.h"
#include "webkit/glue/webkit_glue.h"
// The maximum number of entries that a navigation controller can store.
@@ -209,6 +211,12 @@ void NavigationControllerBase::LoadEntry(NavigationEntry* entry) {
// TODO(pkasting): http://b/1113085 Should this use DiscardPendingEntry()?
DiscardPendingEntryInternal();
pending_entry_ = entry;
+ // TODO(brettw) the reinterpret cast can be removed once we combine the
+ // NavigationController and the NavigationControllerBase.
+ NotificationService::current()->Notify(
+ NOTIFY_NAV_ENTRY_PENDING,
+ Source<NavigationController>(reinterpret_cast<NavigationController*>(this)),
+ NotificationService::NoDetails());
NavigateToPendingEntry(false);
}
@@ -241,6 +249,7 @@ void NavigationControllerBase::DidNavigateToEntry(NavigationEntry* entry) {
// active WebContents, because we have just navigated to it.
if (entry->GetPageID() > GetMaxPageID()) {
InsertEntry(entry);
+ NotifyNavigationEntryCommitted();
return;
}
@@ -298,7 +307,7 @@ void NavigationControllerBase::DidNavigateToEntry(NavigationEntry* entry) {
delete entry;
- NotifyNavigationStateChanged();
+ NotifyNavigationEntryCommitted();
}
void NavigationControllerBase::DiscardPendingEntry() {
@@ -337,12 +346,15 @@ void NavigationControllerBase::InsertEntry(NavigationEntry* entry) {
// Prune any entries which are in front of the current entry.
if (current_size > 0) {
+ bool pruned = false;
while (last_committed_entry_index_ < (current_size - 1)) {
+ pruned = true;
delete entries_[current_size - 1];
entries_.pop_back();
current_size--;
}
- NotifyPrunedEntries();
+ if (pruned) // Only notify if we did prune something.
+ NotifyPrunedEntries();
}
if (entries_.size() >= max_entry_count_)
@@ -350,8 +362,6 @@ void NavigationControllerBase::InsertEntry(NavigationEntry* entry) {
entries_.push_back(entry);
last_committed_entry_index_ = static_cast<int>(entries_.size()) - 1;
-
- NotifyNavigationStateChanged();
}
void NavigationControllerBase::RemoveLastEntry() {
@@ -370,10 +380,11 @@ void NavigationControllerBase::RemoveLastEntry() {
NotifyPrunedEntries();
}
- NotifyNavigationStateChanged();
}
void NavigationControllerBase::RemoveEntryAtIndex(int index) {
+ // TODO(brettw) this is only called to remove the first one when we've got
+ // too many entries. It should probably be more specific for this case.
if (index >= static_cast<int>(entries_.size()) ||
index == pending_entry_index_ || index == last_committed_entry_index_) {
NOTREACHED();
@@ -390,8 +401,8 @@ void NavigationControllerBase::RemoveEntryAtIndex(int index) {
last_committed_entry_index_ = -1;
}
- NotifyPrunedEntries();
- NotifyNavigationStateChanged();
+ // TODO(brettw) bug 1324021: we probably need some notification here so the
+ // session service can stay in sync.
}
void NavigationControllerBase::ResetInternal() {
diff --git a/chrome/browser/navigation_controller_base.h b/chrome/browser/navigation_controller_base.h
index e712ff3..0faf365 100644
--- a/chrome/browser/navigation_controller_base.h
+++ b/chrome/browser/navigation_controller_base.h
@@ -175,7 +175,7 @@ class NavigationControllerBase {
// Allows the derived class to issue notifications that a load has been
// committed.
- virtual void NotifyNavigationStateChanged() {}
+ virtual void NotifyNavigationEntryCommitted() {}
// Invoked when entries have been pruned, or removed. For example, if the
// current entries are [google, digg, yahoo], with the current entry google,
diff --git a/chrome/browser/navigation_controller_unittest.cc b/chrome/browser/navigation_controller_unittest.cc
index 9176df6..d815a54 100644
--- a/chrome/browser/navigation_controller_unittest.cc
+++ b/chrome/browser/navigation_controller_unittest.cc
@@ -39,7 +39,9 @@
#include "chrome/browser/tab_contents.h"
#include "chrome/browser/tab_contents_delegate.h"
#include "chrome/browser/tab_contents_factory.h"
+#include "chrome/common/notification_types.h"
#include "chrome/common/stl_util-inl.h"
+#include "chrome/test/test_notification_tracker.h"
#include "chrome/test/testing_profile.h"
#include "net/base/net_util.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -290,6 +292,16 @@ class NavigationControllerHistoryTest : public NavigationControllerTest {
std::wstring profile_path_;
};
+void RegisterForAllNavNotifications(TestNotificationTracker* tracker,
+ NavigationController* controller) {
+ tracker->ListenFor(NOTIFY_NAV_ENTRY_COMMITTED,
+ Source<NavigationController>(controller));
+ tracker->ListenFor(NOTIFY_NAV_LIST_PRUNED,
+ Source<NavigationController>(controller));
+ tracker->ListenFor(NOTIFY_NAV_ENTRY_CHANGED,
+ Source<NavigationController>(controller));
+}
+
} // namespace
TEST_F(NavigationControllerTest, Defaults) {
@@ -306,12 +318,18 @@ TEST_F(NavigationControllerTest, Defaults) {
}
TEST_F(NavigationControllerTest, LoadURL) {
+ TestNotificationTracker notifications;
+ RegisterForAllNavNotifications(&notifications, contents->controller());
+
const GURL url1("test1:foo1");
const GURL url2("test1:foo2");
contents->controller()->LoadURL(url1, PageTransition::TYPED);
+ // Creating a pending notification should not have issued any of the
+ // notifications we're listening for.
+ EXPECT_EQ(0, notifications.size());
- // the load should now be pending
+ // The load should now be pending.
EXPECT_TRUE(contents->pending_entry());
EXPECT_EQ(contents->controller()->GetEntryCount(), 0);
EXPECT_EQ(contents->controller()->GetLastCommittedEntryIndex(), -1);
@@ -322,9 +340,14 @@ TEST_F(NavigationControllerTest, LoadURL) {
EXPECT_FALSE(contents->controller()->CanGoForward());
EXPECT_EQ(contents->GetMaxPageID(), -1);
+ // We should have gotten no notifications from the preceeding checks.
+ EXPECT_EQ(0, notifications.size());
+
contents->CompleteNavigation(0);
+ EXPECT_TRUE(notifications.Check2AndReset(NOTIFY_NAV_ENTRY_COMMITTED,
+ NOTIFY_NAV_ENTRY_CHANGED));
- // the load should now be committed
+ // The load should now be committed.
EXPECT_EQ(contents->controller()->GetEntryCount(), 1);
EXPECT_EQ(contents->controller()->GetLastCommittedEntryIndex(), 0);
EXPECT_EQ(contents->controller()->GetPendingEntryIndex(), -1);
@@ -334,10 +357,10 @@ TEST_F(NavigationControllerTest, LoadURL) {
EXPECT_FALSE(contents->controller()->CanGoForward());
EXPECT_EQ(contents->GetMaxPageID(), 0);
- // load another...
+ // Load another...
contents->controller()->LoadURL(url2, PageTransition::TYPED);
- // the load should now be pending
+ // The load should now be pending.
EXPECT_TRUE(contents->pending_entry());
EXPECT_EQ(contents->controller()->GetEntryCount(), 1);
EXPECT_EQ(contents->controller()->GetLastCommittedEntryIndex(), 0);
@@ -350,8 +373,10 @@ TEST_F(NavigationControllerTest, LoadURL) {
EXPECT_EQ(contents->GetMaxPageID(), 0);
contents->CompleteNavigation(1);
+ EXPECT_TRUE(notifications.Check2AndReset(NOTIFY_NAV_ENTRY_COMMITTED,
+ NOTIFY_NAV_ENTRY_CHANGED));
- // the load should now be committed
+ // The load should now be committed.
EXPECT_EQ(contents->controller()->GetEntryCount(), 2);
EXPECT_EQ(contents->controller()->GetLastCommittedEntryIndex(), 1);
EXPECT_EQ(contents->controller()->GetPendingEntryIndex(), -1);
@@ -365,13 +390,23 @@ TEST_F(NavigationControllerTest, LoadURL) {
// Tests what happens when the same page is loaded again. Should not create a
// new session history entry.
TEST_F(NavigationControllerTest, LoadURL_SamePage) {
+ TestNotificationTracker notifications;
+ RegisterForAllNavNotifications(&notifications, contents->controller());
+
const GURL url1("test1:foo1");
contents->controller()->LoadURL(url1, PageTransition::TYPED);
+ EXPECT_EQ(0, notifications.size());
contents->CompleteNavigation(0);
+ EXPECT_TRUE(notifications.Check2AndReset(NOTIFY_NAV_ENTRY_COMMITTED,
+ NOTIFY_NAV_ENTRY_CHANGED));
+
contents->controller()->LoadURL(url1, PageTransition::TYPED);
+ EXPECT_EQ(0, notifications.size());
contents->CompleteNavigation(0);
+ EXPECT_TRUE(notifications.Check2AndReset(NOTIFY_NAV_ENTRY_COMMITTED,
+ NOTIFY_NAV_ENTRY_CHANGED));
// should not have produced a new session history entry
EXPECT_EQ(contents->controller()->GetEntryCount(), 1);
@@ -384,14 +419,21 @@ TEST_F(NavigationControllerTest, LoadURL_SamePage) {
}
TEST_F(NavigationControllerTest, LoadURL_Discarded) {
+ TestNotificationTracker notifications;
+ RegisterForAllNavNotifications(&notifications, contents->controller());
+
const GURL url1("test1:foo1");
const GURL url2("test1:foo2");
contents->controller()->LoadURL(url1, PageTransition::TYPED);
+ EXPECT_EQ(0, notifications.size());
contents->CompleteNavigation(0);
+ EXPECT_TRUE(notifications.Check2AndReset(NOTIFY_NAV_ENTRY_COMMITTED,
+ NOTIFY_NAV_ENTRY_CHANGED));
contents->controller()->LoadURL(url2, PageTransition::TYPED);
contents->controller()->DiscardPendingEntry();
+ EXPECT_EQ(0, notifications.size());
// should not have produced a new session history entry
EXPECT_EQ(contents->controller()->GetEntryCount(), 1);
@@ -404,12 +446,19 @@ TEST_F(NavigationControllerTest, LoadURL_Discarded) {
}
TEST_F(NavigationControllerTest, Reload) {
+ TestNotificationTracker notifications;
+ RegisterForAllNavNotifications(&notifications, contents->controller());
+
const GURL url1("test1:foo1");
contents->controller()->LoadURL(url1, PageTransition::TYPED);
+ EXPECT_EQ(0, notifications.size());
contents->CompleteNavigation(0);
+ EXPECT_TRUE(notifications.Check2AndReset(NOTIFY_NAV_ENTRY_COMMITTED,
+ NOTIFY_NAV_ENTRY_CHANGED));
contents->controller()->Reload();
+ EXPECT_EQ(0, notifications.size());
// the reload is pending...
EXPECT_EQ(contents->controller()->GetEntryCount(), 1);
@@ -421,6 +470,8 @@ TEST_F(NavigationControllerTest, Reload) {
EXPECT_FALSE(contents->controller()->CanGoForward());
contents->CompleteNavigation(0);
+ EXPECT_TRUE(notifications.Check2AndReset(NOTIFY_NAV_ENTRY_COMMITTED,
+ NOTIFY_NAV_ENTRY_CHANGED));
// now the reload is committed...
EXPECT_EQ(contents->controller()->GetEntryCount(), 1);
@@ -434,17 +485,25 @@ TEST_F(NavigationControllerTest, Reload) {
// Tests what happens when a reload navigation produces a new page.
TEST_F(NavigationControllerTest, Reload_GeneratesNewPage) {
+ TestNotificationTracker notifications;
+ RegisterForAllNavNotifications(&notifications, contents->controller());
+
const GURL url1("test1:foo1");
const GURL url2("test1:foo2");
contents->controller()->LoadURL(url1, PageTransition::TYPED);
contents->CompleteNavigation(0);
+ EXPECT_TRUE(notifications.Check2AndReset(NOTIFY_NAV_ENTRY_COMMITTED,
+ NOTIFY_NAV_ENTRY_CHANGED));
contents->controller()->Reload();
+ EXPECT_EQ(0, notifications.size());
contents->pending_entry()->SetURL(url2);
contents->pending_entry()->SetTransitionType(PageTransition::LINK);
contents->CompleteNavigation(1);
+ EXPECT_TRUE(notifications.Check2AndReset(NOTIFY_NAV_ENTRY_COMMITTED,
+ NOTIFY_NAV_ENTRY_CHANGED));
// now the reload is committed...
EXPECT_EQ(contents->controller()->GetEntryCount(), 2);
@@ -458,16 +517,24 @@ TEST_F(NavigationControllerTest, Reload_GeneratesNewPage) {
// Tests what happens when we navigate back successfully
TEST_F(NavigationControllerTest, Back) {
+ TestNotificationTracker notifications;
+ RegisterForAllNavNotifications(&notifications, contents->controller());
+
const GURL url1("test1:foo1");
const GURL url2("test1:foo2");
contents->controller()->LoadURL(url1, PageTransition::TYPED);
contents->CompleteNavigation(0);
+ EXPECT_TRUE(notifications.Check2AndReset(NOTIFY_NAV_ENTRY_COMMITTED,
+ NOTIFY_NAV_ENTRY_CHANGED));
contents->controller()->LoadURL(url2, PageTransition::TYPED);
contents->CompleteNavigation(1);
+ EXPECT_TRUE(notifications.Check2AndReset(NOTIFY_NAV_ENTRY_COMMITTED,
+ NOTIFY_NAV_ENTRY_CHANGED));
contents->controller()->GoBack();
+ EXPECT_EQ(0, notifications.size());
// should now have a pending navigation to go back...
EXPECT_EQ(contents->controller()->GetEntryCount(), 2);
@@ -479,6 +546,8 @@ TEST_F(NavigationControllerTest, Back) {
EXPECT_TRUE(contents->controller()->CanGoForward());
contents->CompleteNavigation(0);
+ EXPECT_TRUE(notifications.Check2AndReset(NOTIFY_NAV_ENTRY_COMMITTED,
+ NOTIFY_NAV_ENTRY_CHANGED));
// the back navigation completed successfully
EXPECT_EQ(contents->controller()->GetEntryCount(), 2);
@@ -492,17 +561,25 @@ TEST_F(NavigationControllerTest, Back) {
// Tests what happens when a back navigation produces a new page.
TEST_F(NavigationControllerTest, Back_GeneratesNewPage) {
+ TestNotificationTracker notifications;
+ RegisterForAllNavNotifications(&notifications, contents->controller());
+
const GURL url1("test1:foo1");
const GURL url2("test1:foo2");
const GURL url3("test1:foo3");
contents->controller()->LoadURL(url1, PageTransition::TYPED);
contents->CompleteNavigation(0);
+ EXPECT_TRUE(notifications.Check2AndReset(NOTIFY_NAV_ENTRY_COMMITTED,
+ NOTIFY_NAV_ENTRY_CHANGED));
contents->controller()->LoadURL(url2, PageTransition::TYPED);
contents->CompleteNavigation(1);
+ EXPECT_TRUE(notifications.Check2AndReset(NOTIFY_NAV_ENTRY_COMMITTED,
+ NOTIFY_NAV_ENTRY_CHANGED));
contents->controller()->GoBack();
+ EXPECT_EQ(0, notifications.size());
// should now have a pending navigation to go back...
EXPECT_EQ(contents->controller()->GetEntryCount(), 2);
@@ -516,6 +593,8 @@ TEST_F(NavigationControllerTest, Back_GeneratesNewPage) {
contents->pending_entry()->SetURL(url3);
contents->pending_entry()->SetTransitionType(PageTransition::LINK);
contents->CompleteNavigation(2);
+ EXPECT_TRUE(notifications.Check2AndReset(NOTIFY_NAV_ENTRY_COMMITTED,
+ NOTIFY_NAV_ENTRY_CHANGED));
// the back navigation resulted in a completely new navigation.
// TODO(darin): perhaps this behavior will be confusing to users?
@@ -530,17 +609,26 @@ TEST_F(NavigationControllerTest, Back_GeneratesNewPage) {
// Tests what happens when we navigate forward successfully
TEST_F(NavigationControllerTest, Forward) {
+ TestNotificationTracker notifications;
+ RegisterForAllNavNotifications(&notifications, contents->controller());
+
const GURL url1("test1:foo1");
const GURL url2("test1:foo2");
contents->controller()->LoadURL(url1, PageTransition::TYPED);
contents->CompleteNavigation(0);
+ EXPECT_TRUE(notifications.Check2AndReset(NOTIFY_NAV_ENTRY_COMMITTED,
+ NOTIFY_NAV_ENTRY_CHANGED));
contents->controller()->LoadURL(url2, PageTransition::TYPED);
contents->CompleteNavigation(1);
+ EXPECT_TRUE(notifications.Check2AndReset(NOTIFY_NAV_ENTRY_COMMITTED,
+ NOTIFY_NAV_ENTRY_CHANGED));
contents->controller()->GoBack();
contents->CompleteNavigation(0);
+ EXPECT_TRUE(notifications.Check2AndReset(NOTIFY_NAV_ENTRY_COMMITTED,
+ NOTIFY_NAV_ENTRY_CHANGED));
contents->controller()->GoForward();
@@ -554,6 +642,8 @@ TEST_F(NavigationControllerTest, Forward) {
EXPECT_FALSE(contents->controller()->CanGoForward());
contents->CompleteNavigation(1);
+ EXPECT_TRUE(notifications.Check2AndReset(NOTIFY_NAV_ENTRY_COMMITTED,
+ NOTIFY_NAV_ENTRY_CHANGED));
// the forward navigation completed successfully
EXPECT_EQ(contents->controller()->GetEntryCount(), 2);
@@ -567,20 +657,30 @@ TEST_F(NavigationControllerTest, Forward) {
// Tests what happens when a forward navigation produces a new page.
TEST_F(NavigationControllerTest, Forward_GeneratesNewPage) {
+ TestNotificationTracker notifications;
+ RegisterForAllNavNotifications(&notifications, contents->controller());
+
const GURL url1("test1:foo1");
const GURL url2("test1:foo2");
const GURL url3("test1:foo3");
contents->controller()->LoadURL(url1, PageTransition::TYPED);
contents->CompleteNavigation(0);
+ EXPECT_TRUE(notifications.Check2AndReset(NOTIFY_NAV_ENTRY_COMMITTED,
+ NOTIFY_NAV_ENTRY_CHANGED));
contents->controller()->LoadURL(url2, PageTransition::TYPED);
contents->CompleteNavigation(1);
+ EXPECT_TRUE(notifications.Check2AndReset(NOTIFY_NAV_ENTRY_COMMITTED,
+ NOTIFY_NAV_ENTRY_CHANGED));
contents->controller()->GoBack();
contents->CompleteNavigation(0);
+ EXPECT_TRUE(notifications.Check2AndReset(NOTIFY_NAV_ENTRY_COMMITTED,
+ NOTIFY_NAV_ENTRY_CHANGED));
contents->controller()->GoForward();
+ EXPECT_EQ(0, notifications.size());
// should now have a pending navigation to go forward...
EXPECT_EQ(contents->controller()->GetEntryCount(), 2);
@@ -594,6 +694,9 @@ TEST_F(NavigationControllerTest, Forward_GeneratesNewPage) {
contents->pending_entry()->SetURL(url3);
contents->pending_entry()->SetTransitionType(PageTransition::LINK);
contents->CompleteNavigation(2);
+ EXPECT_TRUE(notifications.Check3AndReset(NOTIFY_NAV_LIST_PRUNED,
+ NOTIFY_NAV_ENTRY_COMMITTED,
+ NOTIFY_NAV_ENTRY_CHANGED));
EXPECT_EQ(contents->controller()->GetEntryCount(), 2);
EXPECT_EQ(contents->controller()->GetLastCommittedEntryIndex(), 1);
@@ -605,17 +708,24 @@ TEST_F(NavigationControllerTest, Forward_GeneratesNewPage) {
}
TEST_F(NavigationControllerTest, LinkClick) {
+ TestNotificationTracker notifications;
+ RegisterForAllNavNotifications(&notifications, contents->controller());
+
const GURL url1("test1:foo1");
const GURL url2("test1:foo2");
contents->controller()->LoadURL(url1, PageTransition::TYPED);
contents->CompleteNavigation(0);
+ EXPECT_TRUE(notifications.Check2AndReset(NOTIFY_NAV_ENTRY_COMMITTED,
+ NOTIFY_NAV_ENTRY_CHANGED));
contents->set_pending_entry(new NavigationEntry(kTestContentsType1, NULL, 0,
url2,
std::wstring(),
PageTransition::LINK));
contents->CompleteNavigation(1);
+ EXPECT_TRUE(notifications.Check2AndReset(NOTIFY_NAV_ENTRY_COMMITTED,
+ NOTIFY_NAV_ENTRY_CHANGED));
// should not have produced a new session history entry
EXPECT_EQ(contents->controller()->GetEntryCount(), 2);
@@ -628,11 +738,16 @@ TEST_F(NavigationControllerTest, LinkClick) {
}
TEST_F(NavigationControllerTest, SwitchTypes) {
+ TestNotificationTracker notifications;
+ RegisterForAllNavNotifications(&notifications, contents->controller());
+
const GURL url1("test1:foo");
const GURL url2("test2:foo");
contents->controller()->LoadURL(url1, PageTransition::TYPED);
contents->CompleteNavigation(0);
+ EXPECT_TRUE(notifications.Check2AndReset(NOTIFY_NAV_ENTRY_COMMITTED,
+ NOTIFY_NAV_ENTRY_CHANGED));
TestContents* initial_contents = contents;
@@ -642,6 +757,8 @@ TEST_F(NavigationControllerTest, SwitchTypes) {
ASSERT_TRUE(initial_contents != contents);
contents->CompleteNavigation(0);
+ EXPECT_TRUE(notifications.Check2AndReset(NOTIFY_NAV_ENTRY_COMMITTED,
+ NOTIFY_NAV_ENTRY_CHANGED));
// A second navigation entry should have been committed even though the
// PageIDs are the same. PageIDs are scoped to the tab contents type.
@@ -657,6 +774,8 @@ TEST_F(NavigationControllerTest, SwitchTypes) {
contents->controller()->GoBack();
ASSERT_TRUE(initial_contents == contents); // switched again!
contents->CompleteNavigation(0);
+ EXPECT_TRUE(notifications.Check2AndReset(NOTIFY_NAV_ENTRY_COMMITTED,
+ NOTIFY_NAV_ENTRY_CHANGED));
EXPECT_EQ(contents->controller()->GetEntryCount(), 2);
EXPECT_EQ(contents->controller()->GetLastCommittedEntryIndex(), 0);
@@ -673,20 +792,27 @@ TEST_F(NavigationControllerTest, SwitchTypes) {
// Tests what happens when we begin to navigate to a new contents type, but
// then that navigation gets discarded instead.
TEST_F(NavigationControllerTest, SwitchTypes_Discard) {
+ TestNotificationTracker notifications;
+ RegisterForAllNavNotifications(&notifications, contents->controller());
+
const GURL url1("test1:foo");
const GURL url2("test2:foo");
contents->controller()->LoadURL(url1, PageTransition::TYPED);
contents->CompleteNavigation(0);
+ EXPECT_TRUE(notifications.Check2AndReset(NOTIFY_NAV_ENTRY_COMMITTED,
+ NOTIFY_NAV_ENTRY_CHANGED));
TestContents* initial_contents = contents;
contents->controller()->LoadURL(url2, PageTransition::TYPED);
+ EXPECT_EQ(0, notifications.size());
// The tab contents should have been replaced
ASSERT_TRUE(initial_contents != contents);
contents->controller()->DiscardPendingEntry();
+ EXPECT_EQ(0, notifications.size());
// The tab contents should have been replaced back
ASSERT_TRUE(initial_contents == contents);
diff --git a/chrome/browser/session_service.cc b/chrome/browser/session_service.cc
index 9ed3d9f..da72060 100644
--- a/chrome/browser/session_service.cc
+++ b/chrome/browser/session_service.cc
@@ -160,7 +160,7 @@ SessionService::~SessionService() {
NotificationService::current()->RemoveObserver(
this, NOTIFY_NAV_ENTRY_CHANGED, NotificationService::AllSources());
NotificationService::current()->RemoveObserver(
- this, NOTIFY_NAV_INDEX_CHANGED, NotificationService::AllSources());
+ this, NOTIFY_NAV_ENTRY_COMMITTED, NotificationService::AllSources());
}
void SessionService::ResetFromCurrentBrowsers() {
@@ -417,7 +417,7 @@ void SessionService::Init(const std::wstring& path) {
NotificationService::current()->AddObserver(
this, NOTIFY_NAV_ENTRY_CHANGED, NotificationService::AllSources());
NotificationService::current()->AddObserver(
- this, NOTIFY_NAV_INDEX_CHANGED, NotificationService::AllSources());
+ this, NOTIFY_NAV_ENTRY_COMMITTED, NotificationService::AllSources());
DCHECK(!path.empty());
commands_since_reset_ = 0;
@@ -450,7 +450,7 @@ void SessionService::Observe(NotificationType type,
changed->index, *changed->changed_entry);
break;
}
- case NOTIFY_NAV_INDEX_CHANGED:
+ case NOTIFY_NAV_ENTRY_COMMITTED:
SetSelectedNavigationIndex(controller->window_id(),
controller->session_id(),
controller->GetCurrentEntryIndex());
diff --git a/chrome/browser/ssl_manager.cc b/chrome/browser/ssl_manager.cc
index be58f24..8454c09 100644
--- a/chrome/browser/ssl_manager.cc
+++ b/chrome/browser/ssl_manager.cc
@@ -247,10 +247,8 @@ void SSLManager::SetMaxSecurityStyle(SecurityStyle style) {
return;
}
- if (entry->ssl().security_style() > style) {
+ if (entry->ssl().security_style() > style)
entry->ssl().set_security_style(style);
- controller_->EntryUpdated(entry);
- }
}
// Delegate API method.
@@ -652,10 +650,10 @@ void SSLManager::DidCommitProvisionalLoad(ProvisionalLoadDetails* details) {
// We may not have an entry if this is a navigation to an initial blank
// page. Reset the SSL information and add the new data we have.
entry->ssl() = NavigationEntry::SSLStatus();
+ InitializeEntryIfNeeded(entry); // For security_style.
entry->ssl().set_cert_id(details->ssl_cert_id());
entry->ssl().set_cert_status(details->ssl_cert_status());
entry->ssl().set_security_bits(details->ssl_security_bits());
- controller_->EntryUpdated(entry);
}
if (details->interstitial_page()) {
diff --git a/chrome/browser/ssl_policy.cc b/chrome/browser/ssl_policy.cc
index dd83357..03e16cc 100644
--- a/chrome/browser/ssl_policy.cc
+++ b/chrome/browser/ssl_policy.cc
@@ -346,7 +346,6 @@ class DefaultPolicy : public SSLPolicy {
NavigationEntry* entry = navigation_controller->GetActiveEntry();
entry->ssl().set_has_mixed_content();
- navigation_controller->EntryUpdated(entry);
}
void OnDenyCertificate(SSLManager::CertError* error) {
diff --git a/chrome/browser/views/location_bar_view.cc b/chrome/browser/views/location_bar_view.cc
index f354ef4..edf43bc 100644
--- a/chrome/browser/views/location_bar_view.cc
+++ b/chrome/browser/views/location_bar_view.cc
@@ -362,9 +362,9 @@ void LocationBarView::OnAutocompleteAccept(
scoped_ptr<AlternateNavURLFetcher> fetcher(
new AlternateNavURLFetcher(alternate_nav_url));
- // The AlternateNavURLFetcher will listen for the next navigation state
- // update notification (expecting it to be a new page load) and hook
- // itself in to that loading process.
+ // The AlternateNavURLFetcher will listen for the pending navigation
+ // notification that will be issued as a result of the "open URL." It
+ // will automatically install itself into that navigation controller.
controller_->ExecuteCommand(IDC_OPENURL);
if (fetcher->state() == AlternateNavURLFetcher::NOT_STARTED) {
// I'm not sure this should be reachable, but I'm not also sure enough
diff --git a/chrome/common/notification_details.h b/chrome/common/notification_details.h
index 9c7fdff..31378c4 100644
--- a/chrome/common/notification_details.h
+++ b/chrome/common/notification_details.h
@@ -41,6 +41,7 @@
class NotificationDetails {
public:
NotificationDetails() : ptr_(NULL) {}
+ NotificationDetails(const NotificationDetails& other) : ptr_(other.ptr_) {}
~NotificationDetails() {}
// NotificationDetails can be used as the index for a map; this method
@@ -58,12 +59,8 @@ class NotificationDetails {
protected:
NotificationDetails(void* ptr) : ptr_(ptr) {}
- NotificationDetails(const NotificationDetails& other) : ptr_(other.ptr_) {}
void* ptr_;
-
-private:
- void operator=(const NotificationDetails&);
};
template <class T>
diff --git a/chrome/common/notification_source.h b/chrome/common/notification_source.h
index 31077e9..049a12d 100644
--- a/chrome/common/notification_source.h
+++ b/chrome/common/notification_source.h
@@ -40,6 +40,7 @@
// NotificationService::AllSources().
class NotificationSource {
public:
+ NotificationSource(const NotificationSource& other) : ptr_(other.ptr_) { }
~NotificationSource() {}
// NotificationSource can be used as the index for a map; this method
@@ -56,12 +57,8 @@ class NotificationSource {
protected:
NotificationSource(void* ptr) : ptr_(ptr) {}
- NotificationSource(const NotificationSource& other) : ptr_(other.ptr_) { }
void* ptr_;
-
- private:
- void operator=(const NotificationSource&);
};
template <class T>
diff --git a/chrome/common/notification_types.h b/chrome/common/notification_types.h
index 1080ffa..d2392b7 100644
--- a/chrome/common/notification_types.h
+++ b/chrome/common/notification_types.h
@@ -55,18 +55,35 @@ enum NotificationType {
// NavigationController ------------------------------------------------------
- // A NavigationController's state has changed (a new pending load has been
- // added, a load has committed, etc.).
+ // A new pending navigation has been created. Pending entries are created when
+ // the user requests the navigation. We don't know if it will actually happen
+ // until it does (at this point, it will be "committed." Note that renderer-
+ // initiated navigations such as link clicks will never be pending.
//
- // TODO(brettw) this is vague and I'm not sure that it covers every case. We
- // need to figure out the exact cases where this notificaion should be sent
- // and make sure it is sent in those cases.
- NOTIFY_NAV_STATE_CHANGED,
+ // This notification is called after the pending entry is created, but before
+ // we actually try to navigate. The source will be the NavigationController
+ // that owns the pending entry, and there are no details.
+ NOTIFY_NAV_ENTRY_PENDING,
+
+ // A new non-pending navigation entry has been created. This will correspond
+ // to one NavigationController entry being created (in the case of new
+ // navigations) or renavigated to (for back/forward navigations).
+ NOTIFY_NAV_ENTRY_COMMITTED,
// Indicates that the NavigationController given in the Source has decreased
// its back/forward list count. This is usually the result of going back and
// then doing a new navigation, meaning all the "forward" items are deleted.
- // There are no details.
+ //
+ // This normally happens as a result of a new navigation. It will be followed
+ // by a NOTIFY_NAV_ENTRY_COMMITTED message for the new page that caused the
+ // pruning. It could also be a result of removing an item from the list to fix
+ // up after interstitials.
+ //
+ // The details are an integer indicating the number of items pruned.
+ // Watch out: the NavigationController may start throwing entries away once
+ // the list is a certain size, so you can't use the current size of the
+ // navigation list to tell how many items were pruned, you have to use the
+ // details provided here.
NOTIFY_NAV_LIST_PRUNED,
// Indicates that a NavigationEntry has changed. The source will be the
@@ -74,11 +91,6 @@ enum NotificationType {
// a NavigationController::EntryChangedDetails struct.
NOTIFY_NAV_ENTRY_CHANGED,
- // Indicates that the index of the currently active NavigationEntry has
- // changed. The source will be the NavigationController whose current item
- // changed, and there are no details.
- NOTIFY_NAV_INDEX_CHANGED,
-
// Other load-related (not from NavigationController) ------------------------
// A content load is starting. The source will be a
diff --git a/chrome/test/test_notification_tracker.cc b/chrome/test/test_notification_tracker.cc
new file mode 100644
index 0000000..e17de73
--- /dev/null
+++ b/chrome/test/test_notification_tracker.cc
@@ -0,0 +1,105 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "chrome/test/test_notification_tracker.h"
+#include "chrome/common/notification_types.h"
+
+TestNotificationTracker::Event::Event()
+ : type(NOTIFY_ALL),
+ source(NotificationService::AllSources()),
+ details(NotificationService::NoDetails()) {
+}
+TestNotificationTracker::Event::Event(NotificationType t,
+ NotificationSource s,
+ NotificationDetails d)
+ : type(t),
+ source(s),
+ details(d) {
+}
+
+TestNotificationTracker::TestNotificationTracker() {
+}
+
+TestNotificationTracker::~TestNotificationTracker() {
+ NotificationService* service = NotificationService::current();
+ for (size_t i = 0; i < listening_.size(); i++)
+ service->RemoveObserver(this, listening_[i].first, listening_[i].second);
+ listening_.clear();
+}
+
+void TestNotificationTracker::ListenFor(NotificationType type,
+ const NotificationSource& source) {
+ listening_.push_back(std::make_pair(type, source));
+ NotificationService::current()->AddObserver(this, type, source);
+}
+
+void TestNotificationTracker::Reset() {
+ events_.clear();
+}
+
+bool TestNotificationTracker::Check1AndReset(NotificationType type) {
+ if (size() != 1) {
+ Reset();
+ return false;
+ }
+ bool success = events_[0].type == type;
+ Reset();
+ return success;
+}
+
+bool TestNotificationTracker::Check2AndReset(NotificationType type1,
+ NotificationType type2) {
+ if (size() != 2) {
+ Reset();
+ return false;
+ }
+ bool success = events_[0].type == type1 && events_[1].type == type2;
+ Reset();
+ return success;
+}
+
+bool TestNotificationTracker::Check3AndReset(NotificationType type1,
+ NotificationType type2,
+ NotificationType type3) {
+ if (size() != 3) {
+ Reset();
+ return false;
+ }
+ bool success = events_[0].type == type1 &&
+ events_[1].type == type2 &&
+ events_[2].type == type3;
+ Reset();
+ return success;
+}
+
+void TestNotificationTracker::Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ events_.push_back(Event(type, source, details));
+}
diff --git a/chrome/test/test_notification_tracker.h b/chrome/test/test_notification_tracker.h
new file mode 100644
index 0000000..ca22f6b
--- /dev/null
+++ b/chrome/test/test_notification_tracker.h
@@ -0,0 +1,105 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CHROME_TEST_NOTIFICATION_TRACKER_H_
+#define CHROME_TEST_NOTIFICATION_TRACKER_H_
+
+#include <vector>
+
+#include "chrome/common/notification_service.h"
+
+// Provides an easy way for tests to verify that a given set of notifications
+// was received during test execution.
+class TestNotificationTracker : public NotificationObserver {
+ public:
+ // Records one received notification.
+ struct Event {
+ Event();
+ Event(NotificationType t, NotificationSource s, NotificationDetails d);
+
+ NotificationType type;
+ NotificationSource source;
+ NotificationDetails details;
+ };
+
+ // By default, it won't listen for any notifications. You'll need to call
+ // ListenFor for the notifications you are interested in.
+ TestNotificationTracker();
+
+ ~TestNotificationTracker();
+
+ // Makes this object listen for the given notification with the given source.
+ void ListenFor(NotificationType type, const NotificationSource& source);
+
+ // Makes this object listen for notifications of the given type coming from
+ // any source.
+ void ListenForAll(NotificationType type);
+
+ // Clears the list of events.
+ void Reset();
+
+ // Given notifications type(sp, returns true if the list of notifications
+ // were exactly those listed in the given arg(s), and in the same order.
+ //
+ // This will also reset the list so that the next call will only check for
+ // new notifications. Example:
+ // <do stuff>
+ // Check1AndReset(NOTIFY_A);
+ // <do stuff>
+ // Check2AndReset(NOTIFY_B, NOTIFY_C)
+ bool Check1AndReset(NotificationType type);
+ bool Check2AndReset(NotificationType type1,
+ NotificationType type2);
+ bool Check3AndReset(NotificationType type1,
+ NotificationType type2,
+ NotificationType type3);
+
+ // Returns the number of notifications received since the last reset.
+ size_t size() const { return events_.size(); }
+
+ // Returns the information about the event at the given index. The index must
+ // be in [0, size).
+ const Event& at(size_t i) const { return events_[i]; }
+
+ private:
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // Lists all type/source combinations that we're listening for. These will
+ // need to be unregistered when we are destroyed.
+ std::vector< std::pair<NotificationType, NotificationSource> > listening_;
+
+ // Lists all received since last cleared, in the order they were received.
+ std::vector<Event> events_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestNotificationTracker);
+};
+
+#endif // CHROME_TEST_NOTIFICATION_TRACKER_H_
diff --git a/chrome/test/unit/unittests.vcproj b/chrome/test/unit/unittests.vcproj
index 9aa1c90..ee496de 100644
--- a/chrome/test/unit/unittests.vcproj
+++ b/chrome/test/unit/unittests.vcproj
@@ -182,6 +182,14 @@
>
</File>
<File
+ RelativePath="..\test_notification_tracker.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\test_notification_tracker.h"
+ >
+ </File>
+ <File
RelativePath="..\testing_browser_process.h"
>
</File>
@@ -194,19 +202,19 @@
>
</File>
<File
- RelativePath="..\ui\view_event_test_base.cc"
+ RelativePath="..\..\..\net\url_request\url_request_test_job.cc"
>
</File>
<File
- RelativePath="..\ui\view_event_test_base.h"
+ RelativePath="..\..\..\net\url_request\url_request_test_job.h"
>
</File>
<File
- RelativePath="..\..\..\net\url_request\url_request_test_job.cc"
+ RelativePath="..\ui\view_event_test_base.cc"
>
</File>
<File
- RelativePath="..\..\..\net\url_request\url_request_test_job.h"
+ RelativePath="..\ui\view_event_test_base.h"
>
</File>
</Filter>