Fix breakages in https://codereview.chromium.org/1155713003/
[chromium-blink-merge.git] / ios / web / web_state / web_state_impl_unittest.mm
blob3c7024b5c338f9c399159bae0f25c73c45a519ac
1 // Copyright 2014 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.
5 #include "base/bind.h"
6 #include "base/logging.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/values.h"
9 #include "ios/web/public/load_committed_details.h"
10 #include "ios/web/public/test/test_browser_state.h"
11 #include "ios/web/public/web_state/web_state_observer.h"
12 #include "ios/web/web_state/web_state_impl.h"
13 #include "net/http/http_response_headers.h"
14 #include "net/http/http_util.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "testing/gtest_mac.h"
17 #include "testing/platform_test.h"
18 #include "url/gurl.h"
20 namespace web {
21 namespace {
23 // Test observer to check that the WebStateObserver methods are called as
24 // expected.
25 class TestWebStateObserver : public WebStateObserver {
26  public:
27   TestWebStateObserver(WebState* web_state)
28       : WebStateObserver(web_state),
29         provisional_navigation_started_called_(false),
30         navigation_item_committed_called_(false),
31         page_loaded_called_(false),
32         url_hash_changed_called_(false),
33         history_state_changed_called_(false),
34         web_state_destroyed_called_(false) {}
36   // Methods returning true if the corresponding WebStateObserver method has
37   // been called.
38   bool provisional_navigation_started_called() {
39     return provisional_navigation_started_called_;
40   };
41   bool navigation_item_committed_called() {
42     return navigation_item_committed_called_;
43   }
44   bool page_loaded_called() { return page_loaded_called_; }
45   bool url_hash_changed_called() { return url_hash_changed_called_; }
46   bool history_state_changed_called() { return history_state_changed_called_; }
47   bool web_state_destroyed_called() { return web_state_destroyed_called_; }
49  private:
50   // WebStateObserver implementation:
51   void ProvisionalNavigationStarted(const GURL& url) override {
52     provisional_navigation_started_called_ = true;
53   }
54   void NavigationItemCommitted(
55       const LoadCommittedDetails& load_details) override {
56     navigation_item_committed_called_ = true;
57   }
58   void PageLoaded(PageLoadCompletionStatus load_completion_status) override {
59     page_loaded_called_ =
60         load_completion_status == PageLoadCompletionStatus::SUCCESS;
61   }
62   void UrlHashChanged() override { url_hash_changed_called_ = true; }
63   void HistoryStateChanged() override { history_state_changed_called_ = true; }
64   void WebStateDestroyed() override {
65     web_state_destroyed_called_ = true;
66     Observe(nullptr);
67   }
69   bool provisional_navigation_started_called_;
70   bool navigation_item_committed_called_;
71   bool page_loaded_called_;
72   bool url_hash_changed_called_;
73   bool history_state_changed_called_;
74   bool web_state_destroyed_called_;
77 // Creates and returns an HttpResponseHeader using the string representation.
78 scoped_refptr<net::HttpResponseHeaders> HeadersFromString(const char* string) {
79   std::string raw_string(string);
80   std::string headers_string = net::HttpUtil::AssembleRawHeaders(
81       raw_string.c_str(), raw_string.length());
82   scoped_refptr<net::HttpResponseHeaders> headers(
83       new net::HttpResponseHeaders(headers_string));
84   return headers;
87 // Test callback for script commands.
88 // Sets |is_called| to true if it is called, and checks that the parameters
89 // match their expected values.
90 // |user_is_interacting| is not checked because Bind() has a maximum of 7
91 // parameters.
92 bool HandleScriptCommand(bool* is_called,
93                          bool should_handle,
94                          base::DictionaryValue* expected_value,
95                          const GURL& expected_url,
96                          const base::DictionaryValue& value,
97                          const GURL& url,
98                          bool user_is_interacting) {
99   *is_called = true;
100   EXPECT_TRUE(expected_value->Equals(&value));
101   EXPECT_EQ(expected_url, url);
102   return should_handle;
105 class WebStateTest : public PlatformTest {
106  protected:
107   void SetUp() override {
108     web_state_.reset(new WebStateImpl(&browser_state_));
109     web_state_->SetWebController(nil);
110   }
112   web::TestBrowserState browser_state_;
113   scoped_ptr<WebStateImpl> web_state_;
116 TEST_F(WebStateTest, ResponseHeaders) {
117   GURL real_url("http://foo.com/bar");
118   GURL frame_url("http://frames-r-us.com/");
119   scoped_refptr<net::HttpResponseHeaders> real_headers(HeadersFromString(
120       "HTTP/1.1 200 OK\r\n"
121       "Content-Type: text/html\r\n"
122       "Content-Language: en\r\n"
123       "X-Should-Be-Here: yep\r\n"
124       "\r\n"));
125   scoped_refptr<net::HttpResponseHeaders> frame_headers(HeadersFromString(
126       "HTTP/1.1 200 OK\r\n"
127       "Content-Type: application/pdf\r\n"
128       "Content-Language: fr\r\n"
129       "X-Should-Not-Be-Here: oops\r\n"
130       "\r\n"));
131   // Simulate a load of a page with a frame.
132   web_state_->OnHttpResponseHeadersReceived(real_headers.get(), real_url);
133   web_state_->OnHttpResponseHeadersReceived(frame_headers.get(), frame_url);
134   // Include a hash to be sure it's handled correctly.
135   web_state_->OnPageLoaded(GURL(real_url.spec() + std::string("#baz")), true);
137   // Verify that the right header set was kept.
138   EXPECT_TRUE(
139       web_state_->GetHttpResponseHeaders()->HasHeader("X-Should-Be-Here"));
140   EXPECT_FALSE(
141       web_state_->GetHttpResponseHeaders()->HasHeader("X-Should-Not-Be-Here"));
143   // And that it was parsed correctly.
144   EXPECT_EQ("text/html", web_state_->GetContentsMimeType());
145   EXPECT_EQ("en", web_state_->GetContentLanguageHeader());
148 TEST_F(WebStateTest, ResponseHeaderClearing) {
149   GURL url("http://foo.com/");
150   scoped_refptr<net::HttpResponseHeaders> headers(HeadersFromString(
151       "HTTP/1.1 200 OK\r\n"
152       "Content-Type: text/html\r\n"
153       "Content-Language: en\r\n"
154       "\r\n"));
155   web_state_->OnHttpResponseHeadersReceived(headers.get(), url);
157   // There should be no headers before loading.
158   EXPECT_EQ(NULL, web_state_->GetHttpResponseHeaders());
160   // There should be headers and parsed values after loading.
161   web_state_->OnPageLoaded(url, true);
162   EXPECT_TRUE(web_state_->GetHttpResponseHeaders()->HasHeader("Content-Type"));
163   EXPECT_NE("", web_state_->GetContentsMimeType());
164   EXPECT_NE("", web_state_->GetContentLanguageHeader());
166   // ... but not after loading another page, nor should there be specific
167   // parsed values.
168   web_state_->OnPageLoaded(GURL("http://elsewhere.com/"), true);
169   EXPECT_EQ(NULL, web_state_->GetHttpResponseHeaders());
170   EXPECT_EQ("", web_state_->GetContentsMimeType());
171   EXPECT_EQ("", web_state_->GetContentLanguageHeader());
174 TEST_F(WebStateTest, ObserverTest) {
175   scoped_ptr<TestWebStateObserver> observer(
176       new TestWebStateObserver(web_state_.get()));
177   EXPECT_EQ(web_state_.get(), observer->web_state());
179   // Test that ProvisionalNavigationStarted() is called.
180   EXPECT_FALSE(observer->provisional_navigation_started_called());
181   web_state_->OnProvisionalNavigationStarted(GURL("http://test"));
182   EXPECT_TRUE(observer->provisional_navigation_started_called());
184   // Test that NavigtionItemCommitted() is called.
185   EXPECT_FALSE(observer->navigation_item_committed_called());
186   LoadCommittedDetails details;
187   web_state_->OnNavigationItemCommitted(details);
188   EXPECT_TRUE(observer->navigation_item_committed_called());
190   // Test that DidFinishLoad() is called, only when there is no error.
191   EXPECT_FALSE(observer->page_loaded_called());
192   web_state_->OnPageLoaded(GURL("http://test"), false);
193   EXPECT_FALSE(observer->page_loaded_called());
194   web_state_->OnPageLoaded(GURL("http://test"), true);
195   EXPECT_TRUE(observer->page_loaded_called());
197   // Test that UrlHashChanged() is called.
198   EXPECT_FALSE(observer->url_hash_changed_called());
199   web_state_->OnUrlHashChanged();
200   EXPECT_TRUE(observer->url_hash_changed_called());
202   // Test that HistoryStateChanged() is called.
203   EXPECT_FALSE(observer->history_state_changed_called());
204   web_state_->OnHistoryStateChanged();
205   EXPECT_TRUE(observer->history_state_changed_called());
207   // Test that WebStateDestroyed() is called.
208   EXPECT_FALSE(observer->web_state_destroyed_called());
209   web_state_.reset();
210   EXPECT_TRUE(observer->web_state_destroyed_called());
212   EXPECT_EQ(nullptr, observer->web_state());
215 // Tests that script command callbacks are called correctly.
216 TEST_F(WebStateTest, ScriptCommand) {
217   // Set up two script command callbacks.
218   const std::string kPrefix1("prefix1");
219   const std::string kCommand1("prefix1.command1");
220   base::DictionaryValue value_1;
221   value_1.SetString("a", "b");
222   const GURL kUrl1("http://foo");
223   bool is_called_1 = false;
224   web_state_->AddScriptCommandCallback(
225       base::Bind(&HandleScriptCommand, &is_called_1, true, &value_1, kUrl1),
226       kPrefix1);
228   const std::string kPrefix2("prefix2");
229   const std::string kCommand2("prefix2.command2");
230   base::DictionaryValue value_2;
231   value_2.SetString("c", "d");
232   const GURL kUrl2("http://bar");
233   bool is_called_2 = false;
234   web_state_->AddScriptCommandCallback(
235       base::Bind(&HandleScriptCommand, &is_called_2, false, &value_2, kUrl2),
236       kPrefix2);
238   // Check that a irrelevant or invalid command does not trigger the callbacks.
239   EXPECT_FALSE(
240       web_state_->OnScriptCommandReceived("wohoo.blah", value_1, kUrl1, false));
241   EXPECT_FALSE(is_called_1);
242   EXPECT_FALSE(is_called_2);
244   EXPECT_FALSE(web_state_->OnScriptCommandReceived(
245       "prefix1ButMissingDot", value_1, kUrl1, false));
246   EXPECT_FALSE(is_called_1);
247   EXPECT_FALSE(is_called_2);
249   // Check that only the callback matching the prefix is called, with the
250   // expected parameters and return value;
251   EXPECT_TRUE(
252       web_state_->OnScriptCommandReceived(kCommand1, value_1, kUrl1, false));
253   EXPECT_TRUE(is_called_1);
254   EXPECT_FALSE(is_called_2);
256   // Remove the callback and check it is no longer called.
257   is_called_1 = false;
258   web_state_->RemoveScriptCommandCallback(kPrefix1);
259   EXPECT_FALSE(
260       web_state_->OnScriptCommandReceived(kCommand1, value_1, kUrl1, false));
261   EXPECT_FALSE(is_called_1);
262   EXPECT_FALSE(is_called_2);
264   // Check that a false return value is forwarded correctly.
265   EXPECT_FALSE(
266       web_state_->OnScriptCommandReceived(kCommand2, value_2, kUrl2, false));
267   EXPECT_FALSE(is_called_1);
268   EXPECT_TRUE(is_called_2);
270   web_state_->RemoveScriptCommandCallback(kPrefix2);
273 }  // namespace
274 }  // namespace web