jscript: Use num_set_int where possible.
[wine] / dlls / jscript / tests / caller.c
1 /*
2  * Copyright 2012 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 #include <objsafe.h>
28
29 #include "wine/test.h"
30
31 static const CLSID CLSID_JScript =
32     {0xf414c260,0x6ac0,0x11cf,{0xb6,0xd1,0x00,0xaa,0x00,0xbb,0xbb,0x58}};
33
34 #define DEFINE_EXPECT(func) \
35     static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
36
37 #define SET_EXPECT(func) \
38     expect_ ## func = TRUE
39
40 #define CHECK_EXPECT2(func) \
41     do { \
42         ok(expect_ ##func, "unexpected call " #func "\n"); \
43         called_ ## func = TRUE; \
44     }while(0)
45
46 #define CHECK_EXPECT(func) \
47     do { \
48         CHECK_EXPECT2(func); \
49         expect_ ## func = FALSE; \
50     }while(0)
51
52 #define CHECK_CALLED(func) \
53     do { \
54         ok(called_ ## func, "expected " #func "\n"); \
55         expect_ ## func = called_ ## func = FALSE; \
56     }while(0)
57
58 DEFINE_EXPECT(testArgConv);
59
60 static const WCHAR testW[] = {'t','e','s','t',0};
61
62 static IVariantChangeType *script_change_type;
63 static IDispatch *stored_obj;
64
65 #define DISPID_TEST_TESTARGCONV      0x1000
66
67 static BSTR a2bstr(const char *str)
68 {
69     BSTR ret;
70     int len;
71
72     len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
73     ret = SysAllocStringLen(NULL, len-1);
74     MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
75
76     return ret;
77 }
78
79 static int strcmp_wa(LPCWSTR strw, const char *stra)
80 {
81     CHAR buf[512];
82     WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), 0, 0);
83     return lstrcmpA(buf, stra);
84 }
85
86 typedef struct {
87     int int_result;
88     const char *str_result;
89     VARIANT_BOOL bool_result;
90     int test_double;
91     double double_result;
92 } conv_results_t;
93
94 #define call_change_type(a,b,c,d) _call_change_type(__LINE__,a,b,c,d)
95 static void _call_change_type(unsigned line, IVariantChangeType *change_type, VARIANT *dst, VARIANT *src, VARTYPE vt)
96 {
97     HRESULT hres;
98
99     VariantInit(dst);
100     hres = IVariantChangeType_ChangeType(change_type, dst, src, 0, vt);
101     ok_(__FILE__,line)(hres == S_OK, "ChangeType(%d) failed: %08x\n", vt, hres);
102     ok_(__FILE__,line)(V_VT(dst) == vt, "V_VT(dst) = %d\n", V_VT(dst));
103 }
104
105 #define change_type_fail(a,b,c,d) _change_type_fail(__LINE__,a,b,c,d)
106 static void _change_type_fail(unsigned line, IVariantChangeType *change_type, VARIANT *src, VARTYPE vt, HRESULT exhres)
107 {
108     VARIANT v;
109     HRESULT hres;
110
111     V_VT(&v) = VT_EMPTY;
112     hres = IVariantChangeType_ChangeType(change_type, &v, src, 0, vt);
113     ok_(__FILE__,line)(hres == exhres, "ChangeType failed: %08x, expected %08x\n", hres, exhres);
114 }
115
116 static void test_change_type(IVariantChangeType *change_type, VARIANT *src, const conv_results_t *ex)
117 {
118     VARIANT v;
119
120     call_change_type(change_type, &v, src, VT_I4);
121     ok(V_I4(&v) == ex->int_result, "V_I4(v) = %d, expected %d\n", V_I4(&v), ex->int_result);
122
123     call_change_type(change_type, &v, src, VT_BSTR);
124     ok(!strcmp_wa(V_BSTR(&v), ex->str_result), "V_BSTR(v) = %s, expected %s\n", wine_dbgstr_w(V_BSTR(&v)), ex->str_result);
125     VariantClear(&v);
126
127     call_change_type(change_type, &v, src, VT_BOOL);
128     ok(V_BOOL(&v) == ex->bool_result, "V_BOOL(v) = %x, expected %x\n", V_BOOL(&v), ex->bool_result);
129
130     if(ex->test_double) {
131         call_change_type(change_type, &v, src, VT_R8);
132         ok(V_R8(&v) == ex->double_result, "V_R8(v) = %lf, expected %lf\n", V_R8(&v), ex->double_result);
133
134         call_change_type(change_type, &v, src, VT_R4);
135         ok(V_R4(&v) == (float)ex->double_result, "V_R4(v) = %f, expected %f\n", V_R4(&v), (float)ex->double_result);
136     }
137
138     if(V_VT(src) == VT_NULL)
139         call_change_type(change_type, &v, src, VT_NULL);
140     else
141         change_type_fail(change_type, src, VT_NULL, E_NOTIMPL);
142
143     if(V_VT(src) == VT_EMPTY)
144         call_change_type(change_type, &v, src, VT_EMPTY);
145     else
146         change_type_fail(change_type, src, VT_EMPTY, E_NOTIMPL);
147
148     call_change_type(change_type, &v, src, VT_I2);
149     ok(V_I2(&v) == (INT16)ex->int_result, "V_I2(v) = %d, expected %d\n", V_I2(&v), ex->int_result);
150 }
151
152 static void test_change_types(IVariantChangeType *change_type, IDispatch *obj_disp)
153 {
154     VARIANT v, dst;
155     HRESULT hres;
156
157     static const conv_results_t bool_results[] = {
158         {0, "false", VARIANT_FALSE, 1,0.0},
159         {1, "true", VARIANT_TRUE, 1,1.0}};
160     static const conv_results_t int_results[] = {
161         {0, "0", VARIANT_FALSE, 1,0.0},
162         {-100, "-100", VARIANT_TRUE, 1,-100.0},
163         {0x10010, "65552", VARIANT_TRUE, 1,65552.0}};
164     static const conv_results_t empty_results =
165         {0, "undefined", VARIANT_FALSE, 0,0};
166     static const conv_results_t null_results =
167         {0, "null", VARIANT_FALSE, 0,0};
168     static const conv_results_t obj_results =
169         {10, "strval", VARIANT_TRUE, 1,10.0};
170
171     V_VT(&v) = VT_BOOL;
172     V_BOOL(&v) = VARIANT_FALSE;
173     test_change_type(change_type, &v, bool_results);
174     V_BOOL(&v) = VARIANT_TRUE;
175     test_change_type(change_type, &v, bool_results+1);
176
177     V_VT(&v) = VT_I4;
178     V_I4(&v) = 0;
179     test_change_type(change_type, &v, int_results);
180     V_I4(&v) = -100;
181     test_change_type(change_type, &v, int_results+1);
182     V_I4(&v) = 0x10010;
183     test_change_type(change_type, &v, int_results+2);
184
185     V_VT(&v) = VT_EMPTY;
186     test_change_type(change_type, &v, &empty_results);
187
188     V_VT(&v) = VT_NULL;
189     test_change_type(change_type, &v, &null_results);
190
191     V_VT(&v) = VT_DISPATCH;
192     V_DISPATCH(&v) = obj_disp;
193     test_change_type(change_type, &v, &obj_results);
194
195     V_VT(&v) = VT_BOOL;
196     V_BOOL(&v) = VARIANT_FALSE;
197     V_VT(&dst) = 0xdead;
198     hres = IVariantChangeType_ChangeType(change_type, &dst, &v, 0, VT_I4);
199     ok(hres == DISP_E_BADVARTYPE, "ChangeType failed: %08x, expected DISP_E_BADVARTYPE\n", hres);
200     ok(V_VT(&dst) == 0xdead, "V_VT(dst) = %d\n", V_VT(&dst));
201 }
202
203 static void test_caller(IServiceProvider *caller, IDispatch *arg_obj)
204 {
205     IVariantChangeType *change_type;
206     HRESULT hres;
207
208     hres = IServiceProvider_QueryService(caller, &SID_VariantConversion, &IID_IVariantChangeType, (void**)&change_type);
209     ok(hres == S_OK, "Could not get SID_VariantConversion service: %08x\n", hres);
210
211     ok(change_type == script_change_type, "change_type != script_change_type\n");
212     test_change_types(change_type, arg_obj);
213
214     IVariantChangeType_Release(change_type);
215 }
216
217 static HRESULT WINAPI DispatchEx_QueryInterface(IDispatchEx *iface, REFIID riid, void **ppv)
218 {
219     if(IsEqualGUID(riid, &IID_IUnknown)) {
220         *ppv = iface;
221     }else if(IsEqualGUID(riid, &IID_IDispatch) || IsEqualGUID(riid, &IID_IDispatchEx)) {
222         *ppv = iface;
223     }else if(IsEqualGUID(&IID_IObjectSafety, riid)) {
224         ok(0, "Unexpected IID_IObjectSafety query\n");
225     }else {
226         *ppv = NULL;
227         return E_NOINTERFACE;
228     }
229
230     return S_OK;
231 }
232
233 static ULONG WINAPI DispatchEx_AddRef(IDispatchEx *iface)
234 {
235     return 2;
236 }
237
238 static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface)
239 {
240     return 1;
241 }
242
243 static HRESULT WINAPI DispatchEx_GetTypeInfoCount(IDispatchEx *iface, UINT *pctinfo)
244 {
245     ok(0, "unexpected call\n");
246     return E_NOTIMPL;
247 }
248
249 static HRESULT WINAPI DispatchEx_GetTypeInfo(IDispatchEx *iface, UINT iTInfo,
250                                               LCID lcid, ITypeInfo **ppTInfo)
251 {
252     ok(0, "unexpected call\n");
253     return E_NOTIMPL;
254 }
255
256 static HRESULT WINAPI DispatchEx_GetIDsOfNames(IDispatchEx *iface, REFIID riid,
257                                                 LPOLESTR *rgszNames, UINT cNames,
258                                                 LCID lcid, DISPID *rgDispId)
259 {
260     ok(0, "unexpected call\n");
261     return E_NOTIMPL;
262 }
263
264 static HRESULT WINAPI DispatchEx_Invoke(IDispatchEx *iface, DISPID dispIdMember,
265                             REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
266                             VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
267 {
268     ok(0, "unexpected call\n");
269     return E_NOTIMPL;
270 }
271
272 static HRESULT WINAPI DispatchEx_DeleteMemberByName(IDispatchEx *iface, BSTR bstrName, DWORD grfdex)
273 {
274     ok(0, "unexpected call %s %x\n", wine_dbgstr_w(bstrName), grfdex);
275     return E_NOTIMPL;
276 }
277
278 static HRESULT WINAPI DispatchEx_DeleteMemberByDispID(IDispatchEx *iface, DISPID id)
279 {
280     ok(0, "unexpected call\n");
281     return E_NOTIMPL;
282 }
283
284 static HRESULT WINAPI DispatchEx_GetMemberProperties(IDispatchEx *iface, DISPID id, DWORD grfdexFetch, DWORD *pgrfdex)
285 {
286     ok(0, "unexpected call\n");
287     return E_NOTIMPL;
288 }
289
290 static HRESULT WINAPI DispatchEx_GetMemberName(IDispatchEx *iface, DISPID id, BSTR *pbstrName)
291 {
292     ok(0, "unexpected call\n");
293     return E_NOTIMPL;
294 }
295
296 static HRESULT WINAPI DispatchEx_GetNextDispID(IDispatchEx *iface, DWORD grfdex, DISPID id, DISPID *pid)
297 {
298     ok(0, "unexpected call\n");
299     return E_NOTIMPL;
300 }
301
302 static HRESULT WINAPI DispatchEx_GetNameSpaceParent(IDispatchEx *iface, IUnknown **ppunk)
303 {
304     ok(0, "unexpected call\n");
305     return E_NOTIMPL;
306 }
307
308 static HRESULT WINAPI Test_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
309 {
310     if(!strcmp_wa(bstrName, "testArgConv")) {
311         ok(grfdex == fdexNameCaseSensitive, "grfdex = %x\n", grfdex);
312         *pid = DISPID_TEST_TESTARGCONV;
313         return S_OK;
314     }
315
316     return E_NOTIMPL;
317 }
318
319 static HRESULT WINAPI Test_InvokeEx(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
320         VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
321 {
322     ok(pspCaller != NULL, "pspCaller == NULL\n");
323
324     switch(id) {
325     case DISPID_TEST_TESTARGCONV:
326         CHECK_EXPECT(testArgConv);
327
328         ok(wFlags == INVOKE_FUNC, "wFlags = %x\n", wFlags);
329         ok(pdp != NULL, "pdp == NULL\n");
330         ok(!pdp->rgdispidNamedArgs, "rgdispidNamedArgs != NULL\n");
331         ok(!pvarRes, "pvarRes != NULL\n");
332         ok(pei != NULL, "pei == NULL\n");
333
334         ok(pdp->cArgs == 1, "cArgs = %d\n", pdp->cArgs);
335         ok(V_VT(pdp->rgvarg) == VT_DISPATCH, "V_VT(rgvarg) = %d\n", V_VT(pdp->rgvarg));
336
337         test_caller(pspCaller, V_DISPATCH(pdp->rgvarg));
338
339         stored_obj = V_DISPATCH(pdp->rgvarg);
340         IDispatch_AddRef(stored_obj);
341         break;
342
343     default:
344         ok(0, "unexpected call\n");
345         return E_NOTIMPL;
346     }
347
348     return S_OK;
349 }
350
351 static IDispatchExVtbl testObjVtbl = {
352     DispatchEx_QueryInterface,
353     DispatchEx_AddRef,
354     DispatchEx_Release,
355     DispatchEx_GetTypeInfoCount,
356     DispatchEx_GetTypeInfo,
357     DispatchEx_GetIDsOfNames,
358     DispatchEx_Invoke,
359     Test_GetDispID,
360     Test_InvokeEx,
361     DispatchEx_DeleteMemberByName,
362     DispatchEx_DeleteMemberByDispID,
363     DispatchEx_GetMemberProperties,
364     DispatchEx_GetMemberName,
365     DispatchEx_GetNextDispID,
366     DispatchEx_GetNameSpaceParent
367 };
368
369 static IDispatchEx testObj = { &testObjVtbl };
370
371 static HRESULT WINAPI ActiveScriptSite_QueryInterface(IActiveScriptSite *iface, REFIID riid, void **ppv)
372 {
373     if(IsEqualGUID(&IID_IUnknown, riid)) {
374         *ppv = iface;
375     }else if(IsEqualGUID(&IID_IActiveScriptSite, riid)) {
376         *ppv = iface;
377     }else {
378         *ppv = NULL;
379         return E_NOINTERFACE;
380     }
381
382     IUnknown_AddRef((IUnknown*)*ppv);
383     return S_OK;
384 }
385
386 static ULONG WINAPI ActiveScriptSite_AddRef(IActiveScriptSite *iface)
387 {
388     return 2;
389 }
390
391 static ULONG WINAPI ActiveScriptSite_Release(IActiveScriptSite *iface)
392 {
393     return 1;
394 }
395
396 static HRESULT WINAPI ActiveScriptSite_GetLCID(IActiveScriptSite *iface, LCID *plcid)
397 {
398     *plcid = GetUserDefaultLCID();
399     return S_OK;
400 }
401
402 static HRESULT WINAPI ActiveScriptSite_GetItemInfo(IActiveScriptSite *iface, LPCOLESTR pstrName,
403         DWORD dwReturnMask, IUnknown **ppiunkItem, ITypeInfo **ppti)
404 {
405     ok(dwReturnMask == SCRIPTINFO_IUNKNOWN, "unexpected dwReturnMask %x\n", dwReturnMask);
406     ok(!ppti, "ppti != NULL\n");
407     ok(!strcmp_wa(pstrName, "test"), "pstrName = %s\n", wine_dbgstr_w(pstrName));
408
409     *ppiunkItem = (IUnknown*)&testObj;
410     return S_OK;
411 }
412
413 static HRESULT WINAPI ActiveScriptSite_GetDocVersionString(IActiveScriptSite *iface, BSTR *pbstrVersion)
414 {
415     return E_NOTIMPL;
416 }
417
418 static HRESULT WINAPI ActiveScriptSite_OnScriptTerminate(IActiveScriptSite *iface,
419         const VARIANT *pvarResult, const EXCEPINFO *pexcepinfo)
420 {
421     return E_NOTIMPL;
422 }
423
424 static HRESULT WINAPI ActiveScriptSite_OnStateChange(IActiveScriptSite *iface, SCRIPTSTATE ssScriptState)
425 {
426     return E_NOTIMPL;
427 }
428
429 static HRESULT WINAPI ActiveScriptSite_OnScriptError(IActiveScriptSite *iface, IActiveScriptError *pscripterror)
430 {
431     return E_NOTIMPL;
432 }
433
434 static HRESULT WINAPI ActiveScriptSite_OnEnterScript(IActiveScriptSite *iface)
435 {
436     return E_NOTIMPL;
437 }
438
439 static HRESULT WINAPI ActiveScriptSite_OnLeaveScript(IActiveScriptSite *iface)
440 {
441     return E_NOTIMPL;
442 }
443
444 static const IActiveScriptSiteVtbl ActiveScriptSiteVtbl = {
445     ActiveScriptSite_QueryInterface,
446     ActiveScriptSite_AddRef,
447     ActiveScriptSite_Release,
448     ActiveScriptSite_GetLCID,
449     ActiveScriptSite_GetItemInfo,
450     ActiveScriptSite_GetDocVersionString,
451     ActiveScriptSite_OnScriptTerminate,
452     ActiveScriptSite_OnStateChange,
453     ActiveScriptSite_OnScriptError,
454     ActiveScriptSite_OnEnterScript,
455     ActiveScriptSite_OnLeaveScript
456 };
457
458 static IActiveScriptSite ActiveScriptSite = { &ActiveScriptSiteVtbl };
459
460 #define parse_script_a(p,s) _parse_script_a(__LINE__,p,s)
461 static void _parse_script_a(unsigned line, IActiveScriptParse *parser, const char *script)
462 {
463     BSTR str;
464     HRESULT hres;
465
466     str = a2bstr(script);
467     hres = IActiveScriptParse64_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, 0, NULL, NULL);
468     SysFreeString(str);
469     ok_(__FILE__,line)(hres == S_OK, "ParseScriptText failed: %08x\n", hres);
470 }
471
472 static IActiveScriptParse *create_script(void)
473 {
474     IActiveScriptParse *parser;
475     IActiveScript *script;
476     HRESULT hres;
477
478     hres = CoCreateInstance(&CLSID_JScript, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
479             &IID_IActiveScript, (void**)&script);
480     if(FAILED(hres))
481         return NULL;
482
483     hres = IActiveScript_QueryInterface(script, &IID_IActiveScriptParse, (void**)&parser);
484     ok(hres == S_OK, "Could not get IActiveScriptParse: %08x\n", hres);
485
486     hres = IActiveScriptParse64_InitNew(parser);
487     ok(hres == S_OK, "InitNew failed: %08x\n", hres);
488
489     hres = IActiveScript_SetScriptSite(script, &ActiveScriptSite);
490     ok(hres == S_OK, "SetScriptSite failed: %08x\n", hres);
491
492     hres = IActiveScript_AddNamedItem(script, testW,
493             SCRIPTITEM_ISVISIBLE|SCRIPTITEM_ISSOURCE|SCRIPTITEM_GLOBALMEMBERS);
494     ok(hres == S_OK, "AddNamedItem failed: %08x\n", hres);
495
496     hres = IActiveScript_SetScriptState(script, SCRIPTSTATE_STARTED);
497     ok(hres == S_OK, "SetScriptState(SCRIPTSTATE_STARTED) failed: %08x\n", hres);
498
499     IActiveScript_Release(script);
500
501     return parser;
502 }
503
504 static void run_scripts(void)
505 {
506     IActiveScriptParse *parser;
507     HRESULT hres;
508
509     parser = create_script();
510
511     hres = IActiveScriptParse64_QueryInterface(parser, &IID_IVariantChangeType, (void**)&script_change_type);
512     ok(hres == S_OK, "Could not get IVariantChangeType iface: %08x\n", hres);
513
514     SET_EXPECT(testArgConv);
515     parse_script_a(parser,
516                    "var obj = {"
517                    "    toString: function() { return 'strval'; },"
518                    "    valueOf: function()  { return 10; }"
519                    "};"
520                    "testArgConv(obj);");
521     CHECK_CALLED(testArgConv);
522
523     test_change_types(script_change_type, stored_obj);
524     IDispatch_Release(stored_obj);
525     IVariantChangeType_Release(script_change_type);
526
527     IUnknown_Release(parser);
528 }
529
530 static BOOL check_jscript(void)
531 {
532     IActiveScriptProperty *script_prop;
533     IActiveScriptParse *parser;
534     BSTR str;
535     HRESULT hres;
536
537     parser = create_script();
538     if(!parser)
539         return FALSE;
540
541     str = a2bstr("if(!('localeCompare' in String.prototype)) throw 1;");
542     hres = IActiveScriptParse64_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, 0, NULL, NULL);
543     SysFreeString(str);
544
545     if(hres == S_OK)
546         hres = IUnknown_QueryInterface(parser, &IID_IActiveScriptProperty, (void**)&script_prop);
547     IUnknown_Release(parser);
548     if(hres == S_OK)
549         IActiveScriptProperty_Release(script_prop);
550
551     return hres == S_OK;
552 }
553
554 START_TEST(caller)
555 {
556     CoInitialize(NULL);
557
558     if(check_jscript())
559         run_scripts();
560     else
561         win_skip("Broken (too old) jscript\n");
562
563     CoUninitialize();
564 }