📄 locale.c
字号:
/*
* Unit tests for locale functions
*
* Copyright 2002 YASAR Mehmet
* Copyright 2003 Dmitry Timoshkov
* Copyright 2003 Jon Griffiths
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* NOTES
* We must pass LOCALE_NOUSEROVERRIDE (NUO) to formatting functions so that
* even when the user has overridden their default i8n settings (e.g. in
* the control panel i8n page), we will still get the expected results.
*/
#define WINVER 0x0500
#include <assert.h>
#include <stdlib.h>
#include <stdarg.h>
#include "wine/test.h"
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
#include "winnls.h"
static inline unsigned int strlenW( const WCHAR *str )
{
const WCHAR *s = str;
while (*s) s++;
return s - str;
}
static inline int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
{
if (n <= 0) return 0;
while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
return *str1 - *str2;
}
static inline WCHAR *strchrW( const WCHAR *str, WCHAR ch )
{
do { if (*str == ch) return (WCHAR *)str; } while (*str++);
return NULL;
}
inline static int isdigitW( WCHAR wc )
{
WORD type;
GetStringTypeW( CT_CTYPE1, &wc, 1, &type );
return type & C1_DIGIT;
}
/* Some functions are only in later versions of kernel32.dll */
static HMODULE hKernel32;
static WORD enumCount;
typedef BOOL (WINAPI *EnumSystemLanguageGroupsAFn)(LANGUAGEGROUP_ENUMPROC,
DWORD, LONG_PTR);
static EnumSystemLanguageGroupsAFn pEnumSystemLanguageGroupsA;
typedef BOOL (WINAPI *EnumLanguageGroupLocalesAFn)(LANGGROUPLOCALE_ENUMPROC,
LGRPID, DWORD, LONG_PTR);
static EnumLanguageGroupLocalesAFn pEnumLanguageGroupLocalesA;
typedef BOOL (WINAPI *EnumUILanguagesAFn)(UILANGUAGE_ENUMPROC,
DWORD, LONG_PTR);
static EnumUILanguagesAFn pEnumUILanguagesA;
typedef INT (WINAPI *FoldStringAFn)(DWORD, LPCSTR, INT, LPSTR, INT);
static FoldStringAFn pFoldStringA;
typedef INT (WINAPI *FoldStringWFn)(DWORD, LPCWSTR, INT, LPWSTR, INT);
static FoldStringWFn pFoldStringW;
typedef BOOL (WINAPI *IsValidLanguageGroupFn)(LGRPID, DWORD);
static IsValidLanguageGroupFn pIsValidLanguageGroup;
static void InitFunctionPointers(void)
{
hKernel32 = GetModuleHandleA("kernel32");
if (hKernel32)
{
pEnumSystemLanguageGroupsA = (void*)GetProcAddress(hKernel32, "EnumSystemLanguageGroupsA");
pEnumLanguageGroupLocalesA = (void*)GetProcAddress(hKernel32, "EnumLanguageGroupLocalesA");
pFoldStringA = (void*)GetProcAddress(hKernel32, "FoldStringA");
pFoldStringW = (void*)GetProcAddress(hKernel32, "FoldStringW");
pIsValidLanguageGroup = (void*)GetProcAddress(hKernel32, "IsValidLanguageGroup");
pEnumUILanguagesA = (void*)GetProcAddress(hKernel32, "EnumUILanguagesA");
}
}
#define eq(received, expected, label, type) \
ok((received) == (expected), "%s: got " type " instead of " type "\n", \
(label), (received), (expected))
#define BUFFER_SIZE 128
#define COUNTOF(x) (sizeof(x)/sizeof(x)[0])
#define EXPECT_LEN(len) ok(ret == (len), "Expected Len %d, got %d\n", (len), ret)
#define EXPECT_INVALID ok(GetLastError() == ERROR_INVALID_PARAMETER, \
"Expected ERROR_INVALID_PARAMETER, got %ld\n", GetLastError())
#define EXPECT_BUFFER ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, \
"Expected ERROR_INSUFFICIENT_BUFFER, got %ld\n", GetLastError())
#define EXPECT_FLAGS ok(GetLastError() == ERROR_INVALID_FLAGS, \
"Expected ERROR_INVALID_FLAGS, got %ld\n", GetLastError())
#define EXPECT_INVALIDFLAGS ok(GetLastError() == ERROR_INVALID_FLAGS || \
GetLastError() == ERROR_INVALID_PARAMETER, \
"Expected ERROR_INVALID_FLAGS, got %ld\n", GetLastError())
#define EXPECT_VALID ok(GetLastError() == 0, \
"Expected GetLastError() == 0, got %ld\n", GetLastError())
#define STRINGSA(x,y) strcpy(input, x); strcpy(Expected, y); SetLastError(0); buffer[0] = '\0'
#define EXPECT_LENA EXPECT_LEN((int)strlen(Expected)+1)
#define EXPECT_EQA ok(strncmp(buffer, Expected, strlen(Expected)) == 0, \
"Expected '%s', got '%s'\n", Expected, buffer)
#define STRINGSW(x,y) MultiByteToWideChar(CP_ACP,0,x,-1,input,COUNTOF(input)); \
MultiByteToWideChar(CP_ACP,0,y,-1,Expected,COUNTOF(Expected)); \
SetLastError(0); buffer[0] = '\0'
#define EXPECT_LENW EXPECT_LEN((int)strlenW(Expected)+1)
#define EXPECT_EQW ok(strncmpW(buffer, Expected, strlenW(Expected)) == 0, "Bad conversion\n")
#define EXPECT_FALSE ok(FALSE == ret, "Expected return value FALSE, got TRUE\n")
#define EXPECT_TRUE ok(FALSE != ret, "Expected return value TRUE, got FALSE\n")
#define NUO LOCALE_NOUSEROVERRIDE
static void test_GetLocaleInfoA(void)
{
int ret;
LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
char buffer[BUFFER_SIZE];
ok(lcid == 0x409, "wrong LCID calculated - %ld\n", lcid);
/* HTMLKit and "Font xplorer lite" expect GetLocaleInfoA to
* partially fill the buffer even if it is too short. See bug 637.
*/
SetLastError(0); memset(buffer, 0, COUNTOF(buffer));
ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 0);
ok(ret == 7 && !buffer[0], "Expected len=7, got %d\n", ret);
SetLastError(0); memset(buffer, 0, COUNTOF(buffer));
ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 3);
EXPECT_BUFFER; EXPECT_LEN(0);
ok(!strcmp(buffer, "Mon"), "Expected 'Mon', got '%s'\n", buffer);
SetLastError(0); memset(buffer, 0, COUNTOF(buffer));
ret = GetLocaleInfoA(lcid, NUO|LOCALE_SDAYNAME1, buffer, 10);
EXPECT_VALID; EXPECT_LEN(7);
ok(!strcmp(buffer, "Monday"), "Expected 'Monday', got '%s'\n", buffer);
}
static void test_GetTimeFormatA(void)
{
int ret;
SYSTEMTIME curtime;
LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
char buffer[BUFFER_SIZE], input[BUFFER_SIZE], Expected[BUFFER_SIZE];
memset(&curtime, 2, sizeof(SYSTEMTIME));
STRINGSA("tt HH':'mm'@'ss", ""); /* Invalid time */
ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
curtime.wHour = 8;
curtime.wMinute = 56;
curtime.wSecond = 13;
curtime.wMilliseconds = 22;
STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Valid time */
ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
STRINGSA("tt HH':'mm'@'ss", "A"); /* Insufficent buffer */
ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, 2);
EXPECT_BUFFER; EXPECT_LEN(0); EXPECT_EQA;
STRINGSA("tt HH':'mm'@'ss", "AM 08:56@13"); /* Calculate length only */
ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, NULL, 0);
EXPECT_VALID; EXPECT_LENA;
STRINGSA("", "8 AM"); /* TIME_NOMINUTESORSECONDS, default format */
ret = GetTimeFormatA(lcid, NUO|TIME_NOMINUTESORSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
STRINGSA("m1s2m3s4", ""); /* TIME_NOMINUTESORSECONDS/complex format */
ret = GetTimeFormatA(lcid, TIME_NOMINUTESORSECONDS, &curtime, input, buffer, COUNTOF(buffer));
EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
STRINGSA("", "8:56 AM"); /* TIME_NOSECONDS/Default format */
ret = GetTimeFormatA(lcid, NUO|TIME_NOSECONDS, &curtime, NULL, buffer, COUNTOF(buffer));
EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
STRINGSA("h:m:s tt", "8:56 AM"); /* TIME_NOSECONDS */
strcpy(Expected, "8:56 AM");
ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
STRINGSA("h.@:m.@:s.@:tt", "8.@:56AM"); /* Multiple delimiters */
ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
STRINGSA("s1s2s3", ""); /* Duplicate tokens */
ret = GetTimeFormatA(lcid, TIME_NOSECONDS, &curtime, input, buffer, COUNTOF(buffer));
EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
STRINGSA("t/tt", "A/AM"); /* AM time marker */
ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
curtime.wHour = 13;
STRINGSA("t/tt", "P/PM"); /* PM time marker */
ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
STRINGSA("h1t2tt3m", "156"); /* TIME_NOTIMEMARKER: removes text around time marker token */
ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
STRINGSA("h:m:s tt", "13:56:13 PM"); /* TIME_FORCE24HOURFORMAT */
ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
STRINGSA("h:m:s", "13:56:13"); /* TIME_FORCE24HOURFORMAT doesn't add time marker */
ret = GetTimeFormatA(lcid, TIME_FORCE24HOURFORMAT, &curtime, input, buffer, COUNTOF(buffer));
EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
curtime.wHour = 14; /* change this to 14 or 2pm */
curtime.wMinute = 5;
curtime.wSecond = 3;
STRINGSA("h hh H HH m mm s ss t tt", "2 02 14 14 5 05 3 03 P PM"); /* 24 hrs, leading 0 */
ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
curtime.wHour = 0;
STRINGSA("h/H/hh/HH", "12/0/12/00"); /* "hh" and "HH" */
ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
STRINGSA("h:m:s tt", "12:5:3 AM"); /* non-zero flags should fail with format, doesn't */
ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
/* try to convert formatting strings with more than two letters
* "h:hh:hhh:H:HH:HHH:m:mm:mmm:M:MM:MMM:s:ss:sss:S:SS:SSS"
* NOTE: We expect any letter for which there is an upper case value
* we should see a replacement. For letters that DO NOT have
* upper case values we should see NO REPLACEMENT.
*/
curtime.wHour = 8;
curtime.wMinute = 56;
curtime.wSecond = 13;
curtime.wMilliseconds = 22;
STRINGSA("h:hh:hhh H:HH:HHH m:mm:mmm M:MM:MMM s:ss:sss S:SS:SSS",
"8:08:08 8:08:08 56:56:56 M:MM:MMM 13:13:13 S:SS:SSS");
ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
STRINGSA("h", "text"); /* Don't write to buffer if len is 0 */
strcpy(buffer, "text");
ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, 0);
EXPECT_VALID; EXPECT_LEN(2); EXPECT_EQA;
STRINGSA("h 'h' H 'H' HH 'HH' m 'm' s 's' t 't' tt 'tt'",
"8 h 8 H 08 HH 56 m 13 s A t AM tt"); /* "'" preserves tokens */
ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
STRINGSA("'''", "'"); /* invalid quoted string */
ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
/* test that msdn suggested single quotation usage works as expected */
STRINGSA("''''", "'"); /* single quote mark */
ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
STRINGSA("''HHHHHH", "08"); /* Normal use */
ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
/* and test for normal use of the single quotation mark */
STRINGSA("'''HHHHHH'", "'HHHHHH"); /* Normal use */
ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
STRINGSA("'''HHHHHH", "'HHHHHH"); /* Odd use */
ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
STRINGSA("'123'tt", ""); /* TIME_NOTIMEMARKER drops literals too */
ret = GetTimeFormatA(lcid, TIME_NOTIMEMARKER, &curtime, input, buffer, COUNTOF(buffer));
EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
curtime.wHour = 25;
STRINGSA("'123'tt", ""); /* Invalid time */
ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
EXPECT_INVALID; EXPECT_LEN(0); EXPECT_EQA;
curtime.wHour = 12;
curtime.wMonth = 60; /* Invalid */
STRINGSA("h:m:s", "12:56:13"); /* Invalid date */
ret = GetTimeFormatA(lcid, 0, &curtime, input, buffer, COUNTOF(buffer));
EXPECT_VALID; EXPECT_LENA; EXPECT_EQA;
}
static void test_GetDateFormatA(void)
{
int ret;
SYSTEMTIME curtime;
LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -