jscript: Added Object function invocation implementation.
[wine] / dlls / jscript / tests / run.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 #include <stdio.h>
20
21 #define COBJMACROS
22 #define CONST_VTABLE
23
24 #include <ole2.h>
25 #include <dispex.h>
26 #include <activscp.h>
27
28 #include "wine/test.h"
29
30 static const CLSID CLSID_JScript =
31     {0xf414c260,0x6ac0,0x11cf,{0xb6,0xd1,0x00,0xaa,0x00,0xbb,0xbb,0x58}};
32
33 #define DEFINE_EXPECT(func) \
34     static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
35
36 #define SET_EXPECT(func) \
37     expect_ ## func = TRUE
38
39 #define SET_CALLED(func) \
40     called_ ## func = TRUE
41
42 #define CHECK_EXPECT2(func) \
43     do { \
44         ok(expect_ ##func, "unexpected call " #func "\n"); \
45         called_ ## func = TRUE; \
46     }while(0)
47
48 #define CHECK_EXPECT(func) \
49     do { \
50         CHECK_EXPECT2(func); \
51         expect_ ## func = FALSE; \
52     }while(0)
53
54 #define CHECK_CALLED(func) \
55     do { \
56         ok(called_ ## func, "expected " #func "\n"); \
57         expect_ ## func = called_ ## func = FALSE; \
58     }while(0)
59
60 DEFINE_EXPECT(global_propget_d);
61 DEFINE_EXPECT(global_propget_i);
62 DEFINE_EXPECT(global_propput_d);
63 DEFINE_EXPECT(global_propput_i);
64 DEFINE_EXPECT(global_success_d);
65 DEFINE_EXPECT(global_success_i);
66 DEFINE_EXPECT(global_notexists_d);
67 DEFINE_EXPECT(testobj_delete);
68 DEFINE_EXPECT(testobj_value);
69 DEFINE_EXPECT(testobj_prop_d);
70 DEFINE_EXPECT(testobj_noprop_d);
71 DEFINE_EXPECT(GetItemInfo_testVal);
72
73 #define DISPID_GLOBAL_TESTPROPGET   0x1000
74 #define DISPID_GLOBAL_TESTPROPPUT   0x1001
75 #define DISPID_GLOBAL_REPORTSUCCESS 0x1002
76 #define DISPID_GLOBAL_TRACE         0x1003
77 #define DISPID_GLOBAL_OK            0x1004
78 #define DISPID_GLOBAL_GETVT         0x1005
79 #define DISPID_GLOBAL_TESTOBJ       0x1006
80 #define DISPID_GLOBAL_NULL_BSTR     0x1007
81 #define DISPID_GLOBAL_NULL_DISP     0x1008
82
83 #define DISPID_TESTOBJ_PROP         0x2000
84
85 static const WCHAR testW[] = {'t','e','s','t',0};
86 static const CHAR testA[] = "test";
87 static const WCHAR test_valW[] = {'t','e','s','t','V','a','l',0};
88 static const CHAR test_valA[] = "testVal";
89
90 static BOOL strict_dispid_check;
91 static const char *test_name = "(null)";
92
93 static BSTR a2bstr(const char *str)
94 {
95     BSTR ret;
96     int len;
97
98     len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
99     ret = SysAllocStringLen(NULL, len-1);
100     MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
101
102     return ret;
103 }
104
105 static int strcmp_wa(LPCWSTR strw, const char *stra)
106 {
107     CHAR buf[512];
108     WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), 0, 0);
109     return lstrcmpA(buf, stra);
110 }
111
112 static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv)
113 {
114     *ppv = NULL;
115
116     if(IsEqualGUID(riid, &IID_IUnknown)
117        || IsEqualGUID(riid, &IID_IDispatch)
118        || IsEqualGUID(riid, &IID_IDispatchEx))
119         *ppv = iface;
120     else
121         return E_NOINTERFACE;
122
123     return S_OK;
124 }
125
126 static ULONG WINAPI DispatchEx_AddRef(IDispatchEx *iface)
127 {
128     return 2;
129 }
130
131 static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface)
132 {
133     return 1;
134 }
135
136 static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo)
137 {
138     ok(0, "unexpected call\n");
139     return E_NOTIMPL;
140 }
141
142 static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo,
143                                               LCID lcid, ITypeInfo **ppTInfo)
144 {
145     ok(0, "unexpected call\n");
146     return E_NOTIMPL;
147 }
148
149 static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid,
150                                                 LPOLESTR *rgszNames, UINT cNames,
151                                                 LCID lcid, DISPID *rgDispId)
152 {
153     ok(0, "unexpected call\n");
154     return E_NOTIMPL;
155 }
156
157 static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember,
158                             REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
159                             VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
160 {
161     ok(0, "unexpected call\n");
162     return E_NOTIMPL;
163 }
164
165 static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex)
166 {
167     ok(0, "unexpected call %s %x\n", wine_dbgstr_w(bstrName), grfdex);
168     return E_NOTIMPL;
169 }
170
171 static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id)
172 {
173     ok(0, "unexpected call\n");
174     return E_NOTIMPL;
175 }
176
177 static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
178 {
179     ok(0, "unexpected call\n");
180     return E_NOTIMPL;
181 }
182
183 static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName)
184 {
185     ok(0, "unexpected call\n");
186     return E_NOTIMPL;
187 }
188
189 static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid)
190 {
191     ok(0, "unexpected call\n");
192     return E_NOTIMPL;
193 }
194
195 static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk)
196 {
197     ok(0, "unexpected call\n");
198     return E_NOTIMPL;
199 }
200
201 static HRESULT WINAPI testObj_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
202 {
203     if(!strcmp_wa(bstrName, "prop")) {
204         CHECK_EXPECT(testobj_prop_d);
205         ok(grfdex == fdexNameCaseSensitive, "grfdex = %x\n", grfdex);
206         *pid = DISPID_TESTOBJ_PROP;
207         return S_OK;
208     }
209     if(!strcmp_wa(bstrName, "noprop")) {
210         CHECK_EXPECT(testobj_noprop_d);
211         ok(grfdex == fdexNameCaseSensitive, "grfdex = %x\n", grfdex);
212         return DISP_E_UNKNOWNNAME;
213     }
214
215     ok(0, "unexpected name %s\n", wine_dbgstr_w(bstrName));
216     return E_NOTIMPL;
217 }
218
219 static HRESULT WINAPI testObj_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
220         VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
221 {
222     switch(id) {
223     case DISPID_VALUE:
224         CHECK_EXPECT(testobj_value);
225
226         ok(wFlags == INVOKE_PROPERTYGET, "wFlags = %x\n", wFlags);
227         ok(pdp != NULL, "pdp == NULL\n");
228         ok(!pdp->rgvarg, "rgvarg != NULL\n");
229         ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n");
230         ok(!pdp->cArgs, "cArgs = %d\n", pdp->cArgs);
231         ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs);
232         ok(pvarRes != NULL, "pvarRes == NULL\n");
233         ok(V_VT(pvarRes) ==  VT_EMPTY, "V_VT(pvarRes) = %d\n", V_VT(pvarRes));
234         ok(pei != NULL, "pei == NULL\n");
235
236         V_VT(pvarRes) = VT_I4;
237         V_I4(pvarRes) = 1;
238         return S_OK;
239     }
240
241     ok(0, "unexpected call %x\n", id);
242     return DISP_E_MEMBERNOTFOUND;
243 }
244
245 static HRESULT WINAPI testObj_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex)
246 {
247     CHECK_EXPECT(testobj_delete);
248
249     ok(!strcmp_wa(bstrName, "deleteTest"), "unexpected name %s\n", wine_dbgstr_w(bstrName));
250     ok(grfdex == fdexNameCaseSensitive, "grfdex = %x\n", grfdex);
251     return S_OK;
252 }
253
254 static IDispatchExVtbl testObjVtbl = {
255     DispatchEx_QueryInterface,
256     DispatchEx_AddRef,
257     DispatchEx_Release,
258     DispatchEx_GetTypeInfoCount,
259     DispatchEx_GetTypeInfo,
260     DispatchEx_GetIDsOfNames,
261     DispatchEx_Invoke,
262     testObj_GetDispID,
263     testObj_InvokeEx,
264     testObj_DeleteMemberByName,
265     DispatchEx_DeleteMemberByDispID,
266     DispatchEx_GetMemberProperties,
267     DispatchEx_GetMemberName,
268     DispatchEx_GetNextDispID,
269     DispatchEx_GetNameSpaceParent
270 };
271
272 static IDispatchEx testObj = { &testObjVtbl };
273
274 static HRESULT WINAPI Global_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
275 {
276     if(!strcmp_wa(bstrName, "ok")) {
277         ok(grfdex == fdexNameCaseSensitive, "grfdex = %x\n", grfdex);
278         *pid = DISPID_GLOBAL_OK;
279         return S_OK;
280     }
281     if(!strcmp_wa(bstrName, "trace")) {
282         ok(grfdex == fdexNameCaseSensitive, "grfdex = %x\n", grfdex);
283         *pid = DISPID_GLOBAL_TRACE;
284         return S_OK;
285     }
286     if(!strcmp_wa(bstrName, "reportSuccess")) {
287         CHECK_EXPECT(global_success_d);
288         ok(grfdex == fdexNameCaseSensitive, "grfdex = %x\n", grfdex);
289         *pid = DISPID_GLOBAL_REPORTSUCCESS;
290         return S_OK;
291     }
292     if(!strcmp_wa(bstrName, "testPropGet")) {
293         CHECK_EXPECT(global_propget_d);
294         ok(grfdex == fdexNameCaseSensitive, "grfdex = %x\n", grfdex);
295         *pid = DISPID_GLOBAL_TESTPROPGET;
296         return S_OK;
297     }
298     if(!strcmp_wa(bstrName, "testPropPut")) {
299         CHECK_EXPECT(global_propput_d);
300         ok(grfdex == fdexNameCaseSensitive, "grfdex = %x\n", grfdex);
301         *pid = DISPID_GLOBAL_TESTPROPPUT;
302         return S_OK;
303     }
304     if(!strcmp_wa(bstrName, "getVT")) {
305         ok(grfdex == fdexNameCaseSensitive, "grfdex = %x\n", grfdex);
306         *pid = DISPID_GLOBAL_GETVT;
307         return S_OK;
308     }
309     if(!strcmp_wa(bstrName, "testObj")) {
310         ok(grfdex == fdexNameCaseSensitive, "grfdex = %x\n", grfdex);
311         *pid = DISPID_GLOBAL_TESTOBJ;
312         return S_OK;
313     }
314     if(!strcmp_wa(bstrName, "createNullBSTR")) {
315         *pid = DISPID_GLOBAL_NULL_BSTR;
316         return S_OK;
317     }
318     if(!strcmp_wa(bstrName, "nullDisp")) {
319         *pid = DISPID_GLOBAL_NULL_DISP;
320         return S_OK;
321     }
322     if(!strcmp_wa(bstrName, "notExists")) {
323         CHECK_EXPECT(global_notexists_d);
324         ok(grfdex == fdexNameCaseSensitive, "grfdex = %x\n", grfdex);
325         return DISP_E_UNKNOWNNAME;
326     }
327
328     if(strict_dispid_check)
329         ok(0, "unexpected call %s\n", wine_dbgstr_w(bstrName));
330     return DISP_E_UNKNOWNNAME;
331 }
332
333 static HRESULT WINAPI Global_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
334         VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
335 {
336     switch(id) {
337     case DISPID_GLOBAL_OK:
338         ok(wFlags == INVOKE_FUNC || wFlags == (INVOKE_FUNC|INVOKE_PROPERTYGET), "wFlags = %x\n", wFlags);
339         ok(pdp != NULL, "pdp == NULL\n");
340         ok(pdp->rgvarg != NULL, "rgvarg == NULL\n");
341         ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n");
342         ok(pdp->cArgs == 2, "cArgs = %d\n", pdp->cArgs);
343         ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs);
344         if(wFlags & INVOKE_PROPERTYGET)
345             ok(pvarRes != NULL, "pvarRes == NULL\n");
346         else
347             ok(!pvarRes, "pvarRes != NULL\n");
348         ok(pei != NULL, "pei == NULL\n");
349
350         ok(V_VT(pdp->rgvarg) == VT_BSTR, "V_VT(psp->rgvargs) = %d\n", V_VT(pdp->rgvarg));
351         ok(V_VT(pdp->rgvarg+1) == VT_BOOL, "V_VT(psp->rgvargs+1) = %d\n", V_VT(pdp->rgvarg));
352         ok(V_BOOL(pdp->rgvarg+1), "%s: %s\n", test_name, wine_dbgstr_w(V_BSTR(pdp->rgvarg)));
353
354         return S_OK;
355
356      case DISPID_GLOBAL_TRACE:
357         ok(wFlags == INVOKE_FUNC, "wFlags = %x\n", wFlags);
358         ok(pdp != NULL, "pdp == NULL\n");
359         ok(pdp->rgvarg != NULL, "rgvarg == NULL\n");
360         ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n");
361         ok(pdp->cArgs == 1, "cArgs = %d\n", pdp->cArgs);
362         ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs);
363         ok(!pvarRes, "pvarRes != NULL\n");
364         ok(pei != NULL, "pei == NULL\n");
365
366         ok(V_VT(pdp->rgvarg) == VT_BSTR, "V_VT(psp->rgvargs) = %d\n", V_VT(pdp->rgvarg));
367         if(V_VT(pdp->rgvarg) == VT_BSTR)
368             trace("%s: %s\n", test_name, wine_dbgstr_w(V_BSTR(pdp->rgvarg)));
369
370         return S_OK;
371
372     case DISPID_GLOBAL_REPORTSUCCESS:
373         CHECK_EXPECT(global_success_i);
374
375         ok(wFlags == INVOKE_FUNC, "wFlags = %x\n", wFlags);
376         ok(pdp != NULL, "pdp == NULL\n");
377         ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n");
378         ok(pdp->cArgs == 0, "cArgs = %d\n", pdp->cArgs);
379         ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs);
380         ok(!pvarRes, "pvarRes != NULL\n");
381         ok(pei != NULL, "pei == NULL\n");
382
383         return S_OK;
384
385      case DISPID_GLOBAL_TESTPROPGET:
386         CHECK_EXPECT(global_propget_i);
387
388         ok(wFlags == INVOKE_PROPERTYGET, "wFlags = %x\n", wFlags);
389         ok(pdp != NULL, "pdp == NULL\n");
390         ok(!pdp->rgvarg, "rgvarg != NULL\n");
391         ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n");
392         ok(!pdp->cArgs, "cArgs = %d\n", pdp->cArgs);
393         ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs);
394         ok(pvarRes != NULL, "pvarRes == NULL\n");
395         ok(V_VT(pvarRes) ==  VT_EMPTY, "V_VT(pvarRes) = %d\n", V_VT(pvarRes));
396         ok(pei != NULL, "pei == NULL\n");
397
398         V_VT(pvarRes) = VT_I4;
399         V_I4(pvarRes) = 1;
400
401         return S_OK;
402
403     case DISPID_GLOBAL_TESTPROPPUT:
404         CHECK_EXPECT(global_propput_i);
405
406         ok(wFlags == INVOKE_PROPERTYPUT, "wFlags = %x\n", wFlags);
407         ok(pdp != NULL, "pdp == NULL\n");
408         ok(pdp->rgvarg != NULL, "rgvarg == NULL\n");
409         ok(pdp->rgdispidNamedArgs != NULL, "rgdispidNamedArgs == NULL\n");
410         ok(pdp->cArgs == 1, "cArgs = %d\n", pdp->cArgs);
411         ok(pdp->cNamedArgs == 1, "cNamedArgs = %d\n", pdp->cNamedArgs);
412         ok(pdp->rgdispidNamedArgs[0] == DISPID_PROPERTYPUT, "pdp->rgdispidNamedArgs[0] = %d\n", pdp->rgdispidNamedArgs[0]);
413         ok(!pvarRes, "pvarRes != NULL\n");
414
415         ok(V_VT(pdp->rgvarg) == VT_I4, "V_VT(pdp->rgvarg)=%d\n", V_VT(pdp->rgvarg));
416         ok(V_I4(pdp->rgvarg) == 1, "V_I4(pdp->rgvarg)=%d\n", V_I4(pdp->rgvarg));
417         return S_OK;
418
419      case DISPID_GLOBAL_GETVT:
420         ok(pdp != NULL, "pdp == NULL\n");
421         ok(pdp->rgvarg != NULL, "rgvarg == NULL\n");
422         ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n");
423         ok(pdp->cArgs == 1, "cArgs = %d\n", pdp->cArgs);
424         ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs);
425         ok(pvarRes != NULL, "pvarRes == NULL\n");
426         ok(V_VT(pvarRes) ==  VT_EMPTY, "V_VT(pvarRes) = %d\n", V_VT(pvarRes));
427         ok(pei != NULL, "pei == NULL\n");
428
429         V_VT(pvarRes) = VT_BSTR;
430         switch(V_VT(pdp->rgvarg)) {
431         case VT_EMPTY:
432             V_BSTR(pvarRes) = a2bstr("VT_EMPTY");
433             break;
434         case VT_NULL:
435             V_BSTR(pvarRes) = a2bstr("VT_NULL");
436             break;
437         case VT_I4:
438             V_BSTR(pvarRes) = a2bstr("VT_I4");
439             break;
440         case VT_R8:
441             V_BSTR(pvarRes) = a2bstr("VT_R8");
442             break;
443         case VT_BSTR:
444             V_BSTR(pvarRes) = a2bstr("VT_BSTR");
445             break;
446         case VT_DISPATCH:
447             V_BSTR(pvarRes) = a2bstr("VT_DISPATCH");
448             break;
449         case VT_BOOL:
450             V_BSTR(pvarRes) = a2bstr("VT_BOOL");
451             break;
452         default:
453             ok(0, "unknown vt %d\n", V_VT(pdp->rgvarg));
454             return E_FAIL;
455         }
456
457         return S_OK;
458
459     case DISPID_GLOBAL_TESTOBJ:
460         ok(wFlags == INVOKE_PROPERTYGET, "wFlags = %x\n", wFlags);
461         ok(pdp != NULL, "pdp == NULL\n");
462         ok(!pdp->rgvarg, "rgvarg != NULL\n");
463         ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n");
464         ok(!pdp->cArgs, "cArgs = %d\n", pdp->cArgs);
465         ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs);
466         ok(pvarRes != NULL, "pvarRes == NULL\n");
467         ok(V_VT(pvarRes) ==  VT_EMPTY, "V_VT(pvarRes) = %d\n", V_VT(pvarRes));
468         ok(pei != NULL, "pei == NULL\n");
469
470         V_VT(pvarRes) = VT_DISPATCH;
471         V_DISPATCH(pvarRes) = (IDispatch*)&testObj;
472         return S_OK;
473
474     case DISPID_GLOBAL_NULL_BSTR:
475         if(pvarRes) {
476             V_VT(pvarRes) = VT_BSTR;
477             V_BSTR(pvarRes) = NULL;
478         }
479         return S_OK;
480
481     case DISPID_GLOBAL_NULL_DISP:
482         ok(wFlags == INVOKE_PROPERTYGET, "wFlags = %x\n", wFlags);
483         ok(pdp != NULL, "pdp == NULL\n");
484         ok(!pdp->rgvarg, "rgvarg != NULL\n");
485         ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n");
486         ok(!pdp->cArgs, "cArgs = %d\n", pdp->cArgs);
487         ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs);
488         ok(pvarRes != NULL, "pvarRes == NULL\n");
489         ok(V_VT(pvarRes) ==  VT_EMPTY, "V_VT(pvarRes) = %d\n", V_VT(pvarRes));
490         ok(pei != NULL, "pei == NULL\n");
491
492         V_VT(pvarRes) = VT_DISPATCH;
493         V_DISPATCH(pvarRes) = NULL;
494         return S_OK;
495     }
496
497     ok(0, "unexpected call %x\n", id);
498     return DISP_E_MEMBERNOTFOUND;
499 }
500
501 static IDispatchExVtbl GlobalVtbl = {
502     DispatchEx_QueryInterface,
503     DispatchEx_AddRef,
504     DispatchEx_Release,
505     DispatchEx_GetTypeInfoCount,
506     DispatchEx_GetTypeInfo,
507     DispatchEx_GetIDsOfNames,
508     DispatchEx_Invoke,
509     Global_GetDispID,
510     Global_InvokeEx,
511     DispatchEx_DeleteMemberByName,
512     DispatchEx_DeleteMemberByDispID,
513     DispatchEx_GetMemberProperties,
514     DispatchEx_GetMemberName,
515     DispatchEx_GetNextDispID,
516     DispatchEx_GetNameSpaceParent
517 };
518
519 static IDispatchEx Global = { &GlobalVtbl };
520
521 static HRESULT WINAPI ActiveScriptSite_QueryInterface(IActiveScriptSite *iface, REFIID riid, void **ppv)
522 {
523     *ppv = NULL;
524
525     if(IsEqualGUID(&IID_IUnknown, riid))
526         *ppv = iface;
527     else if(IsEqualGUID(&IID_IActiveScriptSite, riid))
528         *ppv = iface;
529     else
530         return E_NOINTERFACE;
531
532     IUnknown_AddRef((IUnknown*)*ppv);
533     return S_OK;
534 }
535
536 static ULONG WINAPI ActiveScriptSite_AddRef(IActiveScriptSite *iface)
537 {
538     return 2;
539 }
540
541 static ULONG WINAPI ActiveScriptSite_Release(IActiveScriptSite *iface)
542 {
543     return 1;
544 }
545
546 static HRESULT WINAPI ActiveScriptSite_GetLCID(IActiveScriptSite *iface, LCID *plcid)
547 {
548     *plcid = GetUserDefaultLCID();
549     return S_OK;
550 }
551
552 static HRESULT WINAPI ActiveScriptSite_GetItemInfo(IActiveScriptSite *iface, LPCOLESTR pstrName,
553         DWORD dwReturnMask, IUnknown **ppiunkItem, ITypeInfo **ppti)
554 {
555     ok(dwReturnMask == SCRIPTINFO_IUNKNOWN, "unexpected dwReturnMask %x\n", dwReturnMask);
556     ok(!ppti, "ppti != NULL\n");
557
558     if(!strcmp_wa(pstrName, test_valA))
559         CHECK_EXPECT(GetItemInfo_testVal);
560     else if(strcmp_wa(pstrName, testA))
561         ok(0, "unexpected pstrName %s\n", wine_dbgstr_w(pstrName));
562
563     *ppiunkItem = (IUnknown*)&Global;
564     return S_OK;
565 }
566
567 static HRESULT WINAPI ActiveScriptSite_GetDocVersionString(IActiveScriptSite *iface, BSTR *pbstrVersion)
568 {
569     return E_NOTIMPL;
570 }
571
572 static HRESULT WINAPI ActiveScriptSite_OnScriptTerminate(IActiveScriptSite *iface,
573         const VARIANT *pvarResult, const EXCEPINFO *pexcepinfo)
574 {
575     return E_NOTIMPL;
576 }
577
578 static HRESULT WINAPI ActiveScriptSite_OnStateChange(IActiveScriptSite *iface, SCRIPTSTATE ssScriptState)
579 {
580     return E_NOTIMPL;
581 }
582
583 static HRESULT WINAPI ActiveScriptSite_OnScriptError(IActiveScriptSite *iface, IActiveScriptError *pscripterror)
584 {
585     return E_NOTIMPL;
586 }
587
588 static HRESULT WINAPI ActiveScriptSite_OnEnterScript(IActiveScriptSite *iface)
589 {
590     return E_NOTIMPL;
591 }
592
593 static HRESULT WINAPI ActiveScriptSite_OnLeaveScript(IActiveScriptSite *iface)
594 {
595     return E_NOTIMPL;
596 }
597
598 #undef ACTSCPSITE_THIS
599
600 static const IActiveScriptSiteVtbl ActiveScriptSiteVtbl = {
601     ActiveScriptSite_QueryInterface,
602     ActiveScriptSite_AddRef,
603     ActiveScriptSite_Release,
604     ActiveScriptSite_GetLCID,
605     ActiveScriptSite_GetItemInfo,
606     ActiveScriptSite_GetDocVersionString,
607     ActiveScriptSite_OnScriptTerminate,
608     ActiveScriptSite_OnStateChange,
609     ActiveScriptSite_OnScriptError,
610     ActiveScriptSite_OnEnterScript,
611     ActiveScriptSite_OnLeaveScript
612 };
613
614 static IActiveScriptSite ActiveScriptSite = { &ActiveScriptSiteVtbl };
615
616 static IActiveScript *create_script(void)
617 {
618     IActiveScript *script;
619     HRESULT hres;
620
621     hres = CoCreateInstance(&CLSID_JScript, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
622             &IID_IActiveScript, (void**)&script);
623     ok(hres == S_OK, "CoCreateInstance failed: %08x\n", hres);
624
625     return script;
626 }
627
628 static void parse_script(BSTR script_str)
629 {
630     IActiveScriptParse *parser;
631     IActiveScript *engine;
632     HRESULT hres;
633
634     engine = create_script();
635     if(!engine)
636         return;
637
638     hres = IActiveScript_QueryInterface(engine, &IID_IActiveScriptParse, (void**)&parser);
639     ok(hres == S_OK, "Could not get IActiveScriptParse: %08x\n", hres);
640     if (FAILED(hres))
641     {
642         IActiveScript_Release(engine);
643         return;
644     }
645
646     hres = IActiveScriptParse64_InitNew(parser);
647     ok(hres == S_OK, "InitNew failed: %08x\n", hres);
648
649     hres = IActiveScript_SetScriptSite(engine, &ActiveScriptSite);
650     ok(hres == S_OK, "SetScriptSite failed: %08x\n", hres);
651
652     hres = IActiveScript_AddNamedItem(engine, testW,
653             SCRIPTITEM_ISVISIBLE|SCRIPTITEM_ISSOURCE|SCRIPTITEM_GLOBALMEMBERS);
654     ok(hres == S_OK, "AddNamedItem failed: %08x\n", hres);
655
656     hres = IActiveScript_SetScriptState(engine, SCRIPTSTATE_STARTED);
657     ok(hres == S_OK, "SetScriptState(SCRIPTSTATE_STARTED) failed: %08x\n", hres);
658
659     hres = IActiveScriptParse64_ParseScriptText(parser, script_str, NULL, NULL, NULL, 0, 0, 0, NULL, NULL);
660     ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres);
661
662     IActiveScript_Release(engine);
663     IUnknown_Release(parser);
664 }
665
666 static HRESULT parse_htmlscript(BSTR script_str)
667 {
668     IActiveScriptParse *parser;
669     IActiveScript *engine;
670     HRESULT hres;
671     BSTR tmp = a2bstr("</SCRIPT>");
672
673     engine = create_script();
674     if(!engine)
675         return E_FAIL;
676
677     hres = IActiveScript_QueryInterface(engine, &IID_IActiveScriptParse, (void**)&parser);
678     ok(hres == S_OK, "Could not get IActiveScriptParse: %08x\n", hres);
679     if (FAILED(hres))
680     {
681         IActiveScript_Release(engine);
682         return E_FAIL;
683     }
684
685     hres = IActiveScriptParse64_InitNew(parser);
686     ok(hres == S_OK, "InitNew failed: %08x\n", hres);
687
688     hres = IActiveScript_SetScriptSite(engine, &ActiveScriptSite);
689     ok(hres == S_OK, "SetScriptSite failed: %08x\n", hres);
690
691     hres = IActiveScript_AddNamedItem(engine, testW,
692             SCRIPTITEM_ISVISIBLE|SCRIPTITEM_ISSOURCE|SCRIPTITEM_GLOBALMEMBERS);
693     ok(hres == S_OK, "AddNamedItem failed: %08x\n", hres);
694
695     hres = IActiveScript_SetScriptState(engine, SCRIPTSTATE_STARTED);
696     ok(hres == S_OK, "SetScriptState(SCRIPTSTATE_STARTED) failed: %08x\n", hres);
697
698     hres = IActiveScriptParse64_ParseScriptText(parser, script_str, NULL, NULL, tmp, 0, 0, 0, NULL, NULL);
699
700     IActiveScript_Release(engine);
701     IUnknown_Release(parser);
702     SysFreeString(tmp);
703
704     return hres;
705 }
706
707 static void parse_script_a(const char *src)
708 {
709     BSTR tmp = a2bstr(src);
710     parse_script(tmp);
711     SysFreeString(tmp);
712 }
713
714 static HRESULT parse_htmlscript_a(const char *src)
715 {
716     HRESULT hres;
717     BSTR tmp = a2bstr(src);
718     hres = parse_htmlscript(tmp);
719     SysFreeString(tmp);
720
721     return hres;
722 }
723
724 static BSTR get_script_from_file(const char *filename)
725 {
726     DWORD size, len;
727     HANDLE file, map;
728     const char *file_map;
729     BSTR ret;
730
731     file = CreateFileA(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
732     if(file == INVALID_HANDLE_VALUE) {
733         trace("Could not open file: %u\n", GetLastError());
734         return NULL;
735     }
736
737     size = GetFileSize(file, NULL);
738
739     map = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL);
740     CloseHandle(file);
741     if(map == INVALID_HANDLE_VALUE) {
742         trace("Could not create file mapping: %u\n", GetLastError());
743         return NULL;
744     }
745
746     file_map = MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
747     CloseHandle(map);
748     if(!file_map) {
749         trace("MapViewOfFile failed: %u\n", GetLastError());
750         return NULL;
751     }
752
753     len = MultiByteToWideChar(CP_ACP, 0, file_map, size, NULL, 0);
754     ret = SysAllocStringLen(NULL, len);
755     MultiByteToWideChar(CP_ACP, 0, file_map, size, ret, len);
756
757     UnmapViewOfFile(file_map);
758
759     return ret;
760 }
761
762 static void run_from_file(const char *filename)
763 {
764     BSTR script_str = get_script_from_file(filename);
765
766     strict_dispid_check = FALSE;
767
768     if(script_str)
769         parse_script(script_str);
770
771     SysFreeString(script_str);
772 }
773
774 static void run_from_res(const char *name)
775 {
776     const char *data;
777     DWORD size, len;
778     BSTR str;
779     HRSRC src;
780
781     strict_dispid_check = FALSE;
782     test_name = name;
783
784     src = FindResourceA(NULL, name, (LPCSTR)40);
785     ok(src != NULL, "Could not find resource %s\n", name);
786
787     size = SizeofResource(NULL, src);
788     data = LoadResource(NULL, src);
789
790     len = MultiByteToWideChar(CP_ACP, 0, data, size, NULL, 0);
791     str = SysAllocStringLen(NULL, len);
792     len = MultiByteToWideChar(CP_ACP, 0, data, size, str, len);
793
794     SET_EXPECT(global_success_d);
795     SET_EXPECT(global_success_i);
796     parse_script(str);
797     CHECK_CALLED(global_success_d);
798     CHECK_CALLED(global_success_i);
799
800     SysFreeString(str);
801 }
802
803 static void test_isvisible(BOOL global_members)
804 {
805     IActiveScriptParse *parser;
806     IActiveScript *engine;
807     HRESULT hres;
808
809     static const WCHAR script_textW[] =
810         {'v','a','r',' ','v',' ','=',' ','t','e','s','t','V','a','l',';',0};
811
812     engine = create_script();
813     if(!engine)
814         return;
815
816     hres = IActiveScript_QueryInterface(engine, &IID_IActiveScriptParse, (void**)&parser);
817     ok(hres == S_OK, "Could not get IActiveScriptParse: %08x\n", hres);
818     if (FAILED(hres))
819     {
820         IActiveScript_Release(engine);
821         return;
822     }
823
824     hres = IActiveScriptParse64_InitNew(parser);
825     ok(hres == S_OK, "InitNew failed: %08x\n", hres);
826
827     hres = IActiveScript_SetScriptSite(engine, &ActiveScriptSite);
828     ok(hres == S_OK, "SetScriptSite failed: %08x\n", hres);
829
830     if(global_members)
831         SET_EXPECT(GetItemInfo_testVal);
832     hres = IActiveScript_AddNamedItem(engine, test_valW,
833             SCRIPTITEM_ISVISIBLE|SCRIPTITEM_ISSOURCE|
834             (global_members ? SCRIPTITEM_GLOBALMEMBERS : 0));
835     ok(hres == S_OK, "AddNamedItem failed: %08x\n", hres);
836     if(global_members)
837         CHECK_CALLED(GetItemInfo_testVal);
838
839     hres = IActiveScript_SetScriptState(engine, SCRIPTSTATE_STARTED);
840     ok(hres == S_OK, "SetScriptState(SCRIPTSTATE_STARTED) failed: %08x\n", hres);
841
842     if(!global_members)
843         SET_EXPECT(GetItemInfo_testVal);
844     hres = IActiveScriptParse64_ParseScriptText(parser, script_textW, NULL, NULL, NULL, 0, 0, 0, NULL, NULL);
845     ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres);
846     if(!global_members)
847         CHECK_CALLED(GetItemInfo_testVal);
848
849     hres = IActiveScriptParse64_ParseScriptText(parser, script_textW, NULL, NULL, NULL, 0, 0, 0, NULL, NULL);
850     ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres);
851
852     IActiveScript_Release(engine);
853     IUnknown_Release(parser);
854 }
855
856 static void run_tests(void)
857 {
858     HRESULT hres;
859
860     strict_dispid_check = TRUE;
861
862     parse_script_a("");
863     parse_script_a("/* empty */ ;");
864
865     SET_EXPECT(global_propget_d);
866     SET_EXPECT(global_propget_i);
867     parse_script_a("testPropGet;");
868     CHECK_CALLED(global_propget_d);
869     CHECK_CALLED(global_propget_i);
870
871     SET_EXPECT(global_propput_d);
872     SET_EXPECT(global_propput_i);
873     parse_script_a("testPropPut = 1;");
874     CHECK_CALLED(global_propput_d);
875     CHECK_CALLED(global_propput_i);
876
877     SET_EXPECT(global_success_d);
878     SET_EXPECT(global_success_i);
879     parse_script_a("reportSuccess();");
880     CHECK_CALLED(global_success_d);
881     CHECK_CALLED(global_success_i);
882
883     SET_EXPECT(testobj_delete);
884     parse_script_a("delete testObj.deleteTest;");
885     CHECK_CALLED(testobj_delete);
886
887     parse_script_a("ok(typeof(test) === 'object', \"typeof(test) != 'object'\");");
888
889     parse_script_a("function reportSuccess() {}; reportSuccess();");
890
891     SET_EXPECT(global_propget_d);
892     parse_script_a("var testPropGet");
893     CHECK_CALLED(global_propget_d);
894
895     SET_EXPECT(global_notexists_d);
896     parse_script_a("var notExists; notExists = 1;");
897     CHECK_CALLED(global_notexists_d);
898
899     parse_script_a("function f() { var testPropGet; }");
900
901     parse_script_a("ok((testObj instanceof Object) === false, 'testObj is instance of Object');");
902
903     SET_EXPECT(testobj_prop_d);
904     parse_script_a("ok(('prop' in testObj) === true, 'prop is not in testObj');");
905     CHECK_CALLED(testobj_prop_d);
906
907     SET_EXPECT(testobj_noprop_d);
908     parse_script_a("ok(('noprop' in testObj) === false, 'noprop is in testObj');");
909     CHECK_CALLED(testobj_noprop_d);
910
911     SET_EXPECT(testobj_value);
912     parse_script_a("ok(String(testObj) === '1', 'wrong testObj value');");
913     CHECK_CALLED(testobj_value);
914
915     run_from_res("lang.js");
916     run_from_res("api.js");
917     run_from_res("regexp.js");
918
919     test_isvisible(FALSE);
920     test_isvisible(TRUE);
921
922     hres = parse_htmlscript_a("<!--");
923     ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres);
924     hres = parse_htmlscript_a("-->");
925     ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres);
926     hres = parse_htmlscript_a("<!--\nvar a=1;\n-->\n");
927     ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres);
928     hres = parse_htmlscript_a("<!--\n<!-- ignore this\n-->\n");
929     ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres);
930     hres = parse_htmlscript_a("var a=1;\nif(a-->0) a=5;\n");
931     ok(hres == S_OK, "ParseScriptText failed: %08x\n", hres);
932     hres = parse_htmlscript_a("var a=1;\nif(a\n-->0) a=5;\n");
933     ok(hres != S_OK, "ParseScriptText have not failed\n");
934 }
935
936 START_TEST(run)
937 {
938     int argc;
939     char **argv;
940
941     argc = winetest_get_mainargs(&argv);
942
943     CoInitialize(NULL);
944
945     if(argc > 2)
946         run_from_file(argv[2]);
947     else
948         run_tests();
949
950     CoUninitialize();
951 }