1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "content/public/test/test_navigation_observer.h" 6 7#include "base/bind.h" 8#include "base/message_loop/message_loop.h" 9#include "base/run_loop.h" 10#include "base/stl_util.h" 11#include "content/public/browser/notification_service.h" 12#include "content/public/browser/notification_types.h" 13#include "content/public/browser/web_contents_observer.h" 14#include "content/public/test/test_utils.h" 15#include "testing/gtest/include/gtest/gtest.h" 16 17namespace content { 18 19class TestNavigationObserver::TestWebContentsObserver 20 : public WebContentsObserver { 21 public: 22 TestWebContentsObserver(TestNavigationObserver* parent, 23 WebContents* web_contents) 24 : WebContentsObserver(web_contents), 25 parent_(parent) { 26 } 27 28 private: 29 // WebContentsObserver: 30 virtual void NavigationEntryCommitted( 31 const LoadCommittedDetails& load_details) OVERRIDE { 32 parent_->OnNavigationEntryCommitted(this, web_contents(), load_details); 33 } 34 35 virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE { 36 parent_->OnWebContentsDestroyed(this, web_contents); 37 } 38 39 TestNavigationObserver* parent_; 40 41 DISALLOW_COPY_AND_ASSIGN(TestWebContentsObserver); 42}; 43 44TestNavigationObserver::TestNavigationObserver( 45 WebContents* web_contents, 46 int number_of_navigations) 47 : navigation_started_(false), 48 navigations_completed_(0), 49 number_of_navigations_(number_of_navigations), 50 done_(false), 51 running_(false), 52 web_contents_created_callback_( 53 base::Bind( 54 &TestNavigationObserver::OnWebContentsCreated, 55 base::Unretained(this))) { 56 if (web_contents) 57 RegisterAsObserver(web_contents); 58} 59 60TestNavigationObserver::TestNavigationObserver( 61 WebContents* web_contents) 62 : navigation_started_(false), 63 navigations_completed_(0), 64 number_of_navigations_(1), 65 done_(false), 66 running_(false), 67 web_contents_created_callback_( 68 base::Bind( 69 &TestNavigationObserver::OnWebContentsCreated, 70 base::Unretained(this))) { 71 if (web_contents) 72 RegisterAsObserver(web_contents); 73} 74 75TestNavigationObserver::~TestNavigationObserver() { 76 StopWatchingNewWebContents(); 77 78 STLDeleteContainerPointers(web_contents_observers_.begin(), 79 web_contents_observers_.end()); 80} 81 82void TestNavigationObserver::WaitForObservation( 83 const base::Closure& wait_loop_callback, 84 const base::Closure& done_callback) { 85 if (done_) 86 return; 87 88 EXPECT_FALSE(running_); 89 running_ = true; 90 done_callback_ = done_callback; 91 wait_loop_callback.Run(); 92 EXPECT_TRUE(done_); 93} 94 95void TestNavigationObserver::Wait() { 96 base::RunLoop run_loop; 97 WaitForObservation( 98 base::Bind(&base::RunLoop::Run, base::Unretained(&run_loop)), 99 GetQuitTaskForRunLoop(&run_loop)); 100} 101 102void TestNavigationObserver::StartWatchingNewWebContents() { 103 WebContents::AddCreatedCallback(web_contents_created_callback_); 104} 105 106void TestNavigationObserver::StopWatchingNewWebContents() { 107 WebContents::RemoveCreatedCallback(web_contents_created_callback_); 108} 109 110void TestNavigationObserver::RegisterAsObserver( 111 WebContents* web_contents) { 112 web_contents_observers_.insert( 113 new TestWebContentsObserver(this, web_contents)); 114 115 NotificationSource notification_source = 116 Source<NavigationController>(&web_contents->GetController()); 117 registrar_.Add(this, NOTIFICATION_LOAD_START, notification_source); 118 registrar_.Add(this, NOTIFICATION_LOAD_STOP, notification_source); 119} 120 121void TestNavigationObserver::Observe( 122 int type, const NotificationSource& source, 123 const NotificationDetails& details) { 124 switch (type) { 125 case NOTIFICATION_LOAD_START: 126 navigation_started_ = true; 127 break; 128 case NOTIFICATION_LOAD_STOP: 129 if (navigation_started_ && 130 ++navigations_completed_ == number_of_navigations_) { 131 navigation_started_ = false; 132 done_ = true; 133 if (running_) { 134 running_ = false; 135 done_callback_.Run(); 136 } 137 } 138 break; 139 default: 140 NOTREACHED(); 141 } 142} 143 144void TestNavigationObserver::OnWebContentsCreated(WebContents* web_contents) { 145 RegisterAsObserver(web_contents); 146} 147 148void TestNavigationObserver::OnWebContentsDestroyed( 149 TestWebContentsObserver* observer, 150 WebContents* web_contents) { 151 web_contents_observers_.erase(observer); 152 delete observer; 153 154 NotificationSource notification_source = 155 Source<NavigationController>(&web_contents->GetController()); 156 registrar_.Remove(this, NOTIFICATION_LOAD_START, notification_source); 157 registrar_.Remove(this, NOTIFICATION_LOAD_STOP, notification_source); 158} 159 160void TestNavigationObserver::OnNavigationEntryCommitted( 161 TestWebContentsObserver* observer, 162 WebContents* web_contents, 163 const LoadCommittedDetails& load_details) { 164 navigation_started_ = true; 165} 166 167} // namespace content 168