• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /********************************************************************
4  * COPYRIGHT:
5  * Copyright (c) 1997-2013 International Business Machines Corporation and
6  * others. All Rights Reserved.
7  ********************************************************************/
8 
9 /***********************************************************************
10  * Modification history
11  * Date        Name        Description
12  * 07/09/2007  srl         Copied from dadrcoll.cpp
13  ***********************************************************************/
14 
15 #include "unicode/utypes.h"
16 
17 #if !UCONFIG_NO_FORMATTING
18 
19 #include "unicode/tstdtmod.h"
20 #include "tsdate.h"
21 #include "dadrfmt.h"
22 #include "unicode/calendar.h"
23 #include "intltest.h"
24 #include <string.h>
25 #include "unicode/schriter.h"
26 #include "unicode/regex.h"
27 #include "unicode/smpdtfmt.h"
28 #include "dbgutil.h"
29 #include "fldset.h"
30 
31 
32 #include <stdio.h>
33 
DataDrivenFormatTest()34 DataDrivenFormatTest::DataDrivenFormatTest() {
35     UErrorCode status = U_ZERO_ERROR;
36     driver = TestDataModule::getTestDataModule("format", *this, status);
37 }
38 
~DataDrivenFormatTest()39 DataDrivenFormatTest::~DataDrivenFormatTest() {
40     delete driver;
41 }
42 
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)43 void DataDrivenFormatTest::runIndexedTest(int32_t index, UBool exec,
44         const char* &name, char* /*par */) {
45     if (driver != nullptr) {
46         if (exec) {
47             //  logln("Begin ");
48         }
49         const DataMap *info= nullptr;
50         UErrorCode status= U_ZERO_ERROR;
51         TestData *testData = driver->createTestData(index, status);
52         if (U_SUCCESS(status)) {
53             name = testData->getName();
54             if (testData->getInfo(info, status)) {
55                 log(info->getString("Description", status));
56             }
57             if (exec) {
58                 log(name);
59                 logln("---");
60                 logln("");
61 
62                 processTest(testData);
63             }
64             delete testData;
65         } else {
66             name = "";
67         }
68     } else {
69         dataerrln("format/DataDriven*Test data (format.res) not initialized!");
70         name = "";
71     }
72 
73 }
74 
75 
76 
77 /*
78  *             Headers { "locale", "zone", "spec", "date", "str"}
79             // locale: locale including calendar type
80             // zone:   time zone name, or "" to not explicitly set zone
81             // spec:   either 'PATTERN=y mm h' etc, or 'DATE=SHORT,TIME=LONG'
82             // date:   either an unsigned long (millis), or a calendar spec ERA=0,YEAR=1, etc.. applied to the calendar type specified by the locale
83             // str:   the expected unicode string
84             Cases {
85                {
86                     "en_US@calendar=gregorian",
87                     "",
88                     "DATE=SHORT,TIME=SHORT",
89                     "ERA=1,YEAR=2007,MONTH=AUGUST,DATE=8,HOUR=18,MINUTE=54,SECOND=12",
90                     "8/8/2007 6:54pm"
91                },
92  * */
93 
94 
testConvertDate(TestData * testData,const DataMap *,UBool fmt)95 void DataDrivenFormatTest::testConvertDate(TestData *testData,
96         const DataMap * /* settings */, UBool fmt) {
97     UnicodeString kPATTERN("PATTERN="); // TODO: static
98     UnicodeString kMILLIS("MILLIS="); // TODO: static
99     UnicodeString kRELATIVE_MILLIS("RELATIVE_MILLIS="); // TODO: static
100     UnicodeString kRELATIVE_ADD("RELATIVE_ADD:"); // TODO: static
101 
102     UErrorCode status = U_ZERO_ERROR;
103     SimpleDateFormat basicFmt(UnicodeString("EEE MMM dd yyyy / YYYY'-W'ww-ee"),
104             status);
105     if (U_FAILURE(status)) {
106         dataerrln("FAIL: Couldn't create basic SimpleDateFormat: %s",
107                 u_errorName(status));
108         return;
109     }
110 
111     const DataMap *currentCase= nullptr;
112     // Start the processing
113     int n = 0;
114     while (testData->nextCase(currentCase, status)) {
115         char calLoc[256] = "";
116         DateTimeStyleSet styleSet;
117         UnicodeString pattern;
118         UBool usePattern = false;
119         (void)usePattern;   // Suppress unused warning.
120         CalendarFieldsSet fromSet;
121         UDate fromDate = 0;
122         UBool useDate = false;
123 
124         UDate now = Calendar::getNow();
125 
126         ++n;
127 
128         char theCase[200];
129         snprintf(theCase, sizeof(theCase), "case %d:", n);
130         UnicodeString caseString(theCase, "");
131 
132         // load params
133         UnicodeString locale = currentCase->getString("locale", status);
134         if (U_FAILURE(status)) {
135             errln("case %d: No 'locale' line.", n);
136             continue;
137         }
138         UnicodeString zone = currentCase->getString("zone", status);
139         if (U_FAILURE(status)) {
140             errln("case %d: No 'zone' line.", n);
141             continue;
142         }
143         UnicodeString spec = currentCase->getString("spec", status);
144         if(U_FAILURE(status)) {
145             errln("case %d: No 'spec' line.", n);
146             continue;
147         }
148         UnicodeString date = currentCase->getString("date", status);
149         if(U_FAILURE(status)) {
150             errln("case %d: No 'date' line.", n);
151             continue;
152         }
153         UnicodeString expectStr= currentCase->getString("str", status);
154         if(U_FAILURE(status)) {
155             errln("case %d: No 'str' line.", n);
156             continue;
157         }
158 
159         DateFormat *format = nullptr;
160 
161         // Process: 'locale'
162         locale.extract(0, locale.length(), calLoc, (const char*)nullptr); // default codepage.  Invariant codepage doesn't have '@'!
163         Locale loc(calLoc);
164         if(spec.startsWith(kPATTERN)) {
165             pattern = UnicodeString(spec,kPATTERN.length());
166             usePattern = true;
167             format = new SimpleDateFormat(pattern, loc, status);
168             if(U_FAILURE(status)) {
169                 errln("case %d: could not create SimpleDateFormat from pattern: %s", n, u_errorName(status));
170                 continue;
171             }
172         } else {
173             if(styleSet.parseFrom(spec, status)<0 || U_FAILURE(status)) {
174                 errln("case %d: could not parse spec as style fields: %s", n, u_errorName(status));
175                 continue;
176             }
177             format = DateFormat::createDateTimeInstance(
178                 static_cast<DateFormat::EStyle>(styleSet.getDateStyle()),
179                 static_cast<DateFormat::EStyle>(styleSet.getTimeStyle()), loc);
180             if(format == nullptr ) {
181                 errln("case %d: could not create SimpleDateFormat from styles.", n);
182                 continue;
183             }
184         }
185 
186         Calendar *cal = Calendar::createInstance(loc, status);
187         if(U_FAILURE(status)) {
188             errln("case %d: could not create calendar from %s", n, calLoc);
189         }
190 
191         if (zone.length() > 0) {
192             TimeZone * tz = TimeZone::createTimeZone(zone);
193             cal->setTimeZone(*tz);
194             format->setTimeZone(*tz);
195             delete tz;
196         }
197 
198         // parse 'date'
199         if(date.startsWith(kMILLIS)) {
200             UnicodeString millis = UnicodeString(date, kMILLIS.length());
201             useDate = true;
202             fromDate = udbg_stod(millis);
203         } else if(date.startsWith(kRELATIVE_MILLIS)) {
204             UnicodeString millis = UnicodeString(date, kRELATIVE_MILLIS.length());
205             useDate = true;
206             fromDate = udbg_stod(millis) + now;
207         } else if(date.startsWith(kRELATIVE_ADD)) {
208             UnicodeString add = UnicodeString(date, kRELATIVE_ADD.length());  // "add" is a string indicating which fields to add
209             if(fromSet.parseFrom(add, status)<0 || U_FAILURE(status)) {
210                 errln("case %d: could not parse date as RELATIVE_ADD calendar fields: %s", n, u_errorName(status));
211                 continue;
212             }
213             useDate=true;
214             cal->clear();
215             cal->setTime(now, status);
216             for (int q=0; q<UCAL_FIELD_COUNT; q++) {
217                 if (fromSet.isSet(static_cast<UCalendarDateFields>(q))) {
218                     //int32_t oldv = cal->get((UCalendarDateFields)q, status);
219                     if (q == UCAL_DATE) {
220                         cal->add(static_cast<UCalendarDateFields>(q),
221                                  fromSet.get(static_cast<UCalendarDateFields>(q)), status);
222                     } else {
223                         cal->set(static_cast<UCalendarDateFields>(q),
224                                  fromSet.get(static_cast<UCalendarDateFields>(q)));
225                     }
226                     //int32_t newv = cal->get((UCalendarDateFields)q, status);
227                 }
228             }
229             fromDate = cal->getTime(status);
230             if(U_FAILURE(status)) {
231                 errln("case %d: could not apply date as RELATIVE_ADD calendar fields: %s", n, u_errorName(status));
232                 continue;
233             }
234         } else if(fromSet.parseFrom(date, status)<0 || U_FAILURE(status)) {
235             errln("case %d: could not parse date as calendar fields: %s", n, u_errorName(status));
236             continue;
237         }
238 
239         // now, do it.
240         if (fmt) {
241             FieldPosition pos;
242 //            logln((UnicodeString)"#"+n+" "+locale+"/"+from+" >>> "+toCalLoc+"/"
243 //                    +to);
244             cal->clear();
245             UnicodeString output;
246             output.remove();
247 
248             if(useDate) {
249 //                cal->setTime(fromDate, status);
250 //                if(U_FAILURE(status)) {
251 //                    errln("case %d: could not set time on calendar: %s", n, u_errorName(status));
252 //                    continue;
253 //                }
254                 format->format(fromDate, output, pos, status);
255             } else {
256                 fromSet.setOnCalendar(cal, status);
257                 if(U_FAILURE(status)) {
258                     errln("case %d: could not set fields on calendar: %s", n, u_errorName(status));
259                     continue;
260                 }
261                 format->format(*cal, output, pos);
262             }
263 
264             // check erro result from 'format'
265             if(U_FAILURE(status)) {
266                 errln("case %d: could not format(): %s", n, u_errorName(status)); // TODO: use 'pos'
267             }
268 //            if(pos.getBeginIndex()==0 && pos.getEndIndex()==0) { // TODO: more precise error?
269 //                errln("WARNING: case %d: format's pos returned (0,0) - error ??", n);
270 //            }
271 
272             if(output == expectStr) {
273                 logln(caseString+": format: SUCCESS! "+UnicodeString("expect=output=")+output);
274             } else {
275                 UnicodeString result;
276                 UnicodeString result2;
277                 errln(caseString+": format:  output!=expectStr, got " + *udbg_escape(output, &result) + " expected " + *udbg_escape(expectStr, &result2));
278             }
279         } else {
280             cal->clear();
281             ParsePosition pos;
282             format->parse(expectStr,*cal,pos);
283             if(useDate) {
284                 UDate gotDate = cal->getTime(status);
285                 if(U_FAILURE(status)) {
286                     errln(caseString+": parse: could not get time on calendar: "+UnicodeString(u_errorName(status)));
287                     continue;
288                 }
289                 if(gotDate == fromDate) {
290                     logln(caseString+": parse: SUCCESS! "+UnicodeString("gotDate=parseDate=")+expectStr);
291                 } else {
292                     UnicodeString expectDateStr, gotDateStr;
293                     basicFmt.format(fromDate,expectDateStr);
294                     basicFmt.format(gotDate,gotDateStr);
295                     errln(caseString+": parse: FAIL. parsed '"+expectStr+"' and got "+gotDateStr+", expected " + expectDateStr);
296                 }
297             } else {
298 //                Calendar *cal2 = cal->clone();
299 //                cal2->clear();
300 //                fromSet.setOnCalendar(cal2, status);
301                 if(U_FAILURE(status)) {
302                     errln("case %d: parse: could not set fields on calendar: %s", n, u_errorName(status));
303                     continue;
304                 }
305 
306                 CalendarFieldsSet diffSet;
307 //                diffSet.clear();
308                 if (!fromSet.matches(cal, diffSet, status)) {
309                     UnicodeString diffs = diffSet.diffFrom(fromSet, status);
310                     errln(UnicodeString("FAIL: ") + caseString
311                             +", Differences: '"+ diffs
312                             +"', status: "+ u_errorName(status));
313                 } else if (U_FAILURE(status)) {
314                     errln("FAIL: "+caseString+" parse SET SOURCE calendar Failed to match: "
315                             +u_errorName(status));
316                 } else {
317                     logln("PASS: "+caseString+" parse.");
318                 }
319 
320 
321 
322             }
323         }
324         delete cal;
325         delete format;
326 
327     }
328 //    delete basicFmt;
329 }
330 
processTest(TestData * testData)331 void DataDrivenFormatTest::processTest(TestData *testData) {
332     //Format *cal= nullptr;
333     //const char16_t *arguments= nullptr;
334     //int32_t argLen = 0;
335     char testType[256] = "";
336     const DataMap *settings= nullptr;
337     //const char16_t *type= nullptr;
338     UErrorCode status = U_ZERO_ERROR;
339     UnicodeString testSetting;
340     int n = 0;
341     while (testData->nextSettings(settings, status)) {
342         status = U_ZERO_ERROR;
343         // try to get a locale
344         testSetting = settings->getString("Type", status);
345         if (U_SUCCESS(status)) {
346             if ((++n)>0) {
347                 logln("---");
348             }
349             logln(testSetting + "---");
350             testSetting.extract(0, testSetting.length(), testType, "");
351         } else {
352             errln("Unable to extract 'Type'. Skipping..");
353             continue;
354         }
355 
356         if (!strcmp(testType, "date_format")) {
357             testConvertDate(testData, settings, true);
358         } else if (!strcmp(testType, "date_parse")) {
359             testConvertDate(testData, settings, false);
360         } else {
361             errln("Unknown type: %s", testType);
362         }
363     }
364 }
365 
366 #endif
367