| // Copyright 2014 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 "ios/web/web_state/web_state_impl.h" |
| |
| #include <stddef.h> |
| |
| #include <memory> |
| |
| #include "base/base64.h" |
| #include "base/bind.h" |
| #include "base/logging.h" |
| #include "base/mac/bind_objc_block.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/test/ios/wait_util.h" |
| #include "base/values.h" |
| #import "ios/web/public/java_script_dialog_presenter.h" |
| #include "ios/web/public/load_committed_details.h" |
| #include "ios/web/public/test/test_browser_state.h" |
| #include "ios/web/public/test/web_test.h" |
| #include "ios/web/public/web_state/context_menu_params.h" |
| #include "ios/web/public/web_state/global_web_state_observer.h" |
| #include "ios/web/public/web_state/web_state_delegate.h" |
| #include "ios/web/public/web_state/web_state_observer.h" |
| #include "ios/web/public/web_state/web_state_policy_decider.h" |
| #include "ios/web/web_state/global_web_state_event_tracker.h" |
| #import "ios/web/web_state/ui/crw_web_controller.h" |
| #include "net/http/http_response_headers.h" |
| #include "net/http/http_util.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "testing/gtest_mac.h" |
| #include "url/gurl.h" |
| |
| using testing::_; |
| using testing::Assign; |
| using testing::AtMost; |
| using testing::DoAll; |
| using testing::Return; |
| |
| namespace web { |
| namespace { |
| |
| // Test observer to check that the GlobalWebStateObserver methods are called as |
| // expected. |
| class TestGlobalWebStateObserver : public GlobalWebStateObserver { |
| public: |
| TestGlobalWebStateObserver() |
| : GlobalWebStateObserver(), |
| navigation_items_pruned_called_(false), |
| navigation_item_changed_called_(false), |
| navigation_item_committed_called_(false), |
| did_start_loading_called_(false), |
| did_stop_loading_called_(false), |
| page_loaded_called_with_success_(false), |
| web_state_destroyed_called_(false) {} |
| |
| // Methods returning true if the corresponding GlobalWebStateObserver method |
| // has been called. |
| bool navigation_items_pruned_called() const { |
| return navigation_items_pruned_called_; |
| } |
| bool navigation_item_changed_called() const { |
| return navigation_item_changed_called_; |
| } |
| bool navigation_item_committed_called() const { |
| return navigation_item_committed_called_; |
| } |
| bool did_start_loading_called() const { return did_start_loading_called_; } |
| bool did_stop_loading_called() const { return did_stop_loading_called_; } |
| bool page_loaded_called_with_success() const { |
| return page_loaded_called_with_success_; |
| } |
| bool web_state_destroyed_called() const { |
| return web_state_destroyed_called_; |
| } |
| |
| private: |
| // GlobalWebStateObserver implementation: |
| void NavigationItemsPruned(WebState* web_state, |
| size_t pruned_item_count) override { |
| navigation_items_pruned_called_ = true; |
| } |
| void NavigationItemChanged(WebState* web_state) override { |
| navigation_item_changed_called_ = true; |
| } |
| void NavigationItemCommitted( |
| WebState* web_state, |
| const LoadCommittedDetails& load_details) override { |
| navigation_item_committed_called_ = true; |
| } |
| void WebStateDidStartLoading(WebState* web_state) override { |
| did_start_loading_called_ = true; |
| } |
| void WebStateDidStopLoading(WebState* web_state) override { |
| did_stop_loading_called_ = true; |
| } |
| void PageLoaded(WebState* web_state, |
| PageLoadCompletionStatus load_completion_status) override { |
| page_loaded_called_with_success_ = |
| load_completion_status == PageLoadCompletionStatus::SUCCESS; |
| } |
| void WebStateDestroyed(WebState* web_state) override { |
| web_state_destroyed_called_ = true; |
| } |
| |
| bool navigation_items_pruned_called_; |
| bool navigation_item_changed_called_; |
| bool navigation_item_committed_called_; |
| bool did_start_loading_called_; |
| bool did_stop_loading_called_; |
| bool page_loaded_called_with_success_; |
| bool web_state_destroyed_called_; |
| }; |
| |
| // Test delegate to check that the WebStateDelegate methods are called as |
| // expected. |
| class TestWebStateDelegate : public WebStateDelegate { |
| public: |
| TestWebStateDelegate() |
| : load_progress_changed_called_(false), |
| handle_context_menu_called_(false), |
| get_java_script_dialog_presenter_called_(false) {} |
| |
| // True if the WebStateDelegate LoadProgressChanged method has been called. |
| bool load_progress_changed_called() const { |
| return load_progress_changed_called_; |
| } |
| |
| // True if the WebStateDelegate HandleContextMenu method has been called. |
| bool handle_context_menu_called() const { |
| return handle_context_menu_called_; |
| } |
| |
| // True if the WebStateDelegate GetJavaScriptDialogPresenter method has been |
| // called. |
| bool get_java_script_dialog_presenter_called() const { |
| return get_java_script_dialog_presenter_called_; |
| } |
| |
| void SetJavaScriptDialogPresenter(JavaScriptDialogPresenter* presenter) { |
| presenter_ = presenter; |
| } |
| |
| private: |
| // WebStateDelegate implementation: |
| void LoadProgressChanged(WebState* source, double progress) override { |
| load_progress_changed_called_ = true; |
| } |
| |
| bool HandleContextMenu(WebState* source, |
| const ContextMenuParams& params) override { |
| handle_context_menu_called_ = true; |
| return NO; |
| } |
| |
| JavaScriptDialogPresenter* GetJavaScriptDialogPresenter( |
| WebState* source) override { |
| get_java_script_dialog_presenter_called_ = true; |
| return presenter_; |
| } |
| |
| bool load_progress_changed_called_; |
| bool handle_context_menu_called_; |
| bool get_java_script_dialog_presenter_called_; |
| JavaScriptDialogPresenter* presenter_; |
| }; |
| |
| // Test presenter to check that the JavaScriptDialogPresenter methods are called |
| // as expected. |
| class TestJavaScriptDialogPresenter : public JavaScriptDialogPresenter { |
| public: |
| TestJavaScriptDialogPresenter() |
| : cancel_dialogs_called_(false), run_java_script_dialog_called_(false) {} |
| |
| // True if the JavaScriptDialogPresenter CancelDialogs method has been called. |
| bool cancel_dialogs_called() const { return cancel_dialogs_called_; } |
| |
| // True if the JavaScriptDialogPresenter RunJavaScriptDialog method has been |
| // called. |
| bool run_java_script_dialog_called() const { |
| return run_java_script_dialog_called_; |
| } |
| |
| private: |
| // JavaScriptDialogPresenter implementation: |
| void RunJavaScriptDialog(WebState* web_state, |
| const GURL& origin_url, |
| JavaScriptDialogType java_script_dialog_type, |
| NSString* message_text, |
| NSString* default_prompt_text, |
| const DialogClosedCallback& callback) override { |
| run_java_script_dialog_called_ = true; |
| callback.Run(false, nil); |
| } |
| |
| void CancelDialogs(WebState* web_state) override { |
| cancel_dialogs_called_ = true; |
| } |
| |
| bool cancel_dialogs_called_; |
| bool run_java_script_dialog_called_; |
| }; |
| |
| // Test observer to check that the WebStateObserver methods are called as |
| // expected. |
| class TestWebStateObserver : public WebStateObserver { |
| public: |
| TestWebStateObserver(WebState* web_state) |
| : WebStateObserver(web_state), |
| provisional_navigation_started_called_(false), |
| navigation_items_pruned_called_(false), |
| navigation_item_changed_called_(false), |
| navigation_item_committed_called_(false), |
| page_loaded_called_with_success_(false), |
| url_hash_changed_called_(false), |
| history_state_changed_called_(false), |
| web_state_destroyed_called_(false) {} |
| |
| // Methods returning true if the corresponding WebStateObserver method has |
| // been called. |
| bool provisional_navigation_started_called() const { |
| return provisional_navigation_started_called_; |
| }; |
| bool navigation_items_pruned_called() const { |
| return navigation_items_pruned_called_; |
| } |
| bool navigation_item_changed_called() const { |
| return navigation_item_changed_called_; |
| } |
| bool navigation_item_committed_called() const { |
| return navigation_item_committed_called_; |
| } |
| bool page_loaded_called_with_success() const { |
| return page_loaded_called_with_success_; |
| } |
| bool url_hash_changed_called() const { return url_hash_changed_called_; } |
| bool history_state_changed_called() const { |
| return history_state_changed_called_; |
| } |
| bool web_state_destroyed_called() const { |
| return web_state_destroyed_called_; |
| } |
| |
| private: |
| // WebStateObserver implementation: |
| void ProvisionalNavigationStarted(const GURL& url) override { |
| provisional_navigation_started_called_ = true; |
| } |
| void NavigationItemsPruned(size_t pruned_item_count) override { |
| navigation_items_pruned_called_ = true; |
| } |
| void NavigationItemChanged() override { |
| navigation_item_changed_called_ = true; |
| } |
| void NavigationItemCommitted( |
| const LoadCommittedDetails& load_details) override { |
| navigation_item_committed_called_ = true; |
| } |
| void PageLoaded(PageLoadCompletionStatus load_completion_status) override { |
| page_loaded_called_with_success_ = |
| load_completion_status == PageLoadCompletionStatus::SUCCESS; |
| } |
| void UrlHashChanged() override { url_hash_changed_called_ = true; } |
| void HistoryStateChanged() override { history_state_changed_called_ = true; } |
| void WebStateDestroyed() override { |
| EXPECT_TRUE(web_state()->IsBeingDestroyed()); |
| web_state_destroyed_called_ = true; |
| Observe(nullptr); |
| } |
| |
| bool provisional_navigation_started_called_; |
| bool navigation_items_pruned_called_; |
| bool navigation_item_changed_called_; |
| bool navigation_item_committed_called_; |
| bool page_loaded_called_with_success_; |
| bool url_hash_changed_called_; |
| bool history_state_changed_called_; |
| bool web_state_destroyed_called_; |
| }; |
| |
| // Test decider to check that the WebStatePolicyDecider methods are called as |
| // expected. |
| class MockWebStatePolicyDecider : public WebStatePolicyDecider { |
| public: |
| explicit MockWebStatePolicyDecider(WebState* web_state) |
| : WebStatePolicyDecider(web_state) {} |
| virtual ~MockWebStatePolicyDecider() {} |
| |
| MOCK_METHOD1(ShouldAllowRequest, bool(NSURLRequest* request)); |
| MOCK_METHOD1(ShouldAllowResponse, bool(NSURLResponse* response)); |
| MOCK_METHOD0(WebStateDestroyed, void()); |
| }; |
| |
| // Creates and returns an HttpResponseHeader using the string representation. |
| scoped_refptr<net::HttpResponseHeaders> HeadersFromString(const char* string) { |
| std::string raw_string(string); |
| std::string headers_string = net::HttpUtil::AssembleRawHeaders( |
| raw_string.c_str(), raw_string.length()); |
| scoped_refptr<net::HttpResponseHeaders> headers( |
| new net::HttpResponseHeaders(headers_string)); |
| return headers; |
| } |
| |
| // Test callback for script commands. |
| // Sets |is_called| to true if it is called, and checks that the parameters |
| // match their expected values. |
| // |user_is_interacting| is not checked because Bind() has a maximum of 7 |
| // parameters. |
| bool HandleScriptCommand(bool* is_called, |
| bool should_handle, |
| base::DictionaryValue* expected_value, |
| const GURL& expected_url, |
| const base::DictionaryValue& value, |
| const GURL& url, |
| bool user_is_interacting) { |
| *is_called = true; |
| EXPECT_TRUE(expected_value->Equals(&value)); |
| EXPECT_EQ(expected_url, url); |
| return should_handle; |
| } |
| |
| class WebStateTest : public web::WebTest { |
| protected: |
| void SetUp() override { |
| web_state_.reset(new WebStateImpl(&browser_state_)); |
| } |
| |
| // Loads specified html page into WebState. |
| void LoadHtml(std::string html) { |
| web_state_->GetNavigationManagerImpl().InitializeSession(nil, nil, NO, 0); |
| |
| // Use data: url for loading html page. |
| std::string encoded_html; |
| base::Base64Encode(html, &encoded_html); |
| GURL url("data:text/html;charset=utf8;base64," + encoded_html); |
| web::NavigationManager::WebLoadParams params(url); |
| web_state_->GetNavigationManager()->LoadURLWithParams(params); |
| |
| // Trigger the load. |
| web_state_->SetWebUsageEnabled(true); |
| web_state_->GetView(); |
| |
| // Wait until load is completed. |
| EXPECT_TRUE(web_state_->IsLoading()); |
| base::test::ios::WaitUntilCondition(^bool() { |
| return !web_state_->IsLoading(); |
| }); |
| } |
| |
| web::TestBrowserState browser_state_; |
| std::unique_ptr<WebStateImpl> web_state_; |
| }; |
| |
| TEST_F(WebStateTest, WebUsageEnabled) { |
| // Default is false. |
| ASSERT_FALSE(web_state_->IsWebUsageEnabled()); |
| |
| web_state_->SetWebUsageEnabled(true); |
| EXPECT_TRUE(web_state_->IsWebUsageEnabled()); |
| EXPECT_TRUE(web_state_->GetWebController().webUsageEnabled); |
| |
| web_state_->SetWebUsageEnabled(false); |
| EXPECT_FALSE(web_state_->IsWebUsageEnabled()); |
| EXPECT_FALSE(web_state_->GetWebController().webUsageEnabled); |
| } |
| |
| TEST_F(WebStateTest, ShouldSuppressDialogs) { |
| // Default is false. |
| ASSERT_FALSE(web_state_->ShouldSuppressDialogs()); |
| |
| web_state_->SetShouldSuppressDialogs(true); |
| EXPECT_TRUE(web_state_->ShouldSuppressDialogs()); |
| EXPECT_TRUE(web_state_->GetWebController().shouldSuppressDialogs); |
| |
| web_state_->SetShouldSuppressDialogs(false); |
| EXPECT_FALSE(web_state_->ShouldSuppressDialogs()); |
| EXPECT_FALSE(web_state_->GetWebController().shouldSuppressDialogs); |
| } |
| |
| TEST_F(WebStateTest, ResponseHeaders) { |
| GURL real_url("http://foo.com/bar"); |
| GURL frame_url("http://frames-r-us.com/"); |
| scoped_refptr<net::HttpResponseHeaders> real_headers(HeadersFromString( |
| "HTTP/1.1 200 OK\r\n" |
| "Content-Type: text/html\r\n" |
| "Content-Language: en\r\n" |
| "X-Should-Be-Here: yep\r\n" |
| "\r\n")); |
| scoped_refptr<net::HttpResponseHeaders> frame_headers(HeadersFromString( |
| "HTTP/1.1 200 OK\r\n" |
| "Content-Type: application/pdf\r\n" |
| "Content-Language: fr\r\n" |
| "X-Should-Not-Be-Here: oops\r\n" |
| "\r\n")); |
| // Simulate a load of a page with a frame. |
| web_state_->OnHttpResponseHeadersReceived(real_headers.get(), real_url); |
| web_state_->OnHttpResponseHeadersReceived(frame_headers.get(), frame_url); |
| // Include a hash to be sure it's handled correctly. |
| web_state_->OnNavigationCommitted( |
| GURL(real_url.spec() + std::string("#baz"))); |
| |
| // Verify that the right header set was kept. |
| EXPECT_TRUE( |
| web_state_->GetHttpResponseHeaders()->HasHeader("X-Should-Be-Here")); |
| EXPECT_FALSE( |
| web_state_->GetHttpResponseHeaders()->HasHeader("X-Should-Not-Be-Here")); |
| |
| // And that it was parsed correctly. |
| EXPECT_EQ("text/html", web_state_->GetContentsMimeType()); |
| EXPECT_EQ("en", web_state_->GetContentLanguageHeader()); |
| } |
| |
| TEST_F(WebStateTest, ResponseHeaderClearing) { |
| GURL url("http://foo.com/"); |
| scoped_refptr<net::HttpResponseHeaders> headers(HeadersFromString( |
| "HTTP/1.1 200 OK\r\n" |
| "Content-Type: text/html\r\n" |
| "Content-Language: en\r\n" |
| "\r\n")); |
| web_state_->OnHttpResponseHeadersReceived(headers.get(), url); |
| |
| // There should be no headers before loading. |
| EXPECT_EQ(NULL, web_state_->GetHttpResponseHeaders()); |
| |
| // There should be headers and parsed values after loading. |
| web_state_->OnNavigationCommitted(url); |
| EXPECT_TRUE(web_state_->GetHttpResponseHeaders()->HasHeader("Content-Type")); |
| EXPECT_NE("", web_state_->GetContentsMimeType()); |
| EXPECT_NE("", web_state_->GetContentLanguageHeader()); |
| |
| // ... but not after loading another page, nor should there be specific |
| // parsed values. |
| web_state_->OnNavigationCommitted(GURL("http://elsewhere.com/")); |
| EXPECT_EQ(NULL, web_state_->GetHttpResponseHeaders()); |
| EXPECT_EQ("", web_state_->GetContentsMimeType()); |
| EXPECT_EQ("", web_state_->GetContentLanguageHeader()); |
| } |
| |
| TEST_F(WebStateTest, ObserverTest) { |
| std::unique_ptr<TestWebStateObserver> observer( |
| new TestWebStateObserver(web_state_.get())); |
| EXPECT_EQ(web_state_.get(), observer->web_state()); |
| |
| // Test that ProvisionalNavigationStarted() is called. |
| EXPECT_FALSE(observer->provisional_navigation_started_called()); |
| web_state_->OnProvisionalNavigationStarted(GURL("http://test")); |
| EXPECT_TRUE(observer->provisional_navigation_started_called()); |
| |
| // Test that NavigationItemsPruned() is called. |
| EXPECT_FALSE(observer->navigation_items_pruned_called()); |
| web_state_->OnNavigationItemsPruned(1); |
| EXPECT_TRUE(observer->navigation_items_pruned_called()); |
| |
| // Test that NavigationItemChanged() is called. |
| EXPECT_FALSE(observer->navigation_item_changed_called()); |
| web_state_->OnNavigationItemChanged(); |
| EXPECT_TRUE(observer->navigation_item_changed_called()); |
| |
| // Test that NavigationItemCommitted() is called. |
| EXPECT_FALSE(observer->navigation_item_committed_called()); |
| LoadCommittedDetails details; |
| web_state_->OnNavigationItemCommitted(details); |
| EXPECT_TRUE(observer->navigation_item_committed_called()); |
| |
| // Test that OnPageLoaded() is called with success when there is no error. |
| EXPECT_FALSE(observer->page_loaded_called_with_success()); |
| web_state_->OnPageLoaded(GURL("http://test"), false); |
| EXPECT_FALSE(observer->page_loaded_called_with_success()); |
| web_state_->OnPageLoaded(GURL("http://test"), true); |
| EXPECT_TRUE(observer->page_loaded_called_with_success()); |
| |
| // Test that UrlHashChanged() is called. |
| EXPECT_FALSE(observer->url_hash_changed_called()); |
| web_state_->OnUrlHashChanged(); |
| EXPECT_TRUE(observer->url_hash_changed_called()); |
| |
| // Test that HistoryStateChanged() is called. |
| EXPECT_FALSE(observer->history_state_changed_called()); |
| web_state_->OnHistoryStateChanged(); |
| EXPECT_TRUE(observer->history_state_changed_called()); |
| |
| // Test that WebStateDestroyed() is called. |
| EXPECT_FALSE(observer->web_state_destroyed_called()); |
| web_state_.reset(); |
| EXPECT_TRUE(observer->web_state_destroyed_called()); |
| |
| EXPECT_EQ(nullptr, observer->web_state()); |
| } |
| |
| // Tests that WebStateDelegate methods appropriately called. |
| TEST_F(WebStateTest, DelegateTest) { |
| TestWebStateDelegate delegate; |
| web_state_->SetDelegate(&delegate); |
| |
| // Test that LoadProgressChanged() is called. |
| EXPECT_FALSE(delegate.load_progress_changed_called()); |
| web_state_->SendChangeLoadProgress(0.0); |
| EXPECT_TRUE(delegate.load_progress_changed_called()); |
| |
| // Test that HandleContextMenu() is called. |
| EXPECT_FALSE(delegate.handle_context_menu_called()); |
| web::ContextMenuParams context_menu_params; |
| web_state_->HandleContextMenu(context_menu_params); |
| EXPECT_TRUE(delegate.handle_context_menu_called()); |
| |
| // Test that GetJavaScriptDialogPresenter() is called. |
| TestJavaScriptDialogPresenter presenter; |
| delegate.SetJavaScriptDialogPresenter(&presenter); |
| |
| EXPECT_FALSE(delegate.get_java_script_dialog_presenter_called()); |
| EXPECT_FALSE(presenter.run_java_script_dialog_called()); |
| EXPECT_FALSE(presenter.cancel_dialogs_called()); |
| |
| __block bool callback_called = false; |
| web_state_->RunJavaScriptDialog(GURL(), JAVASCRIPT_DIALOG_TYPE_ALERT, @"", |
| nil, base::BindBlock(^(bool, NSString*) { |
| callback_called = true; |
| })); |
| |
| EXPECT_TRUE(delegate.get_java_script_dialog_presenter_called()); |
| EXPECT_TRUE(presenter.run_java_script_dialog_called()); |
| EXPECT_TRUE(callback_called); |
| |
| EXPECT_FALSE(presenter.cancel_dialogs_called()); |
| web_state_->CancelDialogs(); |
| EXPECT_TRUE(presenter.cancel_dialogs_called()); |
| } |
| |
| // Verifies that GlobalWebStateObservers are called when expected. |
| TEST_F(WebStateTest, GlobalObserverTest) { |
| std::unique_ptr<TestGlobalWebStateObserver> observer( |
| new TestGlobalWebStateObserver()); |
| |
| // Test that NavigationItemsPruned() is called. |
| EXPECT_FALSE(observer->navigation_items_pruned_called()); |
| web_state_->OnNavigationItemsPruned(1); |
| EXPECT_TRUE(observer->navigation_items_pruned_called()); |
| |
| // Test that NavigationItemChanged() is called. |
| EXPECT_FALSE(observer->navigation_item_changed_called()); |
| web_state_->OnNavigationItemChanged(); |
| EXPECT_TRUE(observer->navigation_item_changed_called()); |
| |
| // Test that NavigationItemCommitted() is called. |
| EXPECT_FALSE(observer->navigation_item_committed_called()); |
| LoadCommittedDetails details; |
| web_state_->OnNavigationItemCommitted(details); |
| EXPECT_TRUE(observer->navigation_item_committed_called()); |
| |
| // Test that WebStateDidStartLoading() is called. |
| EXPECT_FALSE(observer->did_start_loading_called()); |
| web_state_->SetIsLoading(true); |
| EXPECT_TRUE(observer->did_start_loading_called()); |
| |
| // Test that WebStateDidStopLoading() is called. |
| EXPECT_FALSE(observer->did_stop_loading_called()); |
| web_state_->SetIsLoading(false); |
| EXPECT_TRUE(observer->did_stop_loading_called()); |
| |
| // Test that OnPageLoaded() is called with success when there is no error. |
| EXPECT_FALSE(observer->page_loaded_called_with_success()); |
| web_state_->OnPageLoaded(GURL("http://test"), false); |
| EXPECT_FALSE(observer->page_loaded_called_with_success()); |
| web_state_->OnPageLoaded(GURL("http://test"), true); |
| EXPECT_TRUE(observer->page_loaded_called_with_success()); |
| |
| // Test that WebStateDestroyed() is called. |
| EXPECT_FALSE(observer->web_state_destroyed_called()); |
| web_state_.reset(); |
| EXPECT_TRUE(observer->web_state_destroyed_called()); |
| } |
| |
| // Verifies that policy deciders are correctly called by the web state. |
| TEST_F(WebStateTest, PolicyDeciderTest) { |
| MockWebStatePolicyDecider decider(web_state_.get()); |
| MockWebStatePolicyDecider decider2(web_state_.get()); |
| EXPECT_EQ(web_state_.get(), decider.web_state()); |
| |
| // Test that ShouldAllowRequest() is called. |
| EXPECT_CALL(decider, ShouldAllowRequest(_)).Times(1).WillOnce(Return(true)); |
| EXPECT_CALL(decider2, ShouldAllowRequest(_)).Times(1).WillOnce(Return(true)); |
| EXPECT_TRUE(web_state_->ShouldAllowRequest(nil)); |
| |
| // Test that ShouldAllowRequest() is stopping on negative answer. Only one |
| // one the decider should be called. |
| { |
| bool decider_called = false; |
| bool decider2_called = false; |
| EXPECT_CALL(decider, ShouldAllowRequest(_)) |
| .Times(AtMost(1)) |
| .WillOnce(DoAll(Assign(&decider_called, true), Return(false))); |
| EXPECT_CALL(decider2, ShouldAllowRequest(_)) |
| .Times(AtMost(1)) |
| .WillOnce(DoAll(Assign(&decider2_called, true), Return(false))); |
| EXPECT_FALSE(web_state_->ShouldAllowRequest(nil)); |
| EXPECT_FALSE(decider_called && decider2_called); |
| } |
| |
| // Test that ShouldAllowResponse() is called. |
| EXPECT_CALL(decider, ShouldAllowResponse(_)).Times(1).WillOnce(Return(true)); |
| EXPECT_CALL(decider2, ShouldAllowResponse(_)).Times(1).WillOnce(Return(true)); |
| EXPECT_TRUE(web_state_->ShouldAllowResponse(nil)); |
| |
| // Test that ShouldAllowResponse() is stopping on negative answer. Only one |
| // one the decider should be called. |
| { |
| bool decider_called = false; |
| bool decider2_called = false; |
| EXPECT_CALL(decider, ShouldAllowResponse(_)) |
| .Times(AtMost(1)) |
| .WillOnce(DoAll(Assign(&decider_called, true), Return(false))); |
| EXPECT_CALL(decider2, ShouldAllowResponse(_)) |
| .Times(AtMost(1)) |
| .WillOnce(DoAll(Assign(&decider2_called, true), Return(false))); |
| EXPECT_FALSE(web_state_->ShouldAllowResponse(nil)); |
| EXPECT_FALSE(decider_called && decider2_called); |
| } |
| |
| // Test that WebStateDestroyed() is called. |
| EXPECT_CALL(decider, WebStateDestroyed()).Times(1); |
| EXPECT_CALL(decider2, WebStateDestroyed()).Times(1); |
| web_state_.reset(); |
| EXPECT_EQ(nullptr, decider.web_state()); |
| } |
| |
| // Tests that script command callbacks are called correctly. |
| TEST_F(WebStateTest, ScriptCommand) { |
| // Set up two script command callbacks. |
| const std::string kPrefix1("prefix1"); |
| const std::string kCommand1("prefix1.command1"); |
| base::DictionaryValue value_1; |
| value_1.SetString("a", "b"); |
| const GURL kUrl1("http://foo"); |
| bool is_called_1 = false; |
| web_state_->AddScriptCommandCallback( |
| base::Bind(&HandleScriptCommand, &is_called_1, true, &value_1, kUrl1), |
| kPrefix1); |
| |
| const std::string kPrefix2("prefix2"); |
| const std::string kCommand2("prefix2.command2"); |
| base::DictionaryValue value_2; |
| value_2.SetString("c", "d"); |
| const GURL kUrl2("http://bar"); |
| bool is_called_2 = false; |
| web_state_->AddScriptCommandCallback( |
| base::Bind(&HandleScriptCommand, &is_called_2, false, &value_2, kUrl2), |
| kPrefix2); |
| |
| // Check that a irrelevant or invalid command does not trigger the callbacks. |
| EXPECT_FALSE( |
| web_state_->OnScriptCommandReceived("wohoo.blah", value_1, kUrl1, false)); |
| EXPECT_FALSE(is_called_1); |
| EXPECT_FALSE(is_called_2); |
| |
| EXPECT_FALSE(web_state_->OnScriptCommandReceived( |
| "prefix1ButMissingDot", value_1, kUrl1, false)); |
| EXPECT_FALSE(is_called_1); |
| EXPECT_FALSE(is_called_2); |
| |
| // Check that only the callback matching the prefix is called, with the |
| // expected parameters and return value; |
| EXPECT_TRUE( |
| web_state_->OnScriptCommandReceived(kCommand1, value_1, kUrl1, false)); |
| EXPECT_TRUE(is_called_1); |
| EXPECT_FALSE(is_called_2); |
| |
| // Remove the callback and check it is no longer called. |
| is_called_1 = false; |
| web_state_->RemoveScriptCommandCallback(kPrefix1); |
| EXPECT_FALSE( |
| web_state_->OnScriptCommandReceived(kCommand1, value_1, kUrl1, false)); |
| EXPECT_FALSE(is_called_1); |
| EXPECT_FALSE(is_called_2); |
| |
| // Check that a false return value is forwarded correctly. |
| EXPECT_FALSE( |
| web_state_->OnScriptCommandReceived(kCommand2, value_2, kUrl2, false)); |
| EXPECT_FALSE(is_called_1); |
| EXPECT_TRUE(is_called_2); |
| |
| web_state_->RemoveScriptCommandCallback(kPrefix2); |
| } |
| |
| // Tests script execution with and without callback. |
| TEST_F(WebStateTest, ScriptExecution) { |
| LoadHtml("<html></html>"); |
| |
| // Execute script without callback. |
| web_state_->ExecuteJavaScript(base::UTF8ToUTF16("window.foo = 'bar'")); |
| |
| // Execute script with callback. |
| __block std::unique_ptr<base::Value> execution_result; |
| web_state_->ExecuteJavaScript(base::UTF8ToUTF16("window.foo"), |
| base::BindBlock(^(const base::Value* value) { |
| ASSERT_TRUE(value); |
| execution_result = value->CreateDeepCopy(); |
| })); |
| base::test::ios::WaitUntilCondition(^bool() { |
| return execution_result.get(); |
| }); |
| |
| std::string string_result; |
| execution_result->GetAsString(&string_result); |
| EXPECT_EQ("bar", string_result); |
| } |
| |
| // Tests loading progress. |
| TEST_F(WebStateTest, LoadingProgress) { |
| EXPECT_FLOAT_EQ(0.0, web_state_->GetLoadingProgress()); |
| LoadHtml("<html></html>"); |
| base::test::ios::WaitUntilCondition(^bool() { |
| return web_state_->GetLoadingProgress() == 1.0; |
| }); |
| } |
| |
| // Tests that page which overrides window.webkit object does not break the |
| // messaging system. |
| TEST_F(WebStateTest, OverridingWebKitObject) { |
| // Add a script command handler. |
| __block bool message_received = false; |
| const web::WebState::ScriptCommandCallback callback = |
| base::BindBlock(^bool(const base::DictionaryValue&, const GURL&, bool) { |
| message_received = true; |
| return true; |
| }); |
| web_state_->AddScriptCommandCallback(callback, "test"); |
| |
| // Load the page which overrides window.webkit object and wait until the |
| // test message is received. |
| LoadHtml( |
| "<script>" |
| " webkit = undefined;" |
| " __gCrWeb.message.invokeOnHost({'command': 'test.webkit-overriding'});" |
| "</script>"); |
| |
| base::test::ios::WaitUntilCondition(^{ |
| return message_received; |
| }); |
| web_state_->RemoveScriptCommandCallback("test"); |
| } |
| |
| } // namespace |
| } // namespace web |