2014-11-21 20:36:46 +01:00
|
|
|
/*
|
|
|
|
* Copyright 2014 Yifu Wang for ESRI
|
|
|
|
*
|
|
|
|
* 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 <errno.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <wchar.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#include <windef.h>
|
|
|
|
#include <winbase.h>
|
|
|
|
#include "wine/test.h"
|
|
|
|
|
|
|
|
#include <locale.h>
|
|
|
|
|
|
|
|
struct MSVCRT_lconv
|
|
|
|
{
|
|
|
|
char* decimal_point;
|
|
|
|
char* thousands_sep;
|
|
|
|
char* grouping;
|
|
|
|
char* int_curr_symbol;
|
|
|
|
char* currency_symbol;
|
|
|
|
char* mon_decimal_point;
|
|
|
|
char* mon_thousands_sep;
|
|
|
|
char* mon_grouping;
|
|
|
|
char* positive_sign;
|
|
|
|
char* negative_sign;
|
|
|
|
char int_frac_digits;
|
|
|
|
char frac_digits;
|
|
|
|
char p_cs_precedes;
|
|
|
|
char p_sep_by_space;
|
|
|
|
char n_cs_precedes;
|
|
|
|
char n_sep_by_space;
|
|
|
|
char p_sign_posn;
|
|
|
|
char n_sign_posn;
|
|
|
|
wchar_t* _W_decimal_point;
|
|
|
|
wchar_t* _W_thousands_sep;
|
|
|
|
wchar_t* _W_int_curr_symbol;
|
|
|
|
wchar_t* _W_currency_symbol;
|
|
|
|
wchar_t* _W_mon_decimal_point;
|
|
|
|
wchar_t* _W_mon_thousands_sep;
|
|
|
|
wchar_t* _W_positive_sign;
|
|
|
|
wchar_t* _W_negative_sign;
|
|
|
|
};
|
|
|
|
|
|
|
|
static char* (CDECL *p_setlocale)(int category, const char* locale);
|
|
|
|
static struct MSVCRT_lconv* (CDECL *p_localeconv)(void);
|
|
|
|
static size_t (CDECL *p_wcstombs_s)(size_t *ret, char* dest, size_t sz, const wchar_t* src, size_t max);
|
2015-05-26 14:54:49 +02:00
|
|
|
static int (CDECL *p__dsign)(double);
|
|
|
|
static int (CDECL *p__fdsign)(float);
|
2015-06-17 11:46:42 +02:00
|
|
|
static wchar_t** (CDECL *p____lc_locale_name_func)(void);
|
2015-07-24 09:13:19 +02:00
|
|
|
static unsigned int (CDECL *p__GetConcurrency)(void);
|
2014-11-21 20:36:46 +01:00
|
|
|
|
|
|
|
static BOOL init(void)
|
|
|
|
{
|
|
|
|
HMODULE module;
|
|
|
|
|
|
|
|
module = LoadLibraryA("msvcr120.dll");
|
|
|
|
if (!module)
|
|
|
|
{
|
|
|
|
win_skip("msvcr120.dll not installed\n");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
p_setlocale = (void*)GetProcAddress(module, "setlocale");
|
|
|
|
p_localeconv = (void*)GetProcAddress(module, "localeconv");
|
|
|
|
p_wcstombs_s = (void*)GetProcAddress(module, "wcstombs_s");
|
2015-05-26 14:54:49 +02:00
|
|
|
p__dsign = (void*)GetProcAddress(module, "_dsign");
|
|
|
|
p__fdsign = (void*)GetProcAddress(module, "_fdsign");
|
2015-06-17 11:46:42 +02:00
|
|
|
p____lc_locale_name_func = (void*)GetProcAddress(module, "___lc_locale_name_func");
|
2015-07-24 09:13:19 +02:00
|
|
|
p__GetConcurrency = (void*)GetProcAddress(module,"?_GetConcurrency@details@Concurrency@@YAIXZ");
|
2014-11-21 20:36:46 +01:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2014-12-05 12:20:54 +01:00
|
|
|
static void test_lconv_helper(const char *locstr)
|
2014-11-21 20:36:46 +01:00
|
|
|
{
|
|
|
|
struct MSVCRT_lconv *lconv;
|
|
|
|
char mbs[256];
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
if(!p_setlocale(LC_ALL, locstr))
|
|
|
|
{
|
|
|
|
win_skip("locale %s not available\n", locstr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
lconv = p_localeconv();
|
|
|
|
|
|
|
|
/* If multi-byte version available, asserts that wide char version also available.
|
|
|
|
* If wide char version can be converted to a multi-byte string , asserts that the
|
|
|
|
* conversion result is the same as the multi-byte version.
|
|
|
|
*/
|
|
|
|
if(strlen(lconv->decimal_point) > 0)
|
|
|
|
ok(wcslen(lconv->_W_decimal_point) > 0, "%s: decimal_point\n", locstr);
|
|
|
|
if(p_wcstombs_s(&i, mbs, 256, lconv->_W_decimal_point, 256) == 0)
|
|
|
|
ok(strcmp(mbs, lconv->decimal_point) == 0, "%s: decimal_point\n", locstr);
|
|
|
|
|
|
|
|
if(strlen(lconv->thousands_sep) > 0)
|
|
|
|
ok(wcslen(lconv->_W_thousands_sep) > 0, "%s: thousands_sep\n", locstr);
|
|
|
|
if(p_wcstombs_s(&i, mbs, 256, lconv->_W_thousands_sep, 256) == 0)
|
|
|
|
ok(strcmp(mbs, lconv->thousands_sep) == 0, "%s: thousands_sep\n", locstr);
|
|
|
|
|
|
|
|
if(strlen(lconv->int_curr_symbol) > 0)
|
|
|
|
ok(wcslen(lconv->_W_int_curr_symbol) > 0, "%s: int_curr_symbol\n", locstr);
|
|
|
|
if(p_wcstombs_s(&i, mbs, 256, lconv->_W_int_curr_symbol, 256) == 0)
|
|
|
|
ok(strcmp(mbs, lconv->int_curr_symbol) == 0, "%s: int_curr_symbol\n", locstr);
|
|
|
|
|
|
|
|
if(strlen(lconv->currency_symbol) > 0)
|
|
|
|
ok(wcslen(lconv->_W_currency_symbol) > 0, "%s: currency_symbol\n", locstr);
|
|
|
|
if(p_wcstombs_s(&i, mbs, 256, lconv->_W_currency_symbol, 256) == 0)
|
|
|
|
ok(strcmp(mbs, lconv->currency_symbol) == 0, "%s: currency_symbol\n", locstr);
|
|
|
|
|
|
|
|
if(strlen(lconv->mon_decimal_point) > 0)
|
|
|
|
ok(wcslen(lconv->_W_mon_decimal_point) > 0, "%s: decimal_point\n", locstr);
|
|
|
|
if(p_wcstombs_s(&i, mbs, 256, lconv->_W_mon_decimal_point, 256) == 0)
|
|
|
|
ok(strcmp(mbs, lconv->mon_decimal_point) == 0, "%s: decimal_point\n", locstr);
|
|
|
|
|
|
|
|
if(strlen(lconv->positive_sign) > 0)
|
|
|
|
ok(wcslen(lconv->_W_positive_sign) > 0, "%s: positive_sign\n", locstr);
|
|
|
|
if(p_wcstombs_s(&i, mbs, 256, lconv->_W_positive_sign, 256) == 0)
|
|
|
|
ok(strcmp(mbs, lconv->positive_sign) == 0, "%s: positive_sign\n", locstr);
|
|
|
|
|
|
|
|
if(strlen(lconv->negative_sign) > 0)
|
|
|
|
ok(wcslen(lconv->_W_negative_sign) > 0, "%s: negative_sign\n", locstr);
|
|
|
|
if(p_wcstombs_s(&i, mbs, 256, lconv->_W_negative_sign, 256) == 0)
|
|
|
|
ok(strcmp(mbs, lconv->negative_sign) == 0, "%s: negative_sign\n", locstr);
|
|
|
|
}
|
|
|
|
|
2014-12-05 12:20:54 +01:00
|
|
|
static void test_lconv(void)
|
2014-11-21 20:36:46 +01:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
const char *locstrs[] =
|
|
|
|
{
|
|
|
|
"American", "Belgian", "Chinese",
|
|
|
|
"Dutch", "English", "French",
|
|
|
|
"German", "Hungarian", "Icelandic",
|
|
|
|
"Japanese", "Korean", "Spanish"
|
|
|
|
};
|
|
|
|
|
|
|
|
for(i = 0; i < sizeof(locstrs) / sizeof(char *); i ++)
|
|
|
|
test_lconv_helper(locstrs[i]);
|
|
|
|
}
|
|
|
|
|
2015-05-26 14:54:49 +02:00
|
|
|
static void test__dsign(void)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = p__dsign(1);
|
|
|
|
ok(ret == 0, "p_dsign(1) = %x\n", ret);
|
|
|
|
ret = p__dsign(0);
|
|
|
|
ok(ret == 0, "p_dsign(0) = %x\n", ret);
|
|
|
|
ret = p__dsign(-1);
|
|
|
|
ok(ret == 0x8000, "p_dsign(-1) = %x\n", ret);
|
|
|
|
|
|
|
|
ret = p__fdsign(1);
|
|
|
|
ok(ret == 0, "p_fdsign(1) = %x\n", ret);
|
|
|
|
ret = p__fdsign(0);
|
|
|
|
ok(ret == 0, "p_fdsign(0) = %x\n", ret);
|
|
|
|
ret = p__fdsign(-1);
|
|
|
|
ok(ret == 0x8000, "p_fdsign(-1) = %x\n", ret);
|
|
|
|
}
|
|
|
|
|
2015-06-17 11:46:42 +02:00
|
|
|
static void test____lc_locale_name_func(void)
|
|
|
|
{
|
|
|
|
struct {
|
|
|
|
const char *locale;
|
|
|
|
const WCHAR name[10];
|
|
|
|
const WCHAR broken_name[10];
|
|
|
|
BOOL todo;
|
|
|
|
} tests[] = {
|
|
|
|
{ "American", {'e','n',0}, {'e','n','-','U','S',0} },
|
|
|
|
{ "Belgian", {'n','l','-','B','E',0} },
|
|
|
|
{ "Chinese", {'z','h',0}, {'z','h','-','C','N',0}, TRUE },
|
|
|
|
{ "Dutch", {'n','l',0}, {'n','l','-','N','L',0} },
|
|
|
|
{ "English", {'e','n',0}, {'e','n','-','U','S',0} },
|
|
|
|
{ "French", {'f','r',0}, {'f','r','-','F','R',0} },
|
|
|
|
{ "German", {'d','e',0}, {'d','e','-','D','E',0} },
|
|
|
|
{ "Hungarian", {'h','u',0}, {'h','u','-','H','U',0} },
|
|
|
|
{ "Icelandic", {'i','s',0}, {'i','s','-','I','S',0} },
|
|
|
|
{ "Japanese", {'j','a',0}, {'j','a','-','J','P',0} },
|
|
|
|
{ "Korean", {'k','o',0}, {'k','o','-','K','R',0} }
|
|
|
|
};
|
|
|
|
int i, j;
|
|
|
|
wchar_t **lc_names;
|
|
|
|
|
|
|
|
for(i=0; i<sizeof(tests)/sizeof(*tests); i++) {
|
|
|
|
if(!p_setlocale(LC_ALL, tests[i].locale))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
lc_names = p____lc_locale_name_func();
|
|
|
|
ok(lc_names[0] == NULL, "%d - lc_names[0] = %s\n", i, wine_dbgstr_w(lc_names[0]));
|
|
|
|
if(tests[i].todo) {
|
|
|
|
todo_wine ok(!lstrcmpW(lc_names[1], tests[i].name) || broken(!lstrcmpW(lc_names[1], tests[i].broken_name)),
|
|
|
|
"%d - lc_names[1] = %s\n", i, wine_dbgstr_w(lc_names[1]));
|
|
|
|
} else {
|
|
|
|
ok(!lstrcmpW(lc_names[1], tests[i].name) || broken(!lstrcmpW(lc_names[1], tests[i].broken_name)),
|
|
|
|
"%d - lc_names[1] = %s\n", i, wine_dbgstr_w(lc_names[1]));
|
|
|
|
}
|
|
|
|
|
|
|
|
for(j=LC_MIN+2; j<=LC_MAX; j++) {
|
|
|
|
ok(!lstrcmpW(lc_names[1], lc_names[j]), "%d - lc_names[%d] = %s, expected %s\n",
|
|
|
|
i, j, wine_dbgstr_w(lc_names[j]), wine_dbgstr_w(lc_names[1]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
p_setlocale(LC_ALL, "C");
|
|
|
|
lc_names = p____lc_locale_name_func();
|
|
|
|
ok(!lc_names[1], "___lc_locale_name_func()[1] = %s\n", wine_dbgstr_w(lc_names[1]));
|
|
|
|
}
|
|
|
|
|
2015-07-24 09:13:19 +02:00
|
|
|
static void test__GetConcurrency(void)
|
|
|
|
{
|
|
|
|
SYSTEM_INFO si;
|
|
|
|
unsigned int c;
|
|
|
|
|
|
|
|
GetSystemInfo(&si);
|
|
|
|
c = (*p__GetConcurrency)();
|
|
|
|
ok(c == si.dwNumberOfProcessors, "expected %u, got %u\n", si.dwNumberOfProcessors, c);
|
|
|
|
}
|
|
|
|
|
2014-11-21 20:36:46 +01:00
|
|
|
START_TEST(msvcr120)
|
|
|
|
{
|
|
|
|
if (!init()) return;
|
|
|
|
test_lconv();
|
2015-05-26 14:54:49 +02:00
|
|
|
test__dsign();
|
2015-06-17 11:46:42 +02:00
|
|
|
test____lc_locale_name_func();
|
2015-07-24 09:13:19 +02:00
|
|
|
test__GetConcurrency();
|
2014-11-21 20:36:46 +01:00
|
|
|
}
|