1// Copyright (C) 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-2013 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 "dadrfmt.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#include "fldset.h" 30 31 32#include <stdio.h> 33 34DataDrivenFormatTest::DataDrivenFormatTest() { 35 UErrorCode status = U_ZERO_ERROR; 36 driver = TestDataModule::getTestDataModule("format", *this, status); 37} 38 39DataDrivenFormatTest::~DataDrivenFormatTest() { 40 delete driver; 41} 42 43void DataDrivenFormatTest::runIndexedTest(int32_t index, UBool exec, 44 const char* &name, char* /*par */) { 45 if (driver != NULL) { 46 if (exec) { 47 // logln("Begin "); 48 } 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)); 56 } 57 if (exec) { 58 log(name); 59 logln("---"); 60 logln(""); 61 62 processTest(testData); 63 } 64 delete testData; 65 } else { 66 name = ""; 67 } 68 } else { 69 dataerrln("format/DataDriven*Test data (format.res) not initialized!"); 70 name = ""; 71 } 72 73} 74 75 76 77/* 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 84 Cases { 85 { 86 "en_US@calendar=gregorian", 87 "", 88 "DATE=SHORT,TIME=SHORT", 89 "ERA=1,YEAR=2007,MONTH=AUGUST,DATE=8,HOUR=18,MINUTE=54,SECOND=12", 90 "8/8/2007 6:54pm" 91 }, 92 * */ 93 94 95void 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 101 102 UErrorCode status = U_ZERO_ERROR; 103 SimpleDateFormat basicFmt(UnicodeString("EEE MMM dd yyyy / YYYY'-W'ww-ee"), 104 status); 105 if (U_FAILURE(status)) { 106 dataerrln("FAIL: Couldn't create basic SimpleDateFormat: %s", 107 u_errorName(status)); 108 return; 109 } 110 111 const DataMap *currentCase= NULL; 112 // Start the processing 113 int n = 0; 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; 121 UDate fromDate = 0; 122 UBool useDate = FALSE; 123 124 UDate now = Calendar::getNow(); 125 126 ++n; 127 128 char theCase[200]; 129 sprintf(theCase, "case %d:", n); 130 UnicodeString caseString(theCase, ""); 131 132 // load params 133 UnicodeString locale = currentCase->getString("locale", status); 134 if (U_FAILURE(status)) { 135 errln("case %d: No 'locale' line.", n); 136 continue; 137 } 138 UnicodeString zone = currentCase->getString("zone", status); 139 if (U_FAILURE(status)) { 140 errln("case %d: No 'zone' line.", n); 141 continue; 142 } 143 UnicodeString spec = currentCase->getString("spec", status); 144 if(U_FAILURE(status)) { 145 errln("case %d: No 'spec' line.", n); 146 continue; 147 } 148 UnicodeString date = currentCase->getString("date", status); 149 if(U_FAILURE(status)) { 150 errln("case %d: No 'date' line.", n); 151 continue; 152 } 153 UnicodeString expectStr= currentCase->getString("str", status); 154 if(U_FAILURE(status)) { 155 errln("case %d: No 'str' line.", n); 156 continue; 157 } 158 159 DateFormat *format = NULL; 160 161 // Process: 'locale' 162 locale.extract(0, locale.length(), calLoc, (const char*)0); // default codepage. Invariant codepage doesn't have '@'! 163 Locale loc(calLoc); 164 if(spec.startsWith(kPATTERN)) { 165 pattern = UnicodeString(spec,kPATTERN.length()); 166 usePattern = TRUE; 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)); 170 continue; 171 } 172 } else { 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)); 175 continue; 176 } 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); 180 continue; 181 } 182 } 183 184 Calendar *cal = Calendar::createInstance(loc, status); 185 if(U_FAILURE(status)) { 186 errln("case %d: could not create calendar from %s", n, calLoc); 187 } 188 189 if (zone.length() > 0) { 190 TimeZone * tz = TimeZone::createTimeZone(zone); 191 cal->setTimeZone(*tz); 192 format->setTimeZone(*tz); 193 delete tz; 194 } 195 196 // parse 'date' 197 if(date.startsWith(kMILLIS)) { 198 UnicodeString millis = UnicodeString(date, kMILLIS.length()); 199 useDate = TRUE; 200 fromDate = udbg_stod(millis); 201 } else if(date.startsWith(kRELATIVE_MILLIS)) { 202 UnicodeString millis = UnicodeString(date, kRELATIVE_MILLIS.length()); 203 useDate = TRUE; 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)); 209 continue; 210 } 211 useDate=TRUE; 212 cal->clear(); 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); 220 } else { 221 cal->set((UCalendarDateFields)q, 222 fromSet.get((UCalendarDateFields)q)); 223 } 224 //int32_t newv = cal->get((UCalendarDateFields)q, status); 225 } 226 } 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)); 230 continue; 231 } 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)); 234 continue; 235 } 236 237 // now, do it. 238 if (fmt) { 239 FieldPosition pos; 240// logln((UnicodeString)"#"+n+" "+locale+"/"+from+" >>> "+toCalLoc+"/" 241// +to); 242 cal->clear(); 243 UnicodeString output; 244 output.remove(); 245 246 if(useDate) { 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)); 250// continue; 251// } 252 format->format(fromDate, output, pos, status); 253 } else { 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)); 257 continue; 258 } 259 format->format(*cal, output, pos); 260 } 261 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' 265 } 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); 268// } 269 270 if(output == expectStr) { 271 logln(caseString+": format: SUCCESS! "+UnicodeString("expect=output=")+output); 272 } else { 273 UnicodeString result; 274 UnicodeString result2; 275 errln(caseString+": format: output!=expectStr, got " + *udbg_escape(output, &result) + " expected " + *udbg_escape(expectStr, &result2)); 276 } 277 } else { 278 cal->clear(); 279 ParsePosition pos; 280 format->parse(expectStr,*cal,pos); 281 if(useDate) { 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))); 285 continue; 286 } 287 if(gotDate == fromDate) { 288 logln(caseString+": parse: SUCCESS! "+UnicodeString("gotDate=parseDate=")+expectStr); 289 } else { 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); 294 } 295 } else { 296// Calendar *cal2 = cal->clone(); 297// cal2->clear(); 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)); 301 continue; 302 } 303 304 CalendarFieldsSet diffSet; 305// diffSet.clear(); 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)); 314 } else { 315 logln("PASS: "+caseString+" parse."); 316 } 317 318 319 320 } 321 } 322 delete cal; 323 delete format; 324 325 } 326// delete basicFmt; 327} 328 329void DataDrivenFormatTest::processTest(TestData *testData) { 330 //Format *cal= NULL; 331 //const UChar *arguments= NULL; 332 //int32_t argLen = 0; 333 char testType[256]; 334 const DataMap *settings= NULL; 335 //const UChar *type= NULL; 336 UErrorCode status = U_ZERO_ERROR; 337 UnicodeString testSetting; 338 int n = 0; 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)) { 344 if ((++n)>0) { 345 logln("---"); 346 } 347 logln(testSetting + "---"); 348 testSetting.extract(0, testSetting.length(), testType, ""); 349 } else { 350 errln("Unable to extract 'Type'. Skipping.."); 351 continue; 352 } 353 354 if (!strcmp(testType, "date_format")) { 355 testConvertDate(testData, settings, true); 356 } else if (!strcmp(testType, "date_parse")) { 357 testConvertDate(testData, settings, false); 358 } else { 359 errln("Unknown type: %s", testType); 360 } 361 } 362} 363 364#endif 365