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
DataDrivenFormatTest()32 DataDrivenFormatTest::DataDrivenFormatTest() {
33 UErrorCode status = U_ZERO_ERROR;
34 driver = TestDataModule::getTestDataModule("format", *this, status);
35 }
36
~DataDrivenFormatTest()37 DataDrivenFormatTest::~DataDrivenFormatTest() {
38 delete driver;
39 }
40
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)41 void 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
testConvertDate(TestData * testData,const DataMap *,UBool fmt)93 void 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
processTest(TestData * testData)327 void 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