Beispiel #1
0
void
CalendarLimitTest::TestLimits(void) {
    static const UDate DEFAULT_START = 944006400000.0; // 1999-12-01T00:00Z
    static const int32_t DEFAULT_END = -120; // Default for non-quick is run 2 minutes

    static const struct {
        const char *type;
        UBool hasLeapMonth;
        UDate actualTestStart;
        int32_t actualTestEnd;
    } 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},
        {NULL,              FALSE,      0, 0}
    };

    int16_t i = 0;
    char buf[64];

    for (i = 0; TestCases[i].type; i++) {
        UErrorCode status = U_ZERO_ERROR;
        uprv_strcpy(buf, "root@calendar=");
        strcat(buf, TestCases[i].type);
        Calendar *cal = Calendar::createInstance(buf, status);
        if (failure(status, "Calendar::createInstance", TRUE)) {
            continue;
        }
        if (uprv_strcmp(cal->getType(), TestCases[i].type) != 0) {
            errln((UnicodeString)"FAIL: Wrong calendar type: " + cal->getType()
                  + " Requested: " + TestCases[i].type);
            delete cal;
            continue;
        }
        // Do the test
        doTheoreticalLimitsTest(*cal, TestCases[i].hasLeapMonth);
        doLimitsTest(*cal, TestCases[i].actualTestStart,TestCases[i].actualTestEnd);
        delete cal;
    }
}
/**
 * Test various API methods for API completeness.
 */
void
IntlCalendarTest::TestTypes()
{
  Calendar *c = NULL;
  UErrorCode status = U_ZERO_ERROR;
  int j;
  const char *locs [40] = { "en_US_VALLEYGIRL",     
                            "en_US_VALLEYGIRL@collation=phonebook;calendar=japanese",
                            "en_US_VALLEYGIRL@collation=phonebook;calendar=gregorian",
                            "ja_JP@calendar=japanese",   
                            "th_TH@calendar=buddhist", 
                            "ja_JP_TRADITIONAL",   
                            "th_TH_TRADITIONAL", 
                            "th_TH_TRADITIONAL@calendar=gregorian", 
                            "en_US",
                            "th_TH",    // Default calendar for th_TH is buddhist
                            "th",       // th's default region is TH and buddhist is used as default for TH
                            "en_TH",    // Default calendar for any locales with region TH is buddhist
                            "en-TH-u-ca-gregory",
                            NULL };
  const char *types[40] = { "gregorian", 
                            "japanese",
                            "gregorian",
                            "japanese",
                            "buddhist",
                            "japanese",
                            "buddhist",
                            "gregorian",  // android-changed.  "buddhist",
                            "gregorian",  // android-changed.  "buddhist",
                            "gregorian",  // android-changed.  "buddhist",
                            "gregorian",  // android-changed.  "buddhist",
                            "gregorian",  // android-changed.  "buddhist",
                            "gregorian",
                            NULL };

  for(j=0;locs[j];j++) {
    logln(UnicodeString("Creating calendar of locale ")  + locs[j]);
    status = U_ZERO_ERROR;
    c = Calendar::createInstance(locs[j], status);
    CHECK(status, "creating '" + UnicodeString(locs[j]) + "' calendar");
    if(U_SUCCESS(status)) {
      logln(UnicodeString(" type is ") + c->getType());
      if(strcmp(c->getType(), types[j])) {
        dataerrln(UnicodeString(locs[j]) + UnicodeString("Calendar type ") + c->getType() + " instead of " + types[j]);
      }
    }
    delete c;
  }
}
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}
    };

    int16_t i = 0;
    char buf[64];

    for (i = 0; TestCases[i].type; i++) {
        UErrorCode status = U_ZERO_ERROR;
        uprv_strcpy(buf, "root@calendar=");
        strcat(buf, TestCases[i].type);
        Calendar *cal = Calendar::createInstance(buf, status);
        if (failure(status, "Calendar::createInstance")) {
            continue;
        }
        if (uprv_strcmp(cal->getType(), TestCases[i].type) != 0) {
            errln((UnicodeString)"FAIL: Wrong calendar type: " + cal->getType()
                + " Requested: " + TestCases[i].type);
            delete cal;
            continue;
        }
        // Do the test
        doTheoreticalLimitsTest(*cal, TestCases[i].hasLeapMonth);
        doLimitsTest(*cal, TestCases[i].actualTestStart);
        delete cal;
    }
}
/**
 * Run a test of a quasi-Gregorian calendar.  This is a calendar
 * that behaves like a Gregorian but has different year/era mappings.
 * The int[] data array should have the format:
 * 
 * { era, year, gregorianYear, month, dayOfMonth, ...  ... , -1 }
 */
void IntlCalendarTest::quasiGregorianTest(Calendar& cal, const Locale& gcl, const int32_t *data) {
  UErrorCode status = U_ZERO_ERROR;
  // As of JDK 1.4.1_01, using the Sun JDK GregorianCalendar as
  // a reference throws us off by one hour.  This is most likely
  // due to the JDK 1.4 incorporation of historical time zones.
  //java.util.Calendar grego = java.util.Calendar.getInstance();
  Calendar *grego = Calendar::createInstance(gcl, status);
  if (U_FAILURE(status)) {
    dataerrln("Error calling Calendar::createInstance"); 
    return;
  }

  int32_t tz1 = cal.get(UCAL_ZONE_OFFSET,status);
  int32_t tz2 = grego -> get (UCAL_ZONE_OFFSET, status);
  if(tz1 != tz2) { 
    errln((UnicodeString)"cal's tz " + tz1 + " != grego's tz " + tz2);
  }

  for (int32_t i=0; data[i]!=-1; ) {
    int32_t era = data[i++];
    int32_t year = data[i++];
    int32_t gregorianYear = data[i++];
    int32_t month = data[i++];
    int32_t dayOfMonth = data[i++];
    
    grego->clear();
    grego->set(gregorianYear, month, dayOfMonth);
    UDate D = grego->getTime(status);
    
    cal.clear();
    cal.set(UCAL_ERA, era);
    cal.set(year, month, dayOfMonth);
    UDate d = cal.getTime(status);
#ifdef U_DEBUG_DUMPCALS
    logln((UnicodeString)"cal  : " + CalendarTest::calToStr(cal));
    logln((UnicodeString)"grego: " + CalendarTest::calToStr(*grego));
#endif
    if (d == D) {
      logln(UnicodeString("OK: ") + era + ":" + year + "/" + (month+1) + "/" + dayOfMonth +
            " => " + d + " (" + UnicodeString(cal.getType()) + ")");
    } else {
      errln(UnicodeString("Fail: (fields to millis)") + era + ":" + year + "/" + (month+1) + "/" + dayOfMonth +
            " => " + d + ", expected " + D + " (" + UnicodeString(cal.getType()) + "Off by: " + (d-D));
    }
    
    // Now, set the gregorian millis on the other calendar
    cal.clear();
    cal.setTime(D, status);
    int e = cal.get(UCAL_ERA, status);
    int y = cal.get(UCAL_YEAR, status);
#ifdef U_DEBUG_DUMPCALS
    logln((UnicodeString)"cal  : " + CalendarTest::calToStr(cal));
    logln((UnicodeString)"grego: " + CalendarTest::calToStr(*grego));
#endif
    if (y == year && e == era) {
      logln((UnicodeString)"OK: " + D + " => " + cal.get(UCAL_ERA, status) + ":" +
            cal.get(UCAL_YEAR, status) + "/" +
            (cal.get(UCAL_MONTH, status)+1) + "/" + cal.get(UCAL_DATE, status) +  " (" + UnicodeString(cal.getType()) + ")");
    } else {
      errln((UnicodeString)"Fail: (millis to fields)" + D + " => " + cal.get(UCAL_ERA, status) + ":" +
            cal.get(UCAL_YEAR, status) + "/" +
            (cal.get(UCAL_MONTH, status)+1) + "/" + cal.get(UCAL_DATE, status) +
            ", expected " + era + ":" + year + "/" + (month+1) + "/" +
            dayOfMonth +  " (" + UnicodeString(cal.getType()));
    }
  }
  delete grego;
  CHECK(status, "err during quasiGregorianTest()");
}
Beispiel #5
0
void
CalendarLimitTest::doLimitsTest(Calendar& cal,
                                const int32_t* fieldsToTest,
                                UDate startDate,
                                int32_t testDuration) {
    static const int32_t FIELDS[] = {
        UCAL_ERA,
        UCAL_YEAR,
        UCAL_MONTH,
        UCAL_WEEK_OF_YEAR,
        UCAL_WEEK_OF_MONTH,
        UCAL_DAY_OF_MONTH,
        UCAL_DAY_OF_YEAR,
        UCAL_DAY_OF_WEEK_IN_MONTH,
        UCAL_YEAR_WOY,
        UCAL_EXTENDED_YEAR,
        -1,
    };

    static const char* FIELD_NAME[] = {
        "ERA", "YEAR", "MONTH", "WEEK_OF_YEAR", "WEEK_OF_MONTH",
        "DAY_OF_MONTH", "DAY_OF_YEAR", "DAY_OF_WEEK",
        "DAY_OF_WEEK_IN_MONTH", "AM_PM", "HOUR", "HOUR_OF_DAY",
        "MINUTE", "SECOND", "MILLISECOND", "ZONE_OFFSET",
        "DST_OFFSET", "YEAR_WOY", "DOW_LOCAL", "EXTENDED_YEAR",
        "JULIAN_DAY", "MILLISECONDS_IN_DAY",
        "IS_LEAP_MONTH"
    };

    UErrorCode status = U_ZERO_ERROR;
    int32_t i, j;
    UnicodeString ymd;

    GregorianCalendar greg(status);
    if (failure(status, "new GregorianCalendar")) {
        return;
    }
    greg.setTime(startDate, status);
    if (failure(status, "GregorianCalendar::setTime")) {
        return;
    }
    logln((UnicodeString)"Start: " + startDate);

    if (fieldsToTest == NULL) {
        fieldsToTest = FIELDS;
    }


    // Keep a record of minima and maxima that we actually see.
    // These are kept in an array of arrays of hashes.
    int32_t limits[UCAL_FIELD_COUNT][4];
    for (j = 0; j < UCAL_FIELD_COUNT; j++) {
        limits[j][0] = INT32_MAX;
        limits[j][1] = INT32_MIN;
        limits[j][2] = INT32_MAX;
        limits[j][3] = INT32_MIN;
    }

    // This test can run for a long time; show progress.
    UDate millis = ucal_getNow();
    UDate mark = millis + 5000; // 5 sec
    millis -= testDuration * 1000; // stop time if testDuration<0

    for (i = 0;
         testDuration > 0 ? i < testDuration
                        : ucal_getNow() < millis;
         ++i) {
        if (ucal_getNow() >= mark) {
            logln((UnicodeString)"(" + i + " days)");
            mark += 5000; // 5 sec
        }
        UDate testMillis = greg.getTime(status);
        cal.setTime(testMillis, status);
        cal.setMinimalDaysInFirstWeek(1);
        if (failure(status, "Calendar set/getTime")) {
            return;
        }
        for (j = 0; fieldsToTest[j] >= 0; ++j) {
            UCalendarDateFields f = (UCalendarDateFields)fieldsToTest[j];
            int32_t v = cal.get(f, status);
            int32_t minActual = cal.getActualMinimum(f, status);
            int32_t maxActual = cal.getActualMaximum(f, status);
            int32_t minLow = cal.getMinimum(f);
            int32_t minHigh = cal.getGreatestMinimum(f);
            int32_t maxLow = cal.getLeastMaximum(f);
            int32_t maxHigh = cal.getMaximum(f);

            if (limits[j][0] > minActual) {
                // the minimum
                limits[j][0] = minActual;
            }
            if (limits[j][1] < minActual) {
                // the greatest minimum
                limits[j][1] = minActual;
            }
            if (limits[j][2] > maxActual) {
                // the least maximum
                limits[j][2] = maxActual;
            }
            if (limits[j][3] < maxActual) {
                // the maximum
                limits[j][3] = maxActual;
            }

            if (minActual < minLow || minActual > minHigh) {
                errln((UnicodeString)"Fail: [" + cal.getType() + "] " +
                      ymdToString(cal, ymd) +
                      " Range for min of " + FIELD_NAME[f] + "(" + f +
                      ")=" + minLow + ".." + minHigh +
                      ", actual_min=" + minActual);
            }
            if (maxActual < maxLow || maxActual > maxHigh) {
                if ( uprv_strcmp(cal.getType(), "chinese") == 0 &&
                        testMillis >= 2842992000000.0  && testMillis <= 2906668800000.0 &&
                     logKnownIssue("12620", "chinese calendar failures for some actualMax tests")) {
                    logln((UnicodeString)"KnownFail: [" + cal.getType() + "] " +
                          ymdToString(cal, ymd) +
                          " Range for max of " + FIELD_NAME[f] + "(" + f +
                          ")=" + maxLow + ".." + maxHigh +
                          ", actual_max=" + maxActual);
                } else {
                    errln((UnicodeString)"Fail: [" + cal.getType() + "] " +
                          ymdToString(cal, ymd) +
                          " Range for max of " + FIELD_NAME[f] + "(" + f +
                          ")=" + maxLow + ".." + maxHigh +
                          ", actual_max=" + maxActual);
                }
            }
            if (v < minActual || v > maxActual) {
                // 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)"KnownFail: [" + cal.getType() + "] " +
                          ymdToString(cal, ymd) +
                          " " + FIELD_NAME[f] + "(" + f + ")=" + v +
                          ", actual=" + minActual + ".." + maxActual +
                          ", allowed=(" + minLow + ".." + minHigh + ")..(" +
                          maxLow + ".." + maxHigh + ")");
                } else if ( uprv_strcmp(cal.getType(), "chinese") == 0 &&
                        testMillis >= 2842992000000.0  && testMillis <= 2906668800000.0 &&
                     logKnownIssue("12620", "chinese calendar failures for some actualMax tests")) {
                    logln((UnicodeString)"KnownFail: [" + 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);
        if (failure(status, "Calendar::add")) {
            return;
        }
    }

    // Check actual maxima and minima seen against ranges returned
    // by API.
    UnicodeString buf;
    for (j = 0; fieldsToTest[j] >= 0; ++j) {
        int32_t rangeLow, rangeHigh;
        UBool fullRangeSeen = TRUE;
        UCalendarDateFields f = (UCalendarDateFields)fieldsToTest[j];

        buf.remove();
        buf.append((UnicodeString)"[" + cal.getType() + "] " + FIELD_NAME[f]);

        // Minumum
        rangeLow = cal.getMinimum(f);
        rangeHigh = cal.getGreatestMinimum(f);
        if (limits[j][0] != rangeLow || limits[j][1] != rangeHigh) {
            fullRangeSeen = FALSE;
        }
        buf.append((UnicodeString)" minima range=" + rangeLow + ".." + rangeHigh);
        buf.append((UnicodeString)" minima actual=" + limits[j][0] + ".." + limits[j][1]);

        // Maximum
        rangeLow = cal.getLeastMaximum(f);
        rangeHigh = cal.getMaximum(f);
        if (limits[j][2] != rangeLow || limits[j][3] != rangeHigh) {
            fullRangeSeen = FALSE;
        }
        buf.append((UnicodeString)" maxima range=" + rangeLow + ".." + rangeHigh);
        buf.append((UnicodeString)" maxima actual=" + limits[j][2] + ".." + limits[j][3]);

        if (fullRangeSeen) {
            logln((UnicodeString)"OK: " + buf);
        } else {
            // This may or may not be an error -- if the range of dates
            // we scan over doesn't happen to contain a minimum or
            // maximum, it doesn't mean some other range won't.
            logln((UnicodeString)"Warning: " + buf);
        }
    }

    logln((UnicodeString)"End: " + greg.getTime(status));
}
Beispiel #6
0
void
CalendarLimitTest::doTheoreticalLimitsTest(Calendar& cal, UBool leapMonth) {
    const char* calType = cal.getType();

    int32_t nDOW = cal.getMaximum(UCAL_DAY_OF_WEEK);
    int32_t maxDOY = cal.getMaximum(UCAL_DAY_OF_YEAR);
    int32_t lmaxDOW = cal.getLeastMaximum(UCAL_DAY_OF_YEAR);
    int32_t maxWOY = cal.getMaximum(UCAL_WEEK_OF_YEAR);
    int32_t lmaxWOY = cal.getLeastMaximum(UCAL_WEEK_OF_YEAR);
    int32_t maxM = cal.getMaximum(UCAL_MONTH) + 1;
    int32_t lmaxM = cal.getLeastMaximum(UCAL_MONTH) + 1;
    int32_t maxDOM = cal.getMaximum(UCAL_DAY_OF_MONTH);
    int32_t lmaxDOM = cal.getLeastMaximum(UCAL_DAY_OF_MONTH);
    int32_t maxDOWIM = cal.getMaximum(UCAL_DAY_OF_WEEK_IN_MONTH);
    int32_t lmaxDOWIM = cal.getLeastMaximum(UCAL_DAY_OF_WEEK_IN_MONTH);
    int32_t maxWOM = cal.getMaximum(UCAL_WEEK_OF_MONTH);
    int32_t lmaxWOM = cal.getLeastMaximum(UCAL_WEEK_OF_MONTH);
    int32_t minDaysInFirstWeek = cal.getMinimalDaysInFirstWeek();

    // Day of year
    int32_t expected;
    if (!leapMonth) {
        expected = maxM*maxDOM;
        if (maxDOY > expected) {
            errln((UnicodeString)"FAIL: [" + calType + "] Maximum value of DAY_OF_YEAR is too big: "
                + maxDOY + "/expected: <=" + expected);
        }
        expected = lmaxM*lmaxDOM;
        if (lmaxDOW < expected) {
            errln((UnicodeString)"FAIL: [" + calType + "] Least maximum value of DAY_OF_YEAR is too small: "
                + lmaxDOW + "/expected: >=" + expected);
        }
    }

    // Week of year
    expected = maxDOY/nDOW + 1;
    if (maxWOY > expected) {
        errln((UnicodeString)"FAIL: [" + calType + "] Maximum value of WEEK_OF_YEAR is too big: "
            + maxWOY + "/expected: <=" + expected);
    }
    expected = lmaxDOW/nDOW;
    if (lmaxWOY < expected) {
        errln((UnicodeString)"FAIL: [" + calType + "] Least maximum value of WEEK_OF_YEAR is too small: "
            + lmaxWOY + "/expected >=" + expected);
    }

    // Day of week in month
    expected = (maxDOM + nDOW - 1)/nDOW;
    if (maxDOWIM != expected) {
        errln((UnicodeString)"FAIL: [" + calType + "] Maximum value of DAY_OF_WEEK_IN_MONTH is incorrect: "
            + maxDOWIM + "/expected: " + expected);
    }
    expected = (lmaxDOM + nDOW - 1)/nDOW;
    if (lmaxDOWIM != expected) {
        errln((UnicodeString)"FAIL: [" + calType + "] Least maximum value of DAY_OF_WEEK_IN_MONTH is incorrect: "
            + lmaxDOWIM + "/expected: " + expected);
    }

    // Week of month
    expected = (maxDOM + (nDOW - 1) + (nDOW - minDaysInFirstWeek)) / nDOW;
    if (maxWOM != expected) {
        errln((UnicodeString)"FAIL: [" + calType + "] Maximum value of WEEK_OF_MONTH is incorrect: "
            + maxWOM + "/expected: " + expected);
    }
    expected = (lmaxDOM + (nDOW - minDaysInFirstWeek)) / nDOW;
    if (lmaxWOM != expected) {
        errln((UnicodeString)"FAIL: [" + calType + "] Least maximum value of WEEK_OF_MONTH is incorrect: "
            + lmaxWOM + "/expected: " + expected);
    }
}