cabab801b72a835bf22854b5fdede70bfb40588f
[reactos.git] / modules / rostests / winetests / oleaut32 / varformat.c
1 /*
2 * VARFORMAT test program
3 *
4 * Copyright 1998 Jean-Claude Cote
5 * Copyright 2006 Google (Benjamin Arai)
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #define WIN32_NO_STATUS
23 #define _INC_WINDOWS
24 #define COM_NO_WINDOWS_H
25
26 //#include <stdarg.h>
27 //#include <stdio.h>
28 //#include <math.h>
29 //#include <float.h>
30
31 //#include "windef.h"
32 //#include "winbase.h"
33 //#include "winsock.h"
34 #include <wine/test.h>
35 //#include "winuser.h"
36 //#include "wingdi.h"
37 #include <winnls.h>
38 //#include "winerror.h"
39 //#include "winnt.h"
40 #include <objbase.h>
41 //#include "wtypes.h"
42 #include <oleauto.h>
43
44 static HMODULE hOleaut32;
45
46 static HRESULT (WINAPI *pVarBstrCmp)(BSTR,BSTR,LCID,ULONG);
47 static HRESULT (WINAPI *pVarFormatNumber)(LPVARIANT,int,int,int,int,ULONG,BSTR*);
48 static HRESULT (WINAPI *pVarFormat)(LPVARIANT,LPOLESTR,int,int,ULONG,BSTR*);
49 static HRESULT (WINAPI *pVarWeekdayName)(int,int,int,ULONG,BSTR*);
50
51 /* Has I8/UI8 data type? */
52 static BOOL has_i8;
53
54 /* Get a conversion function ptr, return if function not available */
55 #define CHECKPTR(func) p##func = (void*)GetProcAddress(hOleaut32, #func); \
56 if (!p##func) { win_skip("function " # func " not available, not testing it\n"); return; }
57
58 static inline int strcmpW( const WCHAR *str1, const WCHAR *str2 )
59 {
60 while (*str1 && (*str1 == *str2)) { str1++; str2++; }
61 return *str1 - *str2;
62 }
63
64 #define FMT_NUMBER(vt,val) \
65 VariantInit(&v); V_VT(&v) = vt; val(&v) = 1; \
66 hres = pVarFormatNumber(&v,2,0,0,0,0,&str); \
67 ok(hres == S_OK, "VarFormatNumber (vt %d): returned %8x\n", vt, hres); \
68 if (hres == S_OK) { \
69 ok(str && strcmpW(str,szResult1) == 0, \
70 "VarFormatNumber (vt %d): string different\n", vt); \
71 SysFreeString(str); \
72 }
73
74 static void test_VarFormatNumber(void)
75 {
76 static const WCHAR szSrc1[] = { '1','\0' };
77 static const WCHAR szResult1[] = { '1','.','0','0','\0' };
78 static const WCHAR szSrc2[] = { '-','1','\0' };
79 static const WCHAR szResult2[] = { '(','1','.','0','0',')','\0' };
80 char buff[8];
81 HRESULT hres;
82 VARIANT v;
83 BSTR str = NULL;
84
85 CHECKPTR(VarFormatNumber);
86
87 GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, buff, sizeof(buff)/sizeof(char));
88 if (buff[0] != '.' || buff[1])
89 {
90 skip("Skipping VarFormatNumber tests as decimal separator is '%s'\n", buff);
91 return;
92 }
93
94 FMT_NUMBER(VT_I1, V_I1);
95 FMT_NUMBER(VT_UI1, V_UI1);
96 FMT_NUMBER(VT_I2, V_I2);
97 FMT_NUMBER(VT_UI2, V_UI2);
98 FMT_NUMBER(VT_I4, V_I4);
99 FMT_NUMBER(VT_UI4, V_UI4);
100 if (has_i8)
101 {
102 FMT_NUMBER(VT_I8, V_I8);
103 FMT_NUMBER(VT_UI8, V_UI8);
104 }
105 FMT_NUMBER(VT_R4, V_R4);
106 FMT_NUMBER(VT_R8, V_R8);
107 FMT_NUMBER(VT_BOOL, V_BOOL);
108
109 V_VT(&v) = VT_BSTR;
110 V_BSTR(&v) = SysAllocString(szSrc1);
111
112 hres = pVarFormatNumber(&v,2,0,0,0,0,&str);
113 ok(hres == S_OK, "VarFormatNumber (bstr): returned %8x\n", hres);
114 if (hres == S_OK)
115 ok(str && strcmpW(str, szResult1) == 0, "VarFormatNumber (bstr): string different\n");
116 SysFreeString(V_BSTR(&v));
117 SysFreeString(str);
118
119 V_BSTR(&v) = SysAllocString(szSrc2);
120 hres = pVarFormatNumber(&v,2,0,-1,0,0,&str);
121 ok(hres == S_OK, "VarFormatNumber (bstr): returned %8x\n", hres);
122 if (hres == S_OK)
123 ok(str && strcmpW(str, szResult2) == 0, "VarFormatNumber (-bstr): string different\n");
124 SysFreeString(V_BSTR(&v));
125 SysFreeString(str);
126 }
127
128 #define SIGNED_VTBITS (VTBIT_I1|VTBIT_I2|VTBIT_I4|VTBIT_I8|VTBIT_R4|VTBIT_R8)
129
130 static const char *szVarFmtFail = "VT %d|0x%04x Format %s: expected 0x%08x, '%s', got 0x%08x, '%s'\n";
131 #define VARFMT(vt,v,val,fmt,ret,str) do { \
132 out = NULL; \
133 V_VT(&in) = (vt); v(&in) = val; \
134 if (fmt) MultiByteToWideChar(CP_ACP, 0, fmt, -1, buffW, sizeof(buffW)/sizeof(WCHAR)); \
135 hres = pVarFormat(&in,fmt ? buffW : NULL,fd,fw,flags,&out); \
136 if (SUCCEEDED(hres)) WideCharToMultiByte(CP_ACP, 0, out, -1, buff, sizeof(buff),0,0); \
137 else buff[0] = '\0'; \
138 ok(hres == ret && (FAILED(ret) || !strcmp(buff, str)), \
139 szVarFmtFail, \
140 (vt)&VT_TYPEMASK,(vt)&~VT_TYPEMASK,fmt?fmt:"<null>",ret,str,hres,buff); \
141 SysFreeString(out); \
142 } while(0)
143
144 typedef struct tagFMTRES
145 {
146 LPCSTR fmt;
147 LPCSTR one_res;
148 LPCSTR zero_res;
149 } FMTRES;
150
151 static const FMTRES VarFormat_results[] =
152 {
153 { NULL, "1", "0" },
154 { "", "1", "0" },
155 { "General Number", "1", "0" },
156 { "Percent", "100.00%", "0.00%" },
157 { "Standard", "1.00", "0.00" },
158 { "Scientific","1.00E+00", "0.00E+00" },
159 { "True/False", "True", "False" },
160 { "On/Off", "On", "Off" },
161 { "Yes/No", "Yes", "No" },
162 { "#", "1", "" },
163 { "##", "1", "" },
164 { "#.#", "1.", "." },
165 { "0", "1", "0" },
166 { "00", "01", "00" },
167 { "0.0", "1.0", "0.0" },
168 { "00\\c\\o\\p\\y", "01copy","00copy" },
169 { "\"pos\";\"neg\"", "pos", "pos" },
170 { "\"pos\";\"neg\";\"zero\"","pos", "zero" }
171 };
172
173 typedef struct tagFMTDATERES
174 {
175 DATE val;
176 LPCSTR fmt;
177 LPCSTR res;
178 } FMTDATERES;
179
180 static const FMTDATERES VarFormat_date_results[] =
181 {
182 { 0.0, "w", "7" },
183 { 0.0, "w", "6" },
184 { 0.0, "w", "5" },
185 { 0.0, "w", "4" },
186 { 0.0, "w", "3" },
187 { 0.0, "w", "2" },
188 { 0.0, "w", "1" }, /* First 7 entries must remain in this order! */
189 { 2.525, "am/pm", "pm" },
190 { 2.525, "AM/PM", "PM" },
191 { 2.525, "A/P", "P" },
192 { 2.525, "a/p", "p" },
193 { 2.525, "q", "1" },
194 { 2.525, "d", "1" },
195 { 2.525, "dd", "01" },
196 { 2.525, "ddd", "Mon" },
197 { 2.525, "dddd", "Monday" },
198 { 2.525, "mmm", "Jan" },
199 { 2.525, "mmmm", "January" },
200 { 2.525, "y", "1" },
201 { 2.525, "yy", "00" },
202 { 2.525, "yyy", "001" },
203 { 2.525, "yyyy", "1900" },
204 { 2.525, "dd mm yyyy hh:mm:ss", "01 01 1900 12:36:00" },
205 { 2.525, "dd mm yyyy mm", "01 01 1900 01" },
206 { 2.525, "dd mm yyyy :mm", "01 01 1900 :01" },
207 { 2.525, "dd mm yyyy hh:mm", "01 01 1900 12:36" },
208 { 2.525, "mm mm", "01 01" },
209 { 2.525, "mm :mm:ss", "01 :01:00" },
210 { 2.525, "mm :ss:mm", "01 :00:01" },
211 { 2.525, "hh:mm :ss:mm", "12:36 :00:01" },
212 { 2.525, "hh:dd :mm:mm", "12:01 :01:01" },
213 { 2.525, "dd:hh :mm:mm", "01:12 :36:01" },
214 { 2.525, "hh :mm:mm", "12 :36:01" },
215 { 2.525, "dd :mm:mm", "01 :01:01" },
216 { 2.525, "dd :mm:nn", "01 :01:36" },
217 { 2.725, "hh:nn:ss A/P", "05:24:00 P" },
218 { 40531.0, "dddd", "Sunday" },
219 { 40531.0, "ddd", "Sun" }
220 };
221
222 /* The following tests require that the time separator is a colon (:) */
223 static const FMTDATERES VarFormat_namedtime_results[] =
224 {
225 { 2.525, "short time", "12:36" },
226 { 2.525, "medium time", "12:36 PM" },
227 { 2.525, "long time", "12:36:00 PM" }
228 };
229
230 #define VNUMFMT(vt,v) \
231 for (i = 0; i < sizeof(VarFormat_results)/sizeof(FMTRES); i++) \
232 { \
233 VARFMT(vt,v,1,VarFormat_results[i].fmt,S_OK,VarFormat_results[i].one_res); \
234 VARFMT(vt,v,0,VarFormat_results[i].fmt,S_OK,VarFormat_results[i].zero_res); \
235 } \
236 if ((1 << vt) & SIGNED_VTBITS) \
237 { \
238 VARFMT(vt,v,-1,"\"pos\";\"neg\"",S_OK,"neg"); \
239 VARFMT(vt,v,-1,"\"pos\";\"neg\";\"zero\"",S_OK,"neg"); \
240 }
241
242 static void test_VarFormat(void)
243 {
244 static const WCHAR szTesting[] = { 't','e','s','t','i','n','g','\0' };
245 static const WCHAR szNum[] = { '3','9','6','9','7','.','1','1','\0' };
246 size_t i;
247 WCHAR buffW[256];
248 char buff[256];
249 VARIANT in;
250 VARIANT_BOOL bTrue = VARIANT_TRUE, bFalse = VARIANT_FALSE;
251 int fd = 0, fw = 0;
252 ULONG flags = 0;
253 BSTR bstrin, out = NULL;
254 HRESULT hres;
255
256 CHECKPTR(VarFormat);
257
258 if (PRIMARYLANGID(LANGIDFROMLCID(GetUserDefaultLCID())) != LANG_ENGLISH)
259 {
260 skip("Skipping VarFormat tests for non English language\n");
261 return;
262 }
263 GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, buff, sizeof(buff)/sizeof(char));
264 if (buff[0] != '.' || buff[1])
265 {
266 skip("Skipping VarFormat tests as decimal separator is '%s'\n", buff);
267 return;
268 }
269 GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_IDIGITS, buff, sizeof(buff)/sizeof(char));
270 if (buff[0] != '2' || buff[1])
271 {
272 skip("Skipping VarFormat tests as decimal places is '%s'\n", buff);
273 return;
274 }
275
276 VARFMT(VT_BOOL,V_BOOL,VARIANT_TRUE,"True/False",S_OK,"True");
277 VARFMT(VT_BOOL,V_BOOL,VARIANT_FALSE,"True/False",S_OK,"False");
278
279 VNUMFMT(VT_I1,V_I1);
280 VNUMFMT(VT_I2,V_I2);
281 VNUMFMT(VT_I4,V_I4);
282 if (has_i8)
283 {
284 VNUMFMT(VT_I8,V_I8);
285 }
286 VNUMFMT(VT_INT,V_INT);
287 VNUMFMT(VT_UI1,V_UI1);
288 VNUMFMT(VT_UI2,V_UI2);
289 VNUMFMT(VT_UI4,V_UI4);
290 if (has_i8)
291 {
292 VNUMFMT(VT_UI8,V_UI8);
293 }
294 VNUMFMT(VT_UINT,V_UINT);
295 VNUMFMT(VT_R4,V_R4);
296 VNUMFMT(VT_R8,V_R8);
297
298 /* Reference types are dereferenced */
299 VARFMT(VT_BOOL|VT_BYREF,V_BOOLREF,&bTrue,"True/False",S_OK,"True");
300 VARFMT(VT_BOOL|VT_BYREF,V_BOOLREF,&bFalse,"True/False",S_OK,"False");
301
302 /* Dates */
303 for (i = 0; i < sizeof(VarFormat_date_results)/sizeof(FMTDATERES); i++)
304 {
305 if (i < 7)
306 fd = i + 1; /* Test first day */
307 else
308 fd = 0;
309 VARFMT(VT_DATE,V_DATE,VarFormat_date_results[i].val,
310 VarFormat_date_results[i].fmt,S_OK,
311 VarFormat_date_results[i].res);
312 }
313
314 /* Named time formats */
315 GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_STIMEFORMAT, buff, sizeof(buff)/sizeof(char));
316 if (strcmp(buff, "h:mm:ss tt"))
317 {
318 skip("Skipping named time tests as time format is '%s'\n", buff);
319 }
320 else
321 {
322 for (i = 0; i < sizeof(VarFormat_namedtime_results)/sizeof(FMTDATERES); i++)
323 {
324 fd = 0;
325 VARFMT(VT_DATE,V_DATE,VarFormat_namedtime_results[i].val,
326 VarFormat_namedtime_results[i].fmt,S_OK,
327 VarFormat_namedtime_results[i].res);
328 }
329 }
330
331 /* Strings */
332 bstrin = SysAllocString(szTesting);
333 VARFMT(VT_BSTR,V_BSTR,bstrin,"",S_OK,"testing");
334 VARFMT(VT_BSTR,V_BSTR,bstrin,"@",S_OK,"testing");
335 VARFMT(VT_BSTR,V_BSTR,bstrin,"&",S_OK,"testing");
336 VARFMT(VT_BSTR,V_BSTR,bstrin,"\\x@\\x@",S_OK,"xtxesting");
337 VARFMT(VT_BSTR,V_BSTR,bstrin,"\\x&\\x&",S_OK,"xtxesting");
338 VARFMT(VT_BSTR,V_BSTR,bstrin,"@\\x",S_OK,"txesting");
339 VARFMT(VT_BSTR,V_BSTR,bstrin,"@@@@@@@@",S_OK," testing");
340 VARFMT(VT_BSTR,V_BSTR,bstrin,"@\\x@@@@@@@",S_OK," xtesting");
341 VARFMT(VT_BSTR,V_BSTR,bstrin,"&&&&&&&&",S_OK,"testing");
342 VARFMT(VT_BSTR,V_BSTR,bstrin,"!&&&&&&&",S_OK,"testing");
343 VARFMT(VT_BSTR,V_BSTR,bstrin,"&&&&&&&!",S_OK,"testing");
344 VARFMT(VT_BSTR,V_BSTR,bstrin,">&&",S_OK,"TESTING");
345 VARFMT(VT_BSTR,V_BSTR,bstrin,"<&&",S_OK,"testing");
346 VARFMT(VT_BSTR,V_BSTR,bstrin,"<&>&",S_OK,"testing");
347 SysFreeString(bstrin);
348 bstrin = SysAllocString(szNum);
349 todo_wine VARFMT(VT_BSTR,V_BSTR,bstrin,"hh:mm",S_OK,"02:38");
350 todo_wine VARFMT(VT_BSTR,V_BSTR,bstrin,"mm-dd-yy",S_OK,"09-06-08");
351 SysFreeString(bstrin);
352 /* Numeric values are converted to strings then output */
353 VARFMT(VT_I1,V_I1,1,"<&>&",S_OK,"1");
354
355 /* Number formats */
356 VARFMT(VT_I4,V_I4,1,"#00000000",S_OK,"00000001");
357 VARFMT(VT_I4,V_I4,1,"000###",S_OK,"000001");
358 VARFMT(VT_I4,V_I4,1,"#00##00#0",S_OK,"00000001");
359 VARFMT(VT_I4,V_I4,1,"1#####0000",S_OK,"10001");
360 VARFMT(VT_I4,V_I4,1,"##abcdefghijklmnopqrstuvwxyz",S_OK,"1abcdefghijklmnopqrstuvwxyz");
361 VARFMT(VT_I4,V_I4,100000,"#,###,###,###",S_OK,"100,000");
362 VARFMT(VT_I4,V_I4,1,"0,000,000,000",S_OK,"0,000,000,001");
363 VARFMT(VT_I4,V_I4,123456789,"#,#.#",S_OK,"123,456,789.");
364 VARFMT(VT_I4,V_I4,123456789,"###, ###, ###",S_OK,"123, 456, 789");
365 VARFMT(VT_I4,V_I4,1,"#;-#",S_OK,"1");
366 VARFMT(VT_I4,V_I4,-1,"#;-#",S_OK,"-1");
367 VARFMT(VT_R8,V_R8,1.23456789,"0#.0#0#0#0#0",S_OK,"01.234567890");
368 VARFMT(VT_R8,V_R8,1.2,"0#.0#0#0#0#0",S_OK,"01.200000000");
369 VARFMT(VT_R8,V_R8,9.87654321,"#0.#0#0#0#0#",S_OK,"9.87654321");
370 VARFMT(VT_R8,V_R8,9.8,"#0.#0#0#0#0#",S_OK,"9.80000000");
371 VARFMT(VT_R8,V_R8,0.00000008,"#0.#0#0#0#0#0",S_OK,"0.0000000800");
372 VARFMT(VT_R8,V_R8,0.00010705,"#0.##########",S_OK,"0.00010705");
373 VARFMT(VT_I4,V_I4,17,"#0",S_OK,"17");
374 VARFMT(VT_I4,V_I4,4711,"#0",S_OK,"4711");
375 VARFMT(VT_I4,V_I4,17,"#00",S_OK,"17");
376 VARFMT(VT_I4,V_I4,100,"0##",S_OK,"100");
377 VARFMT(VT_I4,V_I4,17,"#000",S_OK,"017");
378 VARFMT(VT_I4,V_I4,17,"#0.00",S_OK,"17.00");
379 VARFMT(VT_I4,V_I4,17,"#0000.00",S_OK,"0017.00");
380 VARFMT(VT_I4,V_I4,17,"#.00",S_OK,"17.00");
381 VARFMT(VT_R8,V_R8,1.7,"#.00",S_OK,"1.70");
382 VARFMT(VT_R8,V_R8,.17,"#.00",S_OK,".17");
383 VARFMT(VT_I4,V_I4,17,"#3",S_OK,"173");
384 VARFMT(VT_I4,V_I4,17,"#33",S_OK,"1733");
385 VARFMT(VT_I4,V_I4,17,"#3.33",S_OK,"173.33");
386 VARFMT(VT_I4,V_I4,17,"#3333.33",S_OK,"173333.33");
387 VARFMT(VT_I4,V_I4,17,"#.33",S_OK,"17.33");
388 VARFMT(VT_R8,V_R8,.17,"#.33",S_OK,".33");
389 VARFMT(VT_R8,V_R8,1.7,"0.0000E-000",S_OK,"1.7000E000");
390 VARFMT(VT_R8,V_R8,1.7,"0.0000e-1",S_OK,"1.7000e01");
391 VARFMT(VT_R8,V_R8,86.936849,"#0.000000000000e-000",S_OK,"86.936849000000e000");
392 VARFMT(VT_R8,V_R8,1.7,"#0",S_OK,"2");
393 VARFMT(VT_R8,V_R8,1.7,"#.33",S_OK,"2.33");
394 VARFMT(VT_R8,V_R8,1.7,"#3",S_OK,"23");
395 VARFMT(VT_R8,V_R8,1.73245,"0.0000E+000",S_OK,"1.7325E+000");
396 VARFMT(VT_R8,V_R8,9.9999999,"#0.000000",S_OK,"10.000000");
397 VARFMT(VT_R8,V_R8,1.7,"0.0000e+0#",S_OK,"1.7000e+0");
398 VARFMT(VT_R8,V_R8,100.0001e+0,"0.0000E+0",S_OK,"1.0000E+2");
399 VARFMT(VT_R8,V_R8,1000001,"0.0000e+1",S_OK,"1.0000e+61");
400 VARFMT(VT_R8,V_R8,100.0001e+25,"0.0000e+0",S_OK,"1.0000e+27");
401 VARFMT(VT_R8,V_R8,450.0001e+43,"#000.0000e+0",S_OK,"4500.0010e+42");
402 VARFMT(VT_R8,V_R8,0.0001e-11,"##00.0000e-0",S_OK,"1000.0000e-18");
403 VARFMT(VT_R8,V_R8,0.0317e-11,"0000.0000e-0",S_OK,"3170.0000e-16");
404 VARFMT(VT_R8,V_R8,0.0021e-11,"00##.0000e-0",S_OK,"2100.0000e-17");
405 VARFMT(VT_R8,V_R8,1.0001e-27,"##00.0000e-0",S_OK,"1000.1000e-30");
406 VARFMT(VT_R8,V_R8,47.11,".0000E+0",S_OK,".4711E+2");
407 VARFMT(VT_R8,V_R8,3.0401e-13,"#####.####e-0%",S_OK,"30401.e-15%");
408 VARFMT(VT_R8,V_R8,1.57,"0.00",S_OK,"1.57");
409 VARFMT(VT_R8,V_R8,-1.57,"0.00",S_OK,"-1.57");
410 VARFMT(VT_R8,V_R8,-1.57,"#.##",S_OK,"-1.57");
411 VARFMT(VT_R8,V_R8,-0.1,".#",S_OK,"-.1");
412 VARFMT(VT_R8,V_R8,0.099,"#.#",S_OK,".1");
413 VARFMT(VT_R8,V_R8,0.0999,"#.##",S_OK,".1");
414 VARFMT(VT_R8,V_R8,0.099,"#.##",S_OK,".1");
415 VARFMT(VT_R8,V_R8,0.0099,"#.##",S_OK,".01");
416 VARFMT(VT_R8,V_R8,0.0049,"#.##",S_OK,".");
417 VARFMT(VT_R8,V_R8,0.0094,"#.##",S_OK,".01");
418 VARFMT(VT_R8,V_R8,0.00099,"#.##",S_OK,".");
419 VARFMT(VT_R8,V_R8,0.0995,"#.##",S_OK,".1");
420 VARFMT(VT_R8,V_R8,8.0995,"#.##",S_OK,"8.1");
421 VARFMT(VT_R8,V_R8,0.0994,"#.##",S_OK,".1");
422 VARFMT(VT_R8,V_R8,1.00,"#,##0.00",S_OK,"1.00");
423 VARFMT(VT_R8,V_R8,0.0995,"#.###",S_OK,".1");
424
425
426 /* 'out' is not cleared */
427 out = (BSTR)0x1;
428 hres = pVarFormat(&in,NULL,fd,fw,flags,&out); /* Would crash if out is cleared */
429 ok(hres == S_OK, "got %08x\n", hres);
430 SysFreeString(out);
431 out = NULL;
432
433 /* VT_NULL */
434 V_VT(&in) = VT_NULL;
435 hres = pVarFormat(&in,NULL,fd,fw,0,&out);
436 ok(hres == S_OK, "VarFormat failed with 0x%08x\n", hres);
437 ok(out == NULL, "expected NULL formatted string\n");
438
439 /* Invalid args */
440 hres = pVarFormat(&in,NULL,fd,fw,flags,NULL);
441 ok(hres == E_INVALIDARG, "Null out: expected E_INVALIDARG, got 0x%08x\n", hres);
442 hres = pVarFormat(NULL,NULL,fd,fw,flags,&out);
443 ok(hres == E_INVALIDARG, "Null in: expected E_INVALIDARG, got 0x%08x\n", hres);
444 fd = -1;
445 VARFMT(VT_BOOL,V_BOOL,VARIANT_TRUE,"",E_INVALIDARG,"");
446 fd = 8;
447 VARFMT(VT_BOOL,V_BOOL,VARIANT_TRUE,"",E_INVALIDARG,"");
448 fd = 0; fw = -1;
449 VARFMT(VT_BOOL,V_BOOL,VARIANT_TRUE,"",E_INVALIDARG,"");
450 fw = 4;
451 VARFMT(VT_BOOL,V_BOOL,VARIANT_TRUE,"",E_INVALIDARG,"");
452 }
453
454 static const char *szVarWdnFail =
455 "VarWeekdayName (%d, %d, %d, %d, %x): returned %8x, expected %8x\n";
456 #define VARWDN(iWeekday, fAbbrev, iFirstDay, dwFlags, ret, buff, out, freeOut) \
457 do { \
458 hres = pVarWeekdayName(iWeekday, fAbbrev, iFirstDay, dwFlags, &out); \
459 if (SUCCEEDED(hres)) { \
460 WideCharToMultiByte(CP_ACP, 0, out, -1, buff, sizeof(buff), 0, 0); \
461 if (freeOut) SysFreeString(out); \
462 } else { \
463 buff[0] = '\0'; \
464 } \
465 ok(hres == ret, \
466 szVarWdnFail, \
467 iWeekday, fAbbrev, iFirstDay, dwFlags, &out, hres, ret \
468 ); \
469 } while(0)
470
471 #define VARWDN_F(iWeekday, fAbbrev, iFirstDay, dwFlags, ret) \
472 VARWDN(iWeekday, fAbbrev, iFirstDay, dwFlags, ret, buff, out, 1)
473
474 #define VARWDN_O(iWeekday, fAbbrev, iFirstDay, dwFlags) \
475 VARWDN(iWeekday, fAbbrev, iFirstDay, dwFlags, S_OK, buff, out, 0)
476
477 static void test_VarWeekdayName(void)
478 {
479 char buff[256];
480 BSTR out = NULL;
481 HRESULT hres;
482 int iWeekday, fAbbrev, iFirstDay;
483 BSTR dayNames[7][2]; /* Monday-Sunday, full/abbr */
484 DWORD defaultFirstDay;
485 int firstDay;
486 int day;
487 int size;
488 DWORD localeValue;
489
490 CHECKPTR(VarWeekdayName);
491
492 SetLastError(0xdeadbeef);
493 GetLocaleInfoW(LOCALE_USER_DEFAULT, 0, NULL, 0);
494 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
495 {
496 win_skip("GetLocaleInfoW is not implemented\n");
497 return;
498 }
499
500 /* Initialize days' names */
501 for (day = 0; day <= 6; ++day)
502 {
503 for (fAbbrev = 0; fAbbrev <= 1; ++fAbbrev)
504 {
505 localeValue = fAbbrev ? LOCALE_SABBREVDAYNAME1 : LOCALE_SDAYNAME1;
506 localeValue += day;
507 size = GetLocaleInfoW(LOCALE_USER_DEFAULT, localeValue, NULL, 0);
508 dayNames[day][fAbbrev] = SysAllocStringLen(NULL, size - 1);
509 GetLocaleInfoW(LOCALE_USER_DEFAULT, localeValue,
510 dayNames[day][fAbbrev], size);
511 }
512 }
513
514 /* Get the user's first day of week. 0=Monday, .. */
515 GetLocaleInfoW(
516 LOCALE_USER_DEFAULT, LOCALE_IFIRSTDAYOFWEEK | LOCALE_RETURN_NUMBER,
517 (LPWSTR)&defaultFirstDay, sizeof(defaultFirstDay) / sizeof(WCHAR));
518
519 /* Check invalid arguments */
520 VARWDN_F(0, 0, 4, 0, E_INVALIDARG);
521 VARWDN_F(8, 0, 4, 0, E_INVALIDARG);
522 VARWDN_F(4, 0, -1, 0, E_INVALIDARG);
523 VARWDN_F(4, 0, 8, 0, E_INVALIDARG);
524
525 hres = pVarWeekdayName(1, 0, 0, 0, NULL);
526 ok(E_INVALIDARG == hres,
527 "Null pointer: expected E_INVALIDARG, got 0x%08x\n", hres);
528
529 /* Check all combinations */
530 pVarBstrCmp = (void*)GetProcAddress(hOleaut32, "VarBstrCmp");
531 if (pVarBstrCmp)
532 for (iWeekday = 1; iWeekday <= 7; ++iWeekday)
533 {
534 for (fAbbrev = 0; fAbbrev <= 1; ++fAbbrev)
535 {
536 /* 0 = Default, 1 = Sunday, 2 = Monday, .. */
537 for (iFirstDay = 0; iFirstDay <= 7; ++iFirstDay)
538 {
539 VARWDN_O(iWeekday, fAbbrev, iFirstDay, 0);
540 if (iFirstDay == 0)
541 firstDay = defaultFirstDay;
542 else
543 /* Translate from 0=Sunday to 0=Monday in the modulo 7 space */
544 firstDay = iFirstDay - 2;
545 day = (7 + iWeekday - 1 + firstDay) % 7;
546 ok(VARCMP_EQ == pVarBstrCmp(out, dayNames[day][fAbbrev],
547 LOCALE_USER_DEFAULT, 0),
548 "VarWeekdayName(%d,%d,%d): got wrong dayname: '%s'\n",
549 iWeekday, fAbbrev, iFirstDay, buff);
550 SysFreeString(out);
551 }
552 }
553 }
554
555 /* Cleanup */
556 for (day = 0; day <= 6; ++day)
557 {
558 for (fAbbrev = 0; fAbbrev <= 1; ++fAbbrev)
559 {
560 SysFreeString(dayNames[day][fAbbrev]);
561 }
562 }
563 }
564
565 static void test_VarFormatFromTokens(void)
566 {
567 static WCHAR number_fmt[] = {'#','#','#',',','#','#','0','.','0','0',0};
568 static const WCHAR number[] = {'6',',','9','0',0};
569 static const WCHAR number_us[] = {'6','9','0','.','0','0',0};
570
571 static WCHAR date_fmt[] = {'d','d','-','m','m',0};
572 static const WCHAR date[] = {'1','2','-','1','1',0};
573 static const WCHAR date_us[] = {'1','1','-','1','2',0};
574
575 static WCHAR string_fmt[] = {'@',0};
576 static const WCHAR string_de[] = {'1',',','5',0};
577 static const WCHAR string_us[] = {'1','.','5',0};
578
579 BYTE buff[256];
580 LCID lcid;
581 VARIANT var;
582 BSTR bstr;
583 HRESULT hres;
584
585 V_VT(&var) = VT_BSTR;
586 V_BSTR(&var) = SysAllocString(number);
587
588 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
589 hres = VarTokenizeFormatString(number_fmt, buff, sizeof(buff), 1, 1, lcid, NULL);
590 ok(hres == S_OK, "VarTokenizeFormatString failed: %x\n", hres);
591 hres = VarFormatFromTokens(&var, number_fmt, buff, 0, &bstr, lcid);
592 ok(hres == S_OK, "VarFormatFromTokens failed: %x\n", hres);
593 ok(!strcmpW(bstr, number_us), "incorrectly formatted number: %s\n", wine_dbgstr_w(bstr));
594 SysFreeString(bstr);
595
596 lcid = MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT);
597 hres = VarTokenizeFormatString(number_fmt, buff, sizeof(buff), 1, 1, lcid, NULL);
598 ok(hres == S_OK, "VarTokenizeFormatString failed: %x\n", hres);
599 hres = VarFormatFromTokens(&var, number_fmt, buff, 0, &bstr, lcid);
600 ok(hres == S_OK, "VarFormatFromTokens failed: %x\n", hres);
601 ok(!strcmpW(bstr, number), "incorrectly formatted number: %s\n", wine_dbgstr_w(bstr));
602 SysFreeString(bstr);
603
604 VariantClear(&var);
605
606 V_VT(&var) = VT_BSTR;
607 V_BSTR(&var) = SysAllocString(date);
608
609 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
610 hres = VarTokenizeFormatString(date_fmt, buff, sizeof(buff), 1, 1, lcid, NULL);
611 ok(hres == S_OK, "VarTokenizeFormatString failed: %x\n", hres);
612 hres = VarFormatFromTokens(&var, date_fmt, buff, 0, &bstr, lcid);
613 ok(hres == S_OK, "VarFormatFromTokens failed: %x\n", hres);
614 ok(!strcmpW(bstr, date_us), "incorrectly formatted date: %s\n", wine_dbgstr_w(bstr));
615 SysFreeString(bstr);
616
617 lcid = MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT);
618 hres = VarTokenizeFormatString(date_fmt, buff, sizeof(buff), 1, 1, lcid, NULL);
619 ok(hres == S_OK, "VarTokenizeFormatString failed: %x\n", hres);
620 hres = VarFormatFromTokens(&var, date_fmt, buff, 0, &bstr, lcid);
621 ok(hres == S_OK, "VarFormatFromTokens failed: %x\n", hres);
622 ok(!strcmpW(bstr, date), "incorrectly formatted date: %s\n", wine_dbgstr_w(bstr));
623 SysFreeString(bstr);
624
625 VariantClear(&var);
626
627 V_VT(&var) = VT_R4;
628 V_R4(&var) = 1.5;
629
630 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
631 hres = VarTokenizeFormatString(string_fmt, buff, sizeof(buff), 1, 1, lcid, NULL);
632 ok(hres == S_OK, "VarTokenizeFormatString failed: %x\n", hres);
633 hres = VarFormatFromTokens(&var, string_fmt, buff, 0, &bstr, lcid);
634 ok(hres == S_OK, "VarFormatFromTokens failed: %x\n", hres);
635 ok(!strcmpW(bstr, string_us), "incorrectly formatted string: %s\n", wine_dbgstr_w(bstr));
636 SysFreeString(bstr);
637
638 lcid = MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT);
639 hres = VarTokenizeFormatString(string_fmt, buff, sizeof(buff), 1, 1, lcid, NULL);
640 ok(hres == S_OK, "VarTokenizeFormatString failed: %x\n", hres);
641 hres = VarFormatFromTokens(&var, string_fmt, buff, 0, &bstr, lcid);
642 ok(hres == S_OK, "VarFormatFromTokens failed: %x\n", hres);
643 ok(!strcmpW(bstr, string_de), "incorrectly formatted string: %s\n", wine_dbgstr_w(bstr));
644 SysFreeString(bstr);
645 }
646
647 static void test_GetAltMonthNames(void)
648 {
649 LPOLESTR *str, *str2;
650 HRESULT hr;
651
652 str = (void *)0xdeadbeef;
653 hr = GetAltMonthNames(0, &str);
654 ok(hr == S_OK, "Unexpected return value %08x\n", hr);
655 ok(str == NULL, "Got %p\n", str);
656
657 str = (void *)0xdeadbeef;
658 hr = GetAltMonthNames(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT), &str);
659 ok(hr == S_OK, "Unexpected return value %08x\n", hr);
660 ok(str == NULL, "Got %p\n", str);
661
662 str = NULL;
663 hr = GetAltMonthNames(MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_EGYPT), SORT_DEFAULT), &str);
664 ok(hr == S_OK, "Unexpected return value %08x\n", hr);
665 ok(str != NULL, "Got %p\n", str);
666
667 str2 = NULL;
668 hr = GetAltMonthNames(MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_EGYPT), SORT_DEFAULT), &str2);
669 ok(hr == S_OK, "Unexpected return value %08x\n", hr);
670 ok(str2 == str, "Got %p\n", str2);
671
672 str = NULL;
673 hr = GetAltMonthNames(MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_DEFAULT), SORT_DEFAULT), &str);
674 ok(hr == S_OK, "Unexpected return value %08x\n", hr);
675 ok(str != NULL, "Got %p\n", str);
676
677 str = NULL;
678 hr = GetAltMonthNames(MAKELCID(MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT), SORT_DEFAULT), &str);
679 ok(hr == S_OK, "Unexpected return value %08x\n", hr);
680 ok(str != NULL, "Got %p\n", str);
681 }
682
683 START_TEST(varformat)
684 {
685 hOleaut32 = GetModuleHandleA("oleaut32.dll");
686
687 has_i8 = GetProcAddress(hOleaut32, "VarI8FromI1") != NULL;
688
689 test_VarFormatNumber();
690 test_VarFormat();
691 test_VarWeekdayName();
692 test_VarFormatFromTokens();
693 test_GetAltMonthNames();
694 }