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