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