mshtml: Added IHTMLDOMNode::removeChild implementation.
[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 "mshtmcid.h"
31 #include "mshtmhst.h"
32 #include "docobj.h"
33 #include "dispex.h"
34
35 static const char doc_blank[] = "<html></html>";
36 static const char doc_str1[] = "<html><body>test</body></html>";
37 static const char range_test_str[] =
38     "<html><body>test \na<font size=\"2\">bc\t123<br /> it's\r\n  \t</font>text<br /></body></html>";
39 static const char range_test2_str[] =
40     "<html><body>abc<hr />123<br /><hr />def</body></html>";
41 static const char elem_test_str[] =
42     "<html><head><title>test</title><style>.body { margin-right: 0px; }</style>"
43     "<body>text test<!-- a comment -->"
44     "<a href=\"http://test\" name=\"x\">link</a>"
45     "<input id=\"in\" class=\"testclass\" tabIndex=\"2\" />"
46     "<select id=\"s\"><option id=\"x\">opt1</option><option id=\"y\">opt2</option></select>"
47     "<textarea id=\"X\">text text</textarea>"
48     "<table><tbody></tbody></table>"
49     "<script id=\"sc\" type=\"text/javascript\"></script>"
50     "<test />"
51     "<img id=\"imgid\"/>"
52     "</body></html>";
53 static const char indent_test_str[] =
54     "<html><head><title>test</title></head><body>abc<br /><a href=\"about:blank\">123</a></body></html>";
55
56 static const WCHAR noneW[] = {'N','o','n','e',0};
57
58 static WCHAR characterW[] = {'c','h','a','r','a','c','t','e','r',0};
59 static WCHAR texteditW[] = {'t','e','x','t','e','d','i','t',0};
60 static WCHAR wordW[] = {'w','o','r','d',0};
61
62 static const WCHAR text_javascriptW[] = {'t','e','x','t','/','j','a','v','a','s','c','r','i','p','t',0};
63
64 static const WCHAR idW[] = {'i','d',0};
65
66 typedef enum {
67     ET_NONE,
68     ET_HTML,
69     ET_HEAD,
70     ET_TITLE,
71     ET_BODY,
72     ET_A,
73     ET_INPUT,
74     ET_SELECT,
75     ET_TEXTAREA,
76     ET_OPTION,
77     ET_STYLE,
78     ET_BLOCKQUOTE,
79     ET_P,
80     ET_BR,
81     ET_TABLE,
82     ET_TBODY,
83     ET_SCRIPT,
84     ET_TEST,
85     ET_TESTG,
86     ET_COMMENT,
87     ET_IMG
88 } elem_type_t;
89
90 static REFIID const none_iids[] = {
91     &IID_IUnknown,
92     NULL
93 };
94
95 static REFIID const elem_iids[] = {
96     &IID_IHTMLDOMNode,
97     &IID_IHTMLDOMNode2,
98     &IID_IHTMLElement,
99     &IID_IHTMLElement2,
100     &IID_IDispatchEx,
101     &IID_IConnectionPointContainer,
102     NULL
103 };
104
105 static REFIID const body_iids[] = {
106     &IID_IHTMLDOMNode,
107     &IID_IHTMLDOMNode2,
108     &IID_IHTMLElement,
109     &IID_IHTMLElement2,
110     &IID_IHTMLTextContainer,
111     &IID_IHTMLBodyElement,
112     &IID_IDispatchEx,
113     &IID_IConnectionPointContainer,
114     NULL
115 };
116
117 static REFIID const anchor_iids[] = {
118     &IID_IHTMLDOMNode,
119     &IID_IHTMLDOMNode2,
120     &IID_IHTMLElement,
121     &IID_IHTMLElement2,
122     &IID_IHTMLAnchorElement,
123     &IID_IDispatchEx,
124     &IID_IConnectionPointContainer,
125     NULL
126 };
127
128 static REFIID const input_iids[] = {
129     &IID_IHTMLDOMNode,
130     &IID_IHTMLDOMNode2,
131     &IID_IHTMLElement,
132     &IID_IHTMLElement2,
133     &IID_IHTMLInputElement,
134     &IID_IHTMLInputTextElement,
135     &IID_IDispatchEx,
136     &IID_IConnectionPointContainer,
137     NULL
138 };
139
140 static REFIID const select_iids[] = {
141     &IID_IHTMLDOMNode,
142     &IID_IHTMLDOMNode2,
143     &IID_IHTMLElement,
144     &IID_IHTMLElement2,
145     &IID_IHTMLSelectElement,
146     &IID_IDispatchEx,
147     &IID_IConnectionPointContainer,
148     NULL
149 };
150
151 static REFIID const textarea_iids[] = {
152     &IID_IHTMLDOMNode,
153     &IID_IHTMLDOMNode2,
154     &IID_IHTMLElement,
155     &IID_IHTMLElement2,
156     &IID_IHTMLTextAreaElement,
157     &IID_IDispatchEx,
158     &IID_IConnectionPointContainer,
159     NULL
160 };
161
162 static REFIID const option_iids[] = {
163     &IID_IHTMLDOMNode,
164     &IID_IHTMLDOMNode2,
165     &IID_IHTMLElement,
166     &IID_IHTMLElement2,
167     &IID_IHTMLOptionElement,
168     &IID_IDispatchEx,
169     &IID_IConnectionPointContainer,
170     NULL
171 };
172
173 static REFIID const table_iids[] = {
174     &IID_IHTMLDOMNode,
175     &IID_IHTMLDOMNode2,
176     &IID_IHTMLElement,
177     &IID_IHTMLElement2,
178     &IID_IHTMLTable,
179     &IID_IDispatchEx,
180     &IID_IConnectionPointContainer,
181     NULL
182 };
183
184 static REFIID const script_iids[] = {
185     &IID_IHTMLDOMNode,
186     &IID_IHTMLDOMNode2,
187     &IID_IHTMLElement,
188     &IID_IHTMLElement2,
189     &IID_IHTMLScriptElement,
190     &IID_IDispatchEx,
191     &IID_IConnectionPointContainer,
192     NULL
193 };
194
195 static REFIID const text_iids[] = {
196     &IID_IHTMLDOMNode,
197     &IID_IHTMLDOMNode2,
198     &IID_IHTMLDOMTextNode,
199     NULL
200 };
201
202 static REFIID const location_iids[] = {
203     &IID_IDispatch,
204     &IID_IHTMLLocation,
205     NULL
206 };
207
208 static REFIID const window_iids[] = {
209     &IID_IDispatch,
210     &IID_IHTMLWindow2,
211     &IID_IHTMLWindow3,
212     &IID_IDispatchEx,
213     NULL
214 };
215
216 static REFIID const comment_iids[] = {
217     &IID_IHTMLDOMNode,
218     &IID_IHTMLDOMNode2,
219     &IID_IHTMLElement,
220     &IID_IHTMLElement2,
221     &IID_IHTMLCommentElement,
222     &IID_IDispatchEx,
223     &IID_IConnectionPointContainer,
224     NULL
225 };
226
227 static REFIID const img_iids[] = {
228     &IID_IHTMLDOMNode,
229     &IID_IHTMLDOMNode2,
230     &IID_IHTMLElement,
231     &IID_IHTMLElement2,
232     &IID_IDispatchEx,
233     &IID_IHTMLImgElement,
234     &IID_IConnectionPointContainer,
235     NULL
236 };
237
238 static REFIID const generic_iids[] = {
239     &IID_IHTMLDOMNode,
240     &IID_IHTMLDOMNode2,
241     &IID_IHTMLElement,
242     &IID_IHTMLElement2,
243     &IID_IHTMLGenericElement,
244     &IID_IDispatchEx,
245     &IID_IConnectionPointContainer,
246     NULL
247 };
248
249 typedef struct {
250     const char *tag;
251     REFIID *iids;
252     const IID *dispiid;
253 } elem_type_info_t;
254
255 static const elem_type_info_t elem_type_infos[] = {
256     {"",          none_iids,        NULL},
257     {"HTML",      elem_iids,        NULL},
258     {"HEAD",      elem_iids,        NULL},
259     {"TITLE",     elem_iids,        NULL},
260     {"BODY",      body_iids,        NULL},
261     {"A",         anchor_iids,      NULL},
262     {"INPUT",     input_iids,       &DIID_DispHTMLInputElement},
263     {"SELECT",    select_iids,      &DIID_DispHTMLSelectElement},
264     {"TEXTAREA",  textarea_iids,    NULL},
265     {"OPTION",    option_iids,      &DIID_DispHTMLOptionElement},
266     {"STYLE",     elem_iids,        NULL},
267     {"BLOCKQUOTE",elem_iids,        NULL},
268     {"P",         elem_iids,        NULL},
269     {"BR",        elem_iids,        NULL},
270     {"TABLE",     table_iids,       NULL},
271     {"TBODY",     elem_iids,        NULL},
272     {"SCRIPT",    script_iids,      NULL},
273     {"TEST",      elem_iids,        &DIID_DispHTMLUnknownElement},
274     {"TEST",      generic_iids,     &DIID_DispHTMLGenericElement},
275     {"!",         comment_iids,     &DIID_DispHTMLCommentElement},
276     {"IMG",       img_iids,         &DIID_DispHTMLImg}
277 };
278
279 static const char *dbgstr_w(LPCWSTR str)
280 {
281     static char buf[512];
282     if(!str)
283         return "(null)";
284     WideCharToMultiByte(CP_ACP, 0, str, -1, buf, sizeof(buf), NULL, NULL);
285     return buf;
286 }
287
288 static const char *dbgstr_guid(REFIID riid)
289 {
290     static char buf[50];
291
292     sprintf(buf, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
293             riid->Data1, riid->Data2, riid->Data3, riid->Data4[0],
294             riid->Data4[1], riid->Data4[2], riid->Data4[3], riid->Data4[4],
295             riid->Data4[5], riid->Data4[6], riid->Data4[7]);
296
297     return buf;
298 }
299
300 static int strcmp_wa(LPCWSTR strw, const char *stra)
301 {
302     WCHAR buf[512];
303     MultiByteToWideChar(CP_ACP, 0, stra, -1, buf, sizeof(buf)/sizeof(WCHAR));
304     return lstrcmpW(strw, buf);
305 }
306
307 static BSTR a2bstr(const char *str)
308 {
309     BSTR ret;
310     int len;
311
312     len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
313     ret = SysAllocStringLen(NULL, len);
314     MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
315
316     return ret;
317 }
318
319 static IHTMLDocument2 *create_document(void)
320 {
321     IHTMLDocument2 *doc;
322     HRESULT hres;
323
324     hres = CoCreateInstance(&CLSID_HTMLDocument, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
325             &IID_IHTMLDocument2, (void**)&doc);
326     ok(hres == S_OK, "CoCreateInstance failed: %08x\n", hres);
327
328     return doc;
329 }
330
331 #define test_ifaces(i,ids) _test_ifaces(__LINE__,i,ids)
332 static void _test_ifaces(unsigned line, IUnknown *iface, REFIID *iids)
333 {
334     const IID * const *piid;
335     IUnknown *unk;
336     HRESULT hres;
337
338      for(piid = iids; *piid; piid++) {
339         hres = IDispatch_QueryInterface(iface, *piid, (void**)&unk);
340         ok_(__FILE__,line) (hres == S_OK, "Could not get %s interface: %08x\n", dbgstr_guid(*piid), hres);
341         if(SUCCEEDED(hres))
342             IUnknown_Release(unk);
343     }
344 }
345
346 #define test_disp(u,id) _test_disp(__LINE__,u,id)
347 static void _test_disp(unsigned line, IUnknown *unk, const IID *diid)
348 {
349     IDispatchEx *dispex;
350     ITypeInfo *typeinfo;
351     UINT ticnt;
352     HRESULT hres;
353
354     hres = IUnknown_QueryInterface(unk, &IID_IDispatchEx, (void**)&dispex);
355     ok_(__FILE__,line) (hres == S_OK, "Could not get IDispatch: %08x\n", hres);
356     if(FAILED(hres))
357         return;
358
359     ticnt = 0xdeadbeef;
360     hres = IDispatchEx_GetTypeInfoCount(dispex, &ticnt);
361     ok_(__FILE__,line) (hres == S_OK, "GetTypeInfoCount failed: %08x\n", hres);
362     ok_(__FILE__,line) (ticnt == 1, "ticnt=%u\n", ticnt);
363
364     hres = IDispatchEx_GetTypeInfo(dispex, 0, 0, &typeinfo);
365     ok_(__FILE__,line) (hres == S_OK, "GetTypeInfo failed: %08x\n", hres);
366
367     if(SUCCEEDED(hres)) {
368         TYPEATTR *type_attr;
369
370         hres = ITypeInfo_GetTypeAttr(typeinfo, &type_attr);
371         ok_(__FILE__,line) (hres == S_OK, "GetTypeAttr failed: %08x\n", hres);
372         ok_(__FILE__,line) (IsEqualGUID(&type_attr->guid, diid), "unexpected guid %s\n", dbgstr_guid(&type_attr->guid));
373
374         ITypeInfo_ReleaseTypeAttr(typeinfo, type_attr);
375         ITypeInfo_Release(typeinfo);
376     }
377
378     IDispatchEx_Release(dispex);
379 }
380
381 #define get_elem_iface(u) _get_elem_iface(__LINE__,u)
382 static IHTMLElement *_get_elem_iface(unsigned line, IUnknown *unk)
383 {
384     IHTMLElement *elem;
385     HRESULT hres;
386
387     hres = IUnknown_QueryInterface(unk, &IID_IHTMLElement, (void**)&elem);
388     ok_(__FILE__,line) (hres == S_OK, "Coule not get IHTMLElement: %08x\n", hres);
389     return elem;
390 }
391
392 #define get_elem2_iface(u) _get_elem2_iface(__LINE__,u)
393 static IHTMLElement2 *_get_elem2_iface(unsigned line, IUnknown *unk)
394 {
395     IHTMLElement2 *elem;
396     HRESULT hres;
397
398     hres = IUnknown_QueryInterface(unk, &IID_IHTMLElement2, (void**)&elem);
399     ok_(__FILE__,line) (hres == S_OK, "Coule not get IHTMLElement2: %08x\n", hres);
400     return elem;
401 }
402
403 #define get_node_iface(u) _get_node_iface(__LINE__,u)
404 static IHTMLDOMNode *_get_node_iface(unsigned line, IUnknown *unk)
405 {
406     IHTMLDOMNode *node;
407     HRESULT hres;
408
409     hres = IUnknown_QueryInterface(unk, &IID_IHTMLDOMNode, (void**)&node);
410     ok_(__FILE__,line) (hres == S_OK, "Coule not get IHTMLDOMNode: %08x\n", hres);
411     return node;
412 }
413
414 #define test_node_name(u,n) _test_node_name(__LINE__,u,n)
415 static void _test_node_name(unsigned line, IUnknown *unk, const char *exname)
416 {
417     IHTMLDOMNode *node = _get_node_iface(line, unk);
418     BSTR name;
419     HRESULT hres;
420
421     hres = IHTMLDOMNode_get_nodeName(node, &name);
422     IHTMLDOMNode_Release(node);
423     ok_(__FILE__, line) (hres == S_OK, "get_nodeName failed: %08x\n", hres);
424     ok_(__FILE__, line) (!strcmp_wa(name, exname), "got name: %s, expected %s\n", dbgstr_w(name), exname);
425
426     SysFreeString(name);
427 }
428
429 #define test_elem_tag(u,n) _test_elem_tag(__LINE__,u,n)
430 static void _test_elem_tag(unsigned line, IUnknown *unk, const char *extag)
431 {
432     IHTMLElement *elem = _get_elem_iface(line, unk);
433     BSTR tag;
434     HRESULT hres;
435
436     hres = IHTMLElement_get_tagName(elem, &tag);
437     IHTMLElement_Release(elem);
438     ok_(__FILE__, line) (hres == S_OK, "get_tagName failed: %08x\n", hres);
439     ok_(__FILE__, line) (!strcmp_wa(tag, extag), "got tag: %s, expected %s\n", dbgstr_w(tag), extag);
440
441     SysFreeString(tag);
442 }
443
444 #define test_elem_type(ifc,t) _test_elem_type(__LINE__,ifc,t)
445 static void _test_elem_type(unsigned line, IUnknown *unk, elem_type_t type)
446 {
447     _test_elem_tag(line, unk, elem_type_infos[type].tag);
448     _test_ifaces(line, unk, elem_type_infos[type].iids);
449
450     if(elem_type_infos[type].dispiid)
451         _test_disp(line, unk, elem_type_infos[type].dispiid);
452 }
453
454 #define test_elem_attr(e,n,v) _test_elem_attr(__LINE__,e,n,v)
455 static void _test_elem_attr(unsigned line, IHTMLElement *elem, LPCWSTR name, LPCWSTR exval)
456 {
457     VARIANT value;
458     BSTR tmp;
459     HRESULT hres;
460
461     VariantInit(&value);
462
463     tmp = SysAllocString(name);
464     hres = IHTMLElement_getAttribute(elem, tmp, 0, &value);
465     SysFreeString(tmp);
466     ok_(__FILE__,line) (hres == S_OK, "getAttribute failed: %08x\n", hres);
467
468     if(exval) {
469         ok_(__FILE__,line) (V_VT(&value) == VT_BSTR, "vt=%d\n", V_VT(&value));
470         ok_(__FILE__,line) (!lstrcmpW(exval, V_BSTR(&value)), "unexpected value %s\n", dbgstr_w(V_BSTR(&value)));
471     }else {
472         ok_(__FILE__,line) (V_VT(&value) == VT_NULL, "vt=%d\n", V_VT(&value));
473     }
474
475     VariantClear(&value);
476 }
477
478 static void test_doc_elem(IHTMLDocument2 *doc)
479 {
480     IHTMLElement *elem;
481     IHTMLDocument3 *doc3;
482     HRESULT hres;
483
484     hres = IHTMLDocument2_QueryInterface(doc, &IID_IHTMLDocument3, (void**)&doc3);
485     ok(hres == S_OK, "QueryInterface(IID_IHTMLDocument3) failed: %08x\n", hres);
486
487     hres = IHTMLDocument3_get_documentElement(doc3, &elem);
488     IHTMLDocument3_Release(doc3);
489     ok(hres == S_OK, "get_documentElement failed: %08x\n", hres);
490
491     test_node_name((IUnknown*)elem, "HTML");
492     test_elem_tag((IUnknown*)elem, "HTML");
493
494     IHTMLElement_Release(elem);
495 }
496
497 #define get_doc_elem(d) _get_doc_elem(__LINE__,d)
498 static IHTMLElement *_get_doc_elem(unsigned line, IHTMLDocument2 *doc)
499 {
500     IHTMLElement *elem;
501     IHTMLDocument3 *doc3;
502     HRESULT hres;
503
504     hres = IHTMLDocument2_QueryInterface(doc, &IID_IHTMLDocument3, (void**)&doc3);
505     ok_(__FILE__,line) (hres == S_OK, "Could not get IHTMLDocument3 interface: %08x\n", hres);
506     hres = IHTMLDocument3_get_documentElement(doc3, &elem);
507     ok_(__FILE__,line) (hres == S_OK, "get_documentElement failed: %08x\n", hres);
508     IHTMLDocument3_Release(doc3);
509
510     return elem;
511 }
512
513 #define test_option_text(o,t) _test_option_text(__LINE__,o,t)
514 static void _test_option_text(unsigned line, IHTMLOptionElement *option, const char *text)
515 {
516     BSTR bstr;
517     HRESULT hres;
518
519     hres = IHTMLOptionElement_get_text(option, &bstr);
520     ok_(__FILE__,line) (hres == S_OK, "get_text failed: %08x\n", hres);
521     ok_(__FILE__,line) (!strcmp_wa(bstr, text), "text=%s\n", dbgstr_w(bstr));
522     SysFreeString(bstr);
523 }
524
525 #define test_option_put_text(o,t) _test_option_put_text(__LINE__,o,t)
526 static void _test_option_put_text(unsigned line, IHTMLOptionElement *option, const char *text)
527 {
528     BSTR bstr;
529     HRESULT hres;
530
531     bstr = a2bstr(text);
532     hres = IHTMLOptionElement_put_text(option, bstr);
533     SysFreeString(bstr);
534     ok(hres == S_OK, "put_text failed: %08x\n", hres);
535
536     _test_option_text(line, option, text);
537 }
538
539 #define test_option_value(o,t) _test_option_value(__LINE__,o,t)
540 static void _test_option_value(unsigned line, IHTMLOptionElement *option, const char *value)
541 {
542     BSTR bstr;
543     HRESULT hres;
544
545     hres = IHTMLOptionElement_get_value(option, &bstr);
546     ok_(__FILE__,line) (hres == S_OK, "get_value failed: %08x\n", hres);
547     ok_(__FILE__,line) (!strcmp_wa(bstr, value), "value=%s\n", dbgstr_w(bstr));
548     SysFreeString(bstr);
549 }
550
551 #define test_option_put_value(o,t) _test_option_put_value(__LINE__,o,t)
552 static void _test_option_put_value(unsigned line, IHTMLOptionElement *option, const char *value)
553 {
554     BSTR bstr;
555     HRESULT hres;
556
557     bstr = a2bstr(value);
558     hres = IHTMLOptionElement_put_value(option, bstr);
559     SysFreeString(bstr);
560     ok(hres == S_OK, "put_value failed: %08x\n", hres);
561
562     _test_option_value(line, option, value);
563 }
564
565 #define create_option_elem(d,t,v) _create_option_elem(__LINE__,d,t,v)
566 static IHTMLOptionElement *_create_option_elem(unsigned line, IHTMLDocument2 *doc,
567         const char *txt, const char *val)
568 {
569     IHTMLOptionElementFactory *factory;
570     IHTMLOptionElement *option;
571     IHTMLWindow2 *window;
572     VARIANT text, value, empty;
573     HRESULT hres;
574
575     hres = IHTMLDocument2_get_parentWindow(doc, &window);
576     ok_(__FILE__,line) (hres == S_OK, "get_parentElement failed: %08x\n", hres);
577
578     hres = IHTMLWindow2_get_Option(window, &factory);
579     IHTMLWindow2_Release(window);
580     ok_(__FILE__,line) (hres == S_OK, "get_Option failed: %08x\n", hres);
581
582     V_VT(&text) = VT_BSTR;
583     V_BSTR(&text) = a2bstr(txt);
584     V_VT(&value) = VT_BSTR;
585     V_BSTR(&value) = a2bstr(val);
586     V_VT(&empty) = VT_EMPTY;
587
588     hres = IHTMLOptionElementFactory_create(factory, text, value, empty, empty, &option);
589     ok_(__FILE__,line) (hres == S_OK, "create failed: %08x\n", hres);
590
591     IHTMLOptionElementFactory_Release(factory);
592     VariantClear(&text);
593     VariantClear(&value);
594
595     _test_option_text(line, option, txt);
596     _test_option_value(line, option, val);
597
598     return option;
599 }
600
601 #define test_select_length(s,l) _test_select_length(__LINE__,s,l)
602 static void _test_select_length(unsigned line, IHTMLSelectElement *select, long length)
603 {
604     long len = 0xdeadbeef;
605     HRESULT hres;
606
607     hres = IHTMLSelectElement_get_length(select, &len);
608     ok_(__FILE__,line) (hres == S_OK, "get_length failed: %08x\n", hres);
609     ok_(__FILE__,line) (len == length, "len=%ld, expected %ld\n", len, length);
610 }
611
612 #define test_select_selidx(s,i) _test_select_selidx(__LINE__,s,i)
613 static void _test_select_selidx(unsigned line, IHTMLSelectElement *select, long index)
614 {
615     long idx = 0xdeadbeef;
616     HRESULT hres;
617
618     hres = IHTMLSelectElement_get_selectedIndex(select, &idx);
619     ok_(__FILE__,line) (hres == S_OK, "get_selectedIndex failed: %08x\n", hres);
620     ok_(__FILE__,line) (idx == index, "idx=%ld, expected %ld\n", idx, index);
621 }
622
623 #define test_select_put_selidx(s,i) _test_select_put_selidx(__LINE__,s,i)
624 static void _test_select_put_selidx(unsigned line, IHTMLSelectElement *select, long index)
625 {
626     HRESULT hres;
627
628     hres = IHTMLSelectElement_put_selectedIndex(select, index);
629     ok_(__FILE__,line) (hres == S_OK, "get_selectedIndex failed: %08x\n", hres);
630     _test_select_selidx(line, select, index);
631 }
632
633 #define test_range_text(r,t) _test_range_text(__LINE__,r,t)
634 static void _test_range_text(unsigned line, IHTMLTxtRange *range, const char *extext)
635 {
636     BSTR text;
637     HRESULT hres;
638
639     hres = IHTMLTxtRange_get_text(range, &text);
640     ok_(__FILE__, line) (hres == S_OK, "get_text failed: %08x\n", hres);
641
642     if(extext) {
643         ok_(__FILE__, line) (text != NULL, "text == NULL\n");
644         ok_(__FILE__, line) (!strcmp_wa(text, extext), "text=\"%s\", expected \"%s\"\n", dbgstr_w(text), extext);
645     }else {
646         ok_(__FILE__, line) (text == NULL, "text=\"%s\", expected NULL\n", dbgstr_w(text));
647     }
648
649     SysFreeString(text);
650
651 }
652
653 #define test_range_collapse(r,b) _test_range_collapse(__LINE__,r,b)
654 static void _test_range_collapse(unsigned line, IHTMLTxtRange *range, BOOL b)
655 {
656     HRESULT hres;
657
658     hres = IHTMLTxtRange_collapse(range, b);
659     ok_(__FILE__, line) (hres == S_OK, "collapse failed: %08x\n", hres);
660     _test_range_text(line, range, NULL);
661 }
662
663 #define test_range_expand(r,u,b,t) _test_range_expand(__LINE__,r,u,b,t)
664 static void _test_range_expand(unsigned line, IHTMLTxtRange *range, LPWSTR unit,
665         VARIANT_BOOL exb, const char *extext)
666 {
667     VARIANT_BOOL b = 0xe0e0;
668     HRESULT hres;
669
670     hres = IHTMLTxtRange_expand(range, unit, &b);
671     ok_(__FILE__,line) (hres == S_OK, "expand failed: %08x\n", hres);
672     ok_(__FILE__,line) (b == exb, "b=%x, expected %x\n", b, exb);
673     _test_range_text(line, range, extext);
674 }
675
676 #define test_range_move(r,u,c,e) _test_range_move(__LINE__,r,u,c,e)
677 static void _test_range_move(unsigned line, IHTMLTxtRange *range, LPWSTR unit, long cnt, long excnt)
678 {
679     long c = 0xdeadbeef;
680     HRESULT hres;
681
682     hres = IHTMLTxtRange_move(range, unit, cnt, &c);
683     ok_(__FILE__,line) (hres == S_OK, "move failed: %08x\n", hres);
684     ok_(__FILE__,line) (c == excnt, "count=%ld, expected %ld\n", c, excnt);
685     _test_range_text(line, range, NULL);
686 }
687
688 #define test_range_movestart(r,u,c,e) _test_range_movestart(__LINE__,r,u,c,e)
689 static void _test_range_movestart(unsigned line, IHTMLTxtRange *range,
690         LPWSTR unit, long cnt, long excnt)
691 {
692     long c = 0xdeadbeef;
693     HRESULT hres;
694
695     hres = IHTMLTxtRange_moveStart(range, unit, cnt, &c);
696     ok_(__FILE__,line) (hres == S_OK, "move failed: %08x\n", hres);
697     ok_(__FILE__,line) (c == excnt, "count=%ld, expected %ld\n", c, excnt);
698 }
699
700 #define test_range_moveend(r,u,c,e) _test_range_moveend(__LINE__,r,u,c,e)
701 static void _test_range_moveend(unsigned line, IHTMLTxtRange *range, LPWSTR unit, long cnt, long excnt)
702 {
703     long c = 0xdeadbeef;
704     HRESULT hres;
705
706     hres = IHTMLTxtRange_moveEnd(range, unit, cnt, &c);
707     ok_(__FILE__,line) (hres == S_OK, "move failed: %08x\n", hres);
708     ok_(__FILE__,line) (c == excnt, "count=%ld, expected %ld\n", c, excnt);
709 }
710
711 #define test_range_put_text(r,t) _test_range_put_text(__LINE__,r,t)
712 static void _test_range_put_text(unsigned line, IHTMLTxtRange *range, const char *text)
713 {
714     HRESULT hres;
715     BSTR bstr = a2bstr(text);
716
717     hres = IHTMLTxtRange_put_text(range, bstr);
718     ok_(__FILE__,line) (hres == S_OK, "put_text failed: %08x\n", hres);
719     SysFreeString(bstr);
720     _test_range_text(line, range, NULL);
721 }
722
723 #define test_range_inrange(r1,r2,b) _test_range_inrange(__LINE__,r1,r2,b)
724 static void _test_range_inrange(unsigned line, IHTMLTxtRange *range1, IHTMLTxtRange *range2, VARIANT_BOOL exb)
725 {
726     VARIANT_BOOL b;
727     HRESULT hres;
728
729     b = 0xe0e0;
730     hres = IHTMLTxtRange_inRange(range1, range2, &b);
731     ok_(__FILE__,line) (hres == S_OK, "(1->2) isEqual failed: %08x\n", hres);
732     ok_(__FILE__,line) (b == exb, "(1->2) b=%x, expected %x\n", b, exb);
733 }
734
735 #define test_range_isequal(r1,r2,b) _test_range_isequal(__LINE__,r1,r2,b)
736 static void _test_range_isequal(unsigned line, IHTMLTxtRange *range1, IHTMLTxtRange *range2, VARIANT_BOOL exb)
737 {
738     VARIANT_BOOL b;
739     HRESULT hres;
740
741     b = 0xe0e0;
742     hres = IHTMLTxtRange_isEqual(range1, range2, &b);
743     ok_(__FILE__,line) (hres == S_OK, "(1->2) isEqual failed: %08x\n", hres);
744     ok_(__FILE__,line) (b == exb, "(1->2) b=%x, expected %x\n", b, exb);
745
746     b = 0xe0e0;
747     hres = IHTMLTxtRange_isEqual(range2, range1, &b);
748     ok_(__FILE__,line) (hres == S_OK, "(2->1) isEqual failed: %08x\n", hres);
749     ok_(__FILE__,line) (b == exb, "(2->1) b=%x, expected %x\n", b, exb);
750
751     if(exb) {
752         test_range_inrange(range1, range2, VARIANT_TRUE);
753         test_range_inrange(range2, range1, VARIANT_TRUE);
754     }
755 }
756
757 #define test_range_parent(r,t) _test_range_parent(__LINE__,r,t)
758 static void _test_range_parent(unsigned line, IHTMLTxtRange *range, elem_type_t type)
759 {
760     IHTMLElement *elem;
761     HRESULT hres;
762
763     hres = IHTMLTxtRange_parentElement(range, &elem);
764     ok_(__FILE__,line) (hres == S_OK, "parentElement failed: %08x\n", hres);
765
766     _test_elem_type(line, (IUnknown*)elem, type);
767
768     IHTMLElement_Release(elem);
769 }
770
771 #define test_elem_collection(c,t,l) _test_elem_collection(__LINE__,c,t,l)
772 static void _test_elem_collection(unsigned line, IUnknown *unk,
773         const elem_type_t *elem_types, long exlen)
774 {
775     IHTMLElementCollection *col;
776     long len;
777     DWORD i;
778     VARIANT name, index;
779     IDispatch *disp;
780     HRESULT hres;
781
782     hres = IUnknown_QueryInterface(unk, &IID_IHTMLElementCollection, (void**)&col);
783     ok(hres == S_OK, "Could not get IHTMLElementCollection: %08x\n", hres);
784
785     test_disp((IUnknown*)col, &DIID_DispHTMLElementCollection);
786
787     hres = IHTMLElementCollection_get_length(col, &len);
788     ok_(__FILE__,line) (hres == S_OK, "get_length failed: %08x\n", hres);
789     ok_(__FILE__,line) (len == exlen, "len=%ld, expected %ld\n", len, exlen);
790
791     if(len > exlen)
792         len = exlen;
793
794     V_VT(&index) = VT_EMPTY;
795     V_VT(&name) = VT_I4;
796
797     for(i=0; i<len; i++) {
798         V_I4(&name) = i;
799         disp = (void*)0xdeadbeef;
800         hres = IHTMLElementCollection_item(col, name, index, &disp);
801         ok_(__FILE__,line) (hres == S_OK, "item(%d) failed: %08x\n", i, hres);
802         ok_(__FILE__,line) (disp != NULL, "item returned NULL\n");
803         if(FAILED(hres) || !disp)
804             continue;
805
806         _test_elem_type(line, (IUnknown*)disp, elem_types[i]);
807         IDispatch_Release(disp);
808     }
809
810     V_I4(&name) = len;
811     disp = (void*)0xdeadbeef;
812     hres = IHTMLElementCollection_item(col, name, index, &disp);
813     ok_(__FILE__,line) (hres == S_OK, "item failed: %08x\n", hres);
814     ok_(__FILE__,line) (disp == NULL, "disp != NULL\n");
815
816     V_I4(&name) = -1;
817     disp = (void*)0xdeadbeef;
818     hres = IHTMLElementCollection_item(col, name, index, &disp);
819     ok_(__FILE__,line) (hres == E_INVALIDARG, "item failed: %08x, expected E_INVALIDARG\n", hres);
820     ok_(__FILE__,line) (disp == NULL, "disp != NULL\n");
821
822     IHTMLElementCollection_Release(col);
823 }
824
825 #define get_first_child(n) _get_first_child(__LINE__,n)
826 static IHTMLDOMNode *_get_first_child(unsigned line, IUnknown *unk)
827 {
828     IHTMLDOMNode *node = _get_node_iface(line, unk);
829     IHTMLDOMNode *child = NULL;
830     HRESULT hres;
831
832     hres = IHTMLDOMNode_get_firstChild(node, &child);
833     IHTMLDOMNode_Release(node);
834     ok_(__FILE__,line) (hres == S_OK, "get_firstChild failed: %08x\n", hres);
835
836     return child;
837 }
838
839 #define get_node_type(n) _get_node_type(__LINE__,n)
840 static long _get_node_type(unsigned line, IUnknown *unk)
841 {
842     IHTMLDOMNode *node = _get_node_iface(line, unk);
843     long type = -1;
844     HRESULT hres;
845
846     hres = IHTMLDOMNode_get_nodeType(node, &type);
847     ok(hres == S_OK, "get_nodeType failed: %08x\n", hres);
848
849     IHTMLDOMNode_Release(node);
850
851     return type;
852 }
853
854 #define test_img_set_src(u,s) _test_img_set_src(__LINE__,u,s)
855 static void _test_img_set_src(unsigned line, IUnknown *unk, const char *src)
856 {
857     IHTMLImgElement *img;
858     BSTR tmp;
859     HRESULT hres;
860
861     hres = IUnknown_QueryInterface(unk, &IID_IHTMLImgElement, (void**)&img);
862     ok_(__FILE__,line) (hres == S_OK, "Could not get IHTMLImgElement: %08x\n", hres);
863
864     tmp = a2bstr(src);
865     hres = IHTMLImgElement_put_src(img, tmp);
866     IHTMLImgElement_Release(img);
867     SysFreeString(tmp);
868     ok_(__FILE__,line) (hres == S_OK, "put_src failed: %08x\n", hres);
869 }
870
871 #define test_input_get_disabled(i,b) _test_input_get_disabled(__LINE__,i,b)
872 static void _test_input_get_disabled(unsigned line, IHTMLInputElement *input, VARIANT_BOOL exb)
873 {
874     VARIANT_BOOL disabled = 100;
875     HRESULT hres;
876
877     hres = IHTMLInputElement_get_disabled(input, &disabled);
878     ok_(__FILE__,line) (hres == S_OK, "get_disabled failed: %08x\n", hres);
879     ok_(__FILE__,line) (disabled == exb, "disabled=%x, expected %x\n", disabled, exb);
880 }
881
882 #define test_input_value(o,t) _test_input_value(__LINE__,o,t)
883 static void _test_input_value(unsigned line, IUnknown *unk, const char *exval)
884 {
885     IHTMLInputElement *input;
886     BSTR bstr;
887     HRESULT hres;
888
889     hres = IUnknown_QueryInterface(unk, &IID_IHTMLInputElement, (void**)&input);
890     ok_(__FILE__,line) (hres == S_OK, "Could not get IHTMLInputElement: %08x\n", hres);
891     if(FAILED(hres))
892         return;
893
894     hres = IHTMLInputElement_get_value(input, &bstr);
895     ok_(__FILE__,line) (hres == S_OK, "get_value failed: %08x\n", hres);
896     if(exval)
897         ok_(__FILE__,line) (!strcmp_wa(bstr, exval), "value=%s\n", dbgstr_w(bstr));
898     else
899         ok_(__FILE__,line) (!exval, "exval != NULL\n");
900     SysFreeString(bstr);
901     IHTMLInputElement_Release(input);
902 }
903
904 #define test_input_put_value(o,v) _test_input_put_value(__LINE__,o,v)
905 static void _test_input_put_value(unsigned line, IUnknown *unk, const char *val)
906 {
907     IHTMLInputElement *input;
908     BSTR bstr;
909     HRESULT hres;
910
911     hres = IUnknown_QueryInterface(unk, &IID_IHTMLInputElement, (void**)&input);
912     ok_(__FILE__,line) (hres == S_OK, "Could not get IHTMLInputElement: %08x\n", hres);
913     if(FAILED(hres))
914         return;
915
916     bstr = a2bstr(val);
917     hres = IHTMLInputElement_get_value(input, &bstr);
918     ok_(__FILE__,line) (hres == S_OK, "get_value failed: %08x\n", hres);
919     SysFreeString(bstr);
920     IHTMLInputElement_Release(input);
921 }
922
923 #define get_child_nodes(u) _get_child_nodes(__LINE__,u)
924 static IHTMLDOMChildrenCollection *_get_child_nodes(unsigned line, IUnknown *unk)
925 {
926     IHTMLDOMNode *node = _get_node_iface(line, unk);
927     IHTMLDOMChildrenCollection *col = NULL;
928     IDispatch *disp;
929     HRESULT hres;
930
931     hres = IHTMLDOMNode_get_childNodes(node, &disp);
932     IHTMLDOMNode_Release(node);
933     ok_(__FILE__,line) (hres == S_OK, "get_childNodes failed: %08x\n", hres);
934     if(FAILED(hres))
935         return NULL;
936
937     hres = IDispatch_QueryInterface(disp, &IID_IHTMLDOMChildrenCollection, (void**)&col);
938     IDispatch_Release(disp);
939     ok_(__FILE__,line) (hres == S_OK, "Could not get IHTMLDOMChildrenCollection: %08x\n", hres);
940
941     return col;
942 }
943
944 #define test_elem_class(u,c) _test_elem_class(__LINE__,u,c)
945 static void _test_elem_class(unsigned line, IUnknown *unk, const char *exclass)
946 {
947     IHTMLElement *elem = _get_elem_iface(line, unk);
948     BSTR class = (void*)0xdeadbeef;
949     HRESULT hres;
950
951     hres = IHTMLElement_get_className(elem, &class);
952     IHTMLElement_Release(elem);
953     ok_(__FILE__,line) (hres == S_OK, "get_className failed: %08x\n", hres);
954     if(exclass)
955         ok_(__FILE__,line) (!strcmp_wa(class, exclass), "unexpected className %s\n", dbgstr_w(class));
956     else
957         ok_(__FILE__,line) (!class, "class != NULL\n");
958     SysFreeString(class);
959 }
960
961 #define test_elem_tabindex(u,i) _test_elem_tabindex(__LINE__,u,i)
962 static void _test_elem_tabindex(unsigned line, IUnknown *unk, short exindex)
963 {
964     IHTMLElement2 *elem2 = _get_elem2_iface(line, unk);
965     short index = -3;
966     HRESULT hres;
967
968     hres = IHTMLElement2_get_tabIndex(elem2, &index);
969     IHTMLElement2_Release(elem2);
970     ok_(__FILE__,line) (hres == S_OK, "get_tabIndex failed: %08x\n", hres);
971     ok_(__FILE__,line) (index == exindex, "unexpected index %d\n", index);
972 }
973
974 #define test_elem_set_tabindex(u,i) _test_elem_set_tabindex(__LINE__,u,i)
975 static void _test_elem_set_tabindex(unsigned line, IUnknown *unk, short index)
976 {
977     IHTMLElement2 *elem2 = _get_elem2_iface(line, unk);
978     HRESULT hres;
979
980     hres = IHTMLElement2_put_tabIndex(elem2, index);
981     IHTMLElement2_Release(elem2);
982     ok_(__FILE__,line) (hres == S_OK, "get_tabIndex failed: %08x\n", hres);
983
984     _test_elem_tabindex(line, unk, index);
985 }
986
987 #define test_elem_set_class(u,c) _test_elem_set_class(__LINE__,u,c)
988 static void _test_elem_set_class(unsigned line, IUnknown *unk, const char *class)
989 {
990     IHTMLElement *elem = _get_elem_iface(line, unk);
991     BSTR tmp;
992     HRESULT hres;
993
994     tmp = class ? a2bstr(class) : NULL;
995     hres = IHTMLElement_put_className(elem, tmp);
996     IHTMLElement_Release(elem);
997     ok_(__FILE__,line) (hres == S_OK, "put_className failed: %08x\n", hres);
998     SysFreeString(tmp);
999
1000     _test_elem_class(line, unk, class);
1001 }
1002
1003 #define get_child_item(c,i) _get_child_item(__LINE__,c,i)
1004 static IHTMLDOMNode *_get_child_item(unsigned line, IHTMLDOMChildrenCollection *col, long idx)
1005 {
1006     IHTMLDOMNode *node = NULL;
1007     IDispatch *disp;
1008     HRESULT hres;
1009
1010     hres = IHTMLDOMChildrenCollection_item(col, idx, &disp);
1011     ok(hres == S_OK, "item failed: %08x\n", hres);
1012
1013     node = _get_node_iface(line, (IUnknown*)disp);
1014     IDispatch_Release(disp);
1015
1016     return node;
1017 }
1018
1019 #define test_elem_id(e,i) _test_elem_id(__LINE__,e,i)
1020 static void _test_elem_id(unsigned line, IUnknown *unk, const char *exid)
1021 {
1022     IHTMLElement *elem = _get_elem_iface(line, unk);
1023     BSTR id = (void*)0xdeadbeef;
1024     HRESULT hres;
1025
1026     hres = IHTMLElement_get_id(elem, &id);
1027     IHTMLElement_Release(elem);
1028     ok_(__FILE__,line) (hres == S_OK, "get_id failed: %08x\n", hres);
1029
1030     if(exid)
1031         ok_(__FILE__,line) (!strcmp_wa(id, exid), "unexpected id %s\n", dbgstr_w(id));
1032     else
1033         ok_(__FILE__,line) (!id, "id=%s\n", dbgstr_w(id));
1034
1035     SysFreeString(id);
1036 }
1037
1038 #define test_elem_put_id(u,i) _test_elem_put_id(__LINE__,u,i)
1039 static void _test_elem_put_id(unsigned line, IUnknown *unk, const char *new_id)
1040 {
1041     IHTMLElement *elem = _get_elem_iface(line, unk);
1042     BSTR tmp = a2bstr(new_id);
1043     HRESULT hres;
1044
1045     hres = IHTMLElement_put_id(elem, tmp);
1046     IHTMLElement_Release(elem);
1047     SysFreeString(tmp);
1048     ok_(__FILE__,line) (hres == S_OK, "put_id failed: %08x\n", hres);
1049
1050     _test_elem_id(line, unk, new_id);
1051 }
1052
1053 #define test_node_get_value_str(u,e) _test_node_get_value_str(__LINE__,u,e)
1054 static void _test_node_get_value_str(unsigned line, IUnknown *unk, const char *exval)
1055 {
1056     IHTMLDOMNode *node = _get_node_iface(line, unk);
1057     VARIANT var;
1058     HRESULT hres;
1059
1060     hres = IHTMLDOMNode_get_nodeValue(node, &var);
1061     IHTMLDOMNode_Release(node);
1062     ok_(__FILE__,line) (hres == S_OK, "get_nodeValue failed: %08x, expected VT_BSTR\n", hres);
1063
1064     if(exval) {
1065         ok_(__FILE__,line) (V_VT(&var) == VT_BSTR, "vt=%d\n", V_VT(&var));
1066         ok_(__FILE__,line) (!strcmp_wa(V_BSTR(&var), exval), "unexpected value %s\n", dbgstr_w(V_BSTR(&var)));
1067     }else {
1068         ok_(__FILE__,line) (V_VT(&var) == VT_NULL, "vt=%d, expected VT_NULL\n", V_VT(&var));
1069     }
1070
1071     VariantClear(&var);
1072 }
1073
1074 #define test_node_put_value_str(u,v) _test_node_put_value_str(__LINE__,u,v)
1075 static void _test_node_put_value_str(unsigned line, IUnknown *unk, const char *val)
1076 {
1077     IHTMLDOMNode *node = _get_node_iface(line, unk);
1078     VARIANT var;
1079     HRESULT hres;
1080
1081     V_VT(&var) = VT_BSTR;
1082     V_BSTR(&var) = a2bstr(val);
1083
1084     hres = IHTMLDOMNode_put_nodeValue(node, var);
1085     ok_(__FILE__,line) (hres == S_OK, "get_nodeValue failed: %08x, expected VT_BSTR\n", hres);
1086     IHTMLDOMNode_Release(node);
1087     VariantClear(&var);
1088 }
1089
1090 #define test_elem_client_size(u) _test_elem_client_size(__LINE__,u)
1091 static void _test_elem_client_size(unsigned line, IUnknown *unk)
1092 {
1093     IHTMLElement2 *elem = _get_elem2_iface(line, unk);
1094     long l;
1095     HRESULT hres;
1096
1097     hres = IHTMLElement2_get_clientWidth(elem, &l);
1098     ok_(__FILE__,line) (hres == S_OK, "get_clientWidth failed: %08x\n", hres);
1099     hres = IHTMLElement2_get_clientHeight(elem, &l);
1100     ok_(__FILE__,line) (hres == S_OK, "get_clientHeight failed: %08x\n", hres);
1101
1102     IHTMLElement2_Release(elem);
1103 }
1104
1105 #define test_create_elem(d,t) _test_create_elem(__LINE__,d,t)
1106 static IHTMLElement *_test_create_elem(unsigned line, IHTMLDocument2 *doc, const char *tag)
1107 {
1108     IHTMLElement *elem = NULL;
1109     BSTR tmp;
1110     HRESULT hres;
1111
1112     tmp = a2bstr(tag);
1113     hres = IHTMLDocument2_createElement(doc, tmp, &elem);
1114     ok_(__FILE__,line) (hres == S_OK, "createElement failed: %08x\n", hres);
1115     ok_(__FILE__,line) (elem != NULL, "elem == NULL\n");
1116
1117     return elem;
1118 }
1119
1120 #define test_create_text(d,t) _test_create_text(__LINE__,d,t)
1121 static IHTMLDOMNode *_test_create_text(unsigned line, IHTMLDocument2 *doc, const char *text)
1122 {
1123     IHTMLDocument3 *doc3;
1124     IHTMLDOMNode *node = NULL;
1125     BSTR tmp;
1126     HRESULT hres;
1127
1128     hres = IHTMLDocument2_QueryInterface(doc, &IID_IHTMLDocument3, (void**)&doc3);
1129     ok_(__FILE__,line) (hres == S_OK, "Could not get IHTMLDocument3: %08x\n", hres);
1130
1131     tmp = a2bstr(text);
1132     hres = IHTMLDocument3_createTextNode(doc3, tmp, &node);
1133     IHTMLDocument3_Release(doc3);
1134     ok_(__FILE__,line) (hres == S_OK, "createElement failed: %08x\n", hres);
1135     ok_(__FILE__,line) (node != NULL, "node == NULL\n");
1136
1137     return node;
1138 }
1139
1140 #define test_node_append_child(n,c) _test_node_append_child(__LINE__,n,c)
1141 static IHTMLDOMNode *_test_node_append_child(unsigned line, IUnknown *node_unk, IUnknown *child_unk)
1142 {
1143     IHTMLDOMNode *node = _get_node_iface(line, node_unk);
1144     IHTMLDOMNode *child = _get_node_iface(line, child_unk);
1145     IHTMLDOMNode *new_child = NULL;
1146     HRESULT hres;
1147
1148     hres = IHTMLDOMNode_appendChild(node, child, &new_child);
1149     ok_(__FILE__,line) (hres == S_OK, "appendChild failed: %08x\n", hres);
1150     ok_(__FILE__,line) (new_child != NULL, "new_child == NULL\n");
1151     /* TODO  ok_(__FILE__,line) (new_child != child, "new_child == child\n"); */
1152
1153     IHTMLDOMNode_Release(node);
1154     IHTMLDOMNode_Release(child);
1155
1156     return new_child;
1157 }
1158
1159 #define test_node_remove_child(n,c) _test_node_remove_child(__LINE__,n,c)
1160 static void _test_node_remove_child(unsigned line, IUnknown *unk, IHTMLDOMNode *child)
1161 {
1162     IHTMLDOMNode *node = _get_node_iface(line, unk);
1163     IHTMLDOMNode *new_node = NULL;
1164     HRESULT hres;
1165
1166     hres = IHTMLDOMNode_removeChild(node, child, &new_node);
1167     ok_(__FILE__,line) (hres == S_OK, "appendChild failed: %08x\n", hres);
1168     ok_(__FILE__,line) (new_node != NULL, "new_node == NULL\n");
1169     /* TODO ok_(__FILE__,line) (new_node != child, "new_node == child\n"); */
1170
1171     IHTMLDOMNode_Release(node);
1172     IHTMLDOMNode_Release(new_node);
1173 }
1174
1175 static void test_elem_col_item(IHTMLElementCollection *col, LPCWSTR n,
1176         const elem_type_t *elem_types, long len)
1177 {
1178     IDispatch *disp;
1179     VARIANT name, index;
1180     DWORD i;
1181     HRESULT hres;
1182
1183     V_VT(&index) = VT_EMPTY;
1184     V_VT(&name) = VT_BSTR;
1185     V_BSTR(&name) = SysAllocString(n);
1186
1187     hres = IHTMLElementCollection_item(col, name, index, &disp);
1188     ok(hres == S_OK, "item failed: %08x\n", hres);
1189
1190     test_elem_collection((IUnknown*)disp, elem_types, len);
1191     IDispatch_Release(disp);
1192     ok(hres == S_OK, "Could not get IHTMLElementCollection interface: %08x\n", hres);
1193     if(hres != S_OK)
1194         goto cleanup;
1195
1196     V_VT(&index) = VT_I4;
1197
1198     for(i=0; i<len; i++) {
1199         V_I4(&index) = i;
1200         disp = (void*)0xdeadbeef;
1201         hres = IHTMLElementCollection_item(col, name, index, &disp);
1202         ok(hres == S_OK, "item failed: %08x\n", hres);
1203         ok(disp != NULL, "disp == NULL\n");
1204         if(FAILED(hres) || !disp)
1205             continue;
1206
1207         test_elem_type((IUnknown*)disp, elem_types[i]);
1208
1209         IDispatch_Release(disp);
1210     }
1211
1212     V_I4(&index) = len;
1213     disp = (void*)0xdeadbeef;
1214     hres = IHTMLElementCollection_item(col, name, index, &disp);
1215     ok(hres == S_OK, "item failed: %08x\n", hres);
1216     ok(disp == NULL, "disp != NULL\n");
1217
1218     V_I4(&index) = -1;
1219     disp = (void*)0xdeadbeef;
1220     hres = IHTMLElementCollection_item(col, name, index, &disp);
1221     ok(hres == E_INVALIDARG, "item failed: %08x, expected E_INVALIDARG\n", hres);
1222     ok(disp == NULL, "disp != NULL\n");
1223
1224 cleanup:
1225     SysFreeString(V_BSTR(&name));
1226 }
1227
1228 static IHTMLElement *get_elem_by_id(IHTMLDocument2 *doc, LPCWSTR id, BOOL expect_success)
1229 {
1230     IHTMLElementCollection *col;
1231     IHTMLElement *elem;
1232     IDispatch *disp = (void*)0xdeadbeef;
1233     VARIANT name, index;
1234     HRESULT hres;
1235
1236     hres = IHTMLDocument2_get_all(doc, &col);
1237     ok(hres == S_OK, "get_all failed: %08x\n", hres);
1238     ok(col != NULL, "col == NULL\n");
1239     if(FAILED(hres) || !col)
1240         return NULL;
1241
1242     V_VT(&index) = VT_EMPTY;
1243     V_VT(&name) = VT_BSTR;
1244     V_BSTR(&name) = SysAllocString(id);
1245
1246     hres = IHTMLElementCollection_item(col, name, index, &disp);
1247     IHTMLElementCollection_Release(col);
1248     SysFreeString(V_BSTR(&name));
1249     ok(hres == S_OK, "item failed: %08x\n", hres);
1250     if(!expect_success) {
1251         ok(disp == NULL, "disp != NULL\n");
1252         return NULL;
1253     }
1254
1255     ok(disp != NULL, "disp == NULL\n");
1256     if(!disp)
1257         return NULL;
1258
1259     elem = get_elem_iface((IUnknown*)disp);
1260     IDispatch_Release(disp);
1261
1262     return elem;
1263 }
1264
1265 static IHTMLElement *get_doc_elem_by_id(IHTMLDocument2 *doc, LPCWSTR id)
1266 {
1267     IHTMLDocument3 *doc3;
1268     IHTMLElement *elem;
1269     BSTR tmp;
1270     HRESULT hres;
1271
1272     hres = IHTMLDocument2_QueryInterface(doc, &IID_IHTMLDocument3, (void**)&doc3);
1273     ok(hres == S_OK, "Could not get IHTMLDocument3 iface: %08x\n", hres);
1274
1275     tmp = SysAllocString(id);
1276     hres = IHTMLDocument3_getElementById(doc3, tmp, &elem);
1277     SysFreeString(tmp);
1278     ok(hres == S_OK, "getElementById(%s) failed: %08x\n", dbgstr_w(id), hres);
1279
1280     IHTMLDocument3_Release(doc3);
1281
1282     return elem;
1283 }
1284
1285 static void test_select_elem(IHTMLSelectElement *select)
1286 {
1287     test_select_length(select, 2);
1288     test_select_selidx(select, 0);
1289     test_select_put_selidx(select, 1);
1290 }
1291
1292 static void test_create_option_elem(IHTMLDocument2 *doc)
1293 {
1294     IHTMLOptionElement *option;
1295
1296     option = create_option_elem(doc, "test text", "test value");
1297
1298     test_option_put_text(option, "new text");
1299     test_option_put_value(option, "new value");
1300
1301     IHTMLOptionElement_Release(option);
1302 }
1303
1304 static IHTMLTxtRange *test_create_body_range(IHTMLDocument2 *doc)
1305 {
1306     IHTMLBodyElement *body;
1307     IHTMLTxtRange *range;
1308     IHTMLElement *elem;
1309     HRESULT hres;
1310
1311     hres = IHTMLDocument2_get_body(doc, &elem);
1312     ok(hres == S_OK, "get_body failed: %08x\n", hres);
1313
1314     hres = IHTMLElement_QueryInterface(elem, &IID_IHTMLBodyElement, (void**)&body);
1315     IHTMLElement_Release(elem);
1316
1317     hres = IHTMLBodyElement_createTextRange(body, &range);
1318     IHTMLBodyElement_Release(body);
1319     ok(hres == S_OK, "createTextRange failed: %08x\n", hres);
1320
1321     return range;
1322 }
1323
1324 static void test_txtrange(IHTMLDocument2 *doc)
1325 {
1326     IHTMLTxtRange *body_range, *range, *range2;
1327     IHTMLSelectionObject *selection;
1328     IDispatch *disp_range;
1329     HRESULT hres;
1330
1331     body_range = test_create_body_range(doc);
1332
1333     test_range_text(body_range, "test abc 123\r\nit's text");
1334
1335     hres = IHTMLTxtRange_duplicate(body_range, &range);
1336     ok(hres == S_OK, "duplicate failed: %08x\n", hres);
1337
1338     hres = IHTMLTxtRange_duplicate(body_range, &range2);
1339     ok(hres == S_OK, "duplicate failed: %08x\n", hres);
1340     test_range_isequal(range, range2, VARIANT_TRUE);
1341
1342     test_range_text(range, "test abc 123\r\nit's text");
1343     test_range_text(body_range, "test abc 123\r\nit's text");
1344
1345     test_range_collapse(range, TRUE);
1346     test_range_isequal(range, range2, VARIANT_FALSE);
1347     test_range_inrange(range, range2, VARIANT_FALSE);
1348     test_range_inrange(range2, range, VARIANT_TRUE);
1349     IHTMLTxtRange_Release(range2);
1350
1351     test_range_expand(range, wordW, VARIANT_TRUE, "test ");
1352     test_range_expand(range, wordW, VARIANT_FALSE, "test ");
1353     test_range_move(range, characterW, 2, 2);
1354     test_range_expand(range, wordW, VARIANT_TRUE, "test ");
1355
1356     test_range_collapse(range, FALSE);
1357     test_range_expand(range, wordW, VARIANT_TRUE, "abc ");
1358
1359     test_range_collapse(range, FALSE);
1360     test_range_expand(range, wordW, VARIANT_TRUE, "123");
1361     test_range_expand(range, wordW, VARIANT_FALSE, "123");
1362     test_range_move(range, characterW, 2, 2);
1363     test_range_expand(range, wordW, VARIANT_TRUE, "123");
1364     test_range_moveend(range, characterW, -5, -5);
1365     test_range_text(range, NULL);
1366     test_range_moveend(range, characterW, 3, 3);
1367     test_range_text(range, "c 1");
1368     test_range_expand(range, texteditW, VARIANT_TRUE, "test abc 123\r\nit's text");
1369     test_range_collapse(range, TRUE);
1370     test_range_move(range, characterW, 4, 4);
1371     test_range_moveend(range, characterW, 1, 1);
1372     test_range_text(range, " ");
1373     test_range_move(range, wordW, 1, 1);
1374     test_range_moveend(range, characterW, 2, 2);
1375     test_range_text(range, "ab");
1376
1377     IHTMLTxtRange_Release(range);
1378
1379     hres = IHTMLTxtRange_duplicate(body_range, &range);
1380     ok(hres == S_OK, "duplicate failed: %08x\n", hres);
1381
1382     test_range_text(range, "test abc 123\r\nit's text");
1383     test_range_move(range, characterW, 3, 3);
1384     test_range_moveend(range, characterW, 1, 1);
1385     test_range_text(range, "t");
1386     test_range_moveend(range, characterW, 3, 3);
1387     test_range_text(range, "t ab");
1388     test_range_moveend(range, characterW, -2, -2);
1389     test_range_text(range, "t ");
1390     test_range_move(range, characterW, 6, 6);
1391     test_range_moveend(range, characterW, 3, 3);
1392     test_range_text(range, "123");
1393     test_range_moveend(range, characterW, 2, 2);
1394     test_range_text(range, "123\r\ni");
1395
1396     IHTMLTxtRange_Release(range);
1397
1398     hres = IHTMLTxtRange_duplicate(body_range, &range);
1399     ok(hres == S_OK, "duplicate failed: %08x\n", hres);
1400
1401     test_range_move(range, wordW, 1, 1);
1402     test_range_moveend(range, characterW, 2, 2);
1403     test_range_text(range, "ab");
1404
1405     test_range_move(range, characterW, -2, -2);
1406     test_range_moveend(range, characterW, 2, 2);
1407     test_range_text(range, "t ");
1408
1409     test_range_move(range, wordW, 3, 3);
1410     test_range_move(range, wordW, -2, -2);
1411     test_range_moveend(range, characterW, 2, 2);
1412     test_range_text(range, "ab");
1413
1414     test_range_move(range, characterW, -6, -5);
1415     test_range_moveend(range, characterW, -1, 0);
1416     test_range_moveend(range, characterW, -6, 0);
1417     test_range_move(range, characterW, 2, 2);
1418     test_range_moveend(range, characterW, 2, 2);
1419     test_range_text(range, "st");
1420     test_range_moveend(range, characterW, -6, -4);
1421     test_range_moveend(range, characterW, 2, 2);
1422
1423     IHTMLTxtRange_Release(range);
1424
1425     hres = IHTMLTxtRange_duplicate(body_range, &range);
1426     ok(hres == S_OK, "duplicate failed: %08x\n", hres);
1427
1428     test_range_move(range, wordW, 2, 2);
1429     test_range_moveend(range, characterW, 2, 2);
1430     test_range_text(range, "12");
1431
1432     test_range_move(range, characterW, 15, 14);
1433     test_range_move(range, characterW, -2, -2);
1434     test_range_moveend(range, characterW, 3, 2);
1435     test_range_text(range, "t");
1436     test_range_moveend(range, characterW, -1, -1);
1437     test_range_text(range, "t");
1438     test_range_expand(range, wordW, VARIANT_TRUE, "text");
1439     test_range_move(range, characterW, -2, -2);
1440     test_range_moveend(range, characterW, 2, 2);
1441     test_range_text(range, "s ");
1442     test_range_move(range, characterW, 100, 7);
1443     test_range_move(range, wordW, 1, 0);
1444     test_range_move(range, characterW, -2, -2);
1445     test_range_moveend(range, characterW, 3, 2);
1446     test_range_text(range, "t");
1447
1448     IHTMLTxtRange_Release(range);
1449
1450     hres = IHTMLTxtRange_duplicate(body_range, &range);
1451     ok(hres == S_OK, "duplicate failed: %08x\n", hres);
1452
1453     test_range_collapse(range, TRUE);
1454     test_range_expand(range, wordW, VARIANT_TRUE, "test ");
1455     test_range_put_text(range, "word");
1456     test_range_text(body_range, "wordabc 123\r\nit's text");
1457     test_range_text(range, NULL);
1458     test_range_moveend(range, characterW, 3, 3);
1459     test_range_text(range, "abc");
1460     test_range_movestart(range, characterW, -2, -2);
1461     test_range_text(range, "rdabc");
1462     test_range_movestart(range, characterW, 3, 3);
1463     test_range_text(range, "bc");
1464     test_range_movestart(range, characterW, 4, 4);
1465     test_range_text(range, NULL);
1466     test_range_movestart(range, characterW, -3, -3);
1467     test_range_text(range, "c 1");
1468     test_range_movestart(range, characterW, -7, -6);
1469     test_range_text(range, "wordabc 1");
1470     test_range_movestart(range, characterW, 100, 22);
1471     test_range_text(range, NULL);
1472
1473     IHTMLTxtRange_Release(range);
1474     IHTMLTxtRange_Release(body_range);
1475
1476     hres = IHTMLDocument2_get_selection(doc, &selection);
1477     ok(hres == S_OK, "IHTMLDocument2_get_selection failed: %08x\n", hres);
1478
1479     hres = IHTMLSelectionObject_createRange(selection, &disp_range);
1480     ok(hres == S_OK, "IHTMLSelectionObject_createRange failed: %08x\n", hres);
1481     IHTMLSelectionObject_Release(selection);
1482
1483     hres = IDispatch_QueryInterface(disp_range, &IID_IHTMLTxtRange, (void **)&range);
1484     ok(hres == S_OK, "Could not get IID_IHTMLTxtRange interface: 0x%08x\n", hres);
1485     IDispatch_Release(disp_range);
1486
1487     test_range_text(range, NULL);
1488     test_range_moveend(range, characterW, 3, 3);
1489     test_range_text(range, "wor");
1490     test_range_parent(range, ET_BODY);
1491     test_range_expand(range, texteditW, VARIANT_TRUE, "wordabc 123\r\nit's text");
1492     test_range_expand(range, texteditW, VARIANT_TRUE, "wordabc 123\r\nit's text");
1493     test_range_move(range, characterW, 3, 3);
1494     test_range_expand(range, wordW, VARIANT_TRUE, "wordabc ");
1495     test_range_moveend(range, characterW, -4, -4);
1496     test_range_put_text(range, "abc def ");
1497     test_range_expand(range, texteditW, VARIANT_TRUE, "abc def abc 123\r\nit's text");
1498     test_range_move(range, wordW, 1, 1);
1499     test_range_movestart(range, characterW, -1, -1);
1500     test_range_text(range, " ");
1501     test_range_move(range, wordW, 1, 1);
1502     test_range_moveend(range, characterW, 3, 3);
1503     test_range_text(range, "def");
1504     test_range_put_text(range, "xyz");
1505     test_range_moveend(range, characterW, 1, 1);
1506     test_range_move(range, wordW, 1, 1);
1507     test_range_moveend(range, characterW, 2, 2);
1508     test_range_text(range, "ab");
1509
1510     IHTMLTxtRange_Release(range);
1511 }
1512
1513 static void test_txtrange2(IHTMLDocument2 *doc)
1514 {
1515     IHTMLTxtRange *range;
1516
1517     range = test_create_body_range(doc);
1518
1519     test_range_text(range, "abc\r\n\r\n123\r\n\r\n\r\ndef");
1520     test_range_move(range, characterW, 5, 5);
1521     test_range_moveend(range, characterW, 1, 1);
1522     test_range_text(range, "2");
1523     test_range_move(range, characterW, -3, -3);
1524     test_range_moveend(range, characterW, 3, 3);
1525     test_range_text(range, "c\r\n\r\n1");
1526     test_range_collapse(range, VARIANT_FALSE);
1527     test_range_moveend(range, characterW, 4, 4);
1528     test_range_text(range, "23");
1529     test_range_moveend(range, characterW, 1, 1);
1530     test_range_text(range, "23\r\n\r\n\r\nd");
1531     test_range_moveend(range, characterW, -1, -1);
1532     test_range_text(range, "23");
1533     test_range_moveend(range, characterW, -1, -1);
1534     test_range_text(range, "23");
1535     test_range_moveend(range, characterW, -2, -2);
1536     test_range_text(range, "2");
1537
1538     IHTMLTxtRange_Release(range);
1539 }
1540
1541 static void test_compatmode(IHTMLDocument2 *doc)
1542 {
1543     IHTMLDocument5 *doc5;
1544     BSTR mode;
1545     HRESULT hres;
1546
1547     hres = IHTMLDocument2_QueryInterface(doc, &IID_IHTMLDocument5, (void**)&doc5);
1548     ok(hres == S_OK, "Could not get IHTMLDocument5 interface: %08x\n", hres);
1549     if(FAILED(hres))
1550         return;
1551
1552     hres = IHTMLDocument5_get_compatMode(doc5, &mode);
1553     IHTMLDocument5_Release(doc5);
1554     ok(hres == S_OK, "get_compatMode failed: %08x\n", hres);
1555     ok(!strcmp_wa(mode, "BackCompat"), "compatMode=%s\n", dbgstr_w(mode));
1556     SysFreeString(mode);
1557 }
1558
1559 static void test_location(IHTMLDocument2 *doc)
1560 {
1561     IHTMLLocation *location, *location2;
1562     ULONG ref;
1563     HRESULT hres;
1564
1565     hres = IHTMLDocument2_get_location(doc, &location);
1566     ok(hres == S_OK, "get_location failed: %08x\n", hres);
1567
1568     hres = IHTMLDocument2_get_location(doc, &location2);
1569     ok(hres == S_OK, "get_location failed: %08x\n", hres);
1570
1571     ok(location == location2, "location != location2\n");
1572
1573     test_ifaces((IUnknown*)location, location_iids);
1574
1575     IHTMLLocation_Release(location2);
1576     ref = IHTMLLocation_Release(location);
1577     ok(!ref, "location chould be destroyed here\n");
1578 }
1579
1580 static void test_navigator(IHTMLDocument2 *doc)
1581 {
1582     IHTMLWindow2 *window;
1583     IOmNavigator *navigator, *navigator2;
1584     ULONG ref;
1585     HRESULT hres;
1586
1587     hres = IHTMLDocument2_get_parentWindow(doc, &window);
1588     ok(hres == S_OK, "parentWidnow failed: %08x\n", hres);
1589
1590     hres = IHTMLWindow2_get_navigator(window, &navigator);
1591     ok(hres == S_OK, "get_navigator failed: %08x\n", hres);
1592     ok(navigator != NULL, "navigator == NULL\n");
1593     test_disp((IUnknown*)navigator, &IID_IOmNavigator);
1594
1595     hres = IHTMLWindow2_get_navigator(window, &navigator2);
1596     ok(hres == S_OK, "get_navigator failed: %08x\n", hres);
1597     ok(navigator != navigator2, "navigator2 != navihgator\n");
1598
1599     IHTMLWindow2_Release(window);
1600     IOmNavigator_Release(navigator2);
1601     ref = IOmNavigator_Release(navigator);
1602     ok(!ref, "navigator should be destroyed here\n");
1603 }
1604
1605 static void test_default_style(IHTMLStyle *style)
1606 {
1607     VARIANT_BOOL b;
1608     VARIANT v;
1609     BSTR str;
1610     HRESULT hres;
1611
1612     test_disp((IUnknown*)style, &DIID_DispHTMLStyle);
1613
1614     str = (void*)0xdeadbeef;
1615     hres = IHTMLStyle_get_fontFamily(style, &str);
1616     ok(hres == S_OK, "get_fontFamily failed: %08x\n", hres);
1617     ok(!str, "fontFamily = %s\n", dbgstr_w(str));
1618
1619     str = (void*)0xdeadbeef;
1620     hres = IHTMLStyle_get_fontWeight(style, &str);
1621     ok(hres == S_OK, "get_fontWeight failed: %08x\n", hres);
1622     ok(!str, "fontWeight = %s\n", dbgstr_w(str));
1623
1624     str = (void*)0xdeadbeef;
1625     hres = IHTMLStyle_get_display(style, &str);
1626     ok(hres == S_OK, "get_display failed: %08x\n", hres);
1627     ok(!str, "display = %s\n", dbgstr_w(str));
1628
1629     str = (void*)0xdeadbeef;
1630     hres = IHTMLStyle_get_visibility(style, &str);
1631     ok(hres == S_OK, "get_visibility failed: %08x\n", hres);
1632     ok(!str, "visibility = %s\n", dbgstr_w(str));
1633
1634     V_VT(&v) = VT_NULL;
1635     hres = IHTMLStyle_get_fontSize(style, &v);
1636     ok(hres == S_OK, "get_fontSize failed: %08x\n", hres);
1637     ok(V_VT(&v) == VT_BSTR, "V_VT(fontSize) = %d\n", V_VT(&v));
1638     ok(!V_BSTR(&v), "V_BSTR(fontSize) = %s\n", dbgstr_w(V_BSTR(&v)));
1639
1640     V_VT(&v) = VT_NULL;
1641     hres = IHTMLStyle_get_color(style, &v);
1642     ok(hres == S_OK, "get_color failed: %08x\n", hres);
1643     ok(V_VT(&v) == VT_BSTR, "V_VT(color) = %d\n", V_VT(&v));
1644     ok(!V_BSTR(&v), "V_BSTR(color) = %s\n", dbgstr_w(V_BSTR(&v)));
1645
1646     b = 0xfefe;
1647     hres = IHTMLStyle_get_textDecorationUnderline(style, &b);
1648     ok(hres == S_OK, "get_textDecorationUnderline failed: %08x\n", hres);
1649     ok(b == VARIANT_FALSE, "textDecorationUnderline = %x\n", b);
1650
1651     b = 0xfefe;
1652     hres = IHTMLStyle_get_textDecorationLineThrough(style, &b);
1653     ok(hres == S_OK, "get_textDecorationLineThrough failed: %08x\n", hres);
1654     ok(b == VARIANT_FALSE, "textDecorationLineThrough = %x\n", b);
1655 }
1656
1657 static void test_default_selection(IHTMLDocument2 *doc)
1658 {
1659     IHTMLSelectionObject *selection;
1660     IHTMLTxtRange *range;
1661     IDispatch *disp;
1662     BSTR str;
1663     HRESULT hres;
1664
1665     hres = IHTMLDocument2_get_selection(doc, &selection);
1666     ok(hres == S_OK, "get_selection failed: %08x\n", hres);
1667
1668     hres = IHTMLSelectionObject_get_type(selection, &str);
1669     ok(hres == S_OK, "get_type failed: %08x\n", hres);
1670     ok(!lstrcmpW(str, noneW), "type = %s\n", dbgstr_w(str));
1671     SysFreeString(str);
1672
1673     hres = IHTMLSelectionObject_createRange(selection, &disp);
1674     IHTMLSelectionObject_Release(selection);
1675     ok(hres == S_OK, "createRange failed: %08x\n", hres);
1676
1677     hres = IDispatch_QueryInterface(disp, &IID_IHTMLTxtRange, (void**)&range);
1678     IDispatch_Release(disp);
1679     ok(hres == S_OK, "Could not get IHTMLTxtRange interface: %08x\n", hres);
1680
1681     test_range_text(range, NULL);
1682     IHTMLTxtRange_Release(range);
1683 }
1684
1685 static void test_default_body(IHTMLBodyElement *body)
1686 {
1687     BSTR bstr;
1688     HRESULT hres;
1689
1690     bstr = (void*)0xdeadbeef;
1691     hres = IHTMLBodyElement_get_background(body, &bstr);
1692     ok(hres == S_OK, "get_background failed: %08x\n", hres);
1693     ok(bstr == NULL, "bstr != NULL\n");
1694 }
1695
1696 static void test_window(IHTMLDocument2 *doc)
1697 {
1698     IHTMLWindow2 *window;
1699     IHTMLDocument2 *doc2 = NULL;
1700     HRESULT hres;
1701
1702     hres = IHTMLDocument2_get_parentWindow(doc, &window);
1703     ok(hres == S_OK, "get_parentElement failed: %08x\n", hres);
1704     test_ifaces((IUnknown*)window, window_iids);
1705     test_disp((IUnknown*)window, &DIID_DispHTMLWindow2);
1706
1707     hres = IHTMLWindow2_get_document(window, &doc2);
1708     ok(hres == S_OK, "get_document failed: %08x\n", hres);
1709     ok(doc2 != NULL, "doc2 == NULL\n");
1710
1711     IHTMLDocument_Release(doc2);
1712     IHTMLWindow2_Release(window);
1713 }
1714
1715 static void test_defaults(IHTMLDocument2 *doc)
1716 {
1717     IHTMLStyleSheetsCollection *stylesheetcol;
1718     IHTMLBodyElement *body;
1719     IHTMLElement *elem;
1720     IHTMLStyle *style;
1721     long l;
1722     HRESULT hres;
1723
1724     hres = IHTMLDocument2_get_body(doc, &elem);
1725     ok(hres == S_OK, "get_body failed: %08x\n", hres);
1726
1727     hres = IHTMLElement_QueryInterface(elem, &IID_IHTMLBodyElement, (void**)&body);
1728     ok(hres == S_OK, "Could not get IHTMBodyElement: %08x\n", hres);
1729     test_default_body(body);
1730     IHTMLBodyElement_Release(body);
1731
1732     hres = IHTMLElement_get_style(elem, &style);
1733     IHTMLElement_Release(elem);
1734     ok(hres == S_OK, "get_style failed: %08x\n", hres);
1735
1736     test_default_style(style);
1737     test_window(doc);
1738     test_compatmode(doc);
1739     test_location(doc);
1740     test_navigator(doc);
1741
1742     IHTMLStyle_Release(style);
1743
1744     hres = IHTMLDocument2_get_styleSheets(doc, &stylesheetcol);
1745     ok(hres == S_OK, "get_styleSheets failed: %08x\n", hres);
1746
1747     l = 0xdeadbeef;
1748     hres = IHTMLStyleSheetsCollection_get_length(stylesheetcol, &l);
1749     ok(hres == S_OK, "get_length failed: %08x\n", hres);
1750     ok(l == 0, "length = %ld\n", l);
1751
1752     IHTMLStyleSheetsCollection_Release(stylesheetcol);
1753
1754     test_default_selection(doc);
1755 }
1756
1757 static void test_stylesheet(IDispatch *disp)
1758 {
1759     IHTMLStyleSheetRulesCollection *col = NULL;
1760     IHTMLStyleSheet *stylesheet;
1761     HRESULT hres;
1762
1763     hres = IDispatch_QueryInterface(disp, &IID_IHTMLStyleSheet, (void**)&stylesheet);
1764     ok(hres == S_OK, "Could not get IHTMLStyleSheet: %08x\n", hres);
1765
1766     hres = IHTMLStyleSheet_get_rules(stylesheet, &col);
1767     ok(hres == S_OK, "get_rules failed: %08x\n", hres);
1768     ok(col != NULL, "col == NULL\n");
1769
1770     IHTMLStyleSheetRulesCollection_Release(col);
1771     IHTMLStyleSheet_Release(stylesheet);
1772 }
1773
1774 static void test_stylesheets(IHTMLDocument2 *doc)
1775 {
1776     IHTMLStyleSheetsCollection *col = NULL;
1777     VARIANT idx, res;
1778     long len = 0;
1779     HRESULT hres;
1780
1781     hres = IHTMLDocument2_get_styleSheets(doc, &col);
1782     ok(hres == S_OK, "get_styleSheets failed: %08x\n", hres);
1783     ok(col != NULL, "col == NULL\n");
1784
1785     hres = IHTMLStyleSheetsCollection_get_length(col, &len);
1786     ok(hres == S_OK, "get_length failed: %08x\n", hres);
1787     ok(len == 1, "len=%ld\n", len);
1788
1789     VariantInit(&res);
1790     V_VT(&idx) = VT_I4;
1791     V_I4(&idx) = 0;
1792
1793     hres = IHTMLStyleSheetsCollection_item(col, &idx, &res);
1794     ok(hres == S_OK, "item failed: %08x\n", hres);
1795     ok(V_VT(&res) == VT_DISPATCH, "V_VT(res) = %d\n", V_VT(&res));
1796     ok(V_DISPATCH(&res) != NULL, "V_DISPATCH(&res) == NULL\n");
1797     test_stylesheet(V_DISPATCH(&res));
1798     VariantClear(&res);
1799
1800     V_VT(&res) = VT_I4;
1801     V_VT(&idx) = VT_I4;
1802     V_I4(&idx) = 1;
1803
1804     hres = IHTMLStyleSheetsCollection_item(col, &idx, &res);
1805     ok(hres == E_INVALIDARG, "item failed: %08x, expected E_INVALIDARG\n", hres);
1806     ok(V_VT(&res) == VT_EMPTY, "V_VT(res) = %d\n", V_VT(&res));
1807     ok(V_DISPATCH(&res) != NULL, "V_DISPATCH(&res) == NULL\n");
1808     VariantClear(&res);
1809
1810     IHTMLStyleSheetsCollection_Release(col);
1811 }
1812
1813 static void test_child_col_disp(IHTMLDOMChildrenCollection *col)
1814 {
1815     IDispatchEx *dispex;
1816     IHTMLDOMNode *node;
1817     DISPPARAMS dp = {NULL, NULL, 0, 0};
1818     VARIANT var;
1819     EXCEPINFO ei;
1820     long type;
1821     DISPID id;
1822     BSTR bstr;
1823     HRESULT hres;
1824
1825     static const WCHAR w0[] = {'0',0};
1826     static const WCHAR w100[] = {'1','0','0',0};
1827
1828     hres = IHTMLDOMChildrenCollection_QueryInterface(col, &IID_IDispatchEx, (void**)&dispex);
1829     ok(hres == S_OK, "Could not get IDispatchEx: %08x\n", hres);
1830
1831     bstr = SysAllocString(w0);
1832     hres = IDispatchEx_GetDispID(dispex, bstr, fdexNameCaseSensitive, &id);
1833     ok(hres == S_OK, "GetDispID failed: %08x\n", hres);
1834     SysFreeString(bstr);
1835
1836     VariantInit(&var);
1837     hres = IDispatchEx_InvokeEx(dispex, id, LOCALE_NEUTRAL, INVOKE_PROPERTYGET, &dp, &var, &ei, NULL);
1838     ok(hres == S_OK, "InvokeEx failed: %08x\n", hres);
1839     ok(V_VT(&var) == VT_DISPATCH, "V_VT(var)=%d\n", V_VT(&var));
1840     ok(V_DISPATCH(&var) != NULL, "V_DISPATCH(var) == NULL\n");
1841     node = get_node_iface((IUnknown*)V_DISPATCH(&var));
1842     type = get_node_type((IUnknown*)node);
1843     ok(type == 3, "type=%ld\n", type);
1844     IHTMLDOMNode_Release(node);
1845     VariantClear(&var);
1846
1847     bstr = SysAllocString(w100);
1848     hres = IDispatchEx_GetDispID(dispex, bstr, fdexNameCaseSensitive, &id);
1849     ok(hres == DISP_E_UNKNOWNNAME, "GetDispID failed: %08x, expected DISP_E_UNKNOWNNAME\n", hres);
1850     SysFreeString(bstr);
1851
1852     IDispatchEx_Release(dispex);
1853 }
1854
1855
1856
1857 static void test_elems(IHTMLDocument2 *doc)
1858 {
1859     IHTMLElementCollection *col;
1860     IHTMLDOMChildrenCollection *child_col;
1861     IHTMLElement *elem;
1862     IHTMLDOMNode *node, *node2;
1863     IDispatch *disp;
1864     long type;
1865     HRESULT hres;
1866
1867     static const WCHAR imgidW[] = {'i','m','g','i','d',0};
1868     static const WCHAR inW[] = {'i','n',0};
1869     static const WCHAR xW[] = {'x',0};
1870     static const WCHAR sW[] = {'s',0};
1871     static const WCHAR scW[] = {'s','c',0};
1872     static const WCHAR xxxW[] = {'x','x','x',0};
1873
1874     static const elem_type_t all_types[] = {
1875         ET_HTML,
1876         ET_HEAD,
1877         ET_TITLE,
1878         ET_STYLE,
1879         ET_BODY,
1880         ET_COMMENT,
1881         ET_A,
1882         ET_INPUT,
1883         ET_SELECT,
1884         ET_OPTION,
1885         ET_OPTION,
1886         ET_TEXTAREA,
1887         ET_TABLE,
1888         ET_TBODY,
1889         ET_SCRIPT,
1890         ET_TEST,
1891         ET_IMG
1892     };
1893
1894     static const elem_type_t item_types[] = {
1895         ET_A,
1896         ET_OPTION,
1897         ET_TEXTAREA
1898     };
1899
1900     hres = IHTMLDocument2_get_all(doc, &col);
1901     ok(hres == S_OK, "get_all failed: %08x\n", hres);
1902     test_elem_collection((IUnknown*)col, all_types, sizeof(all_types)/sizeof(all_types[0]));
1903     test_elem_col_item(col, xW, item_types, sizeof(item_types)/sizeof(item_types[0]));
1904     IHTMLElementCollection_Release(col);
1905
1906     elem = get_doc_elem(doc);
1907     ok(hres == S_OK, "get_documentElement failed: %08x\n", hres);
1908     hres = IHTMLElement_get_all(elem, &disp);
1909     IHTMLElement_Release(elem);
1910     ok(hres == S_OK, "get_all failed: %08x\n", hres);
1911
1912     hres = IDispatch_QueryInterface(disp, &IID_IHTMLElementCollection, (void**)&col);
1913     IDispatch_Release(disp);
1914     ok(hres == S_OK, "Could not get IHTMLElementCollection: %08x\n", hres);
1915     test_elem_collection((IUnknown*)col, all_types+1, sizeof(all_types)/sizeof(all_types[0])-1);
1916     IHTMLElementCollection_Release(col);
1917
1918     get_elem_by_id(doc, xxxW, FALSE);
1919     elem = get_doc_elem_by_id(doc, xxxW);
1920     ok(!elem, "elem != NULL\n");
1921
1922     elem = get_doc_elem_by_id(doc, sW);
1923     ok(elem != NULL, "elem == NULL\n");
1924     if(elem) {
1925         test_elem_type((IUnknown*)elem, ET_SELECT);
1926         test_elem_attr(elem, xxxW, NULL);
1927         test_elem_attr(elem, idW, sW);
1928         test_elem_class((IUnknown*)elem, NULL);
1929         test_elem_set_class((IUnknown*)elem, "cl");
1930         test_elem_set_class((IUnknown*)elem, NULL);
1931         test_elem_tabindex((IUnknown*)elem, 0);
1932         test_elem_set_tabindex((IUnknown*)elem, 1);
1933         IHTMLElement_Release(elem);
1934     }
1935
1936     elem = get_elem_by_id(doc, sW, TRUE);
1937     if(elem) {
1938         IHTMLSelectElement *select;
1939
1940         hres = IHTMLElement_QueryInterface(elem, &IID_IHTMLSelectElement, (void**)&select);
1941         ok(hres == S_OK, "Could not get IHTMLSelectElement interface: %08x\n", hres);
1942
1943         test_select_elem(select);
1944
1945         node = get_first_child((IUnknown*)select);
1946         ok(node != NULL, "node == NULL\n");
1947         if(node) {
1948             test_elem_type((IUnknown*)node, ET_OPTION);
1949             IHTMLDOMNode_Release(node);
1950         }
1951
1952         type = get_node_type((IUnknown*)select);
1953         ok(type == 1, "type=%ld\n", type);
1954
1955         IHTMLSelectElement_Release(select);
1956         IHTMLElement_Release(elem);
1957     }
1958
1959     elem = get_elem_by_id(doc, scW, TRUE);
1960     if(elem) {
1961         IHTMLScriptElement *script;
1962         BSTR type;
1963
1964         hres = IHTMLElement_QueryInterface(elem, &IID_IHTMLScriptElement, (void**)&script);
1965         ok(hres == S_OK, "Could not get IHTMLScriptElement interface: %08x\n", hres);
1966
1967         hres = IHTMLScriptElement_get_type(script, &type);
1968         ok(hres == S_OK, "get_type failed: %08x\n", hres);
1969         ok(!lstrcmpW(type, text_javascriptW), "Unexpected type %s\n", dbgstr_w(type));
1970         SysFreeString(type);
1971
1972         IHTMLScriptElement_Release(script);
1973     }
1974
1975     elem = get_elem_by_id(doc, inW, TRUE);
1976     if(elem) {
1977         IHTMLInputElement *input;
1978
1979         hres = IHTMLElement_QueryInterface(elem, &IID_IHTMLInputElement, (void**)&input);
1980         ok(hres == S_OK, "Could not get IHTMLInputElement: %08x\n", hres);
1981
1982         test_elem_id((IUnknown*)elem, "in");
1983         test_elem_put_id((IUnknown*)elem, "newin");
1984         test_input_get_disabled(input, VARIANT_FALSE);
1985         test_elem_client_size((IUnknown*)elem);
1986
1987         test_node_get_value_str((IUnknown*)elem, NULL);
1988         test_node_put_value_str((IUnknown*)elem, "test");
1989         test_node_get_value_str((IUnknown*)elem, NULL);
1990         test_input_value((IUnknown*)elem, NULL);
1991         test_input_put_value((IUnknown*)elem, "test");
1992         test_input_value((IUnknown*)elem, NULL);
1993         test_elem_class((IUnknown*)elem, "testclass");
1994         test_elem_tabindex((IUnknown*)elem, 2);
1995         test_elem_set_tabindex((IUnknown*)elem, 3);
1996
1997         IHTMLInputElement_Release(input);
1998         IHTMLElement_Release(elem);
1999     }
2000
2001     elem = get_elem_by_id(doc, imgidW, TRUE);
2002     if(elem) {
2003         test_img_set_src((IUnknown*)elem, "about:blank");
2004         IHTMLElement_Release(elem);
2005     }
2006
2007     hres = IHTMLDocument2_get_body(doc, &elem);
2008     ok(hres == S_OK, "get_body failed: %08x\n", hres);
2009
2010     node = get_first_child((IUnknown*)elem);
2011     ok(node != NULL, "node == NULL\n");
2012     if(node) {
2013         test_ifaces((IUnknown*)node, text_iids);
2014         test_disp((IUnknown*)node, &DIID_DispHTMLDOMTextNode);
2015
2016         node2 = get_first_child((IUnknown*)node);
2017         ok(!node2, "node2 != NULL\n");
2018
2019         type = get_node_type((IUnknown*)node);
2020         ok(type == 3, "type=%ld\n", type);
2021
2022         test_node_get_value_str((IUnknown*)node, "text test");
2023         test_node_put_value_str((IUnknown*)elem, "test text");
2024         test_node_get_value_str((IUnknown*)node, "text test");
2025
2026         IHTMLDOMNode_Release(node);
2027     }
2028
2029     child_col = get_child_nodes((IUnknown*)elem);
2030     ok(child_col != NULL, "child_coll == NULL\n");
2031     if(child_col) {
2032         long length = 0;
2033
2034         test_disp((IUnknown*)child_col, &DIID_DispDOMChildrenCollection);
2035
2036         hres = IHTMLDOMChildrenCollection_get_length(child_col, &length);
2037         ok(hres == S_OK, "get_length failed: %08x\n", hres);
2038         ok(length, "length=0\n");
2039
2040         node = get_child_item(child_col, 0);
2041         ok(node != NULL, "node == NULL\n");
2042         if(node) {
2043             type = get_node_type((IUnknown*)node);
2044             ok(type == 3, "type=%ld\n", type);
2045             IHTMLDOMNode_Release(node);
2046         }
2047
2048         node = get_child_item(child_col, 1);
2049         ok(node != NULL, "node == NULL\n");
2050         if(node) {
2051             type = get_node_type((IUnknown*)node);
2052             ok(type == 8, "type=%ld\n", type);
2053
2054             test_elem_id((IUnknown*)node, NULL);
2055             IHTMLDOMNode_Release(node);
2056         }
2057
2058         disp = (void*)0xdeadbeef;
2059         hres = IHTMLDOMChildrenCollection_item(child_col, 6000, &disp);
2060         ok(hres == E_INVALIDARG, "item failed: %08x, expected E_INVALIDARG\n", hres);
2061         ok(disp == (void*)0xdeadbeef, "disp=%p\n", disp);
2062
2063         disp = (void*)0xdeadbeef;
2064         hres = IHTMLDOMChildrenCollection_item(child_col, length, &disp);
2065         ok(hres == E_INVALIDARG, "item failed: %08x, expected E_INVALIDARG\n", hres);
2066         ok(disp == (void*)0xdeadbeef, "disp=%p\n", disp);
2067
2068         test_child_col_disp(child_col);
2069
2070         IHTMLDOMChildrenCollection_Release(child_col);
2071     }
2072
2073     IHTMLElement_Release(elem);
2074
2075     test_stylesheets(doc);
2076     test_create_option_elem(doc);
2077 }
2078
2079 static void test_create_elems(IHTMLDocument2 *doc)
2080 {
2081     IHTMLElement *elem, *body, *elem2;
2082     IHTMLDOMNode *node;
2083     IDispatch *disp;
2084     long type;
2085     HRESULT hres;
2086
2087     static const elem_type_t types1[] = { ET_TESTG };
2088
2089     elem = test_create_elem(doc, "TEST");
2090     test_elem_tag((IUnknown*)elem, "TEST");
2091     type = get_node_type((IUnknown*)elem);
2092     ok(type == 1, "type=%ld\n", type);
2093     test_ifaces((IUnknown*)elem, elem_iids);
2094     test_disp((IUnknown*)elem, &DIID_DispHTMLGenericElement);
2095
2096     hres = IHTMLDocument2_get_body(doc, &body);
2097     ok(hres == S_OK, "get_body failed: %08x\n", hres);
2098
2099     node = test_node_append_child((IUnknown*)body, (IUnknown*)elem);
2100     elem2 = get_elem_iface((IUnknown*)node);
2101     IHTMLElement_Release(elem2);
2102
2103     hres = IHTMLElement_get_all(body, &disp);
2104     ok(hres == S_OK, "get_all failed: %08x\n", hres);
2105     test_elem_collection((IUnknown*)disp, types1, sizeof(types1)/sizeof(types1[0]));
2106     IDispatch_Release(disp);
2107
2108     test_node_remove_child((IUnknown*)body, node);
2109
2110     hres = IHTMLElement_get_all(body, &disp);
2111     ok(hres == S_OK, "get_all failed: %08x\n", hres);
2112     test_elem_collection((IUnknown*)disp, NULL, 0);
2113     IDispatch_Release(disp);
2114
2115     IHTMLElement_Release(body);
2116     IHTMLElement_Release(elem);
2117     IHTMLDOMNode_Release(node);
2118
2119     node = test_create_text(doc, "test");
2120     test_ifaces((IUnknown*)node, text_iids);
2121     test_disp((IUnknown*)node, &DIID_DispHTMLDOMTextNode);
2122     IHTMLDOMNode_Release(node);
2123 }
2124
2125 static void test_exec(IUnknown *unk, const GUID *grpid, DWORD cmdid, VARIANT *in, VARIANT *out)
2126 {
2127     IOleCommandTarget *cmdtrg;
2128     HRESULT hres;
2129
2130     hres = IHTMLTxtRange_QueryInterface(unk, &IID_IOleCommandTarget, (void**)&cmdtrg);
2131     ok(hres == S_OK, "Could not get IOleCommandTarget interface: %08x\n", hres);
2132
2133     hres = IOleCommandTarget_Exec(cmdtrg, grpid, cmdid, 0, in, out);
2134     ok(hres == S_OK, "Exec failed: %08x\n", hres);
2135
2136     IOleCommandTarget_Release(cmdtrg);
2137 }
2138
2139 static void test_indent(IHTMLDocument2 *doc)
2140 {
2141     IHTMLElementCollection *col;
2142     IHTMLTxtRange *range;
2143     HRESULT hres;
2144
2145     static const elem_type_t all_types[] = {
2146         ET_HTML,
2147         ET_HEAD,
2148         ET_TITLE,
2149         ET_BODY,
2150         ET_BR,
2151         ET_A,
2152     };
2153
2154     static const elem_type_t indent_types[] = {
2155         ET_HTML,
2156         ET_HEAD,
2157         ET_TITLE,
2158         ET_BODY,
2159         ET_BLOCKQUOTE,
2160         ET_P,
2161         ET_BR,
2162         ET_A,
2163     };
2164
2165     hres = IHTMLDocument2_get_all(doc, &col);
2166     ok(hres == S_OK, "get_all failed: %08x\n", hres);
2167     test_elem_collection((IUnknown*)col, all_types, sizeof(all_types)/sizeof(all_types[0]));
2168     IHTMLElementCollection_Release(col);
2169
2170     range = test_create_body_range(doc);
2171     test_exec((IUnknown*)range, &CGID_MSHTML, IDM_INDENT, NULL, NULL);
2172     IHTMLTxtRange_Release(range);
2173
2174     hres = IHTMLDocument2_get_all(doc, &col);
2175     ok(hres == S_OK, "get_all failed: %08x\n", hres);
2176     test_elem_collection((IUnknown*)col, indent_types, sizeof(indent_types)/sizeof(indent_types[0]));
2177     IHTMLElementCollection_Release(col);
2178 }
2179
2180 static IHTMLDocument2 *notif_doc;
2181 static BOOL doc_complete;
2182
2183 static HRESULT WINAPI PropertyNotifySink_QueryInterface(IPropertyNotifySink *iface,
2184         REFIID riid, void**ppv)
2185 {
2186     if(IsEqualGUID(&IID_IPropertyNotifySink, riid)) {
2187         *ppv = iface;
2188         return S_OK;
2189     }
2190
2191     ok(0, "unexpected call\n");
2192     return E_NOINTERFACE;
2193 }
2194
2195 static ULONG WINAPI PropertyNotifySink_AddRef(IPropertyNotifySink *iface)
2196 {
2197     return 2;
2198 }
2199
2200 static ULONG WINAPI PropertyNotifySink_Release(IPropertyNotifySink *iface)
2201 {
2202     return 1;
2203 }
2204
2205 static HRESULT WINAPI PropertyNotifySink_OnChanged(IPropertyNotifySink *iface, DISPID dispID)
2206 {
2207     if(dispID == DISPID_READYSTATE){
2208         BSTR state;
2209         HRESULT hres;
2210
2211         static const WCHAR completeW[] = {'c','o','m','p','l','e','t','e',0};
2212
2213         hres = IHTMLDocument2_get_readyState(notif_doc, &state);
2214         ok(hres == S_OK, "get_readyState failed: %08x\n", hres);
2215
2216         if(!lstrcmpW(state, completeW))
2217             doc_complete = TRUE;
2218
2219         SysFreeString(state);
2220     }
2221
2222     return S_OK;
2223 }
2224
2225 static HRESULT WINAPI PropertyNotifySink_OnRequestEdit(IPropertyNotifySink *iface, DISPID dispID)
2226 {
2227     ok(0, "unexpected call\n");
2228     return E_NOTIMPL;
2229 }
2230
2231 static IPropertyNotifySinkVtbl PropertyNotifySinkVtbl = {
2232     PropertyNotifySink_QueryInterface,
2233     PropertyNotifySink_AddRef,
2234     PropertyNotifySink_Release,
2235     PropertyNotifySink_OnChanged,
2236     PropertyNotifySink_OnRequestEdit
2237 };
2238
2239 static IPropertyNotifySink PropertyNotifySink = { &PropertyNotifySinkVtbl };
2240
2241 static IHTMLDocument2 *create_doc_with_string(const char *str)
2242 {
2243     IPersistStreamInit *init;
2244     IStream *stream;
2245     IHTMLDocument2 *doc;
2246     HGLOBAL mem;
2247     SIZE_T len;
2248
2249     notif_doc = doc = create_document();
2250     if(!doc)
2251         return NULL;
2252
2253     doc_complete = FALSE;
2254     len = strlen(str);
2255     mem = GlobalAlloc(0, len);
2256     memcpy(mem, str, len);
2257     CreateStreamOnHGlobal(mem, TRUE, &stream);
2258
2259     IHTMLDocument2_QueryInterface(doc, &IID_IPersistStreamInit, (void**)&init);
2260
2261     IPersistStreamInit_Load(init, stream);
2262     IPersistStreamInit_Release(init);
2263     IStream_Release(stream);
2264
2265     return doc;
2266 }
2267
2268 static void do_advise(IUnknown *unk, REFIID riid, IUnknown *unk_advise)
2269 {
2270     IConnectionPointContainer *container;
2271     IConnectionPoint *cp;
2272     DWORD cookie;
2273     HRESULT hres;
2274
2275     hres = IUnknown_QueryInterface(unk, &IID_IConnectionPointContainer, (void**)&container);
2276     ok(hres == S_OK, "QueryInterface(IID_IConnectionPointContainer) failed: %08x\n", hres);
2277
2278     hres = IConnectionPointContainer_FindConnectionPoint(container, riid, &cp);
2279     IConnectionPointContainer_Release(container);
2280     ok(hres == S_OK, "FindConnectionPoint failed: %08x\n", hres);
2281
2282     hres = IConnectionPoint_Advise(cp, unk_advise, &cookie);
2283     IConnectionPoint_Release(cp);
2284     ok(hres == S_OK, "Advise failed: %08x\n", hres);
2285 }
2286
2287 typedef void (*domtest_t)(IHTMLDocument2*);
2288
2289 static void run_domtest(const char *str, domtest_t test)
2290 {
2291     IHTMLDocument2 *doc;
2292     IHTMLElement *body = NULL;
2293     ULONG ref;
2294     MSG msg;
2295     HRESULT hres;
2296
2297     doc = create_doc_with_string(str);
2298     do_advise((IUnknown*)doc, &IID_IPropertyNotifySink, (IUnknown*)&PropertyNotifySink);
2299
2300     while(!doc_complete && GetMessage(&msg, NULL, 0, 0)) {
2301         TranslateMessage(&msg);
2302         DispatchMessage(&msg);
2303     }
2304
2305     hres = IHTMLDocument2_get_body(doc, &body);
2306     ok(hres == S_OK, "get_body failed: %08x\n", hres);
2307
2308     if(body) {
2309         IHTMLElement_Release(body);
2310         test(doc);
2311     }else {
2312         skip("Could not get document body. Assuming no Gecko installed.\n");
2313     }
2314
2315     ref = IHTMLDocument2_Release(doc);
2316     ok(!ref, "ref = %d\n", ref);
2317 }
2318
2319 static void gecko_installer_workaround(BOOL disable)
2320 {
2321     HKEY hkey;
2322     DWORD res;
2323
2324     static BOOL has_url = FALSE;
2325     static char url[2048];
2326
2327     if(!disable && !has_url)
2328         return;
2329
2330     res = RegOpenKey(HKEY_CURRENT_USER, "Software\\Wine\\MSHTML", &hkey);
2331     if(res != ERROR_SUCCESS)
2332         return;
2333
2334     if(disable) {
2335         DWORD type, size = sizeof(url);
2336
2337         res = RegQueryValueEx(hkey, "GeckoUrl", NULL, &type, (PVOID)url, &size);
2338         if(res == ERROR_SUCCESS && type == REG_SZ)
2339             has_url = TRUE;
2340
2341         RegDeleteValue(hkey, "GeckoUrl");
2342     }else {
2343         RegSetValueEx(hkey, "GeckoUrl", 0, REG_SZ, (PVOID)url, lstrlenA(url)+1);
2344     }
2345
2346     RegCloseKey(hkey);
2347 }
2348
2349 START_TEST(dom)
2350 {
2351     gecko_installer_workaround(TRUE);
2352     CoInitialize(NULL);
2353
2354     run_domtest(doc_str1, test_doc_elem);
2355     run_domtest(range_test_str, test_txtrange);
2356     run_domtest(range_test2_str, test_txtrange2);
2357     run_domtest(elem_test_str, test_elems);
2358     run_domtest(doc_blank, test_create_elems);
2359     run_domtest(doc_blank, test_defaults);
2360     run_domtest(indent_test_str, test_indent);
2361
2362     CoUninitialize();
2363     gecko_installer_workaround(FALSE);
2364 }