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-2010, 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 "dadrcal.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
30#include <stdio.h>
31
32DataDrivenCalendarTest::DataDrivenCalendarTest() {
33    UErrorCode status = U_ZERO_ERROR;
34    driver = TestDataModule::getTestDataModule("calendar", *this, status);
35}
36
37DataDrivenCalendarTest::~DataDrivenCalendarTest() {
38    delete driver;
39}
40
41void DataDrivenCalendarTest::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 (calendar.res) not initialized!");
68        name = "";
69    }
70
71}
72
73void DataDrivenCalendarTest::testOps(TestData *testData,
74        const DataMap * /*settings*/) {
75    UErrorCode status = U_ZERO_ERROR;
76    UBool useDate = FALSE; // TODO
77    UnicodeString kMILLIS("MILLIS="); // TODO: static
78    UDate fromDate = 0; // TODO
79    UDate toDate = 0;
80
81    const DataMap *currentCase= NULL;
82    char toCalLoc[256] = "";
83
84    // TODO: static strings?
85    const UnicodeString kADD("add", "");
86    const UnicodeString kROLL("roll", "");
87
88    // Get 'from' time
89    CalendarFieldsSet fromSet, toSet, paramsSet, diffSet;
90    SimpleDateFormat fmt(UnicodeString("EEE MMM dd yyyy / YYYY'-W'ww-ee"),
91            status);
92    if (U_FAILURE(status)) {
93        dataerrln("FAIL: Couldn't create SimpleDateFormat: %s",
94                u_errorName(status));
95        return;
96    }
97    // Start the processing
98    int n = 0;
99    while (testData->nextCase(currentCase, status)) {
100        ++n;
101        Calendar *toCalendar= NULL;
102        Calendar *fromCalendar= NULL;
103
104        // load parameters
105        char theCase[200];
106        sprintf(theCase, "[case %d]", n);
107        UnicodeString caseString(theCase, "");
108        // build to calendar
109        //             Headers { "locale","from","operation","params","to" }
110        // #1 locale
111        const char *param = "locale";
112        UnicodeString locale;
113        UnicodeString testSetting = currentCase->getString(param, status);
114        if (U_FAILURE(status)) {
115            errln(caseString+": Unable to get param '"+param+"' "
116                    + UnicodeString(" - "));
117            continue;
118        }
119        testSetting.extract(0, testSetting.length(), toCalLoc, (const char*)0);
120        fromCalendar = Calendar::createInstance(toCalLoc, status);
121        if (U_FAILURE(status)) {
122            errln(caseString+": Unable to instantiate calendar for "
123                    +testSetting);
124            continue;
125        }
126
127        fromSet.clear();
128        // #2 'from' info
129        param = "from";
130        UnicodeString from = testSetting=currentCase->getString(param, status);
131        if (U_FAILURE(status)) {
132            errln(caseString+": Unable to get parameter '"+param+"' "
133                    + UnicodeString(" - "));
134            continue;
135        }
136
137        if(from.startsWith(kMILLIS)){
138        	UnicodeString millis = UnicodeString(from, kMILLIS.length());
139        	useDate = TRUE;
140        	fromDate = udbg_stod(millis);
141        } else if(fromSet.parseFrom(testSetting, status)<0 || U_FAILURE(status)){
142        	errln(caseString+": Failed to parse '"+param+"' parameter: "
143        	                    +testSetting);
144        	            continue;
145        }
146
147        // #4 'operation' info
148        param = "operation";
149        UnicodeString operation = testSetting=currentCase->getString(param,
150                status);
151        if (U_FAILURE(status)) {
152            errln(caseString+": Unable to get parameter '"+param+"' "
153                    + UnicodeString(" - "));
154            continue;
155        }
156        if (U_FAILURE(status)) {
157            errln(caseString+": Failed to parse '"+param+"' parameter: "
158                    +testSetting);
159            continue;
160        }
161
162        paramsSet.clear();
163        // #3 'params' info
164        param = "params";
165        UnicodeString params = testSetting
166                =currentCase->getString(param, status);
167        if (U_FAILURE(status)) {
168            errln(caseString+": Unable to get parameter '"+param+"' "
169                    + UnicodeString(" - "));
170            continue;
171        }
172        paramsSet.parseFrom(testSetting, status); // parse with inheritance.
173        if (U_FAILURE(status)) {
174            errln(caseString+": Failed to parse '"+param+"' parameter: "
175                    +testSetting);
176            continue;
177        }
178
179        toSet.clear();
180        // #4 'to' info
181        param = "to";
182        UnicodeString to = testSetting=currentCase->getString(param, status);
183        if (U_FAILURE(status)) {
184            errln(caseString+": Unable to get parameter '"+param+"' "
185                    + UnicodeString(" - "));
186            continue;
187        }
188        if(to.startsWith(kMILLIS)){
189        	UnicodeString millis = UnicodeString(to, kMILLIS.length());
190            useDate = TRUE;
191            toDate = udbg_stod(millis);
192        } else if(toSet.parseFrom(testSetting, &fromSet, status)<0 || U_FAILURE(status)){
193            errln(caseString+": Failed to parse '"+param+"' parameter: "
194                   +testSetting);
195            continue;
196        }
197
198        UnicodeString caseContentsString = locale+":  from "+from+": "
199                +operation +" [[[ "+params+" ]]]   >>> "+to;
200        logln(caseString+": "+caseContentsString);
201
202        // ------
203        // now, do it.
204
205        /// prepare calendar
206        if(useDate){
207        	fromCalendar->setTime(fromDate, status);
208        	if (U_FAILURE(status)) {
209        	        	            errln(caseString+" FAIL: Failed to set time on Source calendar: "
210        	        	                    + u_errorName(status));
211        	        	            return;
212        	        	        }
213        } else {
214        	fromSet.setOnCalendar(fromCalendar, status);
215        	        if (U_FAILURE(status)) {
216        	            errln(caseString+" FAIL: Failed to set on Source calendar: "
217        	                    + u_errorName(status));
218        	            return;
219        	        }
220        }
221
222        diffSet.clear();
223        // Is the calendar sane after being set?
224        if (!fromSet.matches(fromCalendar, diffSet, status)) {
225            UnicodeString diffs = diffSet.diffFrom(fromSet, status);
226            errln((UnicodeString)"FAIL: "+caseString
227                    +", SET SOURCE calendar was not set: Differences: "+ diffs
228                    +"', status: "+ u_errorName(status));
229        } else if (U_FAILURE(status)) {
230            errln("FAIL: "+caseString+" SET SOURCE calendar Failed to match: "
231                    +u_errorName(status));
232        } else {
233            logln("PASS: "+caseString+" SET SOURCE calendar match.");
234        }
235
236        // to calendar - copy of from calendar
237        toCalendar = fromCalendar->clone();
238
239        /// perform op
240        for (int q=0; q<UCAL_FIELD_COUNT; q++) {
241            if (paramsSet.isSet((UCalendarDateFields)q)) {
242                if (operation == kROLL) {
243                    toCalendar->roll((UCalendarDateFields)q,
244                            paramsSet.get((UCalendarDateFields)q), status);
245                } else if (operation == kADD) {
246                    toCalendar->add((UCalendarDateFields)q,
247                            paramsSet.get((UCalendarDateFields)q), status);
248                } else {
249                    errln(caseString+ " FAIL: unknown operation "+ operation);
250                }
251                logln(operation + " of "+ paramsSet.get((UCalendarDateFields)q)
252                        +" -> "+u_errorName(status));
253            }
254        }
255        if (U_FAILURE(status)) {
256            errln(caseString+" FAIL: after "+operation+" of "+params+" -> "
257                    +u_errorName(status));
258            continue;
259        }
260
261        // now - what's the result?
262        diffSet.clear();
263
264        if(useDate){
265        	if(!(toCalendar->getTime(status)==toDate) || U_FAILURE(status)){
266        		errln("FAIL: "+caseString+" Match operation had an error: "
267        		                    +u_errorName(status));
268        	}else{
269        		logln(caseString + " SUCCESS: got=expected="+toDate);
270        		logln("PASS: "+caseString+" matched!");
271        	}
272        } else if (!toSet.matches(toCalendar, diffSet, status)) {
273            UnicodeString diffs = diffSet.diffFrom(toSet, status);
274            errln((UnicodeString)"FAIL: "+caseString+" - , "+caseContentsString
275                    +" Differences: "+ diffs +"', status: "
276                    + u_errorName(status));
277        }else if (U_FAILURE(status)) {
278            errln("FAIL: "+caseString+" Match operation had an error: "
279                    +u_errorName(status));
280        }else {
281            logln("PASS: "+caseString+" matched!");
282        }
283
284        delete fromCalendar;
285        delete toCalendar;
286    }
287}
288
289void DataDrivenCalendarTest::testConvert(int32_t n,
290        const CalendarFieldsSet &fromSet, Calendar *fromCalendar,
291        const CalendarFieldsSet &toSet, Calendar *toCalendar, UBool forward) {
292    UErrorCode status = U_ZERO_ERROR;
293    UnicodeString thisString = (UnicodeString)"#"+n+" "+(forward ? "forward"
294            : "reverse")+" "+fromCalendar->getType()+"->"+toCalendar->getType();
295
296    fromCalendar->clear();
297
298    fromSet.setOnCalendar(fromCalendar, status);
299    if (U_FAILURE(status)) {
300        errln("FAIL: Failed to set on Source calendar: %s", u_errorName(status));
301        return;
302    }
303
304    CalendarFieldsSet diffSet;
305
306    diffSet.clear();
307    // Is the calendar sane at the first?
308    if (!fromSet.matches(fromCalendar, diffSet, status)) {
309        UnicodeString diffs = diffSet.diffFrom(fromSet, status);
310        errln((UnicodeString)"FAIL: "+thisString
311                +", SOURCE calendar was not set: Differences: "+ diffs
312                +"', status: "+ u_errorName(status));
313    } else if (U_FAILURE(status)) {
314        errln("FAIL: "+thisString+" SOURCE calendar Failed to match: "
315                +u_errorName(status));
316    } else {
317        logln("PASS: "+thisString+" SOURCE calendar match.");
318    }
319
320    //logln("Set Source calendar: " + from);
321
322    UDate fromTime = fromCalendar->getTime(status);
323    if (U_FAILURE(status)) {
324        errln("FAIL: Failed to get Source time: %s", u_errorName(status));
325        return;
326    }
327
328    diffSet.clear();
329    // Is the calendar sane after being set?
330    if (!fromSet.matches(fromCalendar, diffSet, status)) {
331        UnicodeString diffs = diffSet.diffFrom(fromSet, status);
332        errln((UnicodeString)"FAIL: "+thisString
333                +", SET SOURCE calendar was not set: Differences: "+ diffs
334                +"', status: "+ u_errorName(status));
335    } else if (U_FAILURE(status)) {
336        errln("FAIL: "+thisString+" SET SOURCE calendar Failed to match: "
337                +u_errorName(status));
338    } else {
339        logln("PASS: "+thisString+" SET SOURCE calendar match.");
340    }
341
342    toCalendar->clear();
343    toCalendar->setTime(fromTime, status);
344    if (U_FAILURE(status)) {
345        errln("FAIL: Failed to set Target time: %s", u_errorName(status));
346        return;
347    }
348
349    diffSet.clear();
350    if (!toSet.matches(toCalendar, diffSet, status)) {
351        UnicodeString diffs = diffSet.diffFrom(toSet, status);
352        errln((UnicodeString)"FAIL: "+thisString+", Differences: "+ diffs
353                +"', status: "+ u_errorName(status));
354        SimpleDateFormat fmt(UnicodeString("EEE MMM dd yyyy G"), status);
355        UnicodeString fromString;
356        fmt.format(fromTime, fromString);
357        logln("Source Time: "+fromString+", Source Calendar: "
358                +fromCalendar->getType());
359    } else if (U_FAILURE(status)) {
360        errln("FAIL: "+thisString+" Failed to match: "+u_errorName(status));
361    } else {
362        logln("PASS: "+thisString+" match.");
363    }
364}
365
366void DataDrivenCalendarTest::testConvert(TestData *testData,
367        const DataMap *settings, UBool forward) {
368    UErrorCode status = U_ZERO_ERROR;
369    Calendar *toCalendar= NULL;
370    const DataMap *currentCase= NULL;
371    char toCalLoc[256] = "";
372    char fromCalLoc[256] = "";
373    // build to calendar
374    UnicodeString testSetting = settings->getString("ToCalendar", status);
375    if (U_SUCCESS(status)) {
376        testSetting.extract(0, testSetting.length(), toCalLoc, (const char*)0);
377        toCalendar = Calendar::createInstance(toCalLoc, status);
378        if (U_FAILURE(status)) {
379            dataerrln(UnicodeString("Unable to instantiate ToCalendar for ")+testSetting);
380            return;
381        }
382    }
383
384    CalendarFieldsSet fromSet, toSet, diffSet;
385    SimpleDateFormat fmt(UnicodeString("EEE MMM dd yyyy / YYYY'-W'ww-ee"),
386            status);
387    if (U_FAILURE(status)) {
388        errcheckln(status, "FAIL: Couldn't create SimpleDateFormat: %s",
389                u_errorName(status));
390        return;
391    }
392    // Start the processing
393    int n = 0;
394    while (testData->nextCase(currentCase, status)) {
395        ++n;
396        Calendar *fromCalendar= NULL;
397        UnicodeString locale = currentCase->getString("locale", status);
398        if (U_SUCCESS(status)) {
399            locale.extract(0, locale.length(), fromCalLoc, (const char*)0); // default codepage.  Invariant codepage doesn't have '@'!
400            fromCalendar = Calendar::createInstance(fromCalLoc, status);
401            if (U_FAILURE(status)) {
402                errln("Unable to instantiate fromCalendar for "+locale);
403                return;
404            }
405        } else {
406            errln("No 'locale' line.");
407            continue;
408        }
409
410        fromSet.clear();
411        toSet.clear();
412
413        UnicodeString from = currentCase->getString("from", status);
414        if (U_FAILURE(status)) {
415            errln("No 'from' line.");
416            continue;
417        }
418        fromSet.parseFrom(from, status);
419        if (U_FAILURE(status)) {
420            errln("Failed to parse 'from' parameter: "+from);
421            continue;
422        }
423        UnicodeString to = currentCase->getString("to", status);
424        if (U_FAILURE(status)) {
425            errln("No 'to' line.");
426            continue;
427        }
428        toSet.parseFrom(to, &fromSet, status);
429        if (U_FAILURE(status)) {
430            errln("Failed to parse 'to' parameter: "+to);
431            continue;
432        }
433
434        // now, do it.
435        if (forward) {
436            logln((UnicodeString)"#"+n+" "+locale+"/"+from+" >>> "+toCalLoc+"/"
437                    +to);
438            testConvert(n, fromSet, fromCalendar, toSet, toCalendar, forward);
439        } else {
440            logln((UnicodeString)"#"+n+" "+locale+"/"+from+" <<< "+toCalLoc+"/"
441                    +to);
442            testConvert(n, toSet, toCalendar, fromSet, fromCalendar, forward);
443        }
444
445        delete fromCalendar;
446    }
447    delete toCalendar;
448}
449
450void DataDrivenCalendarTest::processTest(TestData *testData) {
451    //Calendar *cal= NULL;
452    //const UChar *arguments= NULL;
453    //int32_t argLen = 0;
454    char testType[256];
455    const DataMap *settings= NULL;
456    //const UChar *type= NULL;
457    UErrorCode status = U_ZERO_ERROR;
458    UnicodeString testSetting;
459    int n = 0;
460    while (testData->nextSettings(settings, status)) {
461        status = U_ZERO_ERROR;
462        // try to get a locale
463        testSetting = settings->getString("Type", status);
464        if (U_SUCCESS(status)) {
465            if ((++n)>0) {
466                logln("---");
467            }
468            logln(testSetting + "---");
469            testSetting.extract(0, testSetting.length(), testType, "");
470        } else {
471            errln("Unable to extract 'Type'. Skipping..");
472            continue;
473        }
474
475        if (!strcmp(testType, "convert_fwd")) {
476            testConvert(testData, settings, true);
477        } else if (!strcmp(testType, "convert_rev")) {
478            testConvert(testData, settings, false);
479        } else if (!strcmp(testType, "ops")) {
480            testOps(testData, settings);
481        } else {
482            errln("Unknown type: %s", testType);
483        }
484    }
485}
486
487#endif
488