1 // Copyright (c) 2011 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/com_message_event.h" 6 7 #include <atlbase.h> 8 #include <atlcom.h> 9 10 #include "testing/gtest/include/gtest/gtest.h" 11 12 // To allow the unit test read-only access to check protected member variables. 13 class FriendlyComMessageEvent : public ComMessageEvent { 14 public: 15 inline IHTMLEventObj* basic_event() { return basic_event_; } 16 }; 17 18 class ATL_NO_VTABLE MockDumbContainer : 19 public CComObjectRoot, 20 public IOleContainer { 21 public: 22 DECLARE_NOT_AGGREGATABLE(MockDumbContainer) 23 BEGIN_COM_MAP(MockDumbContainer) 24 COM_INTERFACE_ENTRY(IParseDisplayName) 25 COM_INTERFACE_ENTRY(IOleContainer) 26 END_COM_MAP() 27 28 STDMETHOD(ParseDisplayName)(IBindCtx*, LPOLESTR, ULONG*, IMoniker**) { 29 NOTREACHED(); 30 return E_NOTIMPL; 31 } 32 STDMETHOD(EnumObjects)(DWORD, IEnumUnknown**) { 33 NOTREACHED(); 34 return E_NOTIMPL; 35 } 36 STDMETHOD(LockContainer)(BOOL) { 37 NOTREACHED(); 38 return E_NOTIMPL; 39 } 40 }; 41 42 TEST(ComMessageEvent, WithDumbContainer) { 43 CComObject<MockDumbContainer>* container_obj = NULL; 44 CComObject<MockDumbContainer>::CreateInstance(&container_obj); 45 base::win::ScopedComPtr<IOleContainer> container(container_obj); 46 EXPECT_FALSE(!container); 47 48 CComObject<FriendlyComMessageEvent>* event_obj = NULL; 49 CComObject<FriendlyComMessageEvent>::CreateInstance(&event_obj); 50 base::win::ScopedComPtr<IUnknown> event_ref(event_obj); 51 52 bool result = event_obj->Initialize(container, "hi", "http://www.foo.com/", 53 "message"); 54 EXPECT_TRUE(result); 55 EXPECT_TRUE(!event_obj->basic_event()); 56 } 57 58 // Mock object to mimic a "smart" container, e.g. IE, that will 59 // be able to return an IHTMLDocument2 and 4, and from which you 60 // can get an IHTMLEventObj implementation. Doubles as a mock 61 // IHTMLEventObj implementation. 62 class ATL_NO_VTABLE MockSmartContainer : 63 public CComObjectRoot, 64 public IOleContainer, 65 public IHTMLDocument2, 66 public IHTMLDocument4, 67 public IHTMLEventObj { 68 public: 69 DECLARE_NOT_AGGREGATABLE(MockSmartContainer) 70 BEGIN_COM_MAP(MockSmartContainer) 71 COM_INTERFACE_ENTRY_IID(IID_IDispatch, IHTMLEventObj) 72 COM_INTERFACE_ENTRY(IParseDisplayName) 73 COM_INTERFACE_ENTRY(IOleContainer) 74 COM_INTERFACE_ENTRY(IHTMLDocument) 75 COM_INTERFACE_ENTRY(IHTMLDocument2) 76 COM_INTERFACE_ENTRY(IHTMLDocument4) 77 COM_INTERFACE_ENTRY(IHTMLEventObj) 78 END_COM_MAP() 79 80 static const DISPID kDispId = 424242; 81 static const long kResultValue = 42; 82 83 // Only method we actually implement from IHTMLDocument4, to give 84 // out the mock IHTMLEventObj. 85 STDMETHOD(createEventObject)(VARIANT*, IHTMLEventObj** event_obj) { 86 return GetUnknown()->QueryInterface(event_obj); 87 } 88 89 // Dummy IDispatch implementation for unit testing, to validate 90 // passthrough semantics. 91 STDMETHOD(GetIDsOfNames)(REFIID iid, LPOLESTR* names, UINT num_names, 92 LCID lcid, DISPID* disp_ids) { 93 DCHECK(num_names == 1); 94 disp_ids[0] = kDispId; 95 return S_OK; 96 } 97 98 STDMETHOD(Invoke)(DISPID id, REFIID iid, LCID lcid, WORD flags, 99 DISPPARAMS* disp_params, VARIANT* var_result, 100 EXCEPINFO* excep_info, UINT* arg_error) { 101 var_result->vt = VT_I4; 102 var_result->lVal = kResultValue; 103 return S_OK; 104 } 105 106 107 // Do-nothing implementation of the rest of the interface methods. 108 // To make this less verbose, define a macro here and undefine it 109 // at the end of the list. 110 #define STDMETHODNOTIMP(method, parameters) \ 111 STDMETHOD(method) parameters { \ 112 NOTREACHED(); \ 113 return E_NOTIMPL; \ 114 } 115 116 // IDispatch 117 STDMETHODNOTIMP(GetTypeInfoCount, (UINT*)); 118 STDMETHODNOTIMP(GetTypeInfo, (UINT, LCID, ITypeInfo**)); 119 120 // IParseDisplayName 121 STDMETHODNOTIMP(ParseDisplayName, (IBindCtx*, LPOLESTR, ULONG*, IMoniker**)); 122 // IOleContainer 123 STDMETHODNOTIMP(EnumObjects, (DWORD, IEnumUnknown**)); 124 STDMETHODNOTIMP(LockContainer, (BOOL)); 125 // IHTMLDocument 126 STDMETHODNOTIMP(get_Script, (IDispatch**)); 127 // IHTMLDocument2 128 STDMETHODNOTIMP(get_all, (IHTMLElementCollection**)); 129 STDMETHODNOTIMP(get_body, (IHTMLElement**)); 130 STDMETHODNOTIMP(get_activeElement, (IHTMLElement**)); 131 STDMETHODNOTIMP(get_images, (IHTMLElementCollection**)); 132 STDMETHODNOTIMP(get_applets, (IHTMLElementCollection**)); 133 STDMETHODNOTIMP(get_links, (IHTMLElementCollection**)); 134 STDMETHODNOTIMP(get_forms, (IHTMLElementCollection**)); 135 STDMETHODNOTIMP(get_anchors, (IHTMLElementCollection**)); 136 STDMETHODNOTIMP(put_title, (BSTR)); 137 STDMETHODNOTIMP(get_title, (BSTR*)); 138 STDMETHODNOTIMP(get_scripts, (IHTMLElementCollection**)); 139 STDMETHODNOTIMP(put_designMode, (BSTR)); 140 STDMETHODNOTIMP(get_designMode, (BSTR*)); 141 STDMETHODNOTIMP(get_selection, (IHTMLSelectionObject**)); 142 STDMETHODNOTIMP(get_readyState, (BSTR*)); 143 STDMETHODNOTIMP(get_frames, (IHTMLFramesCollection2**)); 144 STDMETHODNOTIMP(get_embeds, (IHTMLElementCollection**)); 145 STDMETHODNOTIMP(get_plugins, (IHTMLElementCollection**)); 146 STDMETHODNOTIMP(put_alinkColor, (VARIANT)); 147 STDMETHODNOTIMP(get_alinkColor, (VARIANT*)); 148 STDMETHODNOTIMP(put_bgColor, (VARIANT)); 149 STDMETHODNOTIMP(get_bgColor, (VARIANT*)); 150 STDMETHODNOTIMP(put_fgColor, (VARIANT)); 151 STDMETHODNOTIMP(get_fgColor, (VARIANT*)); 152 STDMETHODNOTIMP(put_linkColor, (VARIANT)); 153 STDMETHODNOTIMP(get_linkColor, (VARIANT*)); 154 STDMETHODNOTIMP(put_vlinkColor, (VARIANT)); 155 STDMETHODNOTIMP(get_vlinkColor, (VARIANT*)); 156 STDMETHODNOTIMP(get_referrer, (BSTR*)); 157 STDMETHODNOTIMP(get_location, (IHTMLLocation**)); 158 STDMETHODNOTIMP(get_lastModified, (BSTR*)); 159 STDMETHODNOTIMP(put_URL, (BSTR)); 160 STDMETHODNOTIMP(get_URL, (BSTR*)); 161 STDMETHODNOTIMP(put_domain, (BSTR)); 162 STDMETHODNOTIMP(get_domain, (BSTR*)); 163 STDMETHODNOTIMP(put_cookie, (BSTR)); 164 STDMETHODNOTIMP(get_cookie, (BSTR*)); 165 STDMETHODNOTIMP(put_expando, (VARIANT_BOOL)); 166 STDMETHODNOTIMP(get_expando, (VARIANT_BOOL*)); 167 STDMETHODNOTIMP(put_charset, (BSTR)); 168 STDMETHODNOTIMP(get_charset, (BSTR*)); 169 STDMETHODNOTIMP(put_defaultCharset, (BSTR)); 170 STDMETHODNOTIMP(get_defaultCharset, (BSTR*)); 171 STDMETHODNOTIMP(get_mimeType, (BSTR*)); 172 STDMETHODNOTIMP(get_fileSize, (BSTR*)); 173 STDMETHODNOTIMP(get_fileCreatedDate, (BSTR*)); 174 STDMETHODNOTIMP(get_fileModifiedDate, (BSTR*)); 175 STDMETHODNOTIMP(get_fileUpdatedDate, (BSTR*)); 176 STDMETHODNOTIMP(get_security, (BSTR*)); 177 STDMETHODNOTIMP(get_protocol, (BSTR*)); 178 STDMETHODNOTIMP(get_nameProp, (BSTR*)); 179 STDMETHODNOTIMP(write, (SAFEARRAY*)); 180 STDMETHODNOTIMP(writeln, (SAFEARRAY*)); 181 STDMETHODNOTIMP(open, (BSTR, VARIANT, VARIANT, VARIANT, IDispatch**)); 182 STDMETHODNOTIMP(close, ()); 183 STDMETHODNOTIMP(clear, ()); 184 STDMETHODNOTIMP(queryCommandSupported, (BSTR, VARIANT_BOOL*)); 185 STDMETHODNOTIMP(queryCommandEnabled, (BSTR, VARIANT_BOOL*)); 186 STDMETHODNOTIMP(queryCommandState, (BSTR, VARIANT_BOOL*)); 187 STDMETHODNOTIMP(queryCommandIndeterm, (BSTR, VARIANT_BOOL*)); 188 STDMETHODNOTIMP(queryCommandText, (BSTR, BSTR*)); 189 STDMETHODNOTIMP(queryCommandValue, (BSTR, VARIANT*)); 190 STDMETHODNOTIMP(execCommand, (BSTR, VARIANT_BOOL, VARIANT, VARIANT_BOOL*)); 191 STDMETHODNOTIMP(execCommandShowHelp, (BSTR, VARIANT_BOOL*)); 192 STDMETHODNOTIMP(createElement, (BSTR, IHTMLElement**)); 193 STDMETHODNOTIMP(put_onhelp, (VARIANT)); 194 STDMETHODNOTIMP(get_onhelp, (VARIANT*)); 195 STDMETHODNOTIMP(put_onclick, (VARIANT)); 196 STDMETHODNOTIMP(get_onclick, (VARIANT*)); 197 STDMETHODNOTIMP(put_ondblclick, (VARIANT)); 198 STDMETHODNOTIMP(get_ondblclick, (VARIANT*)); 199 STDMETHODNOTIMP(put_onkeyup, (VARIANT)); 200 STDMETHODNOTIMP(get_onkeyup, (VARIANT*)); 201 STDMETHODNOTIMP(put_onkeydown, (VARIANT)); 202 STDMETHODNOTIMP(get_onkeydown, (VARIANT*)); 203 STDMETHODNOTIMP(put_onkeypress, (VARIANT)); 204 STDMETHODNOTIMP(get_onkeypress, (VARIANT*)); 205 STDMETHODNOTIMP(put_onmouseup, (VARIANT)); 206 STDMETHODNOTIMP(get_onmouseup, (VARIANT*)); 207 STDMETHODNOTIMP(put_onmousedown, (VARIANT)); 208 STDMETHODNOTIMP(get_onmousedown, (VARIANT*)); 209 STDMETHODNOTIMP(put_onmousemove, (VARIANT)); 210 STDMETHODNOTIMP(get_onmousemove, (VARIANT*)); 211 STDMETHODNOTIMP(put_onmouseout, (VARIANT)); 212 STDMETHODNOTIMP(get_onmouseout, (VARIANT*)); 213 STDMETHODNOTIMP(put_onmouseover, (VARIANT)); 214 STDMETHODNOTIMP(get_onmouseover, (VARIANT*)); 215 STDMETHODNOTIMP(put_onreadystatechange, (VARIANT)); 216 STDMETHODNOTIMP(get_onreadystatechange, (VARIANT*)); 217 STDMETHODNOTIMP(put_onafterupdate, (VARIANT)); 218 STDMETHODNOTIMP(get_onafterupdate, (VARIANT*)); 219 STDMETHODNOTIMP(put_onrowexit, (VARIANT)); 220 STDMETHODNOTIMP(get_onrowexit, (VARIANT*)); 221 STDMETHODNOTIMP(put_onrowenter, (VARIANT)); 222 STDMETHODNOTIMP(get_onrowenter, (VARIANT*)); 223 STDMETHODNOTIMP(put_ondragstart, (VARIANT)); 224 STDMETHODNOTIMP(get_ondragstart, (VARIANT*)); 225 STDMETHODNOTIMP(put_onselectstart, (VARIANT)); 226 STDMETHODNOTIMP(get_onselectstart, (VARIANT*)); 227 STDMETHODNOTIMP(elementFromPoint, (long, long, IHTMLElement**)); 228 STDMETHODNOTIMP(get_parentWindow, (IHTMLWindow2**)); 229 STDMETHODNOTIMP(get_styleSheets, (IHTMLStyleSheetsCollection**)); 230 STDMETHODNOTIMP(put_onbeforeupdate, (VARIANT)); 231 STDMETHODNOTIMP(get_onbeforeupdate, (VARIANT*)); 232 STDMETHODNOTIMP(put_onerrorupdate, (VARIANT)); 233 STDMETHODNOTIMP(get_onerrorupdate, (VARIANT*)); 234 STDMETHODNOTIMP(toString, (BSTR*)); 235 STDMETHODNOTIMP(createStyleSheet, (BSTR, long, IHTMLStyleSheet**)); 236 // IHTMLDocument4 237 STDMETHODNOTIMP(focus, ()); 238 STDMETHODNOTIMP(hasFocus, (VARIANT_BOOL*)); 239 STDMETHODNOTIMP(put_onselectionchange, (VARIANT)); 240 STDMETHODNOTIMP(get_onselectionchange, (VARIANT*)); 241 STDMETHODNOTIMP(get_namespaces, (IDispatch**)); 242 STDMETHODNOTIMP(createDocumentFromUrl, (BSTR, BSTR, IHTMLDocument2**)); 243 STDMETHODNOTIMP(put_media, (BSTR)); 244 STDMETHODNOTIMP(get_media, (BSTR*)); 245 STDMETHODNOTIMP(fireEvent, (BSTR, VARIANT*, VARIANT_BOOL*)); 246 STDMETHODNOTIMP(createRenderStyle, (BSTR, IHTMLRenderStyle**)); 247 STDMETHODNOTIMP(put_oncontrolselect, (VARIANT)); 248 STDMETHODNOTIMP(get_oncontrolselect, (VARIANT*)); 249 STDMETHODNOTIMP(get_URLUnencoded, (BSTR*)); 250 // IHTMLEventObj 251 STDMETHODNOTIMP(get_srcElement, (IHTMLElement**)) 252 STDMETHODNOTIMP(get_altKey, (VARIANT_BOOL*)); 253 STDMETHODNOTIMP(get_ctrlKey, (VARIANT_BOOL*)); 254 STDMETHODNOTIMP(get_shiftKey, (VARIANT_BOOL*)); 255 STDMETHODNOTIMP(put_returnValue, (VARIANT)); 256 STDMETHODNOTIMP(get_returnValue, (VARIANT*)); 257 STDMETHODNOTIMP(put_cancelBubble, (VARIANT_BOOL)); 258 STDMETHODNOTIMP(get_cancelBubble, (VARIANT_BOOL*)); 259 STDMETHODNOTIMP(get_fromElement, (IHTMLElement**)); 260 STDMETHODNOTIMP(get_toElement, (IHTMLElement**)); 261 STDMETHODNOTIMP(put_keyCode, (long)); 262 STDMETHODNOTIMP(get_keyCode, (long*)); 263 STDMETHODNOTIMP(get_button, (long*)); 264 STDMETHODNOTIMP(get_type, (BSTR*)); 265 STDMETHODNOTIMP(get_qualifier, (BSTR*)); 266 STDMETHODNOTIMP(get_reason, (long*)); 267 STDMETHODNOTIMP(get_x, (long*)); 268 STDMETHODNOTIMP(get_y, (long*)); 269 STDMETHODNOTIMP(get_clientX, (long*)); 270 STDMETHODNOTIMP(get_clientY, (long*)); 271 STDMETHODNOTIMP(get_offsetX, (long*)); 272 STDMETHODNOTIMP(get_offsetY, (long*)); 273 STDMETHODNOTIMP(get_screenX, (long*)); 274 STDMETHODNOTIMP(get_screenY, (long*)); 275 STDMETHODNOTIMP(get_srcFilter, (IDispatch**)); 276 #undef STDMETHODNOTIMP 277 }; 278 279 TEST(ComMessageEvent, WithSmartContainer) { 280 CComObject<MockSmartContainer>* container_obj = NULL; 281 CComObject<MockSmartContainer>::CreateInstance(&container_obj); 282 base::win::ScopedComPtr<IOleContainer> container(container_obj); 283 EXPECT_FALSE(!container); 284 285 CComObject<FriendlyComMessageEvent>* event_obj = NULL; 286 CComObject<FriendlyComMessageEvent>::CreateInstance(&event_obj); 287 base::win::ScopedComPtr<IUnknown> event_ref(event_obj); 288 289 bool succeeded = event_obj->Initialize(container, "hi", 290 "http://www.foo.com/", "message"); 291 EXPECT_TRUE(succeeded); 292 EXPECT_FALSE(!event_obj->basic_event()); 293 294 // Name handled natively by CF's ComMessageEvent. 295 DISPID dispid = -1; 296 LPOLESTR name = L"data"; 297 HRESULT hr = event_obj->GetIDsOfNames(IID_IDispatch, &name, 1, 298 LOCALE_USER_DEFAULT, &dispid); 299 EXPECT_HRESULT_SUCCEEDED(hr); 300 EXPECT_EQ(dispid, ComMessageEvent::DISPID_MESSAGE_EVENT_DATA); 301 302 // Name not handled by CF's ComMessageEvent. 303 dispid = -1; 304 name = L"nothandledatallbyanyone"; 305 hr = event_obj->GetIDsOfNames(IID_IDispatch, &name, 1, 306 LOCALE_USER_DEFAULT, &dispid); 307 EXPECT_HRESULT_SUCCEEDED(hr); 308 EXPECT_EQ(dispid, MockSmartContainer::kDispId); 309 310 // Invoke function handled by ComMessageEvent. 311 CComDispatchDriver dispatcher(event_obj); 312 CComVariant result; 313 hr = dispatcher.GetProperty(ComMessageEvent::DISPID_MESSAGE_EVENT_DATA, 314 &result); 315 EXPECT_HRESULT_SUCCEEDED(hr); 316 EXPECT_EQ(result.vt, VT_BSTR); 317 EXPECT_EQ(wcscmp(result.bstrVal, L"hi"), 0); 318 319 // And now check passthrough. 320 result.Clear(); 321 hr = dispatcher.GetProperty(MockSmartContainer::kDispId, &result); 322 EXPECT_HRESULT_SUCCEEDED(hr); 323 EXPECT_EQ(result.vt, VT_I4); 324 EXPECT_EQ(result.lVal, MockSmartContainer::kResultValue); 325 } 326