| /* |
| * VARFORMAT test program |
| * |
| * Copyright 1998 Jean-Claude Cote |
| * Copyright 2006 Google (Benjamin Arai) |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #include <stdarg.h> |
| #include <stdio.h> |
| #include <math.h> |
| #include <float.h> |
| |
| #include "windef.h" |
| #include "winbase.h" |
| #include "winsock2.h" |
| #include "wine/test.h" |
| #include "winuser.h" |
| #include "wingdi.h" |
| #include "winnls.h" |
| #include "winerror.h" |
| #include "winnt.h" |
| |
| #include "wtypes.h" |
| #include "oleauto.h" |
| |
| static HMODULE hOleaut32; |
| |
| static HRESULT (WINAPI *pVarBstrCmp)(BSTR,BSTR,LCID,ULONG); |
| static HRESULT (WINAPI *pVarFormatNumber)(LPVARIANT,int,int,int,int,ULONG,BSTR*); |
| static HRESULT (WINAPI *pVarFormat)(LPVARIANT,LPOLESTR,int,int,ULONG,BSTR*); |
| static HRESULT (WINAPI *pVarWeekdayName)(int,int,int,ULONG,BSTR*); |
| |
| /* Has I8/UI8 data type? */ |
| static BOOL has_i8; |
| |
| /* Get a conversion function ptr, return if function not available */ |
| #define CHECKPTR(func) p##func = (void*)GetProcAddress(hOleaut32, #func); \ |
| if (!p##func) { win_skip("function " # func " not available, not testing it\n"); return; } |
| |
| static inline int strcmpW( const WCHAR *str1, const WCHAR *str2 ) |
| { |
| while (*str1 && (*str1 == *str2)) { str1++; str2++; } |
| return *str1 - *str2; |
| } |
| |
| #define FMT_NUMBER(vt,val) \ |
| VariantInit(&v); V_VT(&v) = vt; val(&v) = 1; \ |
| hres = pVarFormatNumber(&v,2,0,0,0,0,&str); \ |
| ok(hres == S_OK, "VarFormatNumber (vt %d): returned %8x\n", vt, hres); \ |
| if (hres == S_OK) { \ |
| ok(str && strcmpW(str,szResult1) == 0, \ |
| "VarFormatNumber (vt %d): string different\n", vt); \ |
| SysFreeString(str); \ |
| } |
| |
| static void test_VarFormatNumber(void) |
| { |
| static const WCHAR szSrc1[] = { '1','\0' }; |
| static const WCHAR szResult1[] = { '1','.','0','0','\0' }; |
| static const WCHAR szSrc2[] = { '-','1','\0' }; |
| static const WCHAR szResult2[] = { '(','1','.','0','0',')','\0' }; |
| char buff[8]; |
| HRESULT hres; |
| VARIANT v; |
| BSTR str = NULL; |
| |
| CHECKPTR(VarFormatNumber); |
| |
| GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, buff, sizeof(buff)/sizeof(char)); |
| if (buff[0] != '.' || buff[1]) |
| { |
| skip("Skipping VarFormatNumber tests as decimal separator is '%s'\n", buff); |
| return; |
| } |
| |
| FMT_NUMBER(VT_I1, V_I1); |
| FMT_NUMBER(VT_UI1, V_UI1); |
| FMT_NUMBER(VT_I2, V_I2); |
| FMT_NUMBER(VT_UI2, V_UI2); |
| FMT_NUMBER(VT_I4, V_I4); |
| FMT_NUMBER(VT_UI4, V_UI4); |
| if (has_i8) |
| { |
| FMT_NUMBER(VT_I8, V_I8); |
| FMT_NUMBER(VT_UI8, V_UI8); |
| } |
| FMT_NUMBER(VT_R4, V_R4); |
| FMT_NUMBER(VT_R8, V_R8); |
| FMT_NUMBER(VT_BOOL, V_BOOL); |
| |
| V_VT(&v) = VT_BSTR; |
| V_BSTR(&v) = SysAllocString(szSrc1); |
| |
| hres = pVarFormatNumber(&v,2,0,0,0,0,&str); |
| ok(hres == S_OK, "VarFormatNumber (bstr): returned %8x\n", hres); |
| if (hres == S_OK) |
| ok(str && strcmpW(str, szResult1) == 0, "VarFormatNumber (bstr): string different\n"); |
| SysFreeString(V_BSTR(&v)); |
| SysFreeString(str); |
| |
| V_BSTR(&v) = SysAllocString(szSrc2); |
| hres = pVarFormatNumber(&v,2,0,-1,0,0,&str); |
| ok(hres == S_OK, "VarFormatNumber (bstr): returned %8x\n", hres); |
| if (hres == S_OK) |
| ok(str && strcmpW(str, szResult2) == 0, "VarFormatNumber (-bstr): string different\n"); |
| SysFreeString(V_BSTR(&v)); |
| SysFreeString(str); |
| } |
| |
| #define SIGNED_VTBITS (VTBIT_I1|VTBIT_I2|VTBIT_I4|VTBIT_I8|VTBIT_R4|VTBIT_R8) |
| |
| static const char *szVarFmtFail = "VT %d|0x%04x Format %s: expected 0x%08x, '%s', got 0x%08x, '%s'\n"; |
| #define VARFMT(vt,v,val,fmt,ret,str) do { \ |
| out = NULL; \ |
| V_VT(&in) = (vt); v(&in) = val; \ |
| if (fmt) MultiByteToWideChar(CP_ACP, 0, fmt, -1, buffW, sizeof(buffW)/sizeof(WCHAR)); \ |
| hres = pVarFormat(&in,fmt ? buffW : NULL,fd,fw,flags,&out); \ |
| if (SUCCEEDED(hres)) WideCharToMultiByte(CP_ACP, 0, out, -1, buff, sizeof(buff),0,0); \ |
| else buff[0] = '\0'; \ |
| ok(hres == ret && (FAILED(ret) || !strcmp(buff, str)), \ |
| szVarFmtFail, \ |
| (vt)&VT_TYPEMASK,(vt)&~VT_TYPEMASK,fmt?fmt:"<null>",ret,str,hres,buff); \ |
| SysFreeString(out); \ |
| } while(0) |
| |
| typedef struct tagFMTRES |
| { |
| LPCSTR fmt; |
| LPCSTR one_res; |
| LPCSTR zero_res; |
| } FMTRES; |
| |
| static const FMTRES VarFormat_results[] = |
| { |
| { NULL, "1", "0" }, |
| { "", "1", "0" }, |
| { "General Number", "1", "0" }, |
| { "Percent", "100.00%", "0.00%" }, |
| { "Standard", "1.00", "0.00" }, |
| { "Scientific","1.00E+00", "0.00E+00" }, |
| { "True/False", "True", "False" }, |
| { "On/Off", "On", "Off" }, |
| { "Yes/No", "Yes", "No" }, |
| { "#", "1", "" }, |
| { "##", "1", "" }, |
| { "#.#", "1.", "." }, |
| { "0", "1", "0" }, |
| { "00", "01", "00" }, |
| { "0.0", "1.0", "0.0" }, |
| { "00\\c\\o\\p\\y", "01copy","00copy" }, |
| { "\"pos\";\"neg\"", "pos", "pos" }, |
| { "\"pos\";\"neg\";\"zero\"","pos", "zero" } |
| }; |
| |
| typedef struct tagFMTDATERES |
| { |
| DATE val; |
| LPCSTR fmt; |
| LPCSTR res; |
| } FMTDATERES; |
| |
| static const FMTDATERES VarFormat_date_results[] = |
| { |
| { 0.0, "w", "7" }, |
| { 0.0, "w", "6" }, |
| { 0.0, "w", "5" }, |
| { 0.0, "w", "4" }, |
| { 0.0, "w", "3" }, |
| { 0.0, "w", "2" }, |
| { 0.0, "w", "1" }, /* First 7 entries must remain in this order! */ |
| { 2.525, "am/pm", "pm" }, |
| { 2.525, "AM/PM", "PM" }, |
| { 2.525, "A/P", "P" }, |
| { 2.525, "a/p", "p" }, |
| { 2.525, "q", "1" }, |
| { 2.525, "d", "1" }, |
| { 2.525, "dd", "01" }, |
| { 2.525, "ddd", "Mon" }, |
| { 2.525, "dddd", "Monday" }, |
| { 2.525, "mmm", "Jan" }, |
| { 2.525, "mmmm", "January" }, |
| { 2.525, "y", "1" }, |
| { 2.525, "yy", "00" }, |
| { 2.525, "yyy", "001" }, |
| { 2.525, "yyyy", "1900" }, |
| { 2.525, "dd mm yyyy hh:mm:ss", "01 01 1900 12:36:00" }, |
| { 2.525, "dd mm yyyy mm", "01 01 1900 01" }, |
| { 2.525, "dd mm yyyy :mm", "01 01 1900 :01" }, |
| { 2.525, "dd mm yyyy hh:mm", "01 01 1900 12:36" }, |
| { 2.525, "mm mm", "01 01" }, |
| { 2.525, "mm :mm:ss", "01 :01:00" }, |
| { 2.525, "mm :ss:mm", "01 :00:01" }, |
| { 2.525, "hh:mm :ss:mm", "12:36 :00:01" }, |
| { 2.525, "hh:dd :mm:mm", "12:01 :01:01" }, |
| { 2.525, "dd:hh :mm:mm", "01:12 :36:01" }, |
| { 2.525, "hh :mm:mm", "12 :36:01" }, |
| { 2.525, "dd :mm:mm", "01 :01:01" }, |
| { 2.525, "dd :mm:nn", "01 :01:36" }, |
| { 2.725, "hh:nn:ss A/P", "05:24:00 P" }, |
| { 40531.0, "dddd", "Sunday" }, |
| { 40531.0, "ddd", "Sun" } |
| }; |
| |
| /* The following tests require that the time separator is a colon (:) */ |
| static const FMTDATERES VarFormat_namedtime_results[] = |
| { |
| { 2.525, "short time", "12:36" }, |
| { 2.525, "medium time", "12:36 PM" }, |
| { 2.525, "long time", "12:36:00 PM" } |
| }; |
| |
| #define VNUMFMT(vt,v) \ |
| for (i = 0; i < sizeof(VarFormat_results)/sizeof(FMTRES); i++) \ |
| { \ |
| VARFMT(vt,v,1,VarFormat_results[i].fmt,S_OK,VarFormat_results[i].one_res); \ |
| VARFMT(vt,v,0,VarFormat_results[i].fmt,S_OK,VarFormat_results[i].zero_res); \ |
| } \ |
| if ((1 << vt) & SIGNED_VTBITS) \ |
| { \ |
| VARFMT(vt,v,-1,"\"pos\";\"neg\"",S_OK,"neg"); \ |
| VARFMT(vt,v,-1,"\"pos\";\"neg\";\"zero\"",S_OK,"neg"); \ |
| } |
| |
| static void test_VarFormat(void) |
| { |
| static const WCHAR szTesting[] = { 't','e','s','t','i','n','g','\0' }; |
| static const WCHAR szNum[] = { '3','9','6','9','7','.','1','1','\0' }; |
| size_t i; |
| WCHAR buffW[256]; |
| char buff[256]; |
| VARIANT in; |
| VARIANT_BOOL bTrue = VARIANT_TRUE, bFalse = VARIANT_FALSE; |
| int fd = 0, fw = 0; |
| ULONG flags = 0; |
| BSTR bstrin, out = NULL; |
| HRESULT hres; |
| |
| CHECKPTR(VarFormat); |
| |
| if (PRIMARYLANGID(LANGIDFROMLCID(GetUserDefaultLCID())) != LANG_ENGLISH) |
| { |
| skip("Skipping VarFormat tests for non English language\n"); |
| return; |
| } |
| GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, buff, sizeof(buff)/sizeof(char)); |
| if (buff[0] != '.' || buff[1]) |
| { |
| skip("Skipping VarFormat tests as decimal separator is '%s'\n", buff); |
| return; |
| } |
| GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_IDIGITS, buff, sizeof(buff)/sizeof(char)); |
| if (buff[0] != '2' || buff[1]) |
| { |
| skip("Skipping VarFormat tests as decimal places is '%s'\n", buff); |
| return; |
| } |
| |
| VARFMT(VT_BOOL,V_BOOL,VARIANT_TRUE,"True/False",S_OK,"True"); |
| VARFMT(VT_BOOL,V_BOOL,VARIANT_FALSE,"True/False",S_OK,"False"); |
| |
| VNUMFMT(VT_I1,V_I1); |
| VNUMFMT(VT_I2,V_I2); |
| VNUMFMT(VT_I4,V_I4); |
| if (has_i8) |
| { |
| VNUMFMT(VT_I8,V_I8); |
| } |
| VNUMFMT(VT_INT,V_INT); |
| VNUMFMT(VT_UI1,V_UI1); |
| VNUMFMT(VT_UI2,V_UI2); |
| VNUMFMT(VT_UI4,V_UI4); |
| if (has_i8) |
| { |
| VNUMFMT(VT_UI8,V_UI8); |
| } |
| VNUMFMT(VT_UINT,V_UINT); |
| VNUMFMT(VT_R4,V_R4); |
| VNUMFMT(VT_R8,V_R8); |
| |
| /* Reference types are dereferenced */ |
| VARFMT(VT_BOOL|VT_BYREF,V_BOOLREF,&bTrue,"True/False",S_OK,"True"); |
| VARFMT(VT_BOOL|VT_BYREF,V_BOOLREF,&bFalse,"True/False",S_OK,"False"); |
| |
| /* Dates */ |
| for (i = 0; i < sizeof(VarFormat_date_results)/sizeof(FMTDATERES); i++) |
| { |
| if (i < 7) |
| fd = i + 1; /* Test first day */ |
| else |
| fd = 0; |
| VARFMT(VT_DATE,V_DATE,VarFormat_date_results[i].val, |
| VarFormat_date_results[i].fmt,S_OK, |
| VarFormat_date_results[i].res); |
| } |
| |
| /* Named time formats */ |
| GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_STIMEFORMAT, buff, sizeof(buff)/sizeof(char)); |
| if (strcmp(buff, "h:mm:ss tt")) |
| { |
| skip("Skipping named time tests as time format is '%s'\n", buff); |
| } |
| else |
| { |
| for (i = 0; i < sizeof(VarFormat_namedtime_results)/sizeof(FMTDATERES); i++) |
| { |
| fd = 0; |
| VARFMT(VT_DATE,V_DATE,VarFormat_namedtime_results[i].val, |
| VarFormat_namedtime_results[i].fmt,S_OK, |
| VarFormat_namedtime_results[i].res); |
| } |
| } |
| |
| /* Strings */ |
| bstrin = SysAllocString(szTesting); |
| VARFMT(VT_BSTR,V_BSTR,bstrin,"",S_OK,"testing"); |
| VARFMT(VT_BSTR,V_BSTR,bstrin,"@",S_OK,"testing"); |
| VARFMT(VT_BSTR,V_BSTR,bstrin,"&",S_OK,"testing"); |
| VARFMT(VT_BSTR,V_BSTR,bstrin,"\\x@\\x@",S_OK,"xtxesting"); |
| VARFMT(VT_BSTR,V_BSTR,bstrin,"\\x&\\x&",S_OK,"xtxesting"); |
| VARFMT(VT_BSTR,V_BSTR,bstrin,"@\\x",S_OK,"txesting"); |
| VARFMT(VT_BSTR,V_BSTR,bstrin,"@@@@@@@@",S_OK," testing"); |
| VARFMT(VT_BSTR,V_BSTR,bstrin,"@\\x@@@@@@@",S_OK," xtesting"); |
| VARFMT(VT_BSTR,V_BSTR,bstrin,"&&&&&&&&",S_OK,"testing"); |
| VARFMT(VT_BSTR,V_BSTR,bstrin,"!&&&&&&&",S_OK,"testing"); |
| VARFMT(VT_BSTR,V_BSTR,bstrin,"&&&&&&&!",S_OK,"testing"); |
| VARFMT(VT_BSTR,V_BSTR,bstrin,">&&",S_OK,"TESTING"); |
| VARFMT(VT_BSTR,V_BSTR,bstrin,"<&&",S_OK,"testing"); |
| VARFMT(VT_BSTR,V_BSTR,bstrin,"<&>&",S_OK,"testing"); |
| SysFreeString(bstrin); |
| bstrin = SysAllocString(szNum); |
| todo_wine VARFMT(VT_BSTR,V_BSTR,bstrin,"hh:mm",S_OK,"02:38"); |
| todo_wine VARFMT(VT_BSTR,V_BSTR,bstrin,"mm-dd-yy",S_OK,"09-06-08"); |
| SysFreeString(bstrin); |
| /* Numeric values are converted to strings then output */ |
| VARFMT(VT_I1,V_I1,1,"<&>&",S_OK,"1"); |
| |
| /* Number formats */ |
| VARFMT(VT_I4,V_I4,1,"#00000000",S_OK,"00000001"); |
| VARFMT(VT_I4,V_I4,1,"000###",S_OK,"000001"); |
| VARFMT(VT_I4,V_I4,1,"#00##00#0",S_OK,"00000001"); |
| VARFMT(VT_I4,V_I4,1,"1#####0000",S_OK,"10001"); |
| VARFMT(VT_I4,V_I4,1,"##abcdefghijklmnopqrstuvwxyz",S_OK,"1abcdefghijklmnopqrstuvwxyz"); |
| VARFMT(VT_I4,V_I4,100000,"#,###,###,###",S_OK,"100,000"); |
| VARFMT(VT_I4,V_I4,1,"0,000,000,000",S_OK,"0,000,000,001"); |
| VARFMT(VT_I4,V_I4,123456789,"#,#.#",S_OK,"123,456,789."); |
| VARFMT(VT_I4,V_I4,123456789,"###, ###, ###",S_OK,"123, 456, 789"); |
| VARFMT(VT_I4,V_I4,1,"#;-#",S_OK,"1"); |
| VARFMT(VT_I4,V_I4,-1,"#;-#",S_OK,"-1"); |
| VARFMT(VT_R8,V_R8,1.23456789,"0#.0#0#0#0#0",S_OK,"01.234567890"); |
| VARFMT(VT_R8,V_R8,1.2,"0#.0#0#0#0#0",S_OK,"01.200000000"); |
| VARFMT(VT_R8,V_R8,9.87654321,"#0.#0#0#0#0#",S_OK,"9.87654321"); |
| VARFMT(VT_R8,V_R8,9.8,"#0.#0#0#0#0#",S_OK,"9.80000000"); |
| VARFMT(VT_R8,V_R8,0.00000008,"#0.#0#0#0#0#0",S_OK,"0.0000000800"); |
| VARFMT(VT_R8,V_R8,0.00010705,"#0.##########",S_OK,"0.00010705"); |
| VARFMT(VT_I4,V_I4,17,"#0",S_OK,"17"); |
| VARFMT(VT_I4,V_I4,4711,"#0",S_OK,"4711"); |
| VARFMT(VT_I4,V_I4,17,"#00",S_OK,"17"); |
| VARFMT(VT_I4,V_I4,100,"0##",S_OK,"100"); |
| VARFMT(VT_I4,V_I4,17,"#000",S_OK,"017"); |
| VARFMT(VT_I4,V_I4,17,"#0.00",S_OK,"17.00"); |
| VARFMT(VT_I4,V_I4,17,"#0000.00",S_OK,"0017.00"); |
| VARFMT(VT_I4,V_I4,17,"#.00",S_OK,"17.00"); |
| VARFMT(VT_R8,V_R8,1.7,"#.00",S_OK,"1.70"); |
| VARFMT(VT_R8,V_R8,.17,"#.00",S_OK,".17"); |
| VARFMT(VT_I4,V_I4,17,"#3",S_OK,"173"); |
| VARFMT(VT_I4,V_I4,17,"#33",S_OK,"1733"); |
| VARFMT(VT_I4,V_I4,17,"#3.33",S_OK,"173.33"); |
| VARFMT(VT_I4,V_I4,17,"#3333.33",S_OK,"173333.33"); |
| VARFMT(VT_I4,V_I4,17,"#.33",S_OK,"17.33"); |
| VARFMT(VT_R8,V_R8,.17,"#.33",S_OK,".33"); |
| VARFMT(VT_R8,V_R8,1.7,"0.0000E-000",S_OK,"1.7000E000"); |
| VARFMT(VT_R8,V_R8,1.7,"0.0000e-1",S_OK,"1.7000e01"); |
| VARFMT(VT_R8,V_R8,86.936849,"#0.000000000000e-000",S_OK,"86.936849000000e000"); |
| VARFMT(VT_R8,V_R8,1.7,"#0",S_OK,"2"); |
| VARFMT(VT_R8,V_R8,1.7,"#.33",S_OK,"2.33"); |
| VARFMT(VT_R8,V_R8,1.7,"#3",S_OK,"23"); |
| VARFMT(VT_R8,V_R8,1.73245,"0.0000E+000",S_OK,"1.7325E+000"); |
| VARFMT(VT_R8,V_R8,9.9999999,"#0.000000",S_OK,"10.000000"); |
| VARFMT(VT_R8,V_R8,1.7,"0.0000e+0#",S_OK,"1.7000e+0"); |
| VARFMT(VT_R8,V_R8,100.0001e+0,"0.0000E+0",S_OK,"1.0000E+2"); |
| VARFMT(VT_R8,V_R8,1000001,"0.0000e+1",S_OK,"1.0000e+61"); |
| VARFMT(VT_R8,V_R8,100.0001e+25,"0.0000e+0",S_OK,"1.0000e+27"); |
| VARFMT(VT_R8,V_R8,450.0001e+43,"#000.0000e+0",S_OK,"4500.0010e+42"); |
| VARFMT(VT_R8,V_R8,0.0001e-11,"##00.0000e-0",S_OK,"1000.0000e-18"); |
| VARFMT(VT_R8,V_R8,0.0317e-11,"0000.0000e-0",S_OK,"3170.0000e-16"); |
| VARFMT(VT_R8,V_R8,0.0021e-11,"00##.0000e-0",S_OK,"2100.0000e-17"); |
| VARFMT(VT_R8,V_R8,1.0001e-27,"##00.0000e-0",S_OK,"1000.1000e-30"); |
| VARFMT(VT_R8,V_R8,47.11,".0000E+0",S_OK,".4711E+2"); |
| VARFMT(VT_R8,V_R8,3.0401e-13,"#####.####e-0%",S_OK,"30401.e-15%"); |
| VARFMT(VT_R8,V_R8,1.57,"0.00",S_OK,"1.57"); |
| VARFMT(VT_R8,V_R8,-1.57,"0.00",S_OK,"-1.57"); |
| VARFMT(VT_R8,V_R8,-1.57,"#.##",S_OK,"-1.57"); |
| VARFMT(VT_R8,V_R8,-0.1,".#",S_OK,"-.1"); |
| VARFMT(VT_R8,V_R8,0.099,"#.#",S_OK,".1"); |
| VARFMT(VT_R8,V_R8,0.0999,"#.##",S_OK,".1"); |
| VARFMT(VT_R8,V_R8,0.099,"#.##",S_OK,".1"); |
| VARFMT(VT_R8,V_R8,0.0099,"#.##",S_OK,".01"); |
| VARFMT(VT_R8,V_R8,0.0049,"#.##",S_OK,"."); |
| VARFMT(VT_R8,V_R8,0.0094,"#.##",S_OK,".01"); |
| VARFMT(VT_R8,V_R8,0.00099,"#.##",S_OK,"."); |
| VARFMT(VT_R8,V_R8,0.0995,"#.##",S_OK,".1"); |
| VARFMT(VT_R8,V_R8,8.0995,"#.##",S_OK,"8.1"); |
| VARFMT(VT_R8,V_R8,0.0994,"#.##",S_OK,".1"); |
| VARFMT(VT_R8,V_R8,1.00,"#,##0.00",S_OK,"1.00"); |
| VARFMT(VT_R8,V_R8,0.0995,"#.###",S_OK,".1"); |
| |
| |
| /* 'out' is not cleared */ |
| out = (BSTR)0x1; |
| hres = pVarFormat(&in,NULL,fd,fw,flags,&out); /* Would crash if out is cleared */ |
| ok(hres == S_OK, "got %08x\n", hres); |
| SysFreeString(out); |
| out = NULL; |
| |
| /* VT_NULL */ |
| V_VT(&in) = VT_NULL; |
| hres = pVarFormat(&in,NULL,fd,fw,0,&out); |
| ok(hres == S_OK, "VarFormat failed with 0x%08x\n", hres); |
| ok(out == NULL, "expected NULL formatted string\n"); |
| |
| /* Invalid args */ |
| hres = pVarFormat(&in,NULL,fd,fw,flags,NULL); |
| ok(hres == E_INVALIDARG, "Null out: expected E_INVALIDARG, got 0x%08x\n", hres); |
| hres = pVarFormat(NULL,NULL,fd,fw,flags,&out); |
| ok(hres == E_INVALIDARG, "Null in: expected E_INVALIDARG, got 0x%08x\n", hres); |
| fd = -1; |
| VARFMT(VT_BOOL,V_BOOL,VARIANT_TRUE,"",E_INVALIDARG,""); |
| fd = 8; |
| VARFMT(VT_BOOL,V_BOOL,VARIANT_TRUE,"",E_INVALIDARG,""); |
| fd = 0; fw = -1; |
| VARFMT(VT_BOOL,V_BOOL,VARIANT_TRUE,"",E_INVALIDARG,""); |
| fw = 4; |
| VARFMT(VT_BOOL,V_BOOL,VARIANT_TRUE,"",E_INVALIDARG,""); |
| } |
| |
| static const char *szVarWdnFail = |
| "VarWeekdayName (%d, %d, %d, %d, %x): returned %8x, expected %8x\n"; |
| #define VARWDN(iWeekday, fAbbrev, iFirstDay, dwFlags, ret, buff, out, freeOut) \ |
| do { \ |
| hres = pVarWeekdayName(iWeekday, fAbbrev, iFirstDay, dwFlags, &out); \ |
| if (SUCCEEDED(hres)) { \ |
| WideCharToMultiByte(CP_ACP, 0, out, -1, buff, sizeof(buff), 0, 0); \ |
| if (freeOut) SysFreeString(out); \ |
| } else { \ |
| buff[0] = '\0'; \ |
| } \ |
| ok(hres == ret, \ |
| szVarWdnFail, \ |
| iWeekday, fAbbrev, iFirstDay, dwFlags, &out, hres, ret \ |
| ); \ |
| } while(0) |
| |
| #define VARWDN_F(iWeekday, fAbbrev, iFirstDay, dwFlags, ret) \ |
| VARWDN(iWeekday, fAbbrev, iFirstDay, dwFlags, ret, buff, out, 1) |
| |
| #define VARWDN_O(iWeekday, fAbbrev, iFirstDay, dwFlags) \ |
| VARWDN(iWeekday, fAbbrev, iFirstDay, dwFlags, S_OK, buff, out, 0) |
| |
| static void test_VarWeekdayName(void) |
| { |
| char buff[256]; |
| BSTR out = NULL; |
| HRESULT hres; |
| int iWeekday, fAbbrev, iFirstDay; |
| BSTR dayNames[7][2]; /* Monday-Sunday, full/abbr */ |
| DWORD defaultFirstDay; |
| int firstDay; |
| int day; |
| int size; |
| DWORD localeValue; |
| |
| CHECKPTR(VarWeekdayName); |
| |
| SetLastError(0xdeadbeef); |
| GetLocaleInfoW(LOCALE_USER_DEFAULT, 0, NULL, 0); |
| if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) |
| { |
| win_skip("GetLocaleInfoW is not implemented\n"); |
| return; |
| } |
| |
| /* Initialize days' names */ |
| for (day = 0; day <= 6; ++day) |
| { |
| for (fAbbrev = 0; fAbbrev <= 1; ++fAbbrev) |
| { |
| localeValue = fAbbrev ? LOCALE_SABBREVDAYNAME1 : LOCALE_SDAYNAME1; |
| localeValue += day; |
| size = GetLocaleInfoW(LOCALE_USER_DEFAULT, localeValue, NULL, 0); |
| dayNames[day][fAbbrev] = SysAllocStringLen(NULL, size - 1); |
| GetLocaleInfoW(LOCALE_USER_DEFAULT, localeValue, |
| dayNames[day][fAbbrev], size); |
| } |
| } |
| |
| /* Get the user's first day of week. 0=Monday, .. */ |
| GetLocaleInfoW( |
| LOCALE_USER_DEFAULT, LOCALE_IFIRSTDAYOFWEEK | LOCALE_RETURN_NUMBER, |
| (LPWSTR)&defaultFirstDay, sizeof(defaultFirstDay) / sizeof(WCHAR)); |
| |
| /* Check invalid arguments */ |
| VARWDN_F(0, 0, 4, 0, E_INVALIDARG); |
| VARWDN_F(8, 0, 4, 0, E_INVALIDARG); |
| VARWDN_F(4, 0, -1, 0, E_INVALIDARG); |
| VARWDN_F(4, 0, 8, 0, E_INVALIDARG); |
| |
| hres = pVarWeekdayName(1, 0, 0, 0, NULL); |
| ok(E_INVALIDARG == hres, |
| "Null pointer: expected E_INVALIDARG, got 0x%08x\n", hres); |
| |
| /* Check all combinations */ |
| pVarBstrCmp = (void*)GetProcAddress(hOleaut32, "VarBstrCmp"); |
| if (pVarBstrCmp) |
| for (iWeekday = 1; iWeekday <= 7; ++iWeekday) |
| { |
| for (fAbbrev = 0; fAbbrev <= 1; ++fAbbrev) |
| { |
| /* 0 = Default, 1 = Sunday, 2 = Monday, .. */ |
| for (iFirstDay = 0; iFirstDay <= 7; ++iFirstDay) |
| { |
| VARWDN_O(iWeekday, fAbbrev, iFirstDay, 0); |
| if (iFirstDay == 0) |
| firstDay = defaultFirstDay; |
| else |
| /* Translate from 0=Sunday to 0=Monday in the modulo 7 space */ |
| firstDay = iFirstDay - 2; |
| day = (7 + iWeekday - 1 + firstDay) % 7; |
| ok(VARCMP_EQ == pVarBstrCmp(out, dayNames[day][fAbbrev], |
| LOCALE_USER_DEFAULT, 0), |
| "VarWeekdayName(%d,%d,%d): got wrong dayname: '%s'\n", |
| iWeekday, fAbbrev, iFirstDay, buff); |
| SysFreeString(out); |
| } |
| } |
| } |
| |
| /* Cleanup */ |
| for (day = 0; day <= 6; ++day) |
| { |
| for (fAbbrev = 0; fAbbrev <= 1; ++fAbbrev) |
| { |
| SysFreeString(dayNames[day][fAbbrev]); |
| } |
| } |
| } |
| |
| static void test_VarFormatFromTokens(void) |
| { |
| static WCHAR number_fmt[] = {'#','#','#',',','#','#','0','.','0','0',0}; |
| static const WCHAR number[] = {'6',',','9','0',0}; |
| static const WCHAR number_us[] = {'6','9','0','.','0','0',0}; |
| |
| static WCHAR date_fmt[] = {'d','d','-','m','m',0}; |
| static const WCHAR date[] = {'1','2','-','1','1',0}; |
| static const WCHAR date_us[] = {'1','1','-','1','2',0}; |
| |
| static WCHAR string_fmt[] = {'@',0}; |
| static const WCHAR string_de[] = {'1',',','5',0}; |
| static const WCHAR string_us[] = {'1','.','5',0}; |
| |
| BYTE buff[256]; |
| LCID lcid; |
| VARIANT var; |
| BSTR bstr; |
| HRESULT hres; |
| |
| V_VT(&var) = VT_BSTR; |
| V_BSTR(&var) = SysAllocString(number); |
| |
| lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); |
| hres = VarTokenizeFormatString(number_fmt, buff, sizeof(buff), 1, 1, lcid, NULL); |
| ok(hres == S_OK, "VarTokenizeFormatString failed: %x\n", hres); |
| hres = VarFormatFromTokens(&var, number_fmt, buff, 0, &bstr, lcid); |
| ok(hres == S_OK, "VarFormatFromTokens failed: %x\n", hres); |
| ok(!strcmpW(bstr, number_us), "incorrectly formatted number: %s\n", wine_dbgstr_w(bstr)); |
| SysFreeString(bstr); |
| |
| lcid = MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT); |
| hres = VarTokenizeFormatString(number_fmt, buff, sizeof(buff), 1, 1, lcid, NULL); |
| ok(hres == S_OK, "VarTokenizeFormatString failed: %x\n", hres); |
| hres = VarFormatFromTokens(&var, number_fmt, buff, 0, &bstr, lcid); |
| ok(hres == S_OK, "VarFormatFromTokens failed: %x\n", hres); |
| ok(!strcmpW(bstr, number), "incorrectly formatted number: %s\n", wine_dbgstr_w(bstr)); |
| SysFreeString(bstr); |
| |
| VariantClear(&var); |
| |
| V_VT(&var) = VT_BSTR; |
| V_BSTR(&var) = SysAllocString(date); |
| |
| lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); |
| hres = VarTokenizeFormatString(date_fmt, buff, sizeof(buff), 1, 1, lcid, NULL); |
| ok(hres == S_OK, "VarTokenizeFormatString failed: %x\n", hres); |
| hres = VarFormatFromTokens(&var, date_fmt, buff, 0, &bstr, lcid); |
| ok(hres == S_OK, "VarFormatFromTokens failed: %x\n", hres); |
| ok(!strcmpW(bstr, date_us), "incorrectly formatted date: %s\n", wine_dbgstr_w(bstr)); |
| SysFreeString(bstr); |
| |
| lcid = MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT); |
| hres = VarTokenizeFormatString(date_fmt, buff, sizeof(buff), 1, 1, lcid, NULL); |
| ok(hres == S_OK, "VarTokenizeFormatString failed: %x\n", hres); |
| hres = VarFormatFromTokens(&var, date_fmt, buff, 0, &bstr, lcid); |
| ok(hres == S_OK, "VarFormatFromTokens failed: %x\n", hres); |
| ok(!strcmpW(bstr, date), "incorrectly formatted date: %s\n", wine_dbgstr_w(bstr)); |
| SysFreeString(bstr); |
| |
| VariantClear(&var); |
| |
| V_VT(&var) = VT_R4; |
| V_R4(&var) = 1.5; |
| |
| lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); |
| hres = VarTokenizeFormatString(string_fmt, buff, sizeof(buff), 1, 1, lcid, NULL); |
| ok(hres == S_OK, "VarTokenizeFormatString failed: %x\n", hres); |
| hres = VarFormatFromTokens(&var, string_fmt, buff, 0, &bstr, lcid); |
| ok(hres == S_OK, "VarFormatFromTokens failed: %x\n", hres); |
| ok(!strcmpW(bstr, string_us), "incorrectly formatted string: %s\n", wine_dbgstr_w(bstr)); |
| SysFreeString(bstr); |
| |
| lcid = MAKELCID(MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT); |
| hres = VarTokenizeFormatString(string_fmt, buff, sizeof(buff), 1, 1, lcid, NULL); |
| ok(hres == S_OK, "VarTokenizeFormatString failed: %x\n", hres); |
| hres = VarFormatFromTokens(&var, string_fmt, buff, 0, &bstr, lcid); |
| ok(hres == S_OK, "VarFormatFromTokens failed: %x\n", hres); |
| ok(!strcmpW(bstr, string_de), "incorrectly formatted string: %s\n", wine_dbgstr_w(bstr)); |
| SysFreeString(bstr); |
| } |
| |
| static void test_GetAltMonthNames(void) |
| { |
| LPOLESTR *str, *str2; |
| HRESULT hr; |
| |
| str = (void *)0xdeadbeef; |
| hr = GetAltMonthNames(0, &str); |
| ok(hr == S_OK, "Unexpected return value %08x\n", hr); |
| ok(str == NULL, "Got %p\n", str); |
| |
| str = (void *)0xdeadbeef; |
| hr = GetAltMonthNames(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT), &str); |
| ok(hr == S_OK, "Unexpected return value %08x\n", hr); |
| ok(str == NULL, "Got %p\n", str); |
| |
| str = NULL; |
| hr = GetAltMonthNames(MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_EGYPT), SORT_DEFAULT), &str); |
| ok(hr == S_OK, "Unexpected return value %08x\n", hr); |
| ok(str != NULL, "Got %p\n", str); |
| |
| str2 = NULL; |
| hr = GetAltMonthNames(MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_ARABIC_EGYPT), SORT_DEFAULT), &str2); |
| ok(hr == S_OK, "Unexpected return value %08x\n", hr); |
| ok(str2 == str, "Got %p\n", str2); |
| |
| str = NULL; |
| hr = GetAltMonthNames(MAKELCID(MAKELANGID(LANG_RUSSIAN, SUBLANG_DEFAULT), SORT_DEFAULT), &str); |
| ok(hr == S_OK, "Unexpected return value %08x\n", hr); |
| ok(str != NULL, "Got %p\n", str); |
| |
| str = NULL; |
| hr = GetAltMonthNames(MAKELCID(MAKELANGID(LANG_POLISH, SUBLANG_DEFAULT), SORT_DEFAULT), &str); |
| ok(hr == S_OK, "Unexpected return value %08x\n", hr); |
| ok(str != NULL, "Got %p\n", str); |
| } |
| |
| START_TEST(varformat) |
| { |
| hOleaut32 = GetModuleHandleA("oleaut32.dll"); |
| |
| has_i8 = GetProcAddress(hOleaut32, "VarI8FromI1") != NULL; |
| |
| test_VarFormatNumber(); |
| test_VarFormat(); |
| test_VarWeekdayName(); |
| test_VarFormatFromTokens(); |
| test_GetAltMonthNames(); |
| } |