wscript: Implemented Host_get_ScriptName.
[wine] / programs / wscript / tests / run.c
1 /*
2  * Copyright 2011 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 <initguid.h>
25 #include <windows.h>
26 #include <oaidl.h>
27
28 #include "wine/test.h"
29
30 #define DEFINE_EXPECT(func) \
31     static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
32
33 #define SET_EXPECT(func) \
34     expect_ ## func = TRUE
35
36 #define SET_CALLED(func) \
37     called_ ## func = TRUE
38
39 #define CHECK_EXPECT2(func) \
40     do { \
41         ok(expect_ ##func, "unexpected call " #func "\n"); \
42         called_ ## func = TRUE; \
43     }while(0)
44
45 #define CHECK_EXPECT(func) \
46     do { \
47         CHECK_EXPECT2(func); \
48         expect_ ## func = FALSE; \
49     }while(0)
50
51 #define CHECK_CALLED(func) \
52     do { \
53         ok(called_ ## func, "expected " #func "\n"); \
54         expect_ ## func = called_ ## func = FALSE; \
55     }while(0)
56
57 DEFINE_EXPECT(reportSuccess);
58
59 #define DISPID_TESTOBJ_OK                        10000
60 #define DISPID_TESTOBJ_TRACE                     10001
61 #define DISPID_TESTOBJ_REPORTSUCCESS             10002
62 #define DISPID_TESTOBJ_WSCRIPTFULLNAME           10003
63 #define DISPID_TESTOBJ_WSCRIPTPATH               10004
64 #define DISPID_TESTOBJ_WSCRIPTSCRIPTNAME         10005
65
66 #define TESTOBJ_CLSID "{178fc166-f585-4e24-9c13-4bb7faf80646}"
67
68 static const GUID CLSID_TestObj =
69     {0x178fc166,0xf585,0x4e24,{0x9c,0x13,0x4b,0xb7,0xfa,0xf8,0x06,0x46}};
70
71 static const char *script_name;
72
73 static int strcmp_wa(LPCWSTR strw, const char *stra)
74 {
75     WCHAR buf[512];
76     MultiByteToWideChar(CP_ACP, 0, stra, -1, buf, sizeof(buf)/sizeof(WCHAR));
77     return lstrcmpW(strw, buf);
78 }
79
80 static const WCHAR* mystrrchr(const WCHAR *str, WCHAR ch)
81 {
82     const WCHAR *pos = NULL, *current = str;
83     while(*current != 0) {
84         if(*current == ch)
85             pos = current;
86         ++current;
87     }
88     return pos;
89 }
90
91 static BSTR a2bstr(const char *str)
92 {
93     BSTR ret;
94     int len;
95
96     len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
97     ret = SysAllocStringLen(NULL, len-1);
98     MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
99
100     return ret;
101 }
102
103 static HRESULT WINAPI Dispatch_QueryInterface(IDispatch *iface, REFIID riid, void **ppv)
104 {
105     if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IDispatch)) {
106         *ppv = iface;
107         return S_OK;
108     }
109
110     *ppv = NULL;
111     return E_NOINTERFACE;
112 }
113
114 static ULONG WINAPI Dispatch_AddRef(IDispatch *iface)
115 {
116     return 2;
117 }
118
119 static ULONG WINAPI Dispatch_Release(IDispatch *iface)
120 {
121     return 1;
122 }
123
124 static HRESULT WINAPI Dispatch_GetTypeInfoCount(IDispatch *iface, UINT *pctinfo)
125 {
126     ok(0, "unexpected call\n");
127     return E_NOTIMPL;
128 }
129
130 static HRESULT WINAPI Dispatch_GetTypeInfo(IDispatch *iface, UINT iTInfo,
131         LCID lcid, ITypeInfo **ppTInfo)
132 {
133     ok(0, "unexpected call\n");
134     return E_NOTIMPL;
135 }
136
137 static HRESULT WINAPI Dispatch_GetIDsOfNames(IDispatch *iface, REFIID riid,
138         LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
139 {
140     unsigned i;
141
142     for(i=0; i<cNames; i++) {
143         if(!strcmp_wa(rgszNames[i], "ok")) {
144             rgDispId[i] = DISPID_TESTOBJ_OK;
145         }else if(!strcmp_wa(rgszNames[i], "trace")) {
146             rgDispId[i] = DISPID_TESTOBJ_TRACE;
147         }else if(!strcmp_wa(rgszNames[i], "reportSuccess")) {
148             rgDispId[i] = DISPID_TESTOBJ_REPORTSUCCESS;
149         }else if(!strcmp_wa(rgszNames[i], "wscriptFullName")) {
150             rgDispId[i] = DISPID_TESTOBJ_WSCRIPTFULLNAME;
151         }else if(!strcmp_wa(rgszNames[i], "wscriptPath")) {
152             rgDispId[i] = DISPID_TESTOBJ_WSCRIPTPATH;
153         }else if(!strcmp_wa(rgszNames[i], "wscriptScriptName")) {
154             rgDispId[i] = DISPID_TESTOBJ_WSCRIPTSCRIPTNAME;
155         }else {
156             ok(0, "unexpected name %s\n", wine_dbgstr_w(rgszNames[i]));
157             return DISP_E_UNKNOWNNAME;
158         }
159     }
160
161     return S_OK;
162 }
163
164 static HRESULT WINAPI Dispatch_Invoke(IDispatch *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
165                                       WORD wFlags, DISPPARAMS *pdp, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
166 {
167     switch(dispIdMember) {
168     case DISPID_TESTOBJ_OK:
169         ok(wFlags == INVOKE_FUNC, "wFlags = %x\n", wFlags);
170         ok(pdp->cArgs == 2, "cArgs = %d\n", pdp->cArgs);
171         ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs);
172         ok(V_VT(pdp->rgvarg) == VT_BSTR, "V_VT(psp->rgvargs) = %d\n", V_VT(pdp->rgvarg));
173         ok(V_VT(pdp->rgvarg+1) == VT_BOOL, "V_VT(psp->rgvargs+1) = %d\n", V_VT(pdp->rgvarg));
174         ok(V_BOOL(pdp->rgvarg+1), "%s: %s\n", script_name, wine_dbgstr_w(V_BSTR(pdp->rgvarg)));
175         if(pVarResult)
176             V_VT(pVarResult) = VT_EMPTY;
177         break;
178     case DISPID_TESTOBJ_TRACE:
179         ok(wFlags == INVOKE_FUNC, "wFlags = %x\n", wFlags);
180         ok(pdp->cArgs == 1, "cArgs = %d\n", pdp->cArgs);
181         ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs);
182         ok(V_VT(pdp->rgvarg) == VT_BSTR, "V_VT(psp->rgvargs) = %d\n", V_VT(pdp->rgvarg));
183         trace("%s: %s\n", script_name, wine_dbgstr_w(V_BSTR(pdp->rgvarg)));
184         if(pVarResult)
185             V_VT(pVarResult) = VT_EMPTY;
186         break;
187     case DISPID_TESTOBJ_REPORTSUCCESS:
188         CHECK_EXPECT(reportSuccess);
189
190         ok(wFlags == INVOKE_FUNC, "wFlags = %x\n", wFlags);
191         ok(pdp->cArgs == 0, "cArgs = %d\n", pdp->cArgs);
192         ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs);
193         if(pVarResult)
194             V_VT(pVarResult) = VT_EMPTY;
195         break;
196     case DISPID_TESTOBJ_WSCRIPTFULLNAME:
197     {
198         WCHAR fullName[MAX_PATH];
199         const WCHAR wscriptexe[] = {'w','s','c','r','i','p','t','.','e','x','e',0};
200         DWORD res;
201
202         ok(wFlags == INVOKE_PROPERTYGET, "wFlags = %x\n", wFlags);
203         ok(pdp->cArgs == 0, "cArgs = %d\n", pdp->cArgs);
204         ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs);
205         V_VT(pVarResult) = VT_BSTR;
206         res = SearchPathW(NULL, wscriptexe, NULL, sizeof(fullName)/sizeof(WCHAR), fullName, NULL);
207         if(res == 0)
208             return E_FAIL;
209         if(!(V_BSTR(pVarResult) = SysAllocString(fullName)))
210             return E_OUTOFMEMORY;
211         break;
212     }
213     case DISPID_TESTOBJ_WSCRIPTPATH:
214     {
215         WCHAR fullPath[MAX_PATH];
216         const WCHAR wscriptexe[] = {'w','s','c','r','i','p','t','.','e','x','e',0};
217         DWORD res;
218         const WCHAR *pos;
219
220         ok(wFlags == INVOKE_PROPERTYGET, "wFlags = %x\n", wFlags);
221         ok(pdp->cArgs == 0, "cArgs = %d\n", pdp->cArgs);
222         ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs);
223         V_VT(pVarResult) = VT_BSTR;
224         res = SearchPathW(NULL, wscriptexe, NULL, sizeof(fullPath)/sizeof(WCHAR), fullPath, NULL);
225         if(res == 0)
226             return E_FAIL;
227         pos = mystrrchr(fullPath, '\\');
228         if(!(V_BSTR(pVarResult) = SysAllocStringLen(fullPath, pos-fullPath)))
229             return E_OUTOFMEMORY;
230         break;
231     }
232     case DISPID_TESTOBJ_WSCRIPTSCRIPTNAME:
233     {
234         char fullPath[MAX_PATH];
235         char *pos;
236         long res;
237
238         ok(wFlags == INVOKE_PROPERTYGET, "wFlags = %x\n", wFlags);
239         ok(pdp->cArgs == 0, "cArgs = %d\n", pdp->cArgs);
240         ok(!pdp->cNamedArgs, "cNamedArgs = %d\n", pdp->cNamedArgs);
241         V_VT(pVarResult) = VT_BSTR;
242         res = GetFullPathNameA(script_name, sizeof(fullPath)/sizeof(WCHAR), fullPath, &pos);
243         if(!res || res > sizeof(fullPath)/sizeof(WCHAR))
244             return E_FAIL;
245         if(!(V_BSTR(pVarResult) = SysAllocString(a2bstr(pos))))
246             return E_OUTOFMEMORY;
247         break;
248     }
249     default:
250         ok(0, "unexpected dispIdMember %d\n", dispIdMember);
251         return E_NOTIMPL;
252     }
253
254     return S_OK;
255 }
256
257 static IDispatchVtbl testobj_vtbl = {
258     Dispatch_QueryInterface,
259     Dispatch_AddRef,
260     Dispatch_Release,
261     Dispatch_GetTypeInfoCount,
262     Dispatch_GetTypeInfo,
263     Dispatch_GetIDsOfNames,
264     Dispatch_Invoke
265 };
266
267 static IDispatch testobj = { &testobj_vtbl };
268
269 static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv)
270 {
271     if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IClassFactory, riid)) {
272         *ppv = iface;
273         return S_OK;
274     }
275
276     *ppv = NULL;
277     return E_NOINTERFACE;
278 }
279
280 static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface)
281 {
282     return 2;
283 }
284
285 static ULONG WINAPI ClassFactory_Release(IClassFactory *iface)
286 {
287     return 1;
288 }
289
290 static HRESULT WINAPI ClassFactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
291 {
292     ok(!outer, "outer = %p\n", outer);
293     return IDispatch_QueryInterface(&testobj, riid, ppv);
294 }
295
296 static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL dolock)
297 {
298     return S_OK;
299 }
300
301 static const IClassFactoryVtbl ClassFactoryVtbl = {
302     ClassFactory_QueryInterface,
303     ClassFactory_AddRef,
304     ClassFactory_Release,
305     ClassFactory_CreateInstance,
306     ClassFactory_LockServer
307 };
308
309 static IClassFactory testobj_cf = { &ClassFactoryVtbl };
310
311 static void run_test(const char *file_name)
312 {
313     SECURITY_ATTRIBUTES sa = {sizeof(sa), 0, TRUE};
314     char command[MAX_PATH];
315     STARTUPINFOA si = {sizeof(si)};
316     PROCESS_INFORMATION pi;
317     BOOL bres;
318
319     script_name = file_name;
320     sprintf(command, "wscript.exe %s", file_name);
321
322     SET_EXPECT(reportSuccess);
323
324     bres = CreateProcessA(NULL, command, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
325     if(!bres) {
326         win_skip("script.exe is not available\n");
327         SET_CALLED(reportSuccess);
328         return;
329     }
330
331     WaitForSingleObject(pi.hProcess, INFINITE);
332     CloseHandle(pi.hThread);
333     CloseHandle(pi.hProcess);
334
335     CHECK_CALLED(reportSuccess);
336 }
337
338 static BOOL WINAPI test_enum_proc(HMODULE module, LPCTSTR type, LPSTR name, LONG_PTR param)
339 {
340     const char *script_data, *ext;
341     DWORD script_size, size;
342     char file_name[MAX_PATH];
343     HANDLE file;
344     HRSRC src;
345     BOOL res;
346
347     trace("running %s test...\n", name);
348
349     src = FindResourceA(NULL, name, type);
350     ok(src != NULL, "Could not find resource %s: %u\n", name, GetLastError());
351     if(!src)
352         return TRUE;
353
354     script_data = LoadResource(NULL, src);
355     script_size = SizeofResource(NULL, src);
356     while(script_size && !script_data[script_size-1])
357         script_size--;
358
359     ext = strrchr(name, '.');
360     ok(ext != NULL, "no script extension\n");
361     if(!ext)
362       return TRUE;
363
364     sprintf(file_name, "test%s", ext);
365
366     file = CreateFileA(file_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
367             FILE_ATTRIBUTE_NORMAL, NULL);
368     ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError());
369     if(file == INVALID_HANDLE_VALUE)
370         return TRUE;
371
372     res = WriteFile(file, script_data, script_size, &size, NULL);
373     CloseHandle(file);
374     ok(res, "Could not write to file: %u\n", GetLastError());
375     if(!res)
376         return TRUE;
377
378     run_test(file_name);
379
380     DeleteFileA(file_name);
381     return TRUE;
382 }
383
384 static BOOL init_key(const char *key_name, const char *def_value, BOOL init)
385 {
386     HKEY hkey;
387     DWORD res;
388
389     if(!init) {
390         RegDeleteKey(HKEY_CLASSES_ROOT, key_name);
391         return TRUE;
392     }
393
394     res = RegCreateKeyA(HKEY_CLASSES_ROOT, key_name, &hkey);
395     if(res != ERROR_SUCCESS)
396         return FALSE;
397
398     if(def_value)
399         res = RegSetValueA(hkey, NULL, REG_SZ, def_value, strlen(def_value));
400
401     RegCloseKey(hkey);
402     return res == ERROR_SUCCESS;
403 }
404
405 static BOOL init_registry(BOOL init)
406 {
407     return init_key("Wine.Test\\CLSID", TESTOBJ_CLSID, init);
408 }
409
410 static BOOL register_activex(void)
411 {
412     DWORD regid;
413     HRESULT hres;
414
415     if(!init_registry(TRUE)) {
416         init_registry(FALSE);
417         return FALSE;
418     }
419
420     hres = CoRegisterClassObject(&CLSID_TestObj, (IUnknown *)&testobj_cf,
421             CLSCTX_SERVER, REGCLS_MULTIPLEUSE, &regid);
422     ok(hres == S_OK, "Could not register script engine: %08x\n", hres);
423     return TRUE;
424 }
425
426 START_TEST(run)
427 {
428     char **argv;
429     int argc;
430
431     CoInitializeEx(NULL, COINIT_MULTITHREADED);
432     register_activex();
433
434     argc = winetest_get_mainargs(&argv);
435     if(argc > 2)
436         run_test(argv[2]);
437     else
438         EnumResourceNamesA(NULL, "TESTSCRIPT", test_enum_proc, 0);
439
440     init_registry(FALSE);
441     CoUninitialize();
442 }