mshtml: Fixed spaces handling in range object.
[wine] / dlls / mshtml / tests / dom.c
1 /*
2  * Copyright 2007 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #define COBJMACROS
20 #define CONST_VTABLE
21
22 #include <wine/test.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "ole2.h"
29 #include "mshtml.h"
30 #include "docobj.h"
31
32 static const char doc_blank[] = "<html></html>";
33 static const char doc_str1[] = "<html><body>test</body></html>";
34 static const char doc_str2[] =
35     "<html><body>test \na<font size=\"2\">bc\t123<br /> it's\r\n  \t</font>text<br /></body></html>";
36 static const char doc_str3[] =
37     "<html><head><title>test</title><body>"
38     "<a href=\"http://test\" name=\"x\">link</a><input />"
39     "<select id=\"s\"><option id=\"x\">opt1</option><option id=\"y\">opt2</option></select>"
40     "<textarea id=\"X\">text text</textarea>"
41     "</body></html>";
42
43 static const WCHAR noneW[] = {'N','o','n','e',0};
44
45 static WCHAR characterW[] = {'c','h','a','r','a','c','t','e','r',0};
46 static WCHAR texteditW[] = {'t','e','x','t','e','d','i','t',0};
47 static WCHAR wordW[] = {'w','o','r','d',0};
48
49 typedef enum {
50     ET_NONE,
51     ET_HTML,
52     ET_HEAD,
53     ET_TITLE,
54     ET_BODY,
55     ET_A,
56     ET_INPUT,
57     ET_SELECT,
58     ET_TEXTAREA,
59     ET_OPTION
60 } elem_type_t;
61
62 static REFIID const none_iids[] = {
63     &IID_IUnknown,
64     NULL
65 };
66
67 static REFIID const html_iids[] = {
68     &IID_IHTMLDOMNode,
69     &IID_IHTMLElement,
70     &IID_IHTMLElement2,
71     NULL
72 };
73
74 static REFIID const head_iids[] = {
75     &IID_IHTMLDOMNode,
76     &IID_IHTMLElement,
77     &IID_IHTMLElement2,
78     NULL
79 };
80
81 static REFIID const title_iids[] = {
82     &IID_IHTMLDOMNode,
83     &IID_IHTMLElement,
84     &IID_IHTMLElement2,
85     NULL
86 };
87
88 static REFIID const body_iids[] = {
89     &IID_IHTMLDOMNode,
90     &IID_IHTMLElement,
91     &IID_IHTMLElement2,
92     &IID_IHTMLTextContainer,
93     &IID_IHTMLBodyElement,
94     NULL
95 };
96
97 static REFIID const anchor_iids[] = {
98     &IID_IHTMLDOMNode,
99     &IID_IHTMLElement,
100     &IID_IHTMLElement2,
101     &IID_IHTMLAnchorElement,
102     NULL
103 };
104
105 static REFIID const input_iids[] = {
106     &IID_IHTMLDOMNode,
107     &IID_IHTMLElement,
108     &IID_IHTMLElement2,
109     &IID_IHTMLInputElement,
110     &IID_IHTMLInputTextElement,
111     NULL
112 };
113
114 static REFIID const select_iids[] = {
115     &IID_IHTMLDOMNode,
116     &IID_IHTMLElement,
117     &IID_IHTMLElement2,
118     &IID_IHTMLSelectElement,
119     NULL
120 };
121
122 static REFIID const textarea_iids[] = {
123     &IID_IHTMLDOMNode,
124     &IID_IHTMLElement,
125     &IID_IHTMLElement2,
126     &IID_IHTMLTextAreaElement,
127     NULL
128 };
129
130 static REFIID const option_iids[] = {
131     &IID_IHTMLDOMNode,
132     &IID_IHTMLElement,
133     &IID_IHTMLElement2,
134     &IID_IHTMLOptionElement,
135     NULL
136 };
137
138 typedef struct {
139     const char *tag;
140     REFIID *iids;
141 } elem_type_info_t;
142
143 static const elem_type_info_t elem_type_infos[] = {
144     {"",          none_iids},
145     {"HTML",      html_iids},
146     {"HEAD",      head_iids},
147     {"TITLE",     title_iids},
148     {"BODY",      body_iids},
149     {"A",         anchor_iids},
150     {"INPUT",     input_iids},
151     {"SELECT",    select_iids},
152     {"TEXTAREA",  textarea_iids},
153     {"OPTION",    option_iids}
154 };
155
156 static const char *dbgstr_w(LPCWSTR str)
157 {
158     static char buf[512];
159     if(!str)
160         return "(null)";
161     WideCharToMultiByte(CP_ACP, 0, str, -1, buf, sizeof(buf), NULL, NULL);
162     return buf;
163 }
164
165 static const char *dbgstr_guid(REFIID riid)
166 {
167     static char buf[50];
168
169     sprintf(buf, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
170             riid->Data1, riid->Data2, riid->Data3, riid->Data4[0],
171             riid->Data4[1], riid->Data4[2], riid->Data4[3], riid->Data4[4],
172             riid->Data4[5], riid->Data4[6], riid->Data4[7]);
173
174     return buf;
175 }
176
177 static int strcmp_wa(LPCWSTR strw, const char *stra)
178 {
179     WCHAR buf[512];
180     MultiByteToWideChar(CP_ACP, 0, stra, -1, buf, sizeof(buf)/sizeof(WCHAR));
181     return lstrcmpW(strw, buf);
182 }
183
184 static BSTR a2bstr(const char *str)
185 {
186     BSTR ret;
187     int len;
188
189     len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
190     ret = SysAllocStringLen(NULL, len);
191     MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
192
193     return ret;
194 }
195
196 static IHTMLDocument2 *create_document(void)
197 {
198     IHTMLDocument2 *doc;
199     HRESULT hres;
200
201     hres = CoCreateInstance(&CLSID_HTMLDocument, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
202             &IID_IHTMLDocument2, (void**)&doc);
203     ok(hres == S_OK, "CoCreateInstance failed: %08x\n", hres);
204
205     return doc;
206 }
207
208 #define test_ifaces(i,ids) _test_ifaces(__LINE__,i,ids)
209 static void _test_ifaces(unsigned line, IUnknown *iface, REFIID *iids)
210 {
211     const IID * const *piid;
212     IUnknown *unk;
213     HRESULT hres;
214
215      for(piid = iids; *piid; piid++) {
216         hres = IDispatch_QueryInterface(iface, *piid, (void**)&unk);
217         ok_(__FILE__,line) (hres == S_OK, "Could not get %s interface: %08x\n", dbgstr_guid(*piid), hres);
218         if(SUCCEEDED(hres))
219             IUnknown_Release(unk);
220     }
221 }
222
223 #define test_node_name(u,n) _test_node_name(__LINE__,u,n)
224 static void _test_node_name(unsigned line, IUnknown *unk, const char *exname)
225 {
226     IHTMLDOMNode *node;
227     BSTR name;
228     HRESULT hres;
229
230     hres = IUnknown_QueryInterface(unk, &IID_IHTMLDOMNode, (void**)&node);
231     ok_(__FILE__, line) (hres == S_OK, "QueryInterface(IID_IHTMLNode) failed: %08x\n", hres);
232
233     hres = IHTMLDOMNode_get_nodeName(node, &name);
234     IHTMLDOMNode_Release(node);
235     ok_(__FILE__, line) (hres == S_OK, "get_nodeName failed: %08x\n", hres);
236     ok_(__FILE__, line) (!strcmp_wa(name, exname), "got name: %s, expected %s\n", dbgstr_w(name), exname);
237
238     SysFreeString(name);
239 }
240
241 #define test_elem_tag(u,n) _test_elem_tag(__LINE__,u,n)
242 static void _test_elem_tag(unsigned line, IUnknown *unk, const char *extag)
243 {
244     IHTMLElement *elem;
245     BSTR tag;
246     HRESULT hres;
247
248     hres = IUnknown_QueryInterface(unk, &IID_IHTMLElement, (void**)&elem);
249     ok_(__FILE__, line) (hres == S_OK, "QueryInterface(IID_IHTMLElement) failed: %08x\n", hres);
250
251     hres = IHTMLElement_get_tagName(elem, &tag);
252     IHTMLElement_Release(elem);
253     ok_(__FILE__, line) (hres == S_OK, "get_tagName failed: %08x\n", hres);
254     ok_(__FILE__, line) (!strcmp_wa(tag, extag), "got tag: %s, expected %s\n", dbgstr_w(tag), extag);
255
256     SysFreeString(tag);
257 }
258
259 #define test_elem_type(ifc,t) _test_elem_type(__LINE__,ifc,t)
260 static void _test_elem_type(unsigned line, IUnknown *unk, elem_type_t type)
261 {
262     _test_elem_tag(line, unk, elem_type_infos[type].tag);
263     _test_ifaces(line, unk, elem_type_infos[type].iids);
264 }
265
266 static void test_doc_elem(IHTMLDocument2 *doc)
267 {
268     IHTMLElement *elem;
269     IHTMLDocument3 *doc3;
270     HRESULT hres;
271
272     hres = IHTMLDocument2_QueryInterface(doc, &IID_IHTMLDocument3, (void**)&doc3);
273     ok(hres == S_OK, "QueryInterface(IID_IHTMLDocument3) failed: %08x\n", hres);
274
275     hres = IHTMLDocument3_get_documentElement(doc3, &elem);
276     IHTMLDocument3_Release(doc3);
277     ok(hres == S_OK, "get_documentElement failed: %08x\n", hres);
278
279     test_node_name((IUnknown*)elem, "HTML");
280     test_elem_tag((IUnknown*)elem, "HTML");
281
282     IHTMLElement_Release(elem);
283 }
284
285 #define get_doc_elem(d) _get_doc_elem(__LINE__,d)
286 static IHTMLElement *_get_doc_elem(unsigned line, IHTMLDocument2 *doc)
287 {
288     IHTMLElement *elem;
289     IHTMLDocument3 *doc3;
290     HRESULT hres;
291
292     hres = IHTMLDocument2_QueryInterface(doc, &IID_IHTMLDocument3, (void**)&doc3);
293     ok_(__FILE__,line) (hres == S_OK, "Could not get IHTMLDocument3 interface: %08x\n", hres);
294     hres = IHTMLDocument3_get_documentElement(doc3, &elem);
295     ok_(__FILE__,line) (hres == S_OK, "get_documentElement failed: %08x\n", hres);
296     IHTMLDocument3_Release(doc3);
297
298     return elem;
299 }
300
301 #define test_option_text(o,t) _test_option_text(__LINE__,o,t)
302 static void _test_option_text(unsigned line, IHTMLOptionElement *option, const char *text)
303 {
304     BSTR bstr;
305     HRESULT hres;
306
307     hres = IHTMLOptionElement_get_text(option, &bstr);
308     ok_(__FILE__,line) (hres == S_OK, "get_text failed: %08x\n", hres);
309     ok_(__FILE__,line) (!strcmp_wa(bstr, text), "text=%s\n", dbgstr_w(bstr));
310     SysFreeString(bstr);
311 }
312
313 #define test_option_put_text(o,t) _test_option_put_text(__LINE__,o,t)
314 static void _test_option_put_text(unsigned line, IHTMLOptionElement *option, const char *text)
315 {
316     BSTR bstr;
317     HRESULT hres;
318
319     bstr = a2bstr(text);
320     hres = IHTMLOptionElement_put_text(option, bstr);
321     SysFreeString(bstr);
322     ok(hres == S_OK, "put_text failed: %08x\n", hres);
323
324     _test_option_text(line, option, text);
325 }
326
327 #define test_option_value(o,t) _test_option_value(__LINE__,o,t)
328 static void _test_option_value(unsigned line, IHTMLOptionElement *option, const char *value)
329 {
330     BSTR bstr;
331     HRESULT hres;
332
333     hres = IHTMLOptionElement_get_value(option, &bstr);
334     ok_(__FILE__,line) (hres == S_OK, "get_value failed: %08x\n", hres);
335     ok_(__FILE__,line) (!strcmp_wa(bstr, value), "value=%s\n", dbgstr_w(bstr));
336     SysFreeString(bstr);
337 }
338
339 #define test_option_put_value(o,t) _test_option_put_value(__LINE__,o,t)
340 static void _test_option_put_value(unsigned line, IHTMLOptionElement *option, const char *value)
341 {
342     BSTR bstr;
343     HRESULT hres;
344
345     bstr = a2bstr(value);
346     hres = IHTMLOptionElement_put_value(option, bstr);
347     SysFreeString(bstr);
348     ok(hres == S_OK, "put_value failed: %08x\n", hres);
349
350     _test_option_value(line, option, value);
351 }
352
353 #define create_option_elem(d,t,v) _create_option_elem(__LINE__,d,t,v)
354 static IHTMLOptionElement *_create_option_elem(unsigned line, IHTMLDocument2 *doc,
355         const char *txt, const char *val)
356 {
357     IHTMLOptionElementFactory *factory;
358     IHTMLOptionElement *option;
359     IHTMLWindow2 *window;
360     VARIANT text, value, empty;
361     HRESULT hres;
362
363     hres = IHTMLDocument2_get_parentWindow(doc, &window);
364     ok_(__FILE__,line) (hres == S_OK, "get_parentElement failed: %08x\n", hres);
365
366     hres = IHTMLWindow2_get_Option(window, &factory);
367     IHTMLWindow2_Release(window);
368     ok_(__FILE__,line) (hres == S_OK, "get_Option failed: %08x\n", hres);
369
370     V_VT(&text) = VT_BSTR;
371     V_BSTR(&text) = a2bstr(txt);
372     V_VT(&value) = VT_BSTR;
373     V_BSTR(&value) = a2bstr(val);
374     V_VT(&empty) = VT_EMPTY;
375
376     hres = IHTMLOptionElementFactory_create(factory, text, value, empty, empty, &option);
377     ok_(__FILE__,line) (hres == S_OK, "create failed: %08x\n", hres);
378
379     IHTMLOptionElementFactory_Release(factory);
380     VariantClear(&text);
381     VariantClear(&value);
382
383     _test_option_text(line, option, txt);
384     _test_option_value(line, option, val);
385
386     return option;
387 }
388
389 #define test_select_length(s,l) _test_select_length(__LINE__,s,l)
390 static void _test_select_length(unsigned line, IHTMLSelectElement *select, long length)
391 {
392     long len = 0xdeadbeef;
393     HRESULT hres;
394
395     hres = IHTMLSelectElement_get_length(select, &len);
396     ok_(__FILE__,line) (hres == S_OK, "get_length failed: %08x\n", hres);
397     ok_(__FILE__,line) (len == length, "len=%ld, expected %ld\n", len, length);
398 }
399
400 #define test_select_selidx(s,i) _test_select_selidx(__LINE__,s,i)
401 static void _test_select_selidx(unsigned line, IHTMLSelectElement *select, long index)
402 {
403     long idx = 0xdeadbeef;
404     HRESULT hres;
405
406     hres = IHTMLSelectElement_get_selectedIndex(select, &idx);
407     ok_(__FILE__,line) (hres == S_OK, "get_selectedIndex failed: %08x\n", hres);
408     ok_(__FILE__,line) (idx == index, "idx=%ld, expected %ld\n", idx, index);
409 }
410
411 #define test_select_put_selidx(s,i) _test_select_put_selidx(__LINE__,s,i)
412 static void _test_select_put_selidx(unsigned line, IHTMLSelectElement *select, long index)
413 {
414     HRESULT hres;
415
416     hres = IHTMLSelectElement_put_selectedIndex(select, index);
417     ok_(__FILE__,line) (hres == S_OK, "get_selectedIndex failed: %08x\n", hres);
418     _test_select_selidx(line, select, index);
419 }
420
421 #define test_range_text(r,t) _test_range_text(__LINE__,r,t)
422 static void _test_range_text(unsigned line, IHTMLTxtRange *range, const char *extext)
423 {
424     BSTR text;
425     HRESULT hres;
426
427     hres = IHTMLTxtRange_get_text(range, &text);
428     ok_(__FILE__, line) (hres == S_OK, "get_text failed: %08x\n", hres);
429
430     if(extext) {
431         ok_(__FILE__, line) (text != NULL, "text == NULL\n");
432         ok_(__FILE__, line) (!strcmp_wa(text, extext), "text=\"%s\", expected \"%s\"\n", dbgstr_w(text), extext);
433     }else {
434         ok_(__FILE__, line) (text == NULL, "text=\"%s\", expected NULL\n", dbgstr_w(text));
435     }
436
437     SysFreeString(text);
438
439 }
440
441 #define test_range_collapse(r,b) _test_range_collapse(__LINE__,r,b)
442 static void _test_range_collapse(unsigned line, IHTMLTxtRange *range, BOOL b)
443 {
444     HRESULT hres;
445
446     hres = IHTMLTxtRange_collapse(range, b);
447     ok_(__FILE__, line) (hres == S_OK, "collapse failed: %08x\n", hres);
448     _test_range_text(line, range, NULL);
449 }
450
451 #define test_range_expand(r,u,b,t) _test_range_expand(__LINE__,r,u,b,t)
452 static void _test_range_expand(unsigned line, IHTMLTxtRange *range, LPWSTR unit,
453         VARIANT_BOOL exb, const char *extext)
454 {
455     VARIANT_BOOL b = 0xe0e0;
456     HRESULT hres;
457
458     hres = IHTMLTxtRange_expand(range, unit, &b);
459     ok_(__FILE__,line) (hres == S_OK, "expand failed: %08x\n", hres);
460     ok_(__FILE__,line) (b == exb, "b=%x, expected %x\n", b, exb);
461     _test_range_text(line, range, extext);
462 }
463
464 #define test_range_move(r,u,c,e) _test_range_move(__LINE__,r,u,c,e)
465 static void _test_range_move(unsigned line, IHTMLTxtRange *range, LPWSTR unit, long cnt, long excnt)
466 {
467     long c = 0xdeadbeef;
468     HRESULT hres;
469
470     hres = IHTMLTxtRange_move(range, unit, cnt, &c);
471     ok_(__FILE__,line) (hres == S_OK, "move failed: %08x\n", hres);
472     ok_(__FILE__,line) (c == excnt, "count=%ld, expected %ld\n", c, excnt);
473     _test_range_text(line, range, NULL);
474 }
475
476 #define test_range_movestart(r,u,c,e) _test_range_movestart(__LINE__,r,u,c,e)
477 static void _test_range_movestart(unsigned line, IHTMLTxtRange *range,
478         LPWSTR unit, long cnt, long excnt)
479 {
480     long c = 0xdeadbeef;
481     HRESULT hres;
482
483     hres = IHTMLTxtRange_moveStart(range, unit, cnt, &c);
484     ok_(__FILE__,line) (hres == S_OK, "move failed: %08x\n", hres);
485     ok_(__FILE__,line) (c == excnt, "count=%ld, expected %ld\n", c, excnt);
486 }
487
488 #define test_range_moveend(r,u,c,e) _test_range_moveend(__LINE__,r,u,c,e)
489 static void _test_range_moveend(unsigned line, IHTMLTxtRange *range, LPWSTR unit, long cnt, long excnt)
490 {
491     long c = 0xdeadbeef;
492     HRESULT hres;
493
494     hres = IHTMLTxtRange_moveEnd(range, unit, cnt, &c);
495     ok_(__FILE__,line) (hres == S_OK, "move failed: %08x\n", hres);
496     ok_(__FILE__,line) (c == excnt, "count=%ld, expected %ld\n", c, excnt);
497 }
498
499 #define test_range_put_text(r,t) _test_range_put_text(__LINE__,r,t)
500 static void _test_range_put_text(unsigned line, IHTMLTxtRange *range, LPCWSTR text)
501 {
502     HRESULT hres;
503
504     hres = IHTMLTxtRange_put_text(range, (BSTR)text);
505     ok_(__FILE__,line) (hres == S_OK, "put_text failed: %08x\n", hres);
506     _test_range_text(line, range, NULL);
507 }
508
509 #define test_range_inrange(r1,r2,b) _test_range_inrange(__LINE__,r1,r2,b)
510 static void _test_range_inrange(unsigned line, IHTMLTxtRange *range1, IHTMLTxtRange *range2, VARIANT_BOOL exb)
511 {
512     VARIANT_BOOL b;
513     HRESULT hres;
514
515     b = 0xe0e0;
516     hres = IHTMLTxtRange_inRange(range1, range2, &b);
517     ok_(__FILE__,line) (hres == S_OK, "(1->2) isEqual failed: %08x\n", hres);
518     ok_(__FILE__,line) (b == exb, "(1->2) b=%x, expected %x\n", b, exb);
519 }
520
521 #define test_range_isequal(r1,r2,b) _test_range_isequal(__LINE__,r1,r2,b)
522 static void _test_range_isequal(unsigned line, IHTMLTxtRange *range1, IHTMLTxtRange *range2, VARIANT_BOOL exb)
523 {
524     VARIANT_BOOL b;
525     HRESULT hres;
526
527     b = 0xe0e0;
528     hres = IHTMLTxtRange_isEqual(range1, range2, &b);
529     ok_(__FILE__,line) (hres == S_OK, "(1->2) isEqual failed: %08x\n", hres);
530     ok_(__FILE__,line) (b == exb, "(1->2) b=%x, expected %x\n", b, exb);
531
532     b = 0xe0e0;
533     hres = IHTMLTxtRange_isEqual(range2, range1, &b);
534     ok_(__FILE__,line) (hres == S_OK, "(2->1) isEqual failed: %08x\n", hres);
535     ok_(__FILE__,line) (b == exb, "(2->1) b=%x, expected %x\n", b, exb);
536
537     if(exb) {
538         test_range_inrange(range1, range2, VARIANT_TRUE);
539         test_range_inrange(range2, range1, VARIANT_TRUE);
540     }
541 }
542
543 #define test_range_parent(r,t) _test_range_parent(__LINE__,r,t)
544 static void _test_range_parent(unsigned line, IHTMLTxtRange *range, elem_type_t type)
545 {
546     IHTMLElement *elem;
547     HRESULT hres;
548
549     hres = IHTMLTxtRange_parentElement(range, &elem);
550     ok_(__FILE__,line) (hres == S_OK, "parentElement failed: %08x\n", hres);
551
552     _test_elem_type(line, (IUnknown*)elem, type);
553
554     IHTMLElement_Release(elem);
555 }
556
557 static void test_elem_collection(IHTMLElementCollection *col, const elem_type_t *elem_types, long exlen)
558 {
559     long len;
560     DWORD i;
561     VARIANT name, index;
562     IDispatch *disp;
563     HRESULT hres;
564
565     hres = IHTMLElementCollection_get_length(col, &len);
566     ok(hres == S_OK, "get_length failed: %08x\n", hres);
567     ok(len == exlen, "len=%ld, expected %ld\n", len, exlen);
568
569     V_VT(&index) = VT_EMPTY;
570     V_VT(&name) = VT_I4;
571
572     for(i=0; i<len; i++) {
573         V_I4(&name) = i;
574         disp = (void*)0xdeadbeef;
575         hres = IHTMLElementCollection_item(col, name, index, &disp);
576         ok(hres == S_OK, "item(%d) failed: %08x\n", i, hres);
577         ok(disp != NULL, "item returned NULL\n");
578         if(FAILED(hres) || !disp)
579             continue;
580
581         test_elem_type((IUnknown*)disp, elem_types[i]);
582         IDispatch_Release(disp);
583     }
584
585     V_I4(&name) = len;
586     disp = (void*)0xdeadbeef;
587     hres = IHTMLElementCollection_item(col, name, index, &disp);
588     ok(hres == S_OK, "item failed: %08x\n", hres);
589     ok(disp == NULL, "disp != NULL\n");
590
591     V_I4(&name) = -1;
592     disp = (void*)0xdeadbeef;
593     hres = IHTMLElementCollection_item(col, name, index, &disp);
594     ok(hres == E_INVALIDARG, "item failed: %08x, expected E_INVALIDARG\n", hres);
595     ok(disp == NULL, "disp != NULL\n");
596 }
597
598 static void test_elem_col_item(IHTMLElementCollection *col, LPCWSTR n,
599         const elem_type_t *elem_types, long len)
600 {
601     IHTMLElementCollection *elcol;
602     IDispatch *disp;
603     VARIANT name, index;
604     DWORD i;
605     HRESULT hres;
606
607     V_VT(&index) = VT_EMPTY;
608     V_VT(&name) = VT_BSTR;
609     V_BSTR(&name) = SysAllocString(n);
610
611     hres = IHTMLElementCollection_item(col, name, index, &disp);
612     ok(hres == S_OK, "item failed: %08x\n", hres);
613
614     hres = IDispatch_QueryInterface(disp, &IID_IHTMLElementCollection, (void**)&elcol);
615     IDispatch_Release(disp);
616     ok(hres == S_OK, "Could not get IHTMLElementCollection interface: %08x\n", hres);
617     test_elem_collection(elcol, elem_types, len);
618     IHTMLElementCollection_Release(elcol);
619
620     V_VT(&index) = VT_I4;
621
622     for(i=0; i<len; i++) {
623         V_I4(&index) = i;
624         disp = (void*)0xdeadbeef;
625         hres = IHTMLElementCollection_item(col, name, index, &disp);
626         ok(hres == S_OK, "item failed: %08x\n", hres);
627         ok(disp != NULL, "disp == NULL\n");
628         if(FAILED(hres) || !disp)
629             continue;
630
631         test_elem_type((IUnknown*)disp, elem_types[i]);
632
633         IDispatch_Release(disp);
634     }
635
636     V_I4(&index) = len;
637     disp = (void*)0xdeadbeef;
638     hres = IHTMLElementCollection_item(col, name, index, &disp);
639     ok(hres == S_OK, "item failed: %08x\n", hres);
640     ok(disp == NULL, "disp != NULL\n");
641
642     V_I4(&index) = -1;
643     disp = (void*)0xdeadbeef;
644     hres = IHTMLElementCollection_item(col, name, index, &disp);
645     ok(hres == E_INVALIDARG, "item failed: %08x, expected E_INVALIDARG\n", hres);
646     ok(disp == NULL, "disp != NULL\n");
647
648     SysFreeString(V_BSTR(&name));
649 }
650
651 static IHTMLElement *get_elem_by_id(IHTMLDocument2 *doc, LPCWSTR id, BOOL expect_success)
652 {
653     IHTMLElementCollection *col;
654     IHTMLElement *elem;
655     IDispatch *disp = (void*)0xdeadbeef;
656     VARIANT name, index;
657     HRESULT hres;
658
659     hres = IHTMLDocument2_get_all(doc, &col);
660     ok(hres == S_OK, "get_all failed: %08x\n", hres);
661     ok(col != NULL, "col == NULL\n");
662     if(FAILED(hres) || !col)
663         return NULL;
664
665     V_VT(&index) = VT_EMPTY;
666     V_VT(&name) = VT_BSTR;
667     V_BSTR(&name) = SysAllocString(id);
668
669     hres = IHTMLElementCollection_item(col, name, index, &disp);
670     IHTMLElementCollection_Release(col);
671     SysFreeString(V_BSTR(&name));
672     ok(hres == S_OK, "item failed: %08x\n", hres);
673     if(!expect_success) {
674         ok(disp == NULL, "disp != NULL\n");
675         return NULL;
676     }
677
678     ok(disp != NULL, "disp == NULL\n");
679     if(!disp)
680         return NULL;
681
682     hres = IDispatch_QueryInterface(disp, &IID_IHTMLElement, (void**)&elem);
683     IDispatch_Release(disp);
684     ok(hres == S_OK, "Could not get IHTMLElement interface: %08x\n", hres);
685
686     return elem;
687 }
688
689 static void test_select_elem(IHTMLSelectElement *select)
690 {
691     test_select_length(select, 2);
692     test_select_selidx(select, 0);
693     test_select_put_selidx(select, 1);
694 }
695
696 static void test_create_option_elem(IHTMLDocument2 *doc)
697 {
698     IHTMLOptionElement *option;
699
700     option = create_option_elem(doc, "test text", "test value");
701
702     test_option_put_text(option, "new text");
703     test_option_put_value(option, "new value");
704
705     IHTMLOptionElement_Release(option);
706 }
707
708 static void test_txtrange(IHTMLDocument2 *doc)
709 {
710     IHTMLElement *elem;
711     IHTMLBodyElement *body;
712     IHTMLTxtRange *body_range, *range, *range2;
713     IHTMLSelectionObject *selection;
714     IDispatch *disp_range;
715     HRESULT hres;
716
717     hres = IHTMLDocument2_get_body(doc, &elem);
718     ok(hres == S_OK, "get_body failed: %08x\n", hres);
719
720     hres = IHTMLElement_QueryInterface(elem, &IID_IHTMLBodyElement, (void**)&body);
721     IHTMLElement_Release(elem);
722
723     hres = IHTMLBodyElement_createTextRange(body, &body_range);
724     IHTMLBodyElement_Release(body);
725     ok(hres == S_OK, "createTextRange failed: %08x\n", hres);
726
727     test_range_text(body_range, "test abc 123\r\nit's text");
728
729     hres = IHTMLTxtRange_duplicate(body_range, &range);
730     ok(hres == S_OK, "duplicate failed: %08x\n", hres);
731
732     hres = IHTMLTxtRange_duplicate(body_range, &range2);
733     ok(hres == S_OK, "duplicate failed: %08x\n", hres);
734     test_range_isequal(range, range2, VARIANT_TRUE);
735
736     test_range_text(range, "test abc 123\r\nit's text");
737     test_range_text(body_range, "test abc 123\r\nit's text");
738
739     test_range_collapse(range, TRUE);
740     test_range_isequal(range, range2, VARIANT_FALSE);
741     test_range_inrange(range, range2, VARIANT_FALSE);
742     test_range_inrange(range2, range, VARIANT_TRUE);
743     IHTMLTxtRange_Release(range2);
744
745     test_range_expand(range, wordW, VARIANT_TRUE, "test ");
746     test_range_expand(range, wordW, VARIANT_FALSE, "test ");
747     test_range_move(range, characterW, 2, 2);
748     test_range_expand(range, wordW, VARIANT_TRUE, "test ");
749
750     test_range_collapse(range, FALSE);
751     test_range_expand(range, wordW, VARIANT_TRUE, "abc ");
752
753     test_range_collapse(range, FALSE);
754     test_range_expand(range, wordW, VARIANT_TRUE, "123");
755     test_range_expand(range, wordW, VARIANT_FALSE, "123");
756     test_range_move(range, characterW, 2, 2);
757     test_range_expand(range, wordW, VARIANT_TRUE, "123");
758     test_range_moveend(range, characterW, -5, -5);
759     test_range_text(range, NULL);
760     test_range_moveend(range, characterW, 3, 3);
761     test_range_text(range, "c 1");
762
763     IHTMLTxtRange_Release(range);
764
765     hres = IHTMLTxtRange_duplicate(body_range, &range);
766     ok(hres == S_OK, "duplicate failed: %08x\n", hres);
767
768     test_range_text(range, "test abc 123\r\nit's text");
769     test_range_move(range, characterW, 3, 3);
770     test_range_moveend(range, characterW, 1, 1);
771     test_range_text(range, "t");
772     test_range_moveend(range, characterW, 3, 3);
773     test_range_text(range, "t ab");
774     test_range_moveend(range, characterW, -2, -2);
775     test_range_text(range, "t ");
776     test_range_move(range, characterW, 6, 6);
777     test_range_moveend(range, characterW, 3, 3);
778     test_range_text(range, "123");
779     test_range_moveend(range, characterW, 2, 2);
780     test_range_text(range, "123\r\ni");
781
782     IHTMLTxtRange_Release(range);
783
784     hres = IHTMLTxtRange_duplicate(body_range, &range);
785     ok(hres == S_OK, "duplicate failed: %08x\n", hres);
786
787     test_range_move(range, wordW, 1, 1);
788     test_range_moveend(range, characterW, 2, 2);
789     test_range_text(range, "ab");
790
791     test_range_move(range, characterW, -2, -2);
792     test_range_moveend(range, characterW, 2, 2);
793     test_range_text(range, "t ");
794
795     test_range_move(range, wordW, 3, 3);
796     test_range_move(range, wordW, -2, -2);
797     test_range_moveend(range, characterW, 2, 2);
798     test_range_text(range, "ab");
799
800     test_range_move(range, characterW, -6, -5);
801     test_range_moveend(range, characterW, -1, 0);
802     test_range_moveend(range, characterW, -6, 0);
803     test_range_move(range, characterW, 2, 2);
804     test_range_moveend(range, characterW, 2, 2);
805     test_range_text(range, "st");
806     test_range_moveend(range, characterW, -6, -4);
807     test_range_moveend(range, characterW, 2, 2);
808
809     IHTMLTxtRange_Release(range);
810
811     hres = IHTMLTxtRange_duplicate(body_range, &range);
812     ok(hres == S_OK, "duplicate failed: %08x\n", hres);
813
814     test_range_move(range, wordW, 2, 2);
815     test_range_moveend(range, characterW, 2, 2);
816     test_range_text(range, "12");
817
818     test_range_move(range, characterW, 15, 14);
819     test_range_move(range, characterW, -2, -2);
820     test_range_moveend(range, characterW, 3, 2);
821     test_range_text(range, "t");
822     test_range_moveend(range, characterW, -1, -1);
823     test_range_text(range, "t");
824     test_range_expand(range, wordW, VARIANT_TRUE, "text");
825     test_range_move(range, characterW, -2, -2);
826     test_range_moveend(range, characterW, 2, 2);
827     test_range_text(range, "s ");
828     test_range_move(range, characterW, 100, 7);
829     test_range_move(range, wordW, 1, 0);
830     test_range_move(range, characterW, -2, -2);
831     test_range_moveend(range, characterW, 3, 2);
832     test_range_text(range, "t");
833
834     IHTMLTxtRange_Release(range);
835
836     hres = IHTMLTxtRange_duplicate(body_range, &range);
837     ok(hres == S_OK, "duplicate failed: %08x\n", hres);
838
839     test_range_collapse(range, TRUE);
840     test_range_expand(range, wordW, VARIANT_TRUE, "test ");
841     test_range_put_text(range, wordW);
842     test_range_text(body_range, "wordabc 123\r\nit's text");
843     test_range_text(range, NULL);
844     test_range_moveend(range, characterW, 3, 3);
845     test_range_text(range, "abc");
846     test_range_movestart(range, characterW, -2, -2);
847     test_range_text(range, "rdabc");
848     test_range_movestart(range, characterW, 3, 3);
849     test_range_text(range, "bc");
850     test_range_movestart(range, characterW, 4, 4);
851     test_range_text(range, NULL);
852     test_range_movestart(range, characterW, -3, -3);
853     test_range_text(range, "c 1");
854     test_range_movestart(range, characterW, -7, -6);
855     test_range_text(range, "wordabc 1");
856     test_range_movestart(range, characterW, 100, 22);
857     test_range_text(range, NULL);
858
859     IHTMLTxtRange_Release(range);
860     IHTMLTxtRange_Release(body_range);
861
862     hres = IHTMLDocument2_get_selection(doc, &selection);
863     ok(hres == S_OK, "IHTMLDocument2_get_selection failed: %08x\n", hres);
864
865     hres = IHTMLSelectionObject_createRange(selection, &disp_range);
866     ok(hres == S_OK, "IHTMLSelectionObject_createRange failed: %08x\n", hres);
867     IHTMLSelectionObject_Release(selection);
868
869     hres = IDispatch_QueryInterface(disp_range, &IID_IHTMLTxtRange, (void **)&range);
870     ok(hres == S_OK, "Could not get IID_IHTMLTxtRange interface: 0x%08x\n", hres);
871     IDispatch_Release(disp_range);
872
873     test_range_text(range, NULL);
874     test_range_moveend(range, characterW, 3, 3);
875     test_range_text(range, "wor");
876     test_range_parent(range, ET_BODY);
877     test_range_expand(range, texteditW, VARIANT_TRUE, "wordabc 123\r\nit's text");
878     test_range_expand(range, texteditW, VARIANT_TRUE, "wordabc 123\r\nit's text");
879     test_range_move(range, characterW, 3, 3);
880     test_range_expand(range, wordW, VARIANT_TRUE, "wordabc ");
881
882     IHTMLTxtRange_Release(range);
883 }
884
885 static void test_compatmode(IHTMLDocument2 *doc)
886 {
887     IHTMLDocument5 *doc5;
888     BSTR mode;
889     HRESULT hres;
890
891     hres = IHTMLDocument2_QueryInterface(doc, &IID_IHTMLDocument5, (void**)&doc5);
892     ok(hres == S_OK, "Could not get IHTMLDocument5 interface: %08x\n", hres);
893     if(FAILED(hres))
894         return;
895
896     hres = IHTMLDocument5_get_compatMode(doc5, &mode);
897     IHTMLDocument5_Release(doc5);
898     ok(hres == S_OK, "get_compatMode failed: %08x\n", hres);
899     ok(!strcmp_wa(mode, "BackCompat"), "compatMode=%s\n", dbgstr_w(mode));
900     SysFreeString(mode);
901 }
902
903 static void test_default_style(IHTMLStyle *style)
904 {
905     VARIANT_BOOL b;
906     VARIANT v;
907     BSTR str;
908     HRESULT hres;
909
910     str = (void*)0xdeadbeef;
911     hres = IHTMLStyle_get_fontFamily(style, &str);
912     ok(hres == S_OK, "get_fontFamily failed: %08x\n", hres);
913     ok(!str, "fontFamily = %s\n", dbgstr_w(str));
914
915     str = (void*)0xdeadbeef;
916     hres = IHTMLStyle_get_fontWeight(style, &str);
917     ok(hres == S_OK, "get_fontWeight failed: %08x\n", hres);
918     ok(!str, "fontWeight = %s\n", dbgstr_w(str));
919
920     str = (void*)0xdeadbeef;
921     hres = IHTMLStyle_get_display(style, &str);
922     ok(hres == S_OK, "get_display failed: %08x\n", hres);
923     ok(!str, "display = %s\n", dbgstr_w(str));
924
925     str = (void*)0xdeadbeef;
926     hres = IHTMLStyle_get_visibility(style, &str);
927     ok(hres == S_OK, "get_visibility failed: %08x\n", hres);
928     ok(!str, "visibility = %s\n", dbgstr_w(str));
929
930     V_VT(&v) = VT_NULL;
931     hres = IHTMLStyle_get_fontSize(style, &v);
932     ok(hres == S_OK, "get_fontSize failed: %08x\n", hres);
933     ok(V_VT(&v) == VT_BSTR, "V_VT(fontSize) = %d\n", V_VT(&v));
934     ok(!V_BSTR(&v), "V_BSTR(fontSize) = %s\n", dbgstr_w(V_BSTR(&v)));
935
936     V_VT(&v) = VT_NULL;
937     hres = IHTMLStyle_get_color(style, &v);
938     ok(hres == S_OK, "get_color failed: %08x\n", hres);
939     ok(V_VT(&v) == VT_BSTR, "V_VT(color) = %d\n", V_VT(&v));
940     ok(!V_BSTR(&v), "V_BSTR(color) = %s\n", dbgstr_w(V_BSTR(&v)));
941
942     b = 0xfefe;
943     hres = IHTMLStyle_get_textDecorationUnderline(style, &b);
944     ok(hres == S_OK, "get_textDecorationUnderline failed: %08x\n", hres);
945     ok(b == VARIANT_FALSE, "textDecorationUnderline = %x\n", b);
946
947     b = 0xfefe;
948     hres = IHTMLStyle_get_textDecorationLineThrough(style, &b);
949     ok(hres == S_OK, "get_textDecorationLineThrough failed: %08x\n", hres);
950     ok(b == VARIANT_FALSE, "textDecorationLineThrough = %x\n", b);
951 }
952
953 static void test_default_selection(IHTMLDocument2 *doc)
954 {
955     IHTMLSelectionObject *selection;
956     IHTMLTxtRange *range;
957     IDispatch *disp;
958     BSTR str;
959     HRESULT hres;
960
961     hres = IHTMLDocument2_get_selection(doc, &selection);
962     ok(hres == S_OK, "get_selection failed: %08x\n", hres);
963
964     hres = IHTMLSelectionObject_get_type(selection, &str);
965     ok(hres == S_OK, "get_type failed: %08x\n", hres);
966     ok(!lstrcmpW(str, noneW), "type = %s\n", dbgstr_w(str));
967     SysFreeString(str);
968
969     hres = IHTMLSelectionObject_createRange(selection, &disp);
970     IHTMLSelectionObject_Release(selection);
971     ok(hres == S_OK, "createRange failed: %08x\n", hres);
972
973     hres = IDispatch_QueryInterface(disp, &IID_IHTMLTxtRange, (void**)&range);
974     IDispatch_Release(disp);
975     ok(hres == S_OK, "Could not get IHTMLTxtRange interface: %08x\n", hres);
976
977     test_range_text(range, NULL);
978     IHTMLTxtRange_Release(range);
979 }
980
981 static void test_defaults(IHTMLDocument2 *doc)
982 {
983     IHTMLStyleSheetsCollection *stylesheetcol;
984     IHTMLElement *elem;
985     IHTMLStyle *style;
986     long l;
987     HRESULT hres;
988
989     hres = IHTMLDocument2_get_body(doc, &elem);
990     ok(hres == S_OK, "get_body failed: %08x\n", hres);
991
992     hres = IHTMLElement_get_style(elem, &style);
993     IHTMLElement_Release(elem);
994     ok(hres == S_OK, "get_style failed: %08x\n", hres);
995
996     test_default_style(style);
997     test_compatmode(doc);
998
999     IHTMLStyle_Release(style);
1000
1001     hres = IHTMLDocument2_get_styleSheets(doc, &stylesheetcol);
1002     ok(hres == S_OK, "get_styleSheets failed: %08x\n", hres);
1003
1004     l = 0xdeadbeef;
1005     hres = IHTMLStyleSheetsCollection_get_length(stylesheetcol, &l);
1006     ok(hres == S_OK, "get_length failed: %08x\n", hres);
1007     ok(l == 0, "length = %ld\n", l);
1008
1009     IHTMLStyleSheetsCollection_Release(stylesheetcol);
1010
1011     test_default_selection(doc);
1012 }
1013
1014 static void test_elems(IHTMLDocument2 *doc)
1015 {
1016     IHTMLElementCollection *col;
1017     IHTMLElement *elem;
1018     IDispatch *disp;
1019     HRESULT hres;
1020
1021     static const WCHAR xW[] = {'x',0};
1022     static const WCHAR sW[] = {'s',0};
1023     static const WCHAR xxxW[] = {'x','x','x',0};
1024
1025     static const elem_type_t all_types[] = {
1026         ET_HTML,
1027         ET_HEAD,
1028         ET_TITLE,
1029         ET_BODY,
1030         ET_A,
1031         ET_INPUT,
1032         ET_SELECT,
1033         ET_OPTION,
1034         ET_OPTION,
1035         ET_TEXTAREA
1036     };
1037
1038     static const elem_type_t item_types[] = {
1039         ET_A,
1040         ET_OPTION,
1041         ET_TEXTAREA
1042     };
1043
1044     hres = IHTMLDocument2_get_all(doc, &col);
1045     ok(hres == S_OK, "get_all failed: %08x\n", hres);
1046     test_elem_collection(col, all_types, sizeof(all_types)/sizeof(all_types[0]));
1047     test_elem_col_item(col, xW, item_types, sizeof(item_types)/sizeof(item_types[0]));
1048     IHTMLElementCollection_Release(col);
1049
1050     elem = get_doc_elem(doc);
1051     ok(hres == S_OK, "get_documentElement failed: %08x\n", hres);
1052     hres = IHTMLElement_get_all(elem, &disp);
1053     IHTMLElement_Release(elem);
1054     ok(hres == S_OK, "get_all failed: %08x\n", hres);
1055
1056     hres = IDispatch_QueryInterface(disp, &IID_IHTMLElementCollection, (void**)&col);
1057     IDispatch_Release(disp);
1058     ok(hres == S_OK, "Could not get IHTMLElementCollection: %08x\n", hres);
1059     test_elem_collection(col, all_types+1, sizeof(all_types)/sizeof(all_types[0])-1);
1060     IHTMLElementCollection_Release(col);
1061
1062     get_elem_by_id(doc, xxxW, FALSE);
1063     elem = get_elem_by_id(doc, sW, TRUE);
1064     if(elem) {
1065         IHTMLSelectElement *select;
1066
1067         hres = IHTMLElement_QueryInterface(elem, &IID_IHTMLSelectElement, (void**)&select);
1068         ok(hres == S_OK, "Could not get IHTMLSelectElement interface: %08x\n", hres);
1069
1070         test_select_elem(select);
1071
1072         IHTMLSelectElement_Release(select);
1073         IHTMLElement_Release(elem);
1074     }
1075
1076     test_create_option_elem(doc);
1077 }
1078
1079 static IHTMLDocument2 *notif_doc;
1080 static BOOL doc_complete;
1081
1082 static HRESULT WINAPI PropertyNotifySink_QueryInterface(IPropertyNotifySink *iface,
1083         REFIID riid, void**ppv)
1084 {
1085     if(IsEqualGUID(&IID_IPropertyNotifySink, riid)) {
1086         *ppv = iface;
1087         return S_OK;
1088     }
1089
1090     ok(0, "unexpected call\n");
1091     return E_NOINTERFACE;
1092 }
1093
1094 static ULONG WINAPI PropertyNotifySink_AddRef(IPropertyNotifySink *iface)
1095 {
1096     return 2;
1097 }
1098
1099 static ULONG WINAPI PropertyNotifySink_Release(IPropertyNotifySink *iface)
1100 {
1101     return 1;
1102 }
1103
1104 static HRESULT WINAPI PropertyNotifySink_OnChanged(IPropertyNotifySink *iface, DISPID dispID)
1105 {
1106     if(dispID == DISPID_READYSTATE){
1107         BSTR state;
1108         HRESULT hres;
1109
1110         static const WCHAR completeW[] = {'c','o','m','p','l','e','t','e',0};
1111
1112         hres = IHTMLDocument2_get_readyState(notif_doc, &state);
1113         ok(hres == S_OK, "get_readyState failed: %08x\n", hres);
1114
1115         if(!lstrcmpW(state, completeW))
1116             doc_complete = TRUE;
1117
1118         SysFreeString(state);        
1119     }
1120
1121     return S_OK;
1122 }
1123
1124 static HRESULT WINAPI PropertyNotifySink_OnRequestEdit(IPropertyNotifySink *iface, DISPID dispID)
1125 {
1126     ok(0, "unexpected call\n");
1127     return E_NOTIMPL;
1128 }
1129
1130 static IPropertyNotifySinkVtbl PropertyNotifySinkVtbl = {
1131     PropertyNotifySink_QueryInterface,
1132     PropertyNotifySink_AddRef,
1133     PropertyNotifySink_Release,
1134     PropertyNotifySink_OnChanged,
1135     PropertyNotifySink_OnRequestEdit
1136 };
1137
1138 static IPropertyNotifySink PropertyNotifySink = { &PropertyNotifySinkVtbl };
1139
1140 static IHTMLDocument2 *create_doc_with_string(const char *str)
1141 {
1142     IPersistStreamInit *init;
1143     IStream *stream;
1144     IHTMLDocument2 *doc;
1145     HGLOBAL mem;
1146     SIZE_T len;
1147
1148     notif_doc = doc = create_document();
1149     if(!doc)
1150         return NULL;
1151
1152     doc_complete = FALSE;
1153     len = strlen(str);
1154     mem = GlobalAlloc(0, len);
1155     memcpy(mem, str, len);
1156     CreateStreamOnHGlobal(mem, TRUE, &stream);
1157
1158     IHTMLDocument2_QueryInterface(doc, &IID_IPersistStreamInit, (void**)&init);
1159
1160     IPersistStreamInit_Load(init, stream);
1161     IPersistStreamInit_Release(init);
1162     IStream_Release(stream);
1163
1164     return doc;
1165 }
1166
1167 static void do_advise(IUnknown *unk, REFIID riid, IUnknown *unk_advise)
1168 {
1169     IConnectionPointContainer *container;
1170     IConnectionPoint *cp;
1171     DWORD cookie;
1172     HRESULT hres;
1173
1174     hres = IUnknown_QueryInterface(unk, &IID_IConnectionPointContainer, (void**)&container);
1175     ok(hres == S_OK, "QueryInterface(IID_IConnectionPointContainer) failed: %08x\n", hres);
1176
1177     hres = IConnectionPointContainer_FindConnectionPoint(container, riid, &cp);
1178     IConnectionPointContainer_Release(container);
1179     ok(hres == S_OK, "FindConnectionPoint failed: %08x\n", hres);
1180
1181     hres = IConnectionPoint_Advise(cp, unk_advise, &cookie);
1182     IConnectionPoint_Release(cp);
1183     ok(hres == S_OK, "Advise failed: %08x\n", hres);
1184 }
1185
1186 typedef void (*domtest_t)(IHTMLDocument2*);
1187
1188 static void run_domtest(const char *str, domtest_t test)
1189 {
1190     IHTMLDocument2 *doc;
1191     IHTMLElement *body = NULL;
1192     ULONG ref;
1193     MSG msg;
1194     HRESULT hres;
1195
1196     doc = create_doc_with_string(str);
1197     do_advise((IUnknown*)doc, &IID_IPropertyNotifySink, (IUnknown*)&PropertyNotifySink);
1198
1199     while(!doc_complete && GetMessage(&msg, NULL, 0, 0)) {
1200         TranslateMessage(&msg);
1201         DispatchMessage(&msg);
1202     }
1203
1204     hres = IHTMLDocument2_get_body(doc, &body);
1205     ok(hres == S_OK, "get_body failed: %08x\n", hres);
1206
1207     if(body) {
1208         IHTMLElement_Release(body);
1209         test(doc);
1210     }else {
1211         skip("Could not get document body. Assuming no Gecko installed.\n");
1212     }
1213
1214     ref = IHTMLDocument2_Release(doc);
1215     ok(!ref, "ref = %d\n", ref);
1216 }
1217
1218 static void gecko_installer_workaround(BOOL disable)
1219 {
1220     HKEY hkey;
1221     DWORD res;
1222
1223     static BOOL has_url = FALSE;
1224     static char url[2048];
1225
1226     if(!disable && !has_url)
1227         return;
1228
1229     res = RegOpenKey(HKEY_CURRENT_USER, "Software\\Wine\\MSHTML", &hkey);
1230     if(res != ERROR_SUCCESS)
1231         return;
1232
1233     if(disable) {
1234         DWORD type, size = sizeof(url);
1235
1236         res = RegQueryValueEx(hkey, "GeckoUrl", NULL, &type, (PVOID)url, &size);
1237         if(res == ERROR_SUCCESS && type == REG_SZ)
1238             has_url = TRUE;
1239
1240         RegDeleteValue(hkey, "GeckoUrl");
1241     }else {
1242         RegSetValueEx(hkey, "GeckoUrl", 0, REG_SZ, (PVOID)url, lstrlenA(url)+1);
1243     }
1244
1245     RegCloseKey(hkey);
1246 }
1247
1248 START_TEST(dom)
1249 {
1250     gecko_installer_workaround(TRUE);
1251     CoInitialize(NULL);
1252
1253     run_domtest(doc_str1, test_doc_elem);
1254     run_domtest(doc_str2, test_txtrange);
1255     run_domtest(doc_str3, test_elems);
1256     run_domtest(doc_blank, test_defaults);
1257
1258     CoUninitialize();
1259     gecko_installer_workaround(FALSE);
1260 }