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