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
48static 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
73void 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