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.
13class FriendlyComMessageEvent : public ComMessageEvent {
14 public:
15  inline IHTMLEventObj* basic_event() { return basic_event_; }
16};
17
18class 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
42TEST(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.
62class 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
279TEST(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