1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /********************************************************************
5 * Copyright (c) 1997-2013 International Business Machines Corporation and
6 * others. All Rights Reserved.
7 ********************************************************************/
9 /***********************************************************************
10 * Modification history
11 * Date Name Description
12 * 07/09/2007 srl Copied from dadrcoll.cpp
13 ***********************************************************************/
15 #include "unicode/utypes.h"
17 #if !UCONFIG_NO_FORMATTING
19 #include "unicode/tstdtmod.h"
22 #include "unicode/calendar.h"
25 #include "unicode/schriter.h"
26 #include "unicode/regex.h"
27 #include "unicode/smpdtfmt.h"
34 DataDrivenFormatTest::DataDrivenFormatTest() {
35 UErrorCode status
= U_ZERO_ERROR
;
36 driver
= TestDataModule::getTestDataModule("format", *this, status
);
39 DataDrivenFormatTest::~DataDrivenFormatTest() {
43 void DataDrivenFormatTest::runIndexedTest(int32_t index
, UBool exec
,
44 const char* &name
, char* /*par */) {
49 const DataMap
*info
= NULL
;
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
));
62 processTest(testData
);
69 dataerrln("format/DataDriven*Test data (format.res) not initialized!");
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
86 "en_US@calendar=gregorian",
88 "DATE=SHORT,TIME=SHORT",
89 "ERA=1,YEAR=2007,MONTH=AUGUST,DATE=8,HOUR=18,MINUTE=54,SECOND=12",
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
102 UErrorCode status
= U_ZERO_ERROR
;
103 SimpleDateFormat
basicFmt(UnicodeString("EEE MMM dd yyyy / YYYY'-W'ww-ee"),
105 if (U_FAILURE(status
)) {
106 dataerrln("FAIL: Couldn't create basic SimpleDateFormat: %s",
107 u_errorName(status
));
111 const DataMap
*currentCase
= NULL
;
112 // Start the processing
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
;
122 UBool useDate
= FALSE
;
124 UDate now
= Calendar::getNow();
129 sprintf(theCase
, "case %d:", n
);
130 UnicodeString
caseString(theCase
, "");
133 UnicodeString locale
= currentCase
->getString("locale", status
);
134 if (U_FAILURE(status
)) {
135 errln("case %d: No 'locale' line.", n
);
138 UnicodeString zone
= currentCase
->getString("zone", status
);
139 if (U_FAILURE(status
)) {
140 errln("case %d: No 'zone' line.", n
);
143 UnicodeString spec
= currentCase
->getString("spec", status
);
144 if(U_FAILURE(status
)) {
145 errln("case %d: No 'spec' line.", n
);
148 UnicodeString date
= currentCase
->getString("date", status
);
149 if(U_FAILURE(status
)) {
150 errln("case %d: No 'date' line.", n
);
153 UnicodeString expectStr
= currentCase
->getString("str", status
);
154 if(U_FAILURE(status
)) {
155 errln("case %d: No 'str' line.", n
);
159 DateFormat
*format
= NULL
;
162 locale
.extract(0, locale
.length(), calLoc
, (const char*)0); // default codepage. Invariant codepage doesn't have '@'!
164 if(spec
.startsWith(kPATTERN
)) {
165 pattern
= UnicodeString(spec
,kPATTERN
.length());
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
));
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
));
177 format
= DateFormat::createDateTimeInstance((DateFormat::EStyle
)styleSet
.getDateStyle(), (DateFormat::EStyle
)styleSet
.getTimeStyle(), loc
);
178 if(format
== NULL
) {
179 errln("case %d: could not create SimpleDateFormat from styles.", n
);
184 Calendar
*cal
= Calendar::createInstance(loc
, status
);
185 if(U_FAILURE(status
)) {
186 errln("case %d: could not create calendar from %s", n
, calLoc
);
189 if (zone
.length() > 0) {
190 TimeZone
* tz
= TimeZone::createTimeZone(zone
);
191 cal
->setTimeZone(*tz
);
192 format
->setTimeZone(*tz
);
197 if(date
.startsWith(kMILLIS
)) {
198 UnicodeString millis
= UnicodeString(date
, kMILLIS
.length());
200 fromDate
= udbg_stod(millis
);
201 } else if(date
.startsWith(kRELATIVE_MILLIS
)) {
202 UnicodeString millis
= UnicodeString(date
, kRELATIVE_MILLIS
.length());
204 fromDate
= udbg_stod(millis
) + now
;
205 } else if(date
.startsWith(kRELATIVE_ADD
)) {
206 UnicodeString add
= UnicodeString(date
, kRELATIVE_ADD
.length()); // "add" is a string indicating which fields to add
207 if(fromSet
.parseFrom(add
, status
)<0 || U_FAILURE(status
)) {
208 errln("case %d: could not parse date as RELATIVE_ADD calendar fields: %s", n
, u_errorName(status
));
213 cal
->setTime(now
, status
);
214 for (int q
=0; q
<UCAL_FIELD_COUNT
; q
++) {
215 if (fromSet
.isSet((UCalendarDateFields
)q
)) {
216 //int32_t oldv = cal->get((UCalendarDateFields)q, status);
217 if (q
== UCAL_DATE
) {
218 cal
->add((UCalendarDateFields
)q
,
219 fromSet
.get((UCalendarDateFields
)q
), status
);
221 cal
->set((UCalendarDateFields
)q
,
222 fromSet
.get((UCalendarDateFields
)q
));
224 //int32_t newv = cal->get((UCalendarDateFields)q, status);
227 fromDate
= cal
->getTime(status
);
228 if(U_FAILURE(status
)) {
229 errln("case %d: could not apply date as RELATIVE_ADD calendar fields: %s", n
, u_errorName(status
));
232 } else if(fromSet
.parseFrom(date
, status
)<0 || U_FAILURE(status
)) {
233 errln("case %d: could not parse date as calendar fields: %s", n
, u_errorName(status
));
240 // logln((UnicodeString)"#"+n+" "+locale+"/"+from+" >>> "+toCalLoc+"/"
243 UnicodeString output
;
247 // cal->setTime(fromDate, status);
248 // if(U_FAILURE(status)) {
249 // errln("case %d: could not set time on calendar: %s", n, u_errorName(status));
252 format
->format(fromDate
, output
, pos
, status
);
254 fromSet
.setOnCalendar(cal
, status
);
255 if(U_FAILURE(status
)) {
256 errln("case %d: could not set fields on calendar: %s", n
, u_errorName(status
));
259 format
->format(*cal
, output
, pos
);
262 // check erro result from 'format'
263 if(U_FAILURE(status
)) {
264 errln("case %d: could not format(): %s", n
, u_errorName(status
)); // TODO: use 'pos'
266 // if(pos.getBeginIndex()==0 && pos.getEndIndex()==0) { // TODO: more precise error?
267 // errln("WARNING: case %d: format's pos returned (0,0) - error ??", n);
270 if(output
== expectStr
) {
271 logln(caseString
+": format: SUCCESS! "+UnicodeString("expect=output=")+output
);
273 UnicodeString result
;
274 UnicodeString result2
;
275 errln(caseString
+": format: output!=expectStr, got " + *udbg_escape(output
, &result
) + " expected " + *udbg_escape(expectStr
, &result2
));
280 format
->parse(expectStr
,*cal
,pos
);
282 UDate gotDate
= cal
->getTime(status
);
283 if(U_FAILURE(status
)) {
284 errln(caseString
+": parse: could not get time on calendar: "+UnicodeString(u_errorName(status
)));
287 if(gotDate
== fromDate
) {
288 logln(caseString
+": parse: SUCCESS! "+UnicodeString("gotDate=parseDate=")+expectStr
);
290 UnicodeString expectDateStr
, gotDateStr
;
291 basicFmt
.format(fromDate
,expectDateStr
);
292 basicFmt
.format(gotDate
,gotDateStr
);
293 errln(caseString
+": parse: FAIL. parsed '"+expectStr
+"' and got "+gotDateStr
+", expected " + expectDateStr
);
296 // Calendar *cal2 = cal->clone();
298 // fromSet.setOnCalendar(cal2, status);
299 if(U_FAILURE(status
)) {
300 errln("case %d: parse: could not set fields on calendar: %s", n
, u_errorName(status
));
304 CalendarFieldsSet diffSet
;
306 if (!fromSet
.matches(cal
, diffSet
, status
)) {
307 UnicodeString diffs
= diffSet
.diffFrom(fromSet
, status
);
308 errln((UnicodeString
)"FAIL: "+caseString
309 +", Differences: '"+ diffs
310 +"', status: "+ u_errorName(status
));
311 } else if (U_FAILURE(status
)) {
312 errln("FAIL: "+caseString
+" parse SET SOURCE calendar Failed to match: "
313 +u_errorName(status
));
315 logln("PASS: "+caseString
+" parse.");
329 void DataDrivenFormatTest::processTest(TestData
*testData
) {
331 //const UChar *arguments= NULL;
332 //int32_t argLen = 0;
334 const DataMap
*settings
= NULL
;
335 //const UChar *type= NULL;
336 UErrorCode status
= U_ZERO_ERROR
;
337 UnicodeString testSetting
;
339 while (testData
->nextSettings(settings
, status
)) {
340 status
= U_ZERO_ERROR
;
341 // try to get a locale
342 testSetting
= settings
->getString("Type", status
);
343 if (U_SUCCESS(status
)) {
347 logln(testSetting
+ "---");
348 testSetting
.extract(0, testSetting
.length(), testType
, "");
350 errln("Unable to extract 'Type'. Skipping..");
354 if (!strcmp(testType
, "date_format")) {
355 testConvertDate(testData
, settings
, true);
356 } else if (!strcmp(testType
, "date_parse")) {
357 testConvertDate(testData
, settings
, false);
359 errln("Unknown type: %s", testType
);