1 // 2016 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html 3 /*********************************************************************** 4 * Copyright (c) 1997-2009, International Business Machines Corporation 5 * and others. All Rights Reserved. 6 ***********************************************************************/ 7 8 #include "unicode/utypes.h" 9 10 #if !UCONFIG_NO_FORMATTING 11 12 #include "unicode/datefmt.h" 13 #include "unicode/smpdtfmt.h" 14 #include "tsdate.h" 15 #include "putilimp.h" 16 #include "cstring.h" 17 18 #include <float.h> 19 #include <stdlib.h> 20 #include <math.h> 21 22 const double IntlTestDateFormat::ONEYEAR = 365.25 * ONEDAY; // Approximate 23 24 IntlTestDateFormat::~IntlTestDateFormat() {} 25 26 /** 27 * This test does round-trip testing (format -> parse -> format -> parse -> etc.) of 28 * DateFormat. 29 */ 30 // par is ignored throughout this file 31 void IntlTestDateFormat::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ ) 32 { 33 if (exec) logln("TestSuite DateFormat"); 34 switch (index) { 35 case 0: name = "GenericTest"; 36 if (exec) { 37 logln(name); 38 fFormat = DateFormat::createInstance(); 39 fTestName = "createInstance"; 40 fLimit = 3; 41 testFormat(/* par */); 42 } 43 break; 44 case 1: name = "DefaultLocale"; 45 if (exec) { 46 logln(name); 47 testLocale(/*par, */Locale::getDefault(), "Default Locale"); 48 } 49 break; 50 51 case 2: name = "TestAvailableLocales"; 52 if (exec) { 53 logln(name); 54 testAvailableLocales(/* par */); 55 } 56 break; 57 58 case 3: name = "MonsterTest"; 59 if (exec) { 60 logln(name); 61 monsterTest(/*par*/); 62 } 63 break; 64 65 default: name = ""; break; 66 } 67 } 68 69 void 70 IntlTestDateFormat::testLocale(/*char* par, */const Locale& locale, const UnicodeString& localeName) 71 { 72 DateFormat::EStyle timeStyle, dateStyle; 73 74 // For patterns including only time information and a timezone, it may take 75 // up to three iterations, since the timezone may shift as the year number 76 // is determined. For other patterns, 2 iterations should suffice. 77 fLimit = 3; 78 79 for(timeStyle = (DateFormat::EStyle)0; 80 timeStyle < (DateFormat::EStyle)4; 81 timeStyle = (DateFormat::EStyle) (timeStyle+1)) 82 { 83 fTestName = (UnicodeString) "Time test " + (int32_t) timeStyle + " (" + localeName + ")"; 84 fFormat = DateFormat::createTimeInstance(timeStyle, locale); 85 testFormat(/* par */); 86 } 87 88 fLimit = 2; 89 90 for(dateStyle = (DateFormat::EStyle)0; 91 dateStyle < (DateFormat::EStyle)4; 92 dateStyle = (DateFormat::EStyle) (dateStyle+1)) 93 { 94 fTestName = (UnicodeString) "Date test " + (int32_t) dateStyle + " (" + localeName + ")"; 95 fFormat = DateFormat::createDateInstance(dateStyle, locale); 96 testFormat(/* par */); 97 } 98 99 for(dateStyle = (DateFormat::EStyle)0; 100 dateStyle < (DateFormat::EStyle)4; 101 dateStyle = (DateFormat::EStyle) (dateStyle+1)) 102 { 103 for(timeStyle = (DateFormat::EStyle)0; 104 timeStyle < (DateFormat::EStyle)4; 105 timeStyle = (DateFormat::EStyle) (timeStyle+1)) 106 { 107 fTestName = (UnicodeString) "DateTime test " + (int32_t) dateStyle + "/" + (int32_t) timeStyle + " (" + localeName + ")"; 108 fFormat = DateFormat::createDateTimeInstance(dateStyle, timeStyle, locale); 109 testFormat(/* par */); 110 } 111 } 112 } 113 114 void IntlTestDateFormat::testFormat(/* char* par */) 115 { 116 if (fFormat == 0) 117 { 118 dataerrln("FAIL: DateFormat creation failed"); 119 return; 120 } 121 122 describeTest(); 123 124 UDate now = Calendar::getNow(); 125 tryDate(0); 126 tryDate(1278161801778.0); 127 tryDate(5264498352317.0); // Sunday, October 28, 2136 8:39:12 AM PST 128 tryDate(9516987689250.0); // In the year 2271 129 tryDate(now); 130 // Shift 6 months into the future, AT THE SAME TIME OF DAY. 131 // This will test the DST handling. 132 tryDate(now + 6.0*30*ONEDAY); 133 134 UDate limit = now * 10; // Arbitrary limit 135 for (int32_t i=0; i<3; ++i) 136 tryDate(uprv_floor(randDouble() * limit)); 137 138 delete fFormat; 139 } 140 141 void 142 IntlTestDateFormat::describeTest() 143 { 144 // Assume it's a SimpleDateFormat and get some info 145 SimpleDateFormat *s = (SimpleDateFormat*)fFormat; 146 UnicodeString str; 147 logln(fTestName + " Pattern " + s->toPattern(str)); 148 } 149 150 void IntlTestDateFormat::tryDate(UDate theDate) 151 { 152 const int32_t DEPTH = 10; 153 UDate date[DEPTH]; 154 UnicodeString string[DEPTH]; 155 156 int32_t dateMatch = 0; 157 int32_t stringMatch = 0; 158 UBool dump = FALSE; 159 #if defined (U_CAL_DEBUG) 160 dump = TRUE; 161 #endif 162 int32_t i; 163 164 date[0] = theDate; 165 fFormat->format(theDate, string[0]); 166 167 for (i=1; i<DEPTH; ++i) 168 { 169 UErrorCode status = U_ZERO_ERROR; 170 date[i] = fFormat->parse(string[i-1], status); 171 if (U_FAILURE(status)) 172 { 173 describeTest(); 174 errln("**** FAIL: Parse of " + prettify(string[i-1], FALSE) + " failed."); 175 dump = TRUE; 176 break; 177 } 178 fFormat->format(date[i], string[i]); 179 if (dateMatch == 0 && date[i] == date[i-1]) 180 dateMatch = i; 181 else if (dateMatch > 0 && date[i] != date[i-1]) 182 { 183 describeTest(); 184 errln("**** FAIL: Date mismatch after match for " + string[i]); 185 dump = TRUE; 186 break; 187 } 188 if (stringMatch == 0 && string[i] == string[i-1]) 189 stringMatch = i; 190 else if (stringMatch > 0 && string[i] != string[i-1]) 191 { 192 describeTest(); 193 errln("**** FAIL: String mismatch after match for " + string[i]); 194 dump = TRUE; 195 break; 196 } 197 if (dateMatch > 0 && stringMatch > 0) 198 break; 199 } 200 if (i == DEPTH) 201 --i; 202 203 if (stringMatch > fLimit || dateMatch > fLimit) 204 { 205 describeTest(); 206 errln((UnicodeString)"**** FAIL: No string and/or date match within " + fLimit 207 + " iterations for the Date " + string[0] + "\t(" + theDate + ")."); 208 dump = TRUE; 209 } 210 211 if (dump) 212 { 213 for (int32_t k=0; k<=i; ++k) 214 { 215 logln((UnicodeString)"" + k + ": " + date[k] + " F> " + 216 string[k] + " P> "); 217 } 218 } 219 } 220 221 // Return a random double from 0.01 to 1, inclusive 222 double IntlTestDateFormat::randDouble() 223 { 224 // Assume 8-bit (or larger) rand values. Also assume 225 // that the system rand() function is very poor, which it always is. 226 double d=0.0; 227 uint32_t i; 228 char* poke = (char*)&d; 229 do { 230 do { 231 for (i=0; i < sizeof(double); ++i) 232 { 233 poke[i] = (char)(rand() & 0xFF); 234 } 235 } while (uprv_isNaN(d) || uprv_isInfinite(d)); 236 237 if (d < 0.0) 238 d = -d; 239 if (d > 0.0) 240 { 241 double e = uprv_floor(log10(d)); 242 if (e < -2.0) 243 d *= uprv_pow10((int32_t)(-e-2)); 244 else if (e > -1.0) 245 d /= uprv_pow10((int32_t)(e+1)); 246 } 247 // While this is not a real normalized number make another one. 248 } while (uprv_isNaN(d) || uprv_isInfinite(d) 249 || !((-DBL_MAX < d && d < DBL_MAX) || (d < -DBL_MIN && DBL_MIN < d))); 250 return d; 251 } 252 253 void IntlTestDateFormat::testAvailableLocales(/* char* par */) 254 { 255 int32_t count = 0; 256 const Locale* locales = DateFormat::getAvailableLocales(count); 257 logln((UnicodeString)"" + count + " available locales"); 258 if (locales && count) 259 { 260 UnicodeString name; 261 UnicodeString all; 262 for (int32_t i=0; i<count; ++i) 263 { 264 if (i!=0) all += ", "; 265 all += locales[i].getName(); 266 } 267 logln(all); 268 } 269 else dataerrln((UnicodeString)"**** FAIL: Zero available locales or null array pointer"); 270 } 271 272 void IntlTestDateFormat::monsterTest(/*char *par*/) 273 { 274 int32_t count; 275 const Locale* locales = DateFormat::getAvailableLocales(count); 276 if (locales && count) 277 { 278 if (quick && count > 3) { 279 logln("quick test: testing just 3 locales!"); 280 count = 3; 281 } 282 for (int32_t i=0; i<count; ++i) 283 { 284 UnicodeString name = UnicodeString(locales[i].getName(), ""); 285 logln((UnicodeString)"Testing " + name + "..."); 286 testLocale(/*par, */locales[i], name); 287 } 288 } 289 } 290 291 #endif /* #if !UCONFIG_NO_FORMATTING */ 292