- add sources.
[platform/framework/web/crosswalk.git] / src / chrome_frame / test / mock_ie_event_sink_test.cc
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 "chrome_frame/test/mock_ie_event_sink_test.h"
6
7 #include <sstream>
8
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/win/scoped_variant.h"
11 #include "chrome_frame/test/mock_ie_event_sink_actions.h"
12
13 // Needed for CreateFunctor.
14 #define GMOCK_MUTANT_INCLUDE_LATE_OBJECT_BINDING
15 #include "testing/gmock_mutant.h"
16
17 using testing::_;
18 using testing::Cardinality;
19 using testing::Exactly;
20 using testing::ExpectationSet;
21 using testing::InSequence;
22 using testing::StrCaseEq;
23
24 namespace chrome_frame_test {
25
26 // MockIEEventSink methods
27 void MockIEEventSink::OnDocumentComplete(IDispatch* dispatch, VARIANT* url) {
28   if (!event_sink_->IsCFRendering()) {
29     HWND renderer_window = event_sink_->GetRendererWindowSafe();
30     if (renderer_window) {
31       ::NotifyWinEvent(IA2_EVENT_DOCUMENT_LOAD_COMPLETE,
32                        renderer_window,
33                        OBJID_CLIENT, 0L);
34     } else {
35       VLOG(1) << "Browser does not have renderer window";
36     }
37     OnLoad(IN_IE, V_BSTR(url));
38   }
39 }
40
41 ExpectationSet MockIEEventSink::ExpectNavigationCardinality(
42     const std::wstring& url, Cardinality before_cardinality,
43     Cardinality complete_cardinality) {
44   ExpectationSet navigation;
45   if (url.empty()) {
46     navigation += EXPECT_CALL(*this, OnBeforeNavigate2(_, _, _, _, _, _, _))
47         .Times(before_cardinality).RetiresOnSaturation();
48   } else {
49     navigation += EXPECT_CALL(*this, OnBeforeNavigate2(_,
50                               testing::Field(&VARIANT::bstrVal,
51                               StrCaseEq(url)), _, _, _, _, _))
52         .Times(before_cardinality).RetiresOnSaturation();
53   }
54
55   // Hack: OnFileDownload may occur zero or once (for reasons not understood)
56   // before each OnNavigateComplete2 which causes problems for tests expecting
57   // things in sequence. To redress this, expectations which allow multiple
58   // calls are split into expect statements expecting exactly one call or at
59   // most one call.
60   // TODO(kkania): Consider avoiding this problem by creating a mock without
61   // the OnFileDownload call or by removing the dependency of some tests on
62   // InSequence.
63   LOG_IF(WARNING, complete_cardinality.ConservativeUpperBound() > 1000)
64       << "Cardinality upper bound may be too great to be split up into single "
65          "expect statements. If you do not require this navigation to be in "
66          "sequence, do not call this method.";
67   int call_count = 0;
68   InSequence expect_in_sequence_for_scope;
69   while (!complete_cardinality.IsSaturatedByCallCount(call_count)) {
70     navigation += EXPECT_CALL(*this, OnFileDownload(_, _))
71         .Times(testing::AtMost(1))
72         .WillOnce(testing::SetArgumentPointee<1>(VARIANT_TRUE))
73         .RetiresOnSaturation();
74
75     Cardinality split_complete_cardinality = testing::Exactly(1);
76     if (complete_cardinality.IsSatisfiedByCallCount(call_count))
77       split_complete_cardinality = testing::AtMost(1);
78
79     if (url.empty()) {
80       navigation += EXPECT_CALL(*this, OnNavigateComplete2(_, _))
81           .Times(split_complete_cardinality)
82           .RetiresOnSaturation();
83     } else {
84       navigation += EXPECT_CALL(*this, OnNavigateComplete2(_,
85                                 testing::Field(&VARIANT::bstrVal,
86                                 StrCaseEq(url))))
87           .Times(split_complete_cardinality)
88           .RetiresOnSaturation();
89     }
90     call_count++;
91   }
92   return navigation;
93 }
94
95 void MockIEEventSink::ExpectNavigation(bool is_cf, const std::wstring& url) {
96   InSequence expect_in_sequence_for_scope;
97   if (is_cf || GetInstalledIEVersion() == IE_9) {
98     ExpectNavigationCardinality(url, Exactly(1), testing::Between(1, 2));
99   } else {
100     ExpectNavigationCardinality(url, Exactly(1), Exactly(1));
101   }
102 }
103
104 void MockIEEventSink::ExpectNavigationOptionalBefore(bool is_cf,
105                                                      const std::wstring& url) {
106   InSequence expect_in_sequence_for_scope;
107   if (is_cf && GetInstalledIEVersion() == IE_6) {
108     ExpectNavigationCardinality(url, testing::AtMost(1),
109                                 testing::Between(1, 2));
110   } else {
111     ExpectNavigation(is_cf, url);
112   }
113 }
114
115 void MockIEEventSink::ExpectJavascriptWindowOpenNavigation(
116     bool parent_cf, bool new_window_cf, const std::wstring& url) {
117   if (parent_cf) {
118     InSequence expect_in_sequence_for_scope;
119     ExpectNavigation(IN_CF, L"");
120     ExpectNavigationCardinality(L"", testing::AtMost(1),
121                                 testing::Between(1, 2));
122   } else {
123     if (new_window_cf) {
124       ExpectNavigationCardinality(url, testing::AtMost(1), testing::AtMost(1));
125       // Sometimes an extra load occurs here for some reason.
126       EXPECT_CALL(*this, OnLoad(IN_IE, StrCaseEq(url)))
127           .Times(testing::AtMost(1));
128       ExpectNavigationCardinality(url, testing::AtMost(1),
129                                   testing::Between(1, 2));
130     } else {
131       ExpectNavigation(IN_IE, url);
132     }
133   }
134 }
135
136 void MockIEEventSink::ExpectNewWindow(MockIEEventSink* new_window_mock) {
137   DCHECK(new_window_mock);
138
139   // IE8 seems to fire one of these events based on version.
140   EXPECT_CALL(*this, OnNewWindow2(_, _))
141       .Times(testing::AtMost(1));
142   EXPECT_CALL(*this, OnNewWindow3(_, _, _, _, _))
143       .Times(testing::AtMost(1));
144
145   EXPECT_CALL(*this, OnNewBrowserWindow(_, _))
146       .WillOnce(testing::WithArgs<0>(testing::Invoke(testing::CreateFunctor(
147           new_window_mock, &MockIEEventSink::Attach))));
148 }
149
150 void MockIEEventSink::ExpectAnyNavigations() {
151   EXPECT_CALL(*this, OnBeforeNavigate2(_, _, _, _, _, _, _))
152       .Times(testing::AnyNumber());
153   EXPECT_CALL(*this, OnFileDownload(VARIANT_TRUE, _))
154       .Times(testing::AnyNumber());
155   EXPECT_CALL(*this, OnNavigateComplete2(_, _))
156       .Times(testing::AnyNumber());
157 }
158
159 void MockIEEventSink::ExpectDocumentReadystate(int ready_state) {
160   base::win::ScopedComPtr<IWebBrowser2> browser(event_sink_->web_browser2());
161   EXPECT_TRUE(browser != NULL);
162   if (browser) {
163     base::win::ScopedComPtr<IDispatch> document;
164     browser->get_Document(document.Receive());
165     EXPECT_TRUE(document != NULL);
166     if (document) {
167       DISPPARAMS params = { 0 };
168       base::win::ScopedVariant result;
169       EXPECT_HRESULT_SUCCEEDED(document->Invoke(DISPID_READYSTATE, IID_NULL,
170           LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &params,
171           result.Receive(), NULL, NULL));
172       EXPECT_EQ(VT_I4, result.type());
173       if (result.type() == VT_I4) {
174         EXPECT_EQ(ready_state, static_cast<int>(V_I4(&result)));
175       }
176     }
177   }
178 }
179
180 // MockIEEventSinkTest methods
181 MockIEEventSinkTest::MockIEEventSinkTest()
182     : server_mock_(1337, ASCIIToWide(chrome_frame_test::GetLocalIPv4Address()),
183                    GetTestDataFolder()) {
184   loop_.set_snapshot_on_timeout(true);
185   EXPECT_CALL(server_mock_, Get(_, StrCaseEq(L"/favicon.ico"), _))
186       .WillRepeatedly(SendFast("HTTP/1.1 404 Not Found", ""));
187 }
188
189 MockIEEventSinkTest::MockIEEventSinkTest(int port, const std::wstring& address,
190                                          const base::FilePath& root_dir)
191     : server_mock_(port, address, root_dir) {
192   loop_.set_snapshot_on_timeout(true);
193   EXPECT_CALL(server_mock_, Get(_, StrCaseEq(L"/favicon.ico"), _))
194       .WillRepeatedly(SendFast("HTTP/1.1 404 Not Found", ""));
195 }
196
197 void MockIEEventSinkTest::LaunchIEAndNavigate(const std::wstring& url) {
198   LaunchIENavigateAndLoop(url, kChromeFrameLongNavigationTimeout);
199 }
200
201 void MockIEEventSinkTest::LaunchIENavigateAndLoop(const std::wstring& url,
202                                                   base::TimeDelta timeout) {
203   if (GetInstalledIEVersion() >= IE_8) {
204     chrome_frame_test::ClearIESessionHistory();
205   }
206   hung_call_detector_ = HungCOMCallDetector::Setup(ceil(timeout.InSecondsF()));
207   EXPECT_TRUE(hung_call_detector_ != NULL);
208
209   IEEventSink::SetAbnormalShutdown(false);
210
211   EXPECT_CALL(ie_mock_, OnQuit())
212       .WillOnce(QUIT_LOOP(loop_));
213
214   HRESULT hr = ie_mock_.event_sink()->LaunchIEAndNavigate(url, &ie_mock_);
215   ASSERT_HRESULT_SUCCEEDED(hr);
216   if (hr != S_FALSE) {
217     ASSERT_TRUE(ie_mock_.event_sink()->web_browser2() != NULL);
218     loop_.RunFor(timeout);
219   }
220
221   if (hung_call_detector_) {
222     IEEventSink::SetAbnormalShutdown(hung_call_detector_->is_hung());
223     hung_call_detector_->TearDown();
224   }
225 }
226
227 base::FilePath MockIEEventSinkTest::GetTestFilePath(
228     const std::wstring& relative_path) {
229   return server_mock_.root_dir().Append(relative_path);
230 }
231
232 std::wstring MockIEEventSinkTest::GetTestUrl(
233     const std::wstring& relative_path) {
234   return server_mock_.Resolve(relative_path.c_str());
235 }
236
237 }  // namespace chrome_frame_test