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