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.
5 #include "chrome_frame/test/mock_ie_event_sink_test.h"
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"
13 // Needed for CreateFunctor.
14 #define GMOCK_MUTANT_INCLUDE_LATE_OBJECT_BINDING
15 #include "testing/gmock_mutant.h"
18 using testing::Cardinality
;
19 using testing::Exactly
;
20 using testing::ExpectationSet
;
21 using testing::InSequence
;
22 using testing::StrCaseEq
;
24 namespace chrome_frame_test
{
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
,
35 VLOG(1) << "Browser does not have renderer window";
37 OnLoad(IN_IE
, V_BSTR(url
));
41 ExpectationSet
MockIEEventSink::ExpectNavigationCardinality(
42 const std::wstring
& url
, Cardinality before_cardinality
,
43 Cardinality complete_cardinality
) {
44 ExpectationSet navigation
;
46 navigation
+= EXPECT_CALL(*this, OnBeforeNavigate2(_
, _
, _
, _
, _
, _
, _
))
47 .Times(before_cardinality
).RetiresOnSaturation();
49 navigation
+= EXPECT_CALL(*this, OnBeforeNavigate2(_
,
50 testing::Field(&VARIANT::bstrVal
,
51 StrCaseEq(url
)), _
, _
, _
, _
, _
))
52 .Times(before_cardinality
).RetiresOnSaturation();
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
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
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.";
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();
75 Cardinality split_complete_cardinality
= testing::Exactly(1);
76 if (complete_cardinality
.IsSatisfiedByCallCount(call_count
))
77 split_complete_cardinality
= testing::AtMost(1);
80 navigation
+= EXPECT_CALL(*this, OnNavigateComplete2(_
, _
))
81 .Times(split_complete_cardinality
)
82 .RetiresOnSaturation();
84 navigation
+= EXPECT_CALL(*this, OnNavigateComplete2(_
,
85 testing::Field(&VARIANT::bstrVal
,
87 .Times(split_complete_cardinality
)
88 .RetiresOnSaturation();
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));
100 ExpectNavigationCardinality(url
, Exactly(1), Exactly(1));
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));
111 ExpectNavigation(is_cf
, url
);
115 void MockIEEventSink::ExpectJavascriptWindowOpenNavigation(
116 bool parent_cf
, bool new_window_cf
, const std::wstring
& url
) {
118 InSequence expect_in_sequence_for_scope
;
119 ExpectNavigation(IN_CF
, L
"");
120 ExpectNavigationCardinality(L
"", testing::AtMost(1),
121 testing::Between(1, 2));
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));
131 ExpectNavigation(IN_IE
, url
);
136 void MockIEEventSink::ExpectNewWindow(MockIEEventSink
* new_window_mock
) {
137 DCHECK(new_window_mock
);
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));
145 EXPECT_CALL(*this, OnNewBrowserWindow(_
, _
))
146 .WillOnce(testing::WithArgs
<0>(testing::Invoke(testing::CreateFunctor(
147 new_window_mock
, &MockIEEventSink::Attach
))));
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());
159 void MockIEEventSink::ExpectDocumentReadystate(int ready_state
) {
160 base::win::ScopedComPtr
<IWebBrowser2
> browser(event_sink_
->web_browser2());
161 EXPECT_TRUE(browser
!= NULL
);
163 base::win::ScopedComPtr
<IDispatch
> document
;
164 browser
->get_Document(document
.Receive());
165 EXPECT_TRUE(document
!= NULL
);
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
, ¶ms
,
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
)));
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", ""));
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", ""));
197 void MockIEEventSinkTest::LaunchIEAndNavigate(const std::wstring
& url
) {
198 LaunchIENavigateAndLoop(url
, kChromeFrameLongNavigationTimeout
);
201 void MockIEEventSinkTest::LaunchIENavigateAndLoop(const std::wstring
& url
,
202 base::TimeDelta timeout
) {
203 if (GetInstalledIEVersion() >= IE_8
) {
204 chrome_frame_test::ClearIESessionHistory();
206 hung_call_detector_
= HungCOMCallDetector::Setup(ceil(timeout
.InSecondsF()));
207 EXPECT_TRUE(hung_call_detector_
!= NULL
);
209 IEEventSink::SetAbnormalShutdown(false);
211 EXPECT_CALL(ie_mock_
, OnQuit())
212 .WillOnce(QUIT_LOOP(loop_
));
214 HRESULT hr
= ie_mock_
.event_sink()->LaunchIEAndNavigate(url
, &ie_mock_
);
215 ASSERT_HRESULT_SUCCEEDED(hr
);
217 ASSERT_TRUE(ie_mock_
.event_sink()->web_browser2() != NULL
);
218 loop_
.RunFor(timeout
);
221 if (hung_call_detector_
) {
222 IEEventSink::SetAbnormalShutdown(hung_call_detector_
->is_hung());
223 hung_call_detector_
->TearDown();
227 base::FilePath
MockIEEventSinkTest::GetTestFilePath(
228 const std::wstring
& relative_path
) {
229 return server_mock_
.root_dir().Append(relative_path
);
232 std::wstring
MockIEEventSinkTest::GetTestUrl(
233 const std::wstring
& relative_path
) {
234 return server_mock_
.Resolve(relative_path
.c_str());
237 } // namespace chrome_frame_test