2 ********************************************************************************
3 * Copyright (C) 2005-2016, 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 NEW_ARRAY(type,count) (type *) uprv_malloc((count) * sizeof(type))
48 #define DELETE_ARRAY(array) uprv_free((void *) (array))
50 #define STACK_BUFFER_SIZE 32
52 #define LOOP_COUNT 1000
54 static UBool initialized
= FALSE
;
57 * Return a random int64_t where U_INT64_MIN <= ran <= U_INT64_MAX.
59 static uint64_t randomInt64(void)
65 srand((unsigned)time(NULL
));
69 /* Assume rand has at least 12 bits of precision */
70 for (i
= 0; i
< sizeof(ran
); i
+= 1) {
71 ((char*)&ran
)[i
] = (char)((rand() & 0x0FF0) >> 4);
78 * Return a random double where U_DOUBLE_MIN <= ran <= U_DOUBLE_MAX.
80 static double randomDouble(void)
85 srand((unsigned)time(NULL
));
91 /* Assume rand has at least 12 bits of precision */
92 for (i
= 0; i
< sizeof(ran
); i
+= 1) {
93 ((char*)&ran
)[i
] = (char)((rand() & 0x0FF0) >> 4);
95 } while (_isnan(ran
));
97 int64_t numerator
= randomInt64();
100 denomenator
= randomInt64();
102 while (denomenator
== 0);
104 ran
= (double)numerator
/ (double)denomenator
;
111 * Return a random int32_t where U_INT32_MIN <= ran <= U_INT32_MAX.
113 static uint32_t randomInt32(void)
119 srand((unsigned)time(NULL
));
123 /* Assume rand has at least 12 bits of precision */
124 for (i
= 0; i
< sizeof(ran
); i
+= 1) {
125 ((char*)&ran
)[i
] = (char)((rand() & 0x0FF0) >> 4);
131 static UnicodeString
&getWindowsFormat(int32_t lcid
, UBool currency
, UnicodeString
&appendTo
, const wchar_t *fmt
, ...)
133 wchar_t nStackBuffer
[STACK_BUFFER_SIZE
];
134 wchar_t *nBuffer
= nStackBuffer
;
140 /* Due to the arguments causing a result to be <= 23 characters (+2 for NULL and minus),
141 we don't need to reallocate the buffer. */
143 result
= _vsnwprintf(nBuffer
, STACK_BUFFER_SIZE
, fmt
, args
);
146 /* Just to make sure of the above statement, we add this assert */
147 U_ASSERT(result
>=0);
148 // The following code is not used because _vscwprintf isn't available on MinGW at the moment.
153 newLength = _vscwprintf(fmt, args);
156 nBuffer = NEW_ARRAY(UChar, newLength + 1);
159 result = _vsnwprintf(nBuffer, newLength + 1, fmt, args);
164 // vswprintf is sensitive to the locale set by setlocale. For some locales
165 // it doesn't use "." as the decimal separator, which is what GetNumberFormatW
166 // and GetCurrencyFormatW both expect to see.
168 // To fix this, we scan over the string and replace the first non-digits, except
169 // for a leading "-", with a "."
171 // Note: (nBuffer[0] == L'-') will evaluate to 1 if there is a leading '-' in the
172 // number, and 0 otherwise.
173 for (wchar_t *p
= &nBuffer
[nBuffer
[0] == L
'-']; *p
!= L
'\0'; p
+= 1) {
174 if (*p
< L
'0' || *p
> L
'9') {
180 wchar_t stackBuffer
[STACK_BUFFER_SIZE
];
181 wchar_t *buffer
= stackBuffer
;
186 result
= GetCurrencyFormatW(lcid
, 0, nBuffer
, NULL
, buffer
, STACK_BUFFER_SIZE
);
189 DWORD lastError
= GetLastError();
191 if (lastError
== ERROR_INSUFFICIENT_BUFFER
) {
192 int newLength
= GetCurrencyFormatW(lcid
, 0, nBuffer
, NULL
, NULL
, 0);
194 buffer
= NEW_ARRAY(UChar
, newLength
);
196 GetCurrencyFormatW(lcid
, 0, nBuffer
, NULL
, buffer
, newLength
);
200 result
= GetNumberFormatW(lcid
, 0, nBuffer
, NULL
, buffer
, STACK_BUFFER_SIZE
);
203 DWORD lastError
= GetLastError();
205 if (lastError
== ERROR_INSUFFICIENT_BUFFER
) {
206 int newLength
= GetNumberFormatW(lcid
, 0, nBuffer
, NULL
, NULL
, 0);
208 buffer
= NEW_ARRAY(UChar
, newLength
);
210 GetNumberFormatW(lcid
, 0, nBuffer
, NULL
, buffer
, newLength
);
215 appendTo
.append(buffer
, (int32_t) wcslen(buffer
));
217 if (buffer
!= stackBuffer
) {
218 DELETE_ARRAY(buffer
);
221 /*if (nBuffer != nStackBuffer) {
222 DELETE_ARRAY(nBuffer);
228 static void testLocale(const char *localeID
, int32_t lcid
, NumberFormat
*wnf
, UBool currency
, TestLog
*log
)
230 for (int n
= 0; n
< LOOP_COUNT
; n
+= 1) {
231 UnicodeString u3Buffer
, u6Buffer
, udBuffer
;
232 UnicodeString w3Buffer
, w6Buffer
, wdBuffer
;
233 double d
= randomDouble();
234 int32_t i32
= randomInt32();
235 int64_t i64
= randomInt64();
237 getWindowsFormat(lcid
, currency
, wdBuffer
, L
"%.16f", d
);
239 getWindowsFormat(lcid
, currency
, w3Buffer
, L
"%I32d", i32
);
241 getWindowsFormat(lcid
, currency
, w6Buffer
, L
"%I64d", i64
);
243 wnf
->format(d
, udBuffer
);
244 if (udBuffer
.compare(wdBuffer
) != 0) {
245 UnicodeString
locale(localeID
);
247 log
->errln("Double format error for locale " + locale
+
248 ": got " + udBuffer
+ " expected " + wdBuffer
);
251 wnf
->format(i32
, u3Buffer
);
252 if (u3Buffer
.compare(w3Buffer
) != 0) {
253 UnicodeString
locale(localeID
);
255 log
->errln("int32_t format error for locale " + locale
+
256 ": got " + u3Buffer
+ " expected " + w3Buffer
);
259 wnf
->format(i64
, u6Buffer
);
260 if (u6Buffer
.compare(w6Buffer
) != 0) {
261 UnicodeString
locale(localeID
);
263 log
->errln("int64_t format error for locale " + locale
+
264 ": got " + u6Buffer
+ " expected " + w6Buffer
);
269 void Win32NumberTest::testLocales(TestLog
*log
)
271 int32_t lcidCount
= 0;
272 Win32Utilities::LCIDRecord
*lcidRecords
= Win32Utilities::getLocales(lcidCount
);
274 for(int i
= 0; i
< lcidCount
; i
+= 1) {
275 UErrorCode status
= U_ZERO_ERROR
;
278 // NULL localeID means ICU didn't recognize the lcid
279 if (lcidRecords
[i
].localeID
== NULL
) {
283 strcpy(localeID
, lcidRecords
[i
].localeID
);
285 if (strchr(localeID
, '@') > 0) {
286 strcat(localeID
, ";");
288 strcat(localeID
, "@");
291 strcat(localeID
, "compat=host");
293 Locale
ulocale(localeID
);
294 NumberFormat
*wnf
= NumberFormat::createInstance(ulocale
, status
);
295 NumberFormat
*wcf
= NumberFormat::createCurrencyInstance(ulocale
, status
);
297 testLocale(lcidRecords
[i
].localeID
, lcidRecords
[i
].lcid
, wnf
, FALSE
, log
);
298 testLocale(lcidRecords
[i
].localeID
, lcidRecords
[i
].lcid
, wcf
, TRUE
, log
);
301 char *old_locale
= strdup(setlocale(LC_ALL
, NULL
));
303 setlocale(LC_ALL
, "German");
305 testLocale(lcidRecords
[i
].localeID
, lcidRecords
[i
].lcid
, wnf
, FALSE
, log
);
306 testLocale(lcidRecords
[i
].localeID
, lcidRecords
[i
].lcid
, wcf
, TRUE
, log
);
308 setlocale(LC_ALL
, old_locale
);
317 Win32Utilities::freeLocales(lcidRecords
);
320 #endif /* #if !UCONFIG_NO_FORMATTING */
322 #endif /* U_PLATFORM_USES_ONLY_WIN32_API */