OLD | NEW |
| (Empty) |
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, ¶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))); | |
175 } | |
176 } | |
177 } | |
178 } | |
179 | |
180 // MockIEEventSinkTest methods | |
181 MockIEEventSinkTest::MockIEEventSinkTest() | |
182 : server_mock_(1337, | |
183 base::ASCIIToWide(chrome_frame_test::GetLocalIPv4Address()), | |
184 GetTestDataFolder()) { | |
185 loop_.set_snapshot_on_timeout(true); | |
186 EXPECT_CALL(server_mock_, Get(_, StrCaseEq(L"/favicon.ico"), _)) | |
187 .WillRepeatedly(SendFast("HTTP/1.1 404 Not Found", "")); | |
188 } | |
189 | |
190 MockIEEventSinkTest::MockIEEventSinkTest(int port, const std::wstring& address, | |
191 const base::FilePath& root_dir) | |
192 : server_mock_(port, address, root_dir) { | |
193 loop_.set_snapshot_on_timeout(true); | |
194 EXPECT_CALL(server_mock_, Get(_, StrCaseEq(L"/favicon.ico"), _)) | |
195 .WillRepeatedly(SendFast("HTTP/1.1 404 Not Found", "")); | |
196 } | |
197 | |
198 void MockIEEventSinkTest::LaunchIEAndNavigate(const std::wstring& url) { | |
199 LaunchIENavigateAndLoop(url, kChromeFrameLongNavigationTimeout); | |
200 } | |
201 | |
202 void MockIEEventSinkTest::LaunchIENavigateAndLoop(const std::wstring& url, | |
203 base::TimeDelta timeout) { | |
204 if (GetInstalledIEVersion() >= IE_8) { | |
205 chrome_frame_test::ClearIESessionHistory(); | |
206 } | |
207 hung_call_detector_ = HungCOMCallDetector::Setup(ceil(timeout.InSecondsF())); | |
208 EXPECT_TRUE(hung_call_detector_ != NULL); | |
209 | |
210 IEEventSink::SetAbnormalShutdown(false); | |
211 | |
212 EXPECT_CALL(ie_mock_, OnQuit()) | |
213 .WillOnce(QUIT_LOOP(loop_)); | |
214 | |
215 HRESULT hr = ie_mock_.event_sink()->LaunchIEAndNavigate(url, &ie_mock_); | |
216 ASSERT_HRESULT_SUCCEEDED(hr); | |
217 if (hr != S_FALSE) { | |
218 ASSERT_TRUE(ie_mock_.event_sink()->web_browser2() != NULL); | |
219 loop_.RunFor(timeout); | |
220 } | |
221 | |
222 if (hung_call_detector_) { | |
223 IEEventSink::SetAbnormalShutdown(hung_call_detector_->is_hung()); | |
224 hung_call_detector_->TearDown(); | |
225 } | |
226 } | |
227 | |
228 base::FilePath MockIEEventSinkTest::GetTestFilePath( | |
229 const std::wstring& relative_path) { | |
230 return server_mock_.root_dir().Append(relative_path); | |
231 } | |
232 | |
233 std::wstring MockIEEventSinkTest::GetTestUrl( | |
234 const std::wstring& relative_path) { | |
235 return server_mock_.Resolve(relative_path.c_str()); | |
236 } | |
237 | |
238 } // namespace chrome_frame_test | |
OLD | NEW |