quartz: Fix discontinuities in wave parser.
[wine] / dlls / mshtml / tests / script.c
1 /*
2  * Copyright 2008 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 "activscp.h"
31
32 #define DEFINE_EXPECT(func) \
33     static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
34
35 #define SET_EXPECT(func) \
36     do { called_ ## func = FALSE; expect_ ## func = TRUE; } while(0)
37
38 #define CHECK_EXPECT2(func) \
39     do { \
40         ok(expect_ ##func, "unexpected call " #func "\n"); \
41         called_ ## func = TRUE; \
42     }while(0)
43
44 #define CHECK_EXPECT(func) \
45     do { \
46         CHECK_EXPECT2(func); \
47         expect_ ## func = FALSE; \
48     }while(0)
49
50 #define CHECK_CALLED(func) \
51     do { \
52         ok(called_ ## func, "expected " #func "\n"); \
53         expect_ ## func = called_ ## func = FALSE; \
54     }while(0)
55
56 #define CHECK_NOT_CALLED(func) \
57     do { \
58         ok(!called_ ## func, "unexpected " #func "\n"); \
59         expect_ ## func = called_ ## func = FALSE; \
60     }while(0)
61
62 #define CLEAR_CALLED(func) \
63     expect_ ## func = called_ ## func = FALSE
64
65
66 DEFINE_EXPECT(CreateInstance);
67
68
69 #define TESTSCRIPT_CLSID "{178fc163-f585-4e24-9c13-4bb7faf80746}"
70
71 static const GUID CLSID_TestScript =
72     {0x178fc163,0xf585,0x4e24,{0x9c,0x13,0x4b,0xb7,0xfa,0xf8,0x07,0x46}};
73
74 static IHTMLDocument2 *notif_doc;
75 static BOOL doc_complete;
76
77 static const char *debugstr_guid(REFIID riid)
78 {
79     static char buf[50];
80
81     sprintf(buf, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
82             riid->Data1, riid->Data2, riid->Data3, riid->Data4[0],
83             riid->Data4[1], riid->Data4[2], riid->Data4[3], riid->Data4[4],
84             riid->Data4[5], riid->Data4[6], riid->Data4[7]);
85
86     return buf;
87 }
88
89 static HRESULT WINAPI PropertyNotifySink_QueryInterface(IPropertyNotifySink *iface,
90         REFIID riid, void**ppv)
91 {
92     if(IsEqualGUID(&IID_IPropertyNotifySink, riid)) {
93         *ppv = iface;
94         return S_OK;
95     }
96
97     return E_NOINTERFACE;
98 }
99
100 static ULONG WINAPI PropertyNotifySink_AddRef(IPropertyNotifySink *iface)
101 {
102     return 2;
103 }
104
105 static ULONG WINAPI PropertyNotifySink_Release(IPropertyNotifySink *iface)
106 {
107     return 1;
108 }
109
110 static HRESULT WINAPI PropertyNotifySink_OnChanged(IPropertyNotifySink *iface, DISPID dispID)
111 {
112     if(dispID == DISPID_READYSTATE){
113         BSTR state;
114         HRESULT hres;
115
116         static const WCHAR completeW[] = {'c','o','m','p','l','e','t','e',0};
117
118         hres = IHTMLDocument2_get_readyState(notif_doc, &state);
119         ok(hres == S_OK, "get_readyState failed: %08x\n", hres);
120
121         if(!lstrcmpW(state, completeW))
122             doc_complete = TRUE;
123
124         SysFreeString(state);
125     }
126
127     return S_OK;
128 }
129
130 static HRESULT WINAPI PropertyNotifySink_OnRequestEdit(IPropertyNotifySink *iface, DISPID dispID)
131 {
132     ok(0, "unexpected call\n");
133     return E_NOTIMPL;
134 }
135
136 static IPropertyNotifySinkVtbl PropertyNotifySinkVtbl = {
137     PropertyNotifySink_QueryInterface,
138     PropertyNotifySink_AddRef,
139     PropertyNotifySink_Release,
140     PropertyNotifySink_OnChanged,
141     PropertyNotifySink_OnRequestEdit
142 };
143
144 static IPropertyNotifySink PropertyNotifySink = { &PropertyNotifySinkVtbl };
145
146 static IHTMLDocument2 *create_document(void)
147 {
148     IHTMLDocument2 *doc;
149     HRESULT hres;
150
151     hres = CoCreateInstance(&CLSID_HTMLDocument, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
152             &IID_IHTMLDocument2, (void**)&doc);
153     ok(hres == S_OK, "CoCreateInstance failed: %08x\n", hres);
154
155     return doc;
156 }
157
158 static IHTMLDocument2 *create_doc_with_string(const char *str)
159 {
160     IPersistStreamInit *init;
161     IStream *stream;
162     IHTMLDocument2 *doc;
163     HGLOBAL mem;
164     SIZE_T len;
165
166     notif_doc = doc = create_document();
167     if(!doc)
168         return NULL;
169
170     doc_complete = FALSE;
171     len = strlen(str);
172     mem = GlobalAlloc(0, len);
173     memcpy(mem, str, len);
174     CreateStreamOnHGlobal(mem, TRUE, &stream);
175
176     IHTMLDocument2_QueryInterface(doc, &IID_IPersistStreamInit, (void**)&init);
177
178     IPersistStreamInit_Load(init, stream);
179     IPersistStreamInit_Release(init);
180     IStream_Release(stream);
181
182     return doc;
183 }
184
185 static void do_advise(IUnknown *unk, REFIID riid, IUnknown *unk_advise)
186 {
187     IConnectionPointContainer *container;
188     IConnectionPoint *cp;
189     DWORD cookie;
190     HRESULT hres;
191
192     hres = IUnknown_QueryInterface(unk, &IID_IConnectionPointContainer, (void**)&container);
193     ok(hres == S_OK, "QueryInterface(IID_IConnectionPointContainer) failed: %08x\n", hres);
194
195     hres = IConnectionPointContainer_FindConnectionPoint(container, riid, &cp);
196     IConnectionPointContainer_Release(container);
197     ok(hres == S_OK, "FindConnectionPoint failed: %08x\n", hres);
198
199     hres = IConnectionPoint_Advise(cp, unk_advise, &cookie);
200     IConnectionPoint_Release(cp);
201     ok(hres == S_OK, "Advise failed: %08x\n", hres);
202 }
203
204 typedef void (*domtest_t)(IHTMLDocument2*);
205
206 static IHTMLDocument2 *create_and_load_doc(const char *str)
207 {
208     IHTMLDocument2 *doc;
209     IHTMLElement *body = NULL;
210     ULONG ref;
211     MSG msg;
212     HRESULT hres;
213
214     doc = create_doc_with_string(str);
215     do_advise((IUnknown*)doc, &IID_IPropertyNotifySink, (IUnknown*)&PropertyNotifySink);
216
217     while(!doc_complete && GetMessage(&msg, NULL, 0, 0)) {
218         TranslateMessage(&msg);
219         DispatchMessage(&msg);
220     }
221
222     hres = IHTMLDocument2_get_body(doc, &body);
223     ok(hres == S_OK, "get_body failed: %08x\n", hres);
224
225     if(!body) {
226         skip("Could not get document body. Assuming no Gecko installed.\n");
227         ref = IHTMLDocument2_Release(doc);
228         ok(!ref, "ref = %d\n", ref);
229         return NULL;
230     }
231
232     IHTMLElement_Release(body);
233     return doc;
234 }
235
236 static HRESULT WINAPI ActiveScript_QueryInterface(IActiveScript *iface, REFIID riid, void **ppv)
237 {
238     *ppv = NULL;
239
240     if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IActiveScript, riid)) {
241         *ppv = iface;
242         return S_OK;
243     }
244
245     if(IsEqualGUID(&IID_IActiveScriptParse, riid)) {
246         /* TODO */
247         return E_NOINTERFACE;
248     }
249
250     ok(0, "unexpected riid %s\n", debugstr_guid(riid));
251     return E_NOINTERFACE;
252 }
253
254 static ULONG WINAPI ActiveScript_AddRef(IActiveScript *iface)
255 {
256     return 2;
257 }
258
259 static ULONG WINAPI ActiveScript_Release(IActiveScript *iface)
260 {
261     return 1;
262 }
263
264 static HRESULT WINAPI ActiveScript_SetScriptSite(IActiveScript *iface, IActiveScriptSite *pass)
265 {
266     ok(0, "unexpected call\n");
267     return E_NOTIMPL;
268 }
269
270 static HRESULT WINAPI ActiveScript_GetScriptSite(IActiveScript *iface, REFIID riid,
271                                             void **ppvObject)
272 {
273     ok(0, "unexpected call\n");
274     return E_NOTIMPL;
275 }
276
277 static HRESULT WINAPI ActiveScript_SetScriptState(IActiveScript *iface, SCRIPTSTATE ss)
278 {
279     ok(0, "unexpected call\n");
280     return E_NOTIMPL;
281 }
282
283 static HRESULT WINAPI ActiveScript_GetScriptState(IActiveScript *iface, SCRIPTSTATE *pssState)
284 {
285     ok(0, "unexpected call\n");
286     return E_NOTIMPL;
287 }
288
289 static HRESULT WINAPI ActiveScript_Close(IActiveScript *iface)
290 {
291     ok(0, "unexpected call\n");
292     return E_NOTIMPL;
293 }
294
295 static HRESULT WINAPI ActiveScript_AddNamedItem(IActiveScript *iface,
296                                            LPCOLESTR pstrName, DWORD dwFlags)
297 {
298     ok(0, "unexpected call\n");
299     return E_NOTIMPL;
300 }
301
302 static HRESULT WINAPI ActiveScript_AddTypeLib(IActiveScript *iface, REFGUID rguidTypeLib,
303                                          DWORD dwMajor, DWORD dwMinor, DWORD dwFlags)
304 {
305     ok(0, "unexpected call\n");
306     return E_NOTIMPL;
307 }
308
309 static HRESULT WINAPI ActiveScript_GetScriptDispatch(IActiveScript *iface, LPCOLESTR pstrItemName,
310                                                 IDispatch **ppdisp)
311 {
312     ok(0, "unexpected call\n");
313     return E_NOTIMPL;
314 }
315
316 static HRESULT WINAPI ActiveScript_GetCurrentScriptThreadID(IActiveScript *iface,
317                                                        SCRIPTTHREADID *pstridThread)
318 {
319     ok(0, "unexpected call\n");
320     return E_NOTIMPL;
321 }
322
323 static HRESULT WINAPI ActiveScript_GetScriptThreadID(IActiveScript *iface,
324                                                 DWORD dwWin32ThreadId, SCRIPTTHREADID *pstidThread)
325 {
326     ok(0, "unexpected call\n");
327     return E_NOTIMPL;
328 }
329
330 static HRESULT WINAPI ActiveScript_GetScriptThreadState(IActiveScript *iface,
331         SCRIPTTHREADID stidThread, SCRIPTTHREADSTATE *pstsState)
332 {
333     ok(0, "unexpected call\n");
334     return E_NOTIMPL;
335 }
336
337 static HRESULT WINAPI ActiveScript_InterruptScriptThread(IActiveScript *iface,
338         SCRIPTTHREADID stidThread, const EXCEPINFO *pexcepinfo, DWORD dwFlags)
339 {
340     ok(0, "unexpected call\n");
341     return E_NOTIMPL;
342 }
343
344 static HRESULT WINAPI ActiveScript_Clone(IActiveScript *iface, IActiveScript **ppscript)
345 {
346     ok(0, "unexpected call\n");
347     return E_NOTIMPL;
348 }
349
350 static const IActiveScriptVtbl ActiveScriptVtbl = {
351     ActiveScript_QueryInterface,
352     ActiveScript_AddRef,
353     ActiveScript_Release,
354     ActiveScript_SetScriptSite,
355     ActiveScript_GetScriptSite,
356     ActiveScript_SetScriptState,
357     ActiveScript_GetScriptState,
358     ActiveScript_Close,
359     ActiveScript_AddNamedItem,
360     ActiveScript_AddTypeLib,
361     ActiveScript_GetScriptDispatch,
362     ActiveScript_GetCurrentScriptThreadID,
363     ActiveScript_GetScriptThreadID,
364     ActiveScript_GetScriptThreadState,
365     ActiveScript_InterruptScriptThread,
366     ActiveScript_Clone
367 };
368
369 static IActiveScript ActiveScript = { &ActiveScriptVtbl };
370
371 static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv)
372 {
373     *ppv = NULL;
374
375     if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IClassFactory, riid)) {
376         *ppv = iface;
377         return S_OK;
378     }
379
380     if(IsEqualGUID(&IID_IMarshal, riid))
381         return E_NOINTERFACE;
382     if(IsEqualGUID(&CLSID_IdentityUnmarshal, riid))
383         return E_NOINTERFACE;
384
385     ok(0, "unexpected riid %s\n", debugstr_guid(riid));
386     return E_NOTIMPL;
387 }
388
389 static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface)
390 {
391     return 2;
392 }
393
394 static ULONG WINAPI ClassFactory_Release(IClassFactory *iface)
395 {
396     return 1;
397 }
398
399 static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
400 {
401     CHECK_EXPECT(CreateInstance);
402
403     ok(!outer, "outer = %p\n", outer);
404     ok(IsEqualGUID(&IID_IActiveScript, riid), "unexpected riid %s\n", debugstr_guid(riid));
405     *ppv = &ActiveScript;
406     return S_OK;
407 }
408
409 static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL dolock)
410 {
411     ok(0, "unexpected call\n");
412     return S_OK;
413 }
414
415 static const IClassFactoryVtbl ClassFactoryVtbl = {
416     ClassFactory_QueryInterface,
417     ClassFactory_AddRef,
418     ClassFactory_Release,
419     ClassFactory_CreateInstance,
420     ClassFactory_LockServer
421 };
422
423 static IClassFactory script_cf = { &ClassFactoryVtbl };
424
425 static const char simple_script_str[] =
426     "<html><head></head><body>"
427     "<script language=\"TestScript\">simple script</script>"
428     "</body></html>";
429
430 static void test_simple_script(void)
431 {
432     IHTMLDocument2 *doc;
433
434     SET_EXPECT(CreateInstance);
435
436     doc = create_and_load_doc(simple_script_str);
437     if(!doc) return;
438
439     CHECK_CALLED(CreateInstance);
440
441     IHTMLDocument2_Release(doc);
442 }
443
444 static BOOL init_key(const char *key_name, const char *def_value, BOOL init)
445 {
446     HKEY hkey;
447     DWORD res;
448
449     if(!init) {
450         RegDeleteKey(HKEY_CLASSES_ROOT, key_name);
451         return TRUE;
452     }
453
454     res = RegCreateKeyA(HKEY_CLASSES_ROOT, key_name, &hkey);
455     if(res != ERROR_SUCCESS)
456         return FALSE;
457
458     if(def_value)
459         res = RegSetValueA(hkey, NULL, REG_SZ, def_value, strlen(def_value));
460
461     RegCloseKey(hkey);
462
463     return res == ERROR_SUCCESS;
464 }
465
466 static BOOL init_registry(BOOL init)
467 {
468     return init_key("TestScript\\CLSID", TESTSCRIPT_CLSID, init)
469         && init_key("CLSID\\"TESTSCRIPT_CLSID"\\Implemented Categories\\{F0B7A1A1-9847-11CF-8F20-00805F2CD064}",
470                     NULL, init)
471         && init_key("CLSID\\"TESTSCRIPT_CLSID"\\Implemented Categories\\{F0B7A1A2-9847-11CF-8F20-00805F2CD064}",
472                     NULL, init);
473 }
474
475 static BOOL register_script_engine(void)
476 {
477     DWORD regid;
478     HRESULT hres;
479
480     if(!init_registry(TRUE)) {
481         init_registry(FALSE);
482         return FALSE;
483     }
484
485     hres = CoRegisterClassObject(&CLSID_TestScript, (IUnknown *)&script_cf,
486                                  CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &regid);
487     ok(hres == S_OK, "Could not register screipt engine: %08x\n", hres);
488
489     return TRUE;
490 }
491
492 static void gecko_installer_workaround(BOOL disable)
493 {
494     HKEY hkey;
495     DWORD res;
496
497     static BOOL has_url = FALSE;
498     static char url[2048];
499
500     if(!disable && !has_url)
501         return;
502
503     res = RegOpenKey(HKEY_CURRENT_USER, "Software\\Wine\\MSHTML", &hkey);
504     if(res != ERROR_SUCCESS)
505         return;
506
507     if(disable) {
508         DWORD type, size = sizeof(url);
509
510         res = RegQueryValueEx(hkey, "GeckoUrl", NULL, &type, (PVOID)url, &size);
511         if(res == ERROR_SUCCESS && type == REG_SZ)
512             has_url = TRUE;
513
514         RegDeleteValue(hkey, "GeckoUrl");
515     }else {
516         RegSetValueEx(hkey, "GeckoUrl", 0, REG_SZ, (PVOID)url, lstrlenA(url)+1);
517     }
518
519     RegCloseKey(hkey);
520 }
521
522 START_TEST(script)
523 {
524     gecko_installer_workaround(TRUE);
525     CoInitialize(NULL);
526
527     if(register_script_engine()) {
528         test_simple_script();
529         init_registry(FALSE);
530     }else {
531         skip("Could not register TestScript engine\n");
532     }
533
534     CoUninitialize();
535     gecko_installer_workaround(FALSE);
536 }