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