2 ********************************************************************************
3 * Copyright (C) 2005-2011, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 ********************************************************************************
9 ********************************************************************************
12 #include "unicode/utypes.h"
14 #if U_PLATFORM_USES_ONLY_WIN32_API
16 #if !UCONFIG_NO_FORMATTING
18 #include "unicode/format.h"
19 #include "unicode/numfmt.h"
20 #include "unicode/locid.h"
21 #include "unicode/ustring.h"
22 #include "unicode/testlog.h"
23 #include "unicode/utmscale.h"
35 # define WIN32_LEAN_AND_MEAN
47 #define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
48 #define NEW_ARRAY(type,count) (type *) uprv_malloc((count) * sizeof(type))
49 #define DELETE_ARRAY(array) uprv_free((void *) (array))
51 #define STACK_BUFFER_SIZE 32
53 #define LOOP_COUNT 1000
55 static UBool initialized
= FALSE
;
58 * Return a random int64_t where U_INT64_MIN <= ran <= U_INT64_MAX.
60 static uint64_t randomInt64(void)
66 srand((unsigned)time(NULL
));
70 /* Assume rand has at least 12 bits of precision */
71 for (i
= 0; i
< sizeof(ran
); i
+= 1) {
72 ((char*)&ran
)[i
] = (char)((rand() & 0x0FF0) >> 4);
79 * Return a random double where U_DOUBLE_MIN <= ran <= U_DOUBLE_MAX.
81 static double randomDouble(void)
86 srand((unsigned)time(NULL
));
92 /* Assume rand has at least 12 bits of precision */
93 for (i
= 0; i
< sizeof(ran
); i
+= 1) {
94 ((char*)&ran
)[i
] = (char)((rand() & 0x0FF0) >> 4);
96 } while (_isnan(ran
));
98 int64_t numerator
= randomInt64();
101 denomenator
= randomInt64();
103 while (denomenator
== 0);
105 ran
= (double)numerator
/ (double)denomenator
;
112 * Return a random int32_t where U_INT32_MIN <= ran <= U_INT32_MAX.
114 static uint32_t randomInt32(void)
120 srand((unsigned)time(NULL
));
124 /* Assume rand has at least 12 bits of precision */
125 for (i
= 0; i
< sizeof(ran
); i
+= 1) {
126 ((char*)&ran
)[i
] = (char)((rand() & 0x0FF0) >> 4);
132 static UnicodeString
&getWindowsFormat(int32_t lcid
, UBool currency
, UnicodeString
&appendTo
, const wchar_t *fmt
, ...)
134 wchar_t nStackBuffer
[STACK_BUFFER_SIZE
];
135 wchar_t *nBuffer
= nStackBuffer
;
141 /* Due to the arguments causing a result to be <= 23 characters (+2 for NULL and minus),
142 we don't need to reallocate the buffer. */
144 result
= _vsnwprintf(nBuffer
, STACK_BUFFER_SIZE
, fmt
, args
);
147 /* Just to make sure of the above statement, we add this assert */
148 U_ASSERT(result
>=0);
149 // The following code is not used because _vscwprintf isn't available on MinGW at the moment.
154 newLength = _vscwprintf(fmt, args);
157 nBuffer = NEW_ARRAY(UChar, newLength + 1);
160 result = _vsnwprintf(nBuffer, newLength + 1, fmt, args);
165 // vswprintf is sensitive to the locale set by setlocale. For some locales
166 // it doesn't use "." as the decimal separator, which is what GetNumberFormatW
167 // and GetCurrencyFormatW both expect to see.
169 // To fix this, we scan over the string and replace the first non-digits, except
170 // for a leading "-", with a "."
172 // Note: (nBuffer[0] == L'-') will evaluate to 1 if there is a leading '-' in the
173 // number, and 0 otherwise.
174 for (wchar_t *p
= &nBuffer
[nBuffer
[0] == L
'-']; *p
!= L
'\0'; p
+= 1) {
175 if (*p
< L
'0' || *p
> L
'9') {
181 wchar_t stackBuffer
[STACK_BUFFER_SIZE
];
182 wchar_t *buffer
= stackBuffer
;
187 result
= GetCurrencyFormatW(lcid
, 0, nBuffer
, NULL
, buffer
, STACK_BUFFER_SIZE
);
190 DWORD lastError
= GetLastError();
192 if (lastError
== ERROR_INSUFFICIENT_BUFFER
) {
193 int newLength
= GetCurrencyFormatW(lcid
, 0, nBuffer
, NULL
, NULL
, 0);
195 buffer
= NEW_ARRAY(UChar
, newLength
);
197 GetCurrencyFormatW(lcid
, 0, nBuffer
, NULL
, buffer
, newLength
);
201 result
= GetNumberFormatW(lcid
, 0, nBuffer
, NULL
, buffer
, STACK_BUFFER_SIZE
);
204 DWORD lastError
= GetLastError();
206 if (lastError
== ERROR_INSUFFICIENT_BUFFER
) {
207 int newLength
= GetNumberFormatW(lcid
, 0, nBuffer
, NULL
, NULL
, 0);
209 buffer
= NEW_ARRAY(UChar
, newLength
);
211 GetNumberFormatW(lcid
, 0, nBuffer
, NULL
, buffer
, newLength
);
216 appendTo
.append(buffer
, (int32_t) wcslen(buffer
));
218 if (buffer
!= stackBuffer
) {
219 DELETE_ARRAY(buffer
);
222 /*if (nBuffer != nStackBuffer) {
223 DELETE_ARRAY(nBuffer);
229 static void testLocale(const char *localeID
, int32_t lcid
, NumberFormat
*wnf
, UBool currency
, TestLog
*log
)
231 for (int n
= 0; n
< LOOP_COUNT
; n
+= 1) {
232 UnicodeString u3Buffer
, u6Buffer
, udBuffer
;
233 UnicodeString w3Buffer
, w6Buffer
, wdBuffer
;
234 double d
= randomDouble();
235 int32_t i32
= randomInt32();
236 int64_t i64
= randomInt64();
238 getWindowsFormat(lcid
, currency
, wdBuffer
, L
"%.16f", d
);
240 getWindowsFormat(lcid
, currency
, w3Buffer
, L
"%I32d", i32
);
242 getWindowsFormat(lcid
, currency
, w6Buffer
, L
"%I64d", i64
);
244 wnf
->format(d
, udBuffer
);
245 if (udBuffer
.compare(wdBuffer
) != 0) {
246 UnicodeString
locale(localeID
);
248 log
->errln("Double format error for locale " + locale
+
249 ": got " + udBuffer
+ " expected " + wdBuffer
);
252 wnf
->format(i32
, u3Buffer
);
253 if (u3Buffer
.compare(w3Buffer
) != 0) {
254 UnicodeString
locale(localeID
);
256 log
->errln("int32_t format error for locale " + locale
+
257 ": got " + u3Buffer
+ " expected " + w3Buffer
);
260 wnf
->format(i64
, u6Buffer
);
261 if (u6Buffer
.compare(w6Buffer
) != 0) {
262 UnicodeString
locale(localeID
);
264 log
->errln("int64_t format error for locale " + locale
+
265 ": got " + u6Buffer
+ " expected " + w6Buffer
);
270 void Win32NumberTest::testLocales(TestLog
*log
)
272 int32_t lcidCount
= 0;
273 Win32Utilities::LCIDRecord
*lcidRecords
= Win32Utilities::getLocales(lcidCount
);
275 for(int i
= 0; i
< lcidCount
; i
+= 1) {
276 UErrorCode status
= U_ZERO_ERROR
;
279 // NULL localeID means ICU didn't recognize the lcid
280 if (lcidRecords
[i
].localeID
== NULL
) {
284 strcpy(localeID
, lcidRecords
[i
].localeID
);
286 if (strchr(localeID
, '@') > 0) {
287 strcat(localeID
, ";");
289 strcat(localeID
, "@");
292 strcat(localeID
, "compat=host");
294 Locale
ulocale(localeID
);
295 NumberFormat
*wnf
= NumberFormat::createInstance(ulocale
, status
);
296 NumberFormat
*wcf
= NumberFormat::createCurrencyInstance(ulocale
, status
);
298 testLocale(lcidRecords
[i
].localeID
, lcidRecords
[i
].lcid
, wnf
, FALSE
, log
);
299 testLocale(lcidRecords
[i
].localeID
, lcidRecords
[i
].lcid
, wcf
, TRUE
, log
);
302 char *old_locale
= strdup(setlocale(LC_ALL
, NULL
));
304 setlocale(LC_ALL
, "German");
306 testLocale(lcidRecords
[i
].localeID
, lcidRecords
[i
].lcid
, wnf
, FALSE
, log
);
307 testLocale(lcidRecords
[i
].localeID
, lcidRecords
[i
].lcid
, wcf
, TRUE
, log
);
309 setlocale(LC_ALL
, old_locale
);
318 Win32Utilities::freeLocales(lcidRecords
);
321 #endif /* #if !UCONFIG_NO_FORMATTING */
323 #endif /* U_PLATFORM_USES_ONLY_WIN32_API */