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