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 32 DataDrivenFormatTest::DataDrivenFormatTest() { 33 UErrorCode status = U_ZERO_ERROR; 34 driver = TestDataModule::getTestDataModule("format", *this, status); 35 } 36 37 DataDrivenFormatTest::~DataDrivenFormatTest() { 38 delete driver; 39 } 40 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 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 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