]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/test/cintltst/ccaltst.c
ICU-66108.tar.gz
[apple/icu.git] / icuSources / test / cintltst / ccaltst.c
index 9333b51f0c102031af7d2736d32cf3bd920971d5..4e9679abd6115b968526a8157e24d04457ecbd97 100644 (file)
@@ -1,3 +1,5 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
 /********************************************************************
  * Copyright (c) 1997-2016, International Business Machines
  * Corporation and others. All Rights Reserved.
@@ -38,8 +40,10 @@ void TestGetTZTransition(void);
 
 void TestGetWindowsTimeZoneID(void);
 void TestGetTimeZoneIDByWindowsID(void);
-void TestClear(void);
-void TestGetDayPeriods(); /* Apple-specific */
+void TestJpnCalAddSetNextEra(void);
+void TestClear(void); /* Apple-specific */
+void TestPersianCalOverflow(void); /* Apple-specific */
+void TestGetDayPeriods(void); /* Apple-specific */
 
 void addCalTest(TestNode** root);
 
@@ -62,7 +66,9 @@ void addCalTest(TestNode** root)
     addTest(root, &TestGetTZTransition, "tsformat/ccaltst/TestGetTZTransition");
     addTest(root, &TestGetWindowsTimeZoneID, "tsformat/ccaltst/TestGetWindowsTimeZoneID");
     addTest(root, &TestGetTimeZoneIDByWindowsID, "tsformat/ccaltst/TestGetTimeZoneIDByWindowsID");
+    addTest(root, &TestJpnCalAddSetNextEra, "tsformat/ccaltst/TestJpnCalAddSetNextEra");
     addTest(root, &TestClear, "tsformat/ccaltst/TestClear");
+    addTest(root, &TestPersianCalOverflow, "tsformat/ccaltst/TestPersianCalOverflow");
     addTest(root, &TestGetDayPeriods, "tsformat/ccaltst/TestGetDayPeriods"); /* Apple-specific */
 }
 
@@ -113,8 +119,9 @@ static void TestCalendar()
     UDateFormat *datdef = 0;
     UChar *result = 0;
     int32_t resultlength, resultlengthneeded;
-    char tempMsgBuf[256];
-    UChar zone1[32], zone2[32];
+    char tempMsgBuf[1024];  // u_austrcpy() of some formatted dates & times.
+    char tempMsgBuf2[256];  // u_austrcpy() of some formatted dates & times.
+    UChar zone1[64], zone2[64];
     const char *tzver = 0;
     UChar canonicalID[64];
     UBool isSystemID = FALSE;
@@ -228,10 +235,10 @@ static void TestCalendar()
         log_err("FAIL: ucal_getDSTSavings(PST) => %d, expect %d\n", i, 1*60*60*1000);
     }
 
-    /*Test ucal_set/getDefaultTimeZone*/
+    /*Test ucal_set/getDefaultTimeZone and ucal_getHostTimeZone */
     status = U_ZERO_ERROR;
     i = ucal_getDefaultTimeZone(zone1, UPRV_LENGTHOF(zone1), &status);
-    if (U_FAILURE(status)) {
+    if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) {
         log_err("FAIL: ucal_getDefaultTimeZone() => %s\n",
                 u_errorName(status));
     } else {
@@ -247,6 +254,17 @@ static void TestCalendar()
             } else {
                 if (u_strcmp(zone2, EUROPE_PARIS) != 0) {
                     log_data_err("FAIL: ucal_getDefaultTimeZone() did not return Europe/Paris (Are you missing data?)\n");
+                } else {
+                    // Redetect the host timezone, it should be the same as zone1 even though ICU's default timezone has been changed.
+                    i = ucal_getHostTimeZone(zone2, UPRV_LENGTHOF(zone2), &status);
+                    if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) {
+                        log_err("FAIL: ucal_getHostTimeZone() => %s\n", u_errorName(status));
+                    } else {
+                        if (u_strcmp(zone1, zone2) != 0) {
+                            log_err("FAIL: ucal_getHostTimeZone() should give the same host timezone even if the default changed. (Got '%s', Expected '%s').\n",
+                                u_austrcpy(tempMsgBuf, zone2), u_austrcpy(tempMsgBuf2, zone1));
+                        }
+                    }
                 }
             }
         }
@@ -259,7 +277,7 @@ static void TestCalendar()
     tzver = ucal_getTZDataVersion(&status);
     if (U_FAILURE(status)) {
         log_err_status(status, "FAIL: ucal_getTZDataVersion() => %s\n", u_errorName(status));
-    } else if (uprv_strlen(tzver) != 5 /*4 digits + 1 letter*/) {
+    } else if (uprv_strlen(tzver) < 5 || uprv_strlen(tzver) > 7 /*4 digits + 1-3 letters*/) {
         log_err("FAIL: Bad version string was returned by ucal_getTZDataVersion\n");
     } else {
         log_verbose("PASS: ucal_getTZDataVersion returned %s\n", tzver);
@@ -346,6 +364,11 @@ static void TestCalendar()
     datdef=udat_open(UDAT_FULL,UDAT_FULL ,NULL, NULL, 0,NULL,0,&status);
     if(U_FAILURE(status)){
         log_data_err("FAIL: error in creating the dateformat : %s (Are you missing data?)\n", u_errorName(status));
+        ucal_close(caldef2);
+        ucal_close(calfr);
+        ucal_close(calit);
+        ucal_close(calfrclone);
+        ucal_close(caldef);
         return;
     }
     log_verbose("PASS: The current date and time fetched is %s\n", u_austrcpy(tempMsgBuf, myDateFormat(datdef, now)) );
@@ -525,6 +548,10 @@ static void TestGetSetDateAPI()
     if(U_FAILURE(status))
     {
         log_data_err("error in creating the dateformat : %s (Are you missing data?)\n", u_errorName(status));
+        ucal_close(caldef);
+        ucal_close(caldef2);
+        ucal_close(caldef3);
+        udat_close(datdef);
         return;
     }
 
@@ -686,7 +713,7 @@ static void TestGetSetDateAPI()
 
     /*Testing  if setDate works fine  */
     log_verbose("\nTesting the ucal_setDate() function \n");
-    u_uastrcpy(temp, "Dec 17, 1971, 11:05:28 PM");
+    u_uastrcpy(temp, "Dec 17, 1971 at 11:05:28 PM");
     ucal_setDate(caldef,1971, UCAL_DECEMBER, 17, &status);
     if(U_FAILURE(status)){
         log_err("error in setting the calendar date : %s\n", u_errorName(status));
@@ -717,7 +744,7 @@ static void TestGetSetDateAPI()
 
     /*Testing if setDateTime works fine */
     log_verbose("\nTesting the ucal_setDateTime() function \n");
-    u_uastrcpy(temp, "May 3, 1972, 4:30:42 PM");
+    u_uastrcpy(temp, "May 3, 1972 at 4:30:42 PM");
     ucal_setDateTime(caldef,1972, UCAL_MAY, 3, 16, 30, 42, &status);
     if(U_FAILURE(status)){
         log_err("error in setting the calendar date : %s\n", u_errorName(status));
@@ -935,7 +962,7 @@ static void TestAddRollExtensive()
     
     u_uastrcpy(tzID, "PST");
     /*open the calendar used */
-    cal=ucal_open(tzID, u_strlen(tzID), "en_US", UCAL_GREGORIAN, &status);;
+    cal=ucal_open(tzID, u_strlen(tzID), "en_US", UCAL_GREGORIAN, &status);
     if (U_FAILURE(status)) {
         log_data_err("ucal_open() failed : %s - (Are you missing data?)\n", u_errorName(status)); 
         return; 
@@ -1123,7 +1150,7 @@ static void TestGetLimits()
     
     u_uastrcpy(tzID, "PST");
     /*open the calendar used */
-    cal=ucal_open(tzID, u_strlen(tzID), "en_US", UCAL_GREGORIAN, &status);;
+    cal=ucal_open(tzID, u_strlen(tzID), "en_US", UCAL_GREGORIAN, &status);
     if (U_FAILURE(status)) {
         log_data_err("ucal_open() for gregorian calendar failed in TestGetLimits: %s - (Are you missing data?)\n", u_errorName(status));
         return; 
@@ -1221,7 +1248,7 @@ static void TestDOWProgression()
     char tempMsgBuf[256];
     u_strcpy(tzID, fgGMTID);
     /*open the calendar used */
-    cal=ucal_open(tzID, u_strlen(tzID), "en_US", UCAL_TRADITIONAL, &status);;
+    cal=ucal_open(tzID, u_strlen(tzID), "en_US", UCAL_TRADITIONAL, &status);
     if (U_FAILURE(status)) {
         log_data_err("ucal_open failed: %s - (Are you missing data?)\n", u_errorName(status));
         return; 
@@ -1238,30 +1265,33 @@ static void TestDOWProgression()
     log_verbose("\nTesting the DOW progression\n");
     
     initialDOW = ucal_get(cal, UCAL_DAY_OF_WEEK, &status);
-    if (U_FAILURE(status)) { log_data_err("ucal_get() failed: %s (Are you missing data?)\n", u_errorName(status) ); return; }
-    newDOW = initialDOW;
-    do {
-        DOW = newDOW;
-        log_verbose("DOW = %d...\n", DOW);
-        date1=ucal_getMillis(cal, &status);
-        if(U_FAILURE(status)){ log_err("ucal_getMiilis() failed: %s\n", u_errorName(status)); return;}
-        log_verbose("%s\n", u_austrcpy(tempMsgBuf, myDateFormat(datfor, date1)));
-        
-        ucal_add(cal,UCAL_DAY_OF_WEEK, delta, &status);
-        if (U_FAILURE(status)) { log_err("ucal_add() failed: %s\n", u_errorName(status)); return; }
-        
-        newDOW = ucal_get(cal, UCAL_DAY_OF_WEEK, &status);
-        if (U_FAILURE(status)) { log_err("ucal_get() failed: %s\n", u_errorName(status)); return; }
-        expectedDOW = 1 + (DOW + delta - 1) % 7;
-        date1=ucal_getMillis(cal, &status);
-        if(U_FAILURE(status)){ log_err("ucal_getMiilis() failed: %s\n", u_errorName(status)); return;}
-        if (newDOW != expectedDOW) {
-            log_err("Day of week should be %d instead of %d on %s", expectedDOW, newDOW, 
-                u_austrcpy(tempMsgBuf, myDateFormat(datfor, date1)) );    
-            return; 
+    if (U_FAILURE(status)) { 
+        log_data_err("ucal_get() failed: %s (Are you missing data?)\n", u_errorName(status) );
+    } else {
+        newDOW = initialDOW;
+        do {
+            DOW = newDOW;
+            log_verbose("DOW = %d...\n", DOW);
+            date1=ucal_getMillis(cal, &status);
+            if(U_FAILURE(status)){ log_err("ucal_getMiilis() failed: %s\n", u_errorName(status)); break;}
+            log_verbose("%s\n", u_austrcpy(tempMsgBuf, myDateFormat(datfor, date1)));
+
+            ucal_add(cal,UCAL_DAY_OF_WEEK, delta, &status);
+            if (U_FAILURE(status)) { log_err("ucal_add() failed: %s\n", u_errorName(status)); break; }
+
+            newDOW = ucal_get(cal, UCAL_DAY_OF_WEEK, &status);
+            if (U_FAILURE(status)) { log_err("ucal_get() failed: %s\n", u_errorName(status)); break; }
+            expectedDOW = 1 + (DOW + delta - 1) % 7;
+            date1=ucal_getMillis(cal, &status);
+            if(U_FAILURE(status)){ log_err("ucal_getMiilis() failed: %s\n", u_errorName(status)); break;}
+            if (newDOW != expectedDOW) {
+                log_err("Day of week should be %d instead of %d on %s", expectedDOW, newDOW, 
+                        u_austrcpy(tempMsgBuf, myDateFormat(datfor, date1)) );    
+                break; 
+            }
         }
+        while (newDOW != initialDOW);
     }
-    while (newDOW != initialDOW);
     
     ucal_close(cal);
     udat_close(datfor);
@@ -1294,16 +1324,16 @@ static void testZones(int32_t yr, int32_t mo, int32_t dt, int32_t hr, int32_t mn
     char tempMsgBuf[256];
 
     u_strcpy(tzID, fgGMTID);
-    gmtcal=ucal_open(tzID, 3, "en_US", UCAL_TRADITIONAL, &status);;
+    gmtcal=ucal_open(tzID, 3, "en_US", UCAL_TRADITIONAL, &status);
     if (U_FAILURE(status)) {
         log_data_err("ucal_open failed: %s - (Are you missing data?)\n", u_errorName(status)); 
-        return
+        goto cleanup
     }
     u_uastrcpy(tzID, "PST");
     cal = ucal_open(tzID, 3, "en_US", UCAL_TRADITIONAL, &status);
     if (U_FAILURE(status)) {
         log_err("ucal_open failed: %s\n", u_errorName(status));
-        return
+        goto cleanup
     }
     
     datfor=udat_open(UDAT_MEDIUM,UDAT_MEDIUM ,NULL, fgGMTID,-1,NULL, 0, &status);
@@ -1314,13 +1344,13 @@ static void testZones(int32_t yr, int32_t mo, int32_t dt, int32_t hr, int32_t mn
     ucal_setDateTime(gmtcal, yr, mo - 1, dt, hr, mn, sc, &status);
     if (U_FAILURE(status)) {
         log_data_err("ucal_setDateTime failed: %s (Are you missing data?)\n", u_errorName(status));
-        return
+        goto cleanup
     }
     ucal_set(gmtcal, UCAL_MILLISECOND, 0);
     date1 = ucal_getMillis(gmtcal, &status);
     if (U_FAILURE(status)) {
         log_err("ucal_getMillis failed: %s\n", u_errorName(status));
-        return;
+        goto cleanup;
     }
     log_verbose("date = %s\n", u_austrcpy(tempMsgBuf, myDateFormat(datfor, date1)) );
 
@@ -1328,7 +1358,7 @@ static void testZones(int32_t yr, int32_t mo, int32_t dt, int32_t hr, int32_t mn
     ucal_setMillis(cal, date1, &status);
     if (U_FAILURE(status)) {
         log_err("ucal_setMillis() failed: %s\n", u_errorName(status));
-        return;
+        goto cleanup;
     }
 
     offset = ucal_get(cal, UCAL_ZONE_OFFSET, &status);
@@ -1336,7 +1366,7 @@ static void testZones(int32_t yr, int32_t mo, int32_t dt, int32_t hr, int32_t mn
    
     if (U_FAILURE(status)) {
         log_err("ucal_get() failed: %s\n", u_errorName(status));
-        return;
+        goto cleanup;
     }
     temp=(double)((double)offset / 1000.0 / 60.0 / 60.0);
     /*printf("offset for %s %f hr\n", austrdup(myDateFormat(datfor, date1)), temp);*/
@@ -1347,7 +1377,7 @@ static void testZones(int32_t yr, int32_t mo, int32_t dt, int32_t hr, int32_t mn
                     ucal_get(cal, UCAL_MILLISECOND, &status) - offset;
     if (U_FAILURE(status)) {
         log_err("ucal_get() failed: %s\n", u_errorName(status));
-        return;
+        goto cleanup;
     }
     
     expected = ((hr * 60 + mn) * 60 + sc) * 1000;
@@ -1357,6 +1387,8 @@ static void testZones(int32_t yr, int32_t mo, int32_t dt, int32_t hr, int32_t mn
     }
     else
         log_verbose("PASS: the offset between local and GMT is correct\n");
+
+cleanup:
     ucal_close(gmtcal);
     ucal_close(cal);
     udat_close(datfor);
@@ -1631,7 +1663,7 @@ static void TestGetKeywordValuesForLocale() {
                 ALLList = ulist_getListFromEnum(ALL);
                 for (j = 0; j < size; j++) {
                     if ((value = uenum_next(all, &valueLength, &status)) != NULL && U_SUCCESS(status)) {
-                        if (!ulist_containsString(ALLList, value, uprv_strlen(value))) {
+                        if (!ulist_containsString(ALLList, value, (int32_t)uprv_strlen(value))) {
                             log_err("Locale %s have %s not in ALL\n", loc, value);
                             matchAll = FALSE;
                             break;
@@ -1732,10 +1764,17 @@ static const TestDaysOfWeek daysOfWeek_hi_IN[] = { /* Sunday only */
     { UCAL_SATURDAY, UCAL_WEEKDAY,       0        },
     { UCAL_SUNDAY,   UCAL_WEEKEND,       0        },
 };
+static const TestDaysOfWeek daysOfWeek_en_UG[] = { /* Sunday only */
+    { UCAL_MONDAY,   UCAL_WEEKDAY,       0        },
+    { UCAL_FRIDAY,   UCAL_WEEKDAY,       0        },
+    { UCAL_SATURDAY, UCAL_WEEKDAY,       0        },
+    { UCAL_SUNDAY,   UCAL_WEEKEND,       0        },
+};
 static const TestDaysOfWeekList testDays[] = {
     { "en_US", daysOfWeek_en_US, UPRV_LENGTHOF(daysOfWeek_en_US) },
     { "ar_OM", daysOfWeek_ar_OM, UPRV_LENGTHOF(daysOfWeek_ar_OM) },
     { "hi_IN", daysOfWeek_hi_IN, UPRV_LENGTHOF(daysOfWeek_hi_IN) },
+    { "en_UG", daysOfWeek_en_UG, UPRV_LENGTHOF(daysOfWeek_en_UG) },
     { "en_US@rg=OMZZZZ", daysOfWeek_ar_OM, UPRV_LENGTHOF(daysOfWeek_ar_OM) },
     { "hi@rg=USZZZZ",    daysOfWeek_en_US, UPRV_LENGTHOF(daysOfWeek_en_US) },
 };
@@ -1967,7 +2006,7 @@ void TestAmbiguousWallTime() {
     UDate t, expected;
 
     u_uastrcpy(tzID, "America/New_York");
-    ucal = ucal_open(tzID, -1, NULL, UCAL_DEFAULT, &status);
+    ucal = ucal_open(tzID, -1, "en_US", UCAL_DEFAULT, &status);
     if (U_FAILURE(status)) {
         log_err("FAIL: Failed to create a calendar");
         return;
@@ -2379,6 +2418,11 @@ static const UChar tzTronto[] = /* America/Toronto */
 static const UChar sBogus[] = /* Bogus */
     {0x42,0x6F,0x67,0x75,0x73,0x00};
 
+#ifndef U_DEBUG
+static const UChar sBogusWithVariantCharacters[] = /* Bogus with Variant characters: Hèℓℓô Wôřℓδ */
+    {0x48,0xE8,0x2113,0x2113,0xF4,0x20,0x57,0xF4,0x159,0x2113,0x3B4,0x00};
+#endif
+
 void TestGetWindowsTimeZoneID() {
     UErrorCode status;
     UChar winID[64];
@@ -2445,7 +2489,6 @@ void TestGetTimeZoneIDByWindowsID() {
             log_err("FAIL: TZ ID for Eastern Standard Time - CA\n");
         }
     }
-
     {
         status = U_ZERO_ERROR;
         len = ucal_getTimeZoneIDForWindowsID(sBogus, -1, NULL, tzID, UPRV_LENGTHOF(tzID), &status);
@@ -2455,6 +2498,73 @@ void TestGetTimeZoneIDByWindowsID() {
             log_err("FAIL: TZ ID for Bogus\n");
         }
     }
+#ifndef U_DEBUG
+    // This test is only for release mode because it will cause an assertion failure in debug builds.
+    // We don't check the API result for errors as the only purpose of this test is to ensure that
+    // input variant characters don't cause abort() to be called and/or that ICU doesn't crash.
+    {
+        status = U_ZERO_ERROR;
+        len = ucal_getTimeZoneIDForWindowsID(sBogusWithVariantCharacters, -1, NULL, tzID, UPRV_LENGTHOF(tzID), &status);
+    }
+#endif
+}
+
+// The following currently assumes that Reiwa is the last known/valid era.
+// Filed ICU-20551 to generalize this when we have more time...
+void TestJpnCalAddSetNextEra() {
+    UErrorCode status = U_ZERO_ERROR;
+    UCalendar *jCal = ucal_open(NULL, 0, "ja_JP@calendar=japanese", UCAL_DEFAULT, &status);
+    if ( U_FAILURE(status) ) {
+        log_data_err("FAIL: ucal_open for ja_JP@calendar=japanese, status %s\n", u_errorName(status));
+    } else {
+        ucal_clear(jCal); // This sets to 1970, in Showa
+        int32_t sEra = ucal_get(jCal, UCAL_ERA, &status); // Don't assume era number for Showa
+        if ( U_FAILURE(status) ) {
+            log_data_err("FAIL: ucal_get ERA for Showa, status %s\n", u_errorName(status));
+        } else {
+            int32_t iEra, eYear;
+            int32_t startYears[4] = { 1926, 1989, 2019, 0 }; // start years for Showa, Heisei, Reiwa; 0 marks invalid era
+            for (iEra = 1; iEra < 4; iEra++) {
+                status = U_ZERO_ERROR;
+                ucal_clear(jCal);
+                ucal_set(jCal, UCAL_ERA, sEra+iEra);
+                eYear = ucal_get(jCal, UCAL_EXTENDED_YEAR, &status);
+                if ( U_FAILURE(status) ) {
+                    log_err("FAIL: set %d, ucal_get EXTENDED_YEAR, status %s\n", iEra, u_errorName(status));
+                } else if (startYears[iEra] == 0) { // Apple-specific section, for iEra==3
+                    // invalid era, start should be in the far future with non-negative millis
+                    if (eYear < 10000) {
+                        log_err("ERROR: set %d, invalid era should have faraway start year, but get %d\n", iEra, eYear);
+                    }
+                    UDate date = ucal_getMillis(jCal, &status);
+                    if ( U_FAILURE(status) ) {
+                        log_err("FAIL: set %d, ucal_getMillis, status %s\n", iEra, u_errorName(status));
+                    } else if (date < 0) {
+                        log_err("ERROR: set %d, ucal_getMillis should be positive, but get %.1f\n", iEra, date);
+                    }
+                } else if (eYear != startYears[iEra]) {
+                    log_err("ERROR: set %d, expected start year %d but get %d\n", iEra, startYears[iEra], eYear);
+                } else {
+                    ucal_add(jCal, UCAL_ERA, 1, &status);
+                    if ( U_FAILURE(status) ) {
+                        log_err("FAIL: set %d, ucal_add ERA 1, status %s\n", iEra, u_errorName(status));
+                    } else {
+                        eYear = ucal_get(jCal, UCAL_EXTENDED_YEAR, &status);
+                        if ( U_FAILURE(status) ) {
+                            log_err("FAIL: set %d then add ERA 1, ucal_get EXTENDED_YEAR, status %s\n", iEra, u_errorName(status));
+                        } else {
+                            // If this is the last valid era, we expect adding an era to pin to the current era
+                            int32_t nextEraStart = (startYears[iEra+1] == 0)? startYears[iEra]: startYears[iEra+1];
+                            if (eYear != nextEraStart) {
+                                log_err("ERROR: set %d then add ERA 1, expected start year %d but get %d\n", iEra, nextEraStart, eYear);
+                            }
+                        }
+                    }
+                }
+             }
+        }
+        ucal_close(jCal);
+    }
 }
 
 typedef struct {
@@ -2506,6 +2616,37 @@ void TestClear() {
     }
 }
 
+void TestPersianCalOverflow() {
+    const char * locale = "bs_Cyrl@calendar=persian";
+    UErrorCode status = U_ZERO_ERROR;
+    UCalendar * ucal = ucal_open(NULL, 0, locale, UCAL_DEFAULT, &status);
+    if ( U_FAILURE(status) ) {
+        log_data_err("FAIL: ucal_open for locale %s, status %s\n", locale, u_errorName(status)); 
+    } else {
+        int32_t maxMonth = ucal_getLimit(ucal, UCAL_MONTH, UCAL_MAXIMUM, &status);
+        int32_t maxDayOfMonth = ucal_getLimit(ucal, UCAL_DATE, UCAL_MAXIMUM, &status);
+        if ( U_FAILURE(status) ) {
+            log_err("FAIL: ucal_getLimit MONTH/DATE for locale %s, status %s\n", locale, u_errorName(status)); 
+        } else {
+            int32_t jd, month, dayOfMonth;
+            for (jd = 67023580; jd <= 67023584; jd++) { // year 178171, int32_t overflow if jd >= 67023582
+                status = U_ZERO_ERROR;
+                ucal_clear(ucal);
+                ucal_set(ucal, UCAL_JULIAN_DAY, jd);
+                month = ucal_get(ucal, UCAL_MONTH, &status);
+                dayOfMonth = ucal_get(ucal, UCAL_DATE, &status);
+                if ( U_FAILURE(status) ) {
+                    log_err("FAIL: ucal_get MONTH/DATE for locale %s, julianDay %d, status %s\n", locale, jd, u_errorName(status)); 
+                } else if (month > maxMonth || dayOfMonth > maxDayOfMonth) {
+                    log_err("FAIL: locale %s, julianDay %d; maxMonth %d, got month %d; maxDayOfMonth %d, got dayOfMonth %d\n",
+                            locale, jd, maxMonth, month, maxDayOfMonth, dayOfMonth); 
+                }
+            }
+        }
+        ucal_close(ucal);
+    }
+}
+
 /* Apple-specific */
 typedef struct {
     const char * locale;