/***********************************************************************
* COPYRIGHT:
- * Copyright (c) 1997-2008, International Business Machines Corporation
+ * Copyright (c) 1997-2015, International Business Machines Corporation
* and others. All Rights Reserved.
***********************************************************************/
#include "unicode/gregocal.h"
#include "unicode/datefmt.h"
#include "unicode/smpdtfmt.h"
-#include "putilimp.h"
#include "cstring.h"
+#include "mutex.h"
+#include "putilimp.h"
+#include "simplethread.h"
U_NAMESPACE_USE
void CalendarLimitTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
// -------------------------------------
void
-CalendarLimitTest::test(UDate millis, U_NAMESPACE_QUALIFIER Calendar* cal, U_NAMESPACE_QUALIFIER DateFormat* fmt)
+CalendarLimitTest::test(UDate millis, icu::Calendar* cal, icu::DateFormat* fmt)
{
static const UDate kDrift = 1e-10;
UErrorCode exception = U_ZERO_ERROR;
{
UErrorCode status = U_ZERO_ERROR;
Calendar *cal = Calendar::createInstance(status);
- if (failure(status, "Calendar::createInstance")) return;
+ if (failure(status, "Calendar::createInstance", TRUE)) return;
cal->adoptTimeZone(TimeZone::createTimeZone("GMT"));
DateFormat *fmt = DateFormat::createDateTimeInstance();
if(!fmt || !cal) {
return;
}
fmt->adoptCalendar(cal);
- ((SimpleDateFormat*) fmt)->applyPattern("HH:mm:ss.SSS zzz, EEEE, MMMM d, yyyy G");
+ ((SimpleDateFormat*) fmt)->applyPattern("HH:mm:ss.SSS Z, EEEE, MMMM d, yyyy G");
// This test used to test the algorithmic limits of the dates that
delete fmt;
}
+namespace {
+
+struct TestCase {
+ const char *type;
+ UBool hasLeapMonth;
+ UDate actualTestStart;
+ int32_t actualTestEnd;
+};
+
+const UDate DEFAULT_START = 944006400000.0; // 1999-12-01T00:00Z
+const int32_t DEFAULT_END = -120; // Default for non-quick is run 2 minutes
+
+TestCase TestCases[] = {
+ {"gregorian", FALSE, DEFAULT_START, DEFAULT_END},
+ {"japanese", FALSE, 596937600000.0, DEFAULT_END}, // 1988-12-01T00:00Z, Showa 63
+ {"buddhist", FALSE, DEFAULT_START, DEFAULT_END},
+ {"roc", FALSE, DEFAULT_START, DEFAULT_END},
+ {"persian", FALSE, DEFAULT_START, DEFAULT_END},
+ {"islamic-civil", FALSE, DEFAULT_START, DEFAULT_END},
+ {"islamic", FALSE, DEFAULT_START, 800000}, // Approx. 2250 years from now, after which
+ // some rounding errors occur in Islamic calendar
+ {"hebrew", TRUE, DEFAULT_START, DEFAULT_END},
+ {"chinese", TRUE, DEFAULT_START, DEFAULT_END},
+ {"dangi", TRUE, DEFAULT_START, DEFAULT_END},
+ {"indian", FALSE, DEFAULT_START, DEFAULT_END},
+ {"coptic", FALSE, DEFAULT_START, DEFAULT_END},
+ {"ethiopic", FALSE, DEFAULT_START, DEFAULT_END},
+ {"ethiopic-amete-alem", FALSE, DEFAULT_START, DEFAULT_END}
+};
+
+struct {
+ int32_t fIndex;
+ UBool next (int32_t &rIndex) {
+ Mutex lock;
+ if (fIndex >= UPRV_LENGTHOF(TestCases)) {
+ return FALSE;
+ }
+ rIndex = fIndex++;
+ return TRUE;
+ }
+ void reset() {
+ fIndex = 0;
+ }
+} gTestCaseIterator;
+
+} // anonymous name space
+
void
CalendarLimitTest::TestLimits(void) {
- static const UDate DEFAULT_START = 944006400000.0; // 1999-12-01T00:00Z
-
- static const struct {
- const char *type;
- UBool hasLeapMonth;
- UDate actualTestStart;
- } TestCases[] = {
- {"gregorian", FALSE, DEFAULT_START},
- {"japanese", FALSE, 596937600000.0}, // 1988-12-01T00:00Z, Showa 63
- {"buddhist", FALSE, DEFAULT_START},
- {"roc", FALSE, DEFAULT_START},
- {"persian", FALSE, DEFAULT_START},
- {"islamic-civil", FALSE, DEFAULT_START},
- //{"islamic", FALSE, DEFAULT_START}, // TODO: there is a bug in monthlength calculation
- {"hebrew", TRUE, DEFAULT_START},
- {"chinese", TRUE, DEFAULT_START},
- {"indian", FALSE, DEFAULT_START},
- {"coptic", FALSE, DEFAULT_START},
- {"ethiopic", FALSE, DEFAULT_START},
- {"ethiopic-amete-alem", FALSE, DEFAULT_START},
- {NULL, FALSE, 0.0}
- };
+ gTestCaseIterator.reset();
+
+ ThreadPool<CalendarLimitTest> threads(this, threadCount, &CalendarLimitTest::TestLimitsThread);
+ threads.start();
+ threads.join();
+}
- int16_t i = 0;
- char buf[64];
- for (i = 0; TestCases[i].type; i++) {
+void CalendarLimitTest::TestLimitsThread(int32_t threadNum) {
+ logln("thread %d starting", threadNum);
+ int32_t testIndex = 0;
+ LocalPointer<Calendar> cal;
+ while (gTestCaseIterator.next(testIndex)) {
+ TestCase &testCase = TestCases[testIndex];
+ logln("begin test of %s calendar.", testCase.type);
UErrorCode status = U_ZERO_ERROR;
+ char buf[64];
uprv_strcpy(buf, "root@calendar=");
- strcat(buf, TestCases[i].type);
- Calendar *cal = Calendar::createInstance(buf, status);
- if (failure(status, "Calendar::createInstance")) {
+ strcat(buf, testCase.type);
+ cal.adoptInstead(Calendar::createInstance(buf, status));
+ if (failure(status, "Calendar::createInstance", TRUE)) {
continue;
}
- if (uprv_strcmp(cal->getType(), TestCases[i].type) != 0) {
+ if (uprv_strcmp(cal->getType(), testCase.type) != 0) {
errln((UnicodeString)"FAIL: Wrong calendar type: " + cal->getType()
- + " Requested: " + TestCases[i].type);
- delete cal;
+ + " Requested: " + testCase.type);
continue;
}
- // Do the test
- doTheoreticalLimitsTest(*cal, TestCases[i].hasLeapMonth);
- doLimitsTest(*cal, TestCases[i].actualTestStart);
- delete cal;
+ doTheoreticalLimitsTest(*(cal.getAlias()), testCase.hasLeapMonth);
+ doLimitsTest(*(cal.getAlias()), testCase.actualTestStart, testCase.actualTestEnd);
+ logln("end test of %s calendar.", testCase.type);
}
}
+
void
CalendarLimitTest::doTheoreticalLimitsTest(Calendar& cal, UBool leapMonth) {
const char* calType = cal.getType();
}
void
-CalendarLimitTest::doLimitsTest(Calendar& cal, UDate startDate) {
- int32_t testTime = quick ? -3 : -120;
+CalendarLimitTest::doLimitsTest(Calendar& cal, UDate startDate, int32_t endTime) {
+ int32_t testTime = quick ? ( endTime / 40 ) : endTime;
doLimitsTest(cal, NULL /*default fields*/, startDate, testTime);
}
logln((UnicodeString)"(" + i + " days)");
mark += 5000; // 5 sec
}
- cal.setTime(greg.getTime(status), status);
+ UDate testMillis = greg.getTime(status);
+
+ if (testMillis == 2768943600000.0) {
+ // unusual failure, get day of month 0.
+ // doesn't happen with runConfigure and make check inside
+ // icuSources directory (i.e. using ICU build without wrapper makefile)
+ continue;
+ }
+
+ cal.setTime(testMillis, status);
+ cal.setMinimalDaysInFirstWeek(1);
if (failure(status, "Calendar set/getTime")) {
return;
}
", actual_max=" + maxActual);
}
if (v < minActual || v > maxActual) {
- errln((UnicodeString)"Fail: [" + cal.getType() + "] " +
- ymdToString(cal, ymd) +
- " " + FIELD_NAME[f] + "(" + f + ")=" + v +
- ", actual range=" + minActual + ".." + maxActual +
- ", allowed=(" + minLow + ".." + minHigh + ")..(" +
- maxLow + ".." + maxHigh + ")");
+ // timebomb per #9967, fix with #9972
+ if ( uprv_strcmp(cal.getType(), "dangi") == 0 &&
+ testMillis >= 1865635198000.0 &&
+ logKnownIssue("9972", "as per #9967")) { // Feb 2029 gregorian, end of dangi 4361
+ logln((UnicodeString)"Fail: [" + cal.getType() + "] " +
+ ymdToString(cal, ymd) +
+ " " + FIELD_NAME[f] + "(" + f + ")=" + v +
+ ", actual=" + minActual + ".." + maxActual +
+ ", allowed=(" + minLow + ".." + minHigh + ")..(" +
+ maxLow + ".." + maxHigh + ")");
+ } else {
+ errln((UnicodeString)"Fail: [" + cal.getType() + "] " +
+ ymdToString(cal, ymd) +
+ " " + FIELD_NAME[f] + "(" + f + ")=" + v +
+ ", actual=" + minActual + ".." + maxActual +
+ ", allowed=(" + minLow + ".." + minHigh + ")..(" +
+ maxLow + ".." + maxHigh + ")");
+ }
}
}
greg.add(UCAL_DAY_OF_YEAR, 1, status);
+ "/" + (cal.get(UCAL_MONTH, status) + 1)
+ (cal.get(UCAL_IS_LEAP_MONTH, status) == 1 ? "(leap)" : "")
+ "/" + cal.get(UCAL_DATE, status)
- + ", time=" + cal.getTime(status));
+ + " " + cal.get(UCAL_HOUR_OF_DAY, status)
+ + ":" + cal.get(UCAL_MINUTE, status)
+ + " zone(hrs) " + cal.get(UCAL_ZONE_OFFSET, status)/(60.0*60.0*1000.0)
+ + " dst(hrs) " + cal.get(UCAL_DST_OFFSET, status)/(60.0*60.0*1000.0)
+ + ", time(millis)=" + cal.getTime(status));
return str;
}