ICU-13183 for compatibility, get(Base)Skeleton should not include 'a' added by DateTimeMatcher; add tests

X-SVN-Rev: 40133
This commit is contained in:
Peter Edberg 2017-05-24 06:57:45 +00:00
parent 6e8c655270
commit e2e48c9dce
5 changed files with 90 additions and 47 deletions

View file

@ -1917,6 +1917,10 @@ DateTimeMatcher::set(const UnicodeString& pattern, FormatParser* fp, PtnSkeleton
for (i=0; i<UDATPG_FIELD_COUNT; ++i) {
skeletonResult.type[i] = NONE;
}
skeletonResult.original.clear();
skeletonResult.baseOriginal.clear();
skeletonResult.addedDefaultDayPeriod = FALSE;
fp->set(pattern);
for (i=0; i < fp->itemNumber; i++) {
const UnicodeString& value = fp->items[i];
@ -1955,6 +1959,7 @@ DateTimeMatcher::set(const UnicodeString& pattern, FormatParser* fp, PtnSkeleton
skeletonResult.original.populate(UDATPG_DAYPERIOD_FIELD, dtTypes[i].patternChar, dtTypes[i].minLen);
skeletonResult.baseOriginal.populate(UDATPG_DAYPERIOD_FIELD, dtTypes[i].patternChar, dtTypes[i].minLen);
skeletonResult.type[UDATPG_DAYPERIOD_FIELD] = dtTypes[i].type;
skeletonResult.addedDefaultDayPeriod = TRUE;
break;
}
}
@ -2387,13 +2392,27 @@ PtnSkeleton::equals(const PtnSkeleton& other) const {
UnicodeString
PtnSkeleton::getSkeleton() const {
UnicodeString result;
return original.appendTo(result);
result = original.appendTo(result);
int32_t pos;
if (addedDefaultDayPeriod && (pos = result.indexOf(LOW_A)) >= 0) {
// for backward compatibility: if DateTimeMatcher.set added a single 'a' that
// was not in the provided skeleton, remove it here before returning skeleton.
result.remove(pos, 1);
}
return result;
}
UnicodeString
PtnSkeleton::getBaseSkeleton() const {
UnicodeString result;
return baseOriginal.appendTo(result);
result = baseOriginal.appendTo(result);
int32_t pos;
if (addedDefaultDayPeriod && (pos = result.indexOf(LOW_A)) >= 0) {
// for backward compatibility: if DateTimeMatcher.set added a single 'a' that
// was not in the provided skeleton, remove it here before returning skeleton.
result.remove(pos, 1);
}
return result;
}
UChar

View file

@ -156,6 +156,7 @@ public:
int32_t type[UDATPG_FIELD_COUNT];
SkeletonFields original;
SkeletonFields baseOriginal;
UBool addedDefaultDayPeriod;
PtnSkeleton();
PtnSkeleton(const PtnSkeleton& other);

View file

@ -356,6 +356,16 @@ void IntlTestDateTimePatternGeneratorAPI::testAPI(/*char *par*/)
UnicodeString("MMMMMd"),
};
const char* testGetSkeletonAndBase[][3] = {
// pattern skeleton baseSkeleton
{ "dd-MMM", "MMMdd", "MMMd" },
{ "dd/MMMM/yy", "yyMMMMdd", "yMMMMd" },
{ "h", "h", "h" },
{ "ah", "ah", "ah" },
{ "aaaah", "aaaah", "aaaah" },
{ "Bh", "Bh", "Bh" }
};
UnicodeString newDecimal(" "); // space
UnicodeString newAppendItemName("hrs.");
UnicodeString newAppendItemFormat("{1} {0}");
@ -511,34 +521,25 @@ void IntlTestDateTimePatternGeneratorAPI::testAPI(/*char *par*/)
}
// ======== Test getSkeleton and getBaseSkeleton
status = U_ZERO_ERROR;
pattern = UnicodeString("dd-MMM");
UnicodeString expectedSkeleton = UnicodeString("MMMdd");
UnicodeString expectedBaseSkeleton = UnicodeString("MMMd");
UnicodeString retSkeleton = gen->getSkeleton(pattern, status);
if(U_FAILURE(status) || retSkeleton != expectedSkeleton ) {
errln("ERROR: Unexpected result from getSkeleton().\n");
errln(UnicodeString(" Got: ") + retSkeleton + UnicodeString(" Expected: ") + expectedSkeleton );
}
retSkeleton = gen->getBaseSkeleton(pattern, status);
if(U_FAILURE(status) || retSkeleton != expectedBaseSkeleton) {
errln("ERROR: Unexpected result from getBaseSkeleton().\n");
errln(UnicodeString(" Got: ") + retSkeleton + UnicodeString(" Expected:")+ expectedBaseSkeleton);
int32_t i, count = UPRV_LENGTHOF(testGetSkeletonAndBase);
for (i = 0; i < count; i++) {
status = U_ZERO_ERROR;
pattern = UnicodeString(testGetSkeletonAndBase[i][0]);
UnicodeString expectedSkeleton = UnicodeString(testGetSkeletonAndBase[i][1]);
UnicodeString expectedBaseSkeleton = UnicodeString(testGetSkeletonAndBase[i][2]);
UnicodeString retSkeleton = gen->getSkeleton(pattern, status);
if(U_FAILURE(status) || retSkeleton != expectedSkeleton ) {
errln("ERROR: Unexpected result from getSkeleton().\n");
errln(UnicodeString(" Got: ") + retSkeleton + UnicodeString(" Expected: ") + expectedSkeleton );
}
retSkeleton = gen->getBaseSkeleton(pattern, status);
if(U_FAILURE(status) || retSkeleton != expectedBaseSkeleton) {
errln("ERROR: Unexpected result from getBaseSkeleton().\n");
errln(UnicodeString(" Got: ") + retSkeleton + UnicodeString(" Expected:")+ expectedBaseSkeleton);
}
}
pattern = UnicodeString("dd/MMMM/yy");
expectedSkeleton = UnicodeString("yyMMMMdd");
expectedBaseSkeleton = UnicodeString("yMMMMd");
retSkeleton = gen->getSkeleton(pattern, status);
if(U_FAILURE(status) || retSkeleton != expectedSkeleton ) {
errln("ERROR: Unexpected result from getSkeleton().\n");
errln(UnicodeString(" Got: ") + retSkeleton + UnicodeString(" Expected: ") + expectedSkeleton );
}
retSkeleton = gen->getBaseSkeleton(pattern, status);
if(U_FAILURE(status) || retSkeleton != expectedBaseSkeleton) {
errln("ERROR: Unexpected result from getBaseSkeleton().\n");
errln(UnicodeString(" Got: ") + retSkeleton + UnicodeString(" Expected:")+ expectedBaseSkeleton);
}
delete format;
delete zone;
delete gen;
@ -711,7 +712,6 @@ void IntlTestDateTimePatternGeneratorAPI::testAPI(/*char *par*/)
return;
}
UChar newChar;
int32_t i;
for (i=0; i<10; ++i) {
UnicodeString randomSkeleton;
int32_t len = rand() % 20;
@ -771,7 +771,7 @@ void IntlTestDateTimePatternGeneratorAPI::testAPI(/*char *par*/)
}
UnicodeString returnPattern, *ptrSkeleton;
ptrSkeletonEnum->reset(status);
int32_t count=ptrSkeletonEnum->count(status);
count=ptrSkeletonEnum->count(status);
for (i=0; i<count; ++i) {
ptrSkeleton = (UnicodeString *)ptrSkeletonEnum->snext(status);
returnPattern = test->getPatternForSkeleton(*ptrSkeleton);
@ -1137,14 +1137,14 @@ enum { kCharBufMax = 31 };
void IntlTestDateTimePatternGeneratorAPI::testSkeletonsWithDayPeriods() {
const char * patterns[] = {
// since icu4c getEmptyInstance does not call addCanonicalItems (unlike J), set these here:
"a", // should get skeleton a
"H", // should get skeleton H
"m", // should get skeleton m
"s", // should get skeleton s
"a", // should get internal skeleton a
"H", // should get internalskeleton H
"m", // should get internalskeleton m
"s", // should get internalskeleton s
// patterns from which to construct sample data for a locale
//"H", // should get skeleton H
"h a", // should get skeleton ah
"B h", // should get skeleton Bh
//"H", // should get internalskeleton H
"h a", // should get internalskeleton ah
"B h", // should get internalskeleton Bh
};
const char* testItems[][2] = {
// sample requested skeletons and results

View file

@ -2353,19 +2353,30 @@ public class DateTimePatternGenerator implements Freezable<DateTimePatternGenera
@Override
public String toString() {
return appendTo(new StringBuilder()).toString();
return appendTo(new StringBuilder(), false, false).toString();
}
public String toString(boolean skipDayPeriod) {
return appendTo(new StringBuilder(), false, skipDayPeriod).toString();
}
public String toCanonicalString() {
return appendTo(new StringBuilder(), true).toString();
return appendTo(new StringBuilder(), true, false).toString();
}
public String toCanonicalString(boolean skipDayPeriod) {
return appendTo(new StringBuilder(), true, skipDayPeriod).toString();
}
public StringBuilder appendTo(StringBuilder sb) {
return appendTo(sb, false);
return appendTo(sb, false, false);
}
private StringBuilder appendTo(StringBuilder sb, boolean canonical) {
private StringBuilder appendTo(StringBuilder sb, boolean canonical, boolean skipDayPeriod) {
for (int i=0; i<TYPE_LIMIT; ++i) {
if (skipDayPeriod && i == DAYPERIOD) {
continue;
}
appendFieldTo(i, sb, canonical);
}
return sb;
@ -2421,6 +2432,7 @@ public class DateTimePatternGenerator implements Freezable<DateTimePatternGenera
private int[] type = new int[TYPE_LIMIT];
private SkeletonFields original = new SkeletonFields();
private SkeletonFields baseOriginal = new SkeletonFields();
private boolean addedDefaultDayPeriod = false;
// just for testing; fix to make multi-threaded later
// private static FormatParser fp = new FormatParser();
@ -2431,18 +2443,27 @@ public class DateTimePatternGenerator implements Freezable<DateTimePatternGenera
@Override
public String toString() {
return original.toString();
// for backward compatibility: addedDefaultDayPeriod true => DateTimeMatcher.set
// added a single 'a' that was not in the provided skeleton, and it will be
// removed when generating the skeleton to return.
return original.toString(addedDefaultDayPeriod);
}
// returns a string like toString but using the canonical character for most types,
// e.g. M for M or L, E for E or c, y for y or U, etc. The hour field is canonicalized
// to 'H' (for 24-hour types) or 'h' (for 12-hour types)
public String toCanonicalString() {
return original.toCanonicalString();
// for backward compatibility: addedDefaultDayPeriod true => DateTimeMatcher.set
// added a single 'a' that was not in the provided skeleton, and it will be
// removed when generating the skeleton to return.
return original.toCanonicalString(addedDefaultDayPeriod);
}
String getBasePattern() {
return baseOriginal.toString();
// for backward compatibility: addedDefaultDayPeriod true => DateTimeMatcher.set
// added a single 'a' that was not in the provided skeleton, and it will be
// removed when generating the skeleton to return.
return baseOriginal.toString(addedDefaultDayPeriod);
}
DateTimeMatcher set(String pattern, FormatParser fp, boolean allowDuplicateFields) {
@ -2450,6 +2471,7 @@ public class DateTimePatternGenerator implements Freezable<DateTimePatternGenera
Arrays.fill(type, NONE);
original.clear();
baseOriginal.clear();
addedDefaultDayPeriod = false;
fp.set(pattern);
for (Object obj : fp.getItems()) {
@ -2499,6 +2521,7 @@ public class DateTimePatternGenerator implements Freezable<DateTimePatternGenera
original.populate(DAYPERIOD, (char)row[0], row[3]);
baseOriginal.populate(DAYPERIOD, (char)row[0], row[3]);
type[DAYPERIOD] = row[2];
addedDefaultDayPeriod = true;
break;
}
}

View file

@ -91,7 +91,7 @@ public class DateTimeGeneratorTest extends TestFmwk {
// sample data in a locale (base is not in locale, just here for test)
// skel (base) pattern
{ "aH", "H", "H" }, // should ignore a
{ "h", "ah", "h a"},
{ "h", "h", "h a"},
{ "Bh", "Bh", "B h"},
};
String[][] testItems = {
@ -871,8 +871,8 @@ public class DateTimeGeneratorTest extends TestFmwk {
@Test
public void TestGetSkeleton(){
DateTimePatternGenerator dtpg = DateTimePatternGenerator.getInstance();
String[] cases = {"MMDD","MMMDD","MMM-DD","DD/MMM","ddM","MMMMd"};
String[] results = {"MMDD","MMMDD","MMMDD","MMMDD","Mdd","MMMMd"};
String[] cases = {"MMDD","MMMDD","MMM-DD","DD/MMM","ddM","MMMMd","h","ah","aaaah","Bh"};
String[] results = {"MMDD","MMMDD","MMMDD","MMMDD","Mdd","MMMMd","h","ah","aaaah","Bh"};
for(int i=0; i<cases.length; i++){
if(!dtpg.getSkeleton(cases[i]).equals(results[i])){
errln("DateTimePatternGenerator.getSkeleton(String) did " +