]> git.saurik.com Git - apple/icu.git/blob - icuSources/test/intltest/winnmtst.cpp
ICU-57166.0.1.tar.gz
[apple/icu.git] / icuSources / test / intltest / winnmtst.cpp
1 /*
2 ********************************************************************************
3 * Copyright (C) 2005-2016, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 ********************************************************************************
6 *
7 * File WINNMTST.CPP
8 *
9 ********************************************************************************
10 */
11
12 #include "unicode/utypes.h"
13
14 #if U_PLATFORM_USES_ONLY_WIN32_API
15
16 #if !UCONFIG_NO_FORMATTING
17
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"
24
25 #include "winnmfmt.h"
26 #include "winutil.h"
27 #include "winnmtst.h"
28
29 #include "cmemory.h"
30 #include "cstring.h"
31 #include "locmap.h"
32 #include "wintz.h"
33 #include "uassert.h"
34
35 # define WIN32_LEAN_AND_MEAN
36 # define VC_EXTRALEAN
37 # define NOUSER
38 # define NOSERVICE
39 # define NOIME
40 # define NOMCX
41 # include <windows.h>
42 # include <stdio.h>
43 # include <time.h>
44 # include <float.h>
45 # include <locale.h>
46
47 #define NEW_ARRAY(type,count) (type *) uprv_malloc((count) * sizeof(type))
48 #define DELETE_ARRAY(array) uprv_free((void *) (array))
49
50 #define STACK_BUFFER_SIZE 32
51
52 #define LOOP_COUNT 1000
53
54 static UBool initialized = FALSE;
55
56 /**
57 * Return a random int64_t where U_INT64_MIN <= ran <= U_INT64_MAX.
58 */
59 static uint64_t randomInt64(void)
60 {
61 int64_t ran = 0;
62 int32_t i;
63
64 if (!initialized) {
65 srand((unsigned)time(NULL));
66 initialized = TRUE;
67 }
68
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);
72 }
73
74 return ran;
75 }
76
77 /**
78 * Return a random double where U_DOUBLE_MIN <= ran <= U_DOUBLE_MAX.
79 */
80 static double randomDouble(void)
81 {
82 double ran = 0;
83
84 if (!initialized) {
85 srand((unsigned)time(NULL));
86 initialized = TRUE;
87 }
88 #if 0
89 int32_t i;
90 do {
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);
94 }
95 } while (_isnan(ran));
96 #else
97 int64_t numerator = randomInt64();
98 int64_t denomenator;
99 do {
100 denomenator = randomInt64();
101 }
102 while (denomenator == 0);
103
104 ran = (double)numerator / (double)denomenator;
105 #endif
106
107 return ran;
108 }
109
110 /**
111 * Return a random int32_t where U_INT32_MIN <= ran <= U_INT32_MAX.
112 */
113 static uint32_t randomInt32(void)
114 {
115 int32_t ran = 0;
116 int32_t i;
117
118 if (!initialized) {
119 srand((unsigned)time(NULL));
120 initialized = TRUE;
121 }
122
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);
126 }
127
128 return ran;
129 }
130
131 static UnicodeString &getWindowsFormat(int32_t lcid, UBool currency, UnicodeString &appendTo, const wchar_t *fmt, ...)
132 {
133 wchar_t nStackBuffer[STACK_BUFFER_SIZE];
134 wchar_t *nBuffer = nStackBuffer;
135 va_list args;
136 int result;
137
138 nBuffer[0] = 0x0000;
139
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. */
142 va_start(args, fmt);
143 result = _vsnwprintf(nBuffer, STACK_BUFFER_SIZE, fmt, args);
144 va_end(args);
145
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.
149 /*if (result < 0) {
150 int newLength;
151
152 va_start(args, fmt);
153 newLength = _vscwprintf(fmt, args);
154 va_end(args);
155
156 nBuffer = NEW_ARRAY(UChar, newLength + 1);
157
158 va_start(args, fmt);
159 result = _vsnwprintf(nBuffer, newLength + 1, fmt, args);
160 va_end(args);
161 }*/
162
163
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.
167 //
168 // To fix this, we scan over the string and replace the first non-digits, except
169 // for a leading "-", with a "."
170 //
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') {
175 *p = L'.';
176 break;
177 }
178 }
179
180 wchar_t stackBuffer[STACK_BUFFER_SIZE];
181 wchar_t *buffer = stackBuffer;
182
183 buffer[0] = 0x0000;
184
185 if (currency) {
186 result = GetCurrencyFormatW(lcid, 0, nBuffer, NULL, buffer, STACK_BUFFER_SIZE);
187
188 if (result == 0) {
189 DWORD lastError = GetLastError();
190
191 if (lastError == ERROR_INSUFFICIENT_BUFFER) {
192 int newLength = GetCurrencyFormatW(lcid, 0, nBuffer, NULL, NULL, 0);
193
194 buffer = NEW_ARRAY(UChar, newLength);
195 buffer[0] = 0x0000;
196 GetCurrencyFormatW(lcid, 0, nBuffer, NULL, buffer, newLength);
197 }
198 }
199 } else {
200 result = GetNumberFormatW(lcid, 0, nBuffer, NULL, buffer, STACK_BUFFER_SIZE);
201
202 if (result == 0) {
203 DWORD lastError = GetLastError();
204
205 if (lastError == ERROR_INSUFFICIENT_BUFFER) {
206 int newLength = GetNumberFormatW(lcid, 0, nBuffer, NULL, NULL, 0);
207
208 buffer = NEW_ARRAY(UChar, newLength);
209 buffer[0] = 0x0000;
210 GetNumberFormatW(lcid, 0, nBuffer, NULL, buffer, newLength);
211 }
212 }
213 }
214
215 appendTo.append(buffer, (int32_t) wcslen(buffer));
216
217 if (buffer != stackBuffer) {
218 DELETE_ARRAY(buffer);
219 }
220
221 /*if (nBuffer != nStackBuffer) {
222 DELETE_ARRAY(nBuffer);
223 }*/
224
225 return appendTo;
226 }
227
228 static void testLocale(const char *localeID, int32_t lcid, NumberFormat *wnf, UBool currency, TestLog *log)
229 {
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();
236
237 getWindowsFormat(lcid, currency, wdBuffer, L"%.16f", d);
238
239 getWindowsFormat(lcid, currency, w3Buffer, L"%I32d", i32);
240
241 getWindowsFormat(lcid, currency, w6Buffer, L"%I64d", i64);
242
243 wnf->format(d, udBuffer);
244 if (udBuffer.compare(wdBuffer) != 0) {
245 UnicodeString locale(localeID);
246
247 log->errln("Double format error for locale " + locale +
248 ": got " + udBuffer + " expected " + wdBuffer);
249 }
250
251 wnf->format(i32, u3Buffer);
252 if (u3Buffer.compare(w3Buffer) != 0) {
253 UnicodeString locale(localeID);
254
255 log->errln("int32_t format error for locale " + locale +
256 ": got " + u3Buffer + " expected " + w3Buffer);
257 }
258
259 wnf->format(i64, u6Buffer);
260 if (u6Buffer.compare(w6Buffer) != 0) {
261 UnicodeString locale(localeID);
262
263 log->errln("int64_t format error for locale " + locale +
264 ": got " + u6Buffer + " expected " + w6Buffer);
265 }
266 }
267 }
268
269 void Win32NumberTest::testLocales(TestLog *log)
270 {
271 int32_t lcidCount = 0;
272 Win32Utilities::LCIDRecord *lcidRecords = Win32Utilities::getLocales(lcidCount);
273
274 for(int i = 0; i < lcidCount; i += 1) {
275 UErrorCode status = U_ZERO_ERROR;
276 char localeID[128];
277
278 // NULL localeID means ICU didn't recognize the lcid
279 if (lcidRecords[i].localeID == NULL) {
280 continue;
281 }
282
283 strcpy(localeID, lcidRecords[i].localeID);
284
285 if (strchr(localeID, '@') > 0) {
286 strcat(localeID, ";");
287 } else {
288 strcat(localeID, "@");
289 }
290
291 strcat(localeID, "compat=host");
292
293 Locale ulocale(localeID);
294 NumberFormat *wnf = NumberFormat::createInstance(ulocale, status);
295 NumberFormat *wcf = NumberFormat::createCurrencyInstance(ulocale, status);
296
297 testLocale(lcidRecords[i].localeID, lcidRecords[i].lcid, wnf, FALSE, log);
298 testLocale(lcidRecords[i].localeID, lcidRecords[i].lcid, wcf, TRUE, log);
299
300 #if 0
301 char *old_locale = strdup(setlocale(LC_ALL, NULL));
302
303 setlocale(LC_ALL, "German");
304
305 testLocale(lcidRecords[i].localeID, lcidRecords[i].lcid, wnf, FALSE, log);
306 testLocale(lcidRecords[i].localeID, lcidRecords[i].lcid, wcf, TRUE, log);
307
308 setlocale(LC_ALL, old_locale);
309
310 free(old_locale);
311 #endif
312
313 delete wcf;
314 delete wnf;
315 }
316
317 Win32Utilities::freeLocales(lcidRecords);
318 }
319
320 #endif /* #if !UCONFIG_NO_FORMATTING */
321
322 #endif /* U_PLATFORM_USES_ONLY_WIN32_API */