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