1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 ********************************************************************************
5 * Copyright (C) 2005-2016, International Business Machines
6 * Corporation and others. All Rights Reserved.
7 ********************************************************************************
8 *
9 * File WINDTTST.CPP
10 *
11 ********************************************************************************
12 */
13
14 #include "unicode/utypes.h"
15
16 #if U_PLATFORM_USES_ONLY_WIN32_API
17
18 #if !UCONFIG_NO_FORMATTING
19
20 #include "unicode/format.h"
21 #include "unicode/numfmt.h"
22 #include "unicode/locid.h"
23 #include "unicode/ustring.h"
24 #include "unicode/testlog.h"
25 #include "unicode/utmscale.h"
26
27 #include "windtfmt.h"
28 #include "winutil.h"
29 #include "windttst.h"
30
31 #include "dtfmttst.h"
32
33 #include "cmemory.h"
34 #include "cstring.h"
35 #include "locmap.h"
36 #include "wintzimpl.h"
37
38 # define WIN32_LEAN_AND_MEAN
39 # define VC_EXTRALEAN
40 # define NOUSER
41 # define NOSERVICE
42 # define NOIME
43 # define NOMCX
44 # include <windows.h>
45
46 #include <algorithm>
47
getCalendarType(int32_t type)48 static const char *getCalendarType(int32_t type)
49 {
50 switch (type)
51 {
52 case 1:
53 case 2:
54 return "@calendar=gregorian";
55
56 case 3:
57 return "@calendar=japanese";
58
59 case 6:
60 return "@calendar=islamic";
61
62 case 7:
63 return "@calendar=buddhist";
64
65 case 8:
66 return "@calendar=hebrew";
67
68 default:
69 return "";
70 }
71 }
72
testLocales(DateFormatTest * log)73 void Win32DateTimeTest::testLocales(DateFormatTest *log)
74 {
75 SYSTEMTIME winNow;
76 UDate icuNow = 0;
77 SYSTEMTIME st;
78 FILETIME ft;
79 UnicodeString zoneID;
80 const TimeZone *tz = TimeZone::createDefault();
81 TIME_ZONE_INFORMATION tzi;
82
83 tz->getID(zoneID);
84 if (! uprv_getWindowsTimeZoneInfo(&tzi, zoneID.getBuffer(), zoneID.length())) {
85 UBool found = FALSE;
86 int32_t ec = TimeZone::countEquivalentIDs(zoneID);
87
88 for (int z = 0; z < ec; z += 1) {
89 UnicodeString equiv = TimeZone::getEquivalentID(zoneID, z);
90
91 if (found = uprv_getWindowsTimeZoneInfo(&tzi, equiv.getBuffer(), equiv.length())) {
92 break;
93 }
94 }
95
96 if (! found) {
97 GetTimeZoneInformation(&tzi);
98 }
99 }
100
101 GetSystemTime(&st);
102 SystemTimeToFileTime(&st, &ft);
103 SystemTimeToTzSpecificLocalTime(&tzi, &st, &winNow);
104
105 int64_t wftNow = ((int64_t) ft.dwHighDateTime << 32) + ft.dwLowDateTime;
106 UErrorCode status = U_ZERO_ERROR;
107
108 int64_t udtsNow = utmscale_fromInt64(wftNow, UDTS_WINDOWS_FILE_TIME, &status);
109
110 icuNow = (UDate) utmscale_toInt64(udtsNow, UDTS_ICU4C_TIME, &status);
111
112 int32_t lcidCount = 0;
113 Win32Utilities::LCIDRecord *lcidRecords = Win32Utilities::getLocales(lcidCount);
114
115 for(int i = 0; i < lcidCount; i += 1) {
116 UErrorCode status = U_ZERO_ERROR;
117 WCHAR longDateFormat[81], longTimeFormat[81], wdBuffer[256], wtBuffer[256];
118 int32_t calType = 0;
119
120 // NULL localeID means ICU didn't recognize this locale
121 if (lcidRecords[i].localeID == NULL) {
122 continue;
123 }
124
125 // Some locales have had their names change over various OS releases; skip them in the test for now.
126 int32_t failingLocaleLCIDs[] = {
127 0x040a, /* es-ES_tradnl;es-ES-u-co-trad; */
128 0x048c, /* fa-AF;prs-AF;prs-Arab-AF; */
129 0x046b, /* qu-BO;quz-BO;quz-Latn-BO; */
130 0x086b, /* qu-EC;quz-EC;quz-Latn-EC; */
131 0x0c6b, /* qu-PE;quz-PE;quz-Latn-PE; */
132 0x0492 /* ckb-IQ;ku-Arab-IQ; */
133 };
134 bool skip = (std::find(std::begin(failingLocaleLCIDs), std::end(failingLocaleLCIDs), lcidRecords[i].lcid) != std::end(failingLocaleLCIDs));
135 if (skip && log->logKnownIssue("13119", "Windows '@compat=host' fails on down-level versions of the OS")) {
136 log->logln("ticket:13119 - Skipping LCID = 0x%04x", lcidRecords[i].lcid);
137 continue;
138 }
139
140 GetLocaleInfoW(lcidRecords[i].lcid, LOCALE_SLONGDATE, longDateFormat, 81);
141 GetLocaleInfoW(lcidRecords[i].lcid, LOCALE_STIMEFORMAT, longTimeFormat, 81);
142 GetLocaleInfoW(lcidRecords[i].lcid, LOCALE_RETURN_NUMBER|LOCALE_ICALENDARTYPE, (LPWSTR) calType, sizeof(int32_t));
143
144 char localeID[64];
145
146 uprv_strcpy(localeID, lcidRecords[i].localeID);
147 uprv_strcat(localeID, getCalendarType(calType));
148
149 UnicodeString ubBuffer, udBuffer, utBuffer;
150 Locale ulocale(localeID);
151 int32_t wdLength, wtLength;
152
153 wdLength = GetDateFormatW(lcidRecords[i].lcid, DATE_LONGDATE, &winNow, NULL, wdBuffer, UPRV_LENGTHOF(wdBuffer));
154 wtLength = GetTimeFormatW(lcidRecords[i].lcid, 0, &winNow, NULL, wtBuffer, UPRV_LENGTHOF(wtBuffer));
155
156 if (uprv_strchr(localeID, '@') > 0) {
157 uprv_strcat(localeID, ";");
158 } else {
159 uprv_strcat(localeID, "@");
160 }
161
162 uprv_strcat(localeID, "compat=host");
163
164 Locale wlocale(localeID);
165 DateFormat *wbf = DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, wlocale);
166 DateFormat *wdf = DateFormat::createDateInstance(DateFormat::kFull, wlocale);
167 DateFormat *wtf = DateFormat::createTimeInstance(DateFormat::kFull, wlocale);
168
169 wbf->format(icuNow, ubBuffer);
170 wdf->format(icuNow, udBuffer);
171 wtf->format(icuNow, utBuffer);
172
173 if (ubBuffer.indexOf((const UChar *)wdBuffer, wdLength - 1, 0) < 0) {
174 UnicodeString baseName(wlocale.getBaseName());
175 UnicodeString expected((const UChar *)wdBuffer);
176
177 log->errln("DateTime format error for locale " + baseName + ": expected date \"" + expected +
178 "\" got \"" + ubBuffer + "\"");
179 }
180
181 if (ubBuffer.indexOf((const UChar *)wtBuffer, wtLength - 1, 0) < 0) {
182 UnicodeString baseName(wlocale.getBaseName());
183 UnicodeString expected((const UChar *)wtBuffer);
184
185 log->errln("DateTime format error for locale " + baseName + ": expected time \"" + expected +
186 "\" got \"" + ubBuffer + "\"");
187 }
188
189 if (udBuffer.compare((const UChar *)wdBuffer) != 0) {
190 UnicodeString baseName(wlocale.getBaseName());
191 UnicodeString expected((const UChar *)wdBuffer);
192
193 log->errln("Date format error for locale " + baseName + ": expected \"" + expected +
194 "\" got \"" + udBuffer + "\"");
195 }
196
197 if (utBuffer.compare((const UChar *)wtBuffer) != 0) {
198 UnicodeString baseName(wlocale.getBaseName());
199 UnicodeString expected((const UChar *)wtBuffer);
200
201 log->errln("Time format error for locale " + baseName + ": expected \"" + expected +
202 "\" got \"" + utBuffer + "\"");
203 }
204 delete wbf;
205 delete wdf;
206 delete wtf;
207 }
208
209 Win32Utilities::freeLocales(lcidRecords);
210 delete tz;
211 }
212
213 #endif /* #if !UCONFIG_NO_FORMATTING */
214
215 #endif /* U_PLATFORM_USES_ONLY_WIN32_API */
216