ICU-4567 data driven format test

X-SVN-Rev: 22335
This commit is contained in:
Steven R. Loomis 2007-08-10 02:09:24 +00:00
parent f8780f4d57
commit c1e3b68535
13 changed files with 943 additions and 222 deletions

5
.gitattributes vendored
View File

@ -143,6 +143,10 @@ icu4c/source/test/compat/tzdate.c -text
icu4c/source/test/compat/tzone.pl -text
icu4c/source/test/intltest/dadrcal.cpp -text
icu4c/source/test/intltest/dadrcal.h -text
icu4c/source/test/intltest/dadrfmt.cpp -text
icu4c/source/test/intltest/dadrfmt.h -text
icu4c/source/test/intltest/fldset.cpp -text
icu4c/source/test/intltest/fldset.h -text
icu4c/source/test/intltest/tzrulets.h -text
icu4c/source/test/perf/charperf/CharPerf_r.pl -text
icu4c/source/test/perf/convperf/ConvPerf_r.pl -text
@ -173,6 +177,7 @@ icu4c/source/test/perf/ubrkperf/UBrkPerf_r.pl -text
icu4c/source/test/perf/ustrperf/StringPerf_r.pl -text
icu4c/source/test/testdata/TestFont1.otf -text
icu4c/source/test/testdata/calendar.txt -text
icu4c/source/test/testdata/format.txt -text
icu4c/source/test/testdata/icu26_testtypes.res -text
icu4c/source/test/testdata/icu26e_testtypes.res -text
icu4c/source/test/testdata/importtest.bin -text

View File

@ -41,7 +41,7 @@ LIBS = $(LIBCTESTFW) $(LIBICUI18N) $(LIBICUUC) $(LIBICUTOOLUTIL) $(DEFAULT_LIBS)
OBJECTS = aliastst.o allcoll.o apicoll.o astrotst.o callimts.o calregts.o caltest.o \
caltztst.o canittst.o citrtest.o cntabcol.o convtest.o currcoll.o \
dadrcal.o dadrcoll.o dcfmapts.o decoll.o dtfmapts.o dtfmrgts.o dtfmtrtts.o dtfmttst.o \
fldset.o dadrfmt.o dadrcal.o dadrcoll.o dcfmapts.o decoll.o dtfmapts.o dtfmrgts.o dtfmtrtts.o dtfmttst.o \
dtptngts.o encoll.o escoll.o ficoll.o frcoll.o g7coll.o intltest.o \
itercoll.o itformat.o itmajor.o itutil.o jacoll.o lcukocol.o \
loctest.o miscdtfm.o mnkytst.o msfmrgts.o nmfmapts.o nmfmtrt.o \

View File

@ -27,219 +27,6 @@
#include <stdio.h>
/** ------- Calendar Fields Set -------- **/
class CalendarFieldsSet {
public:
CalendarFieldsSet();
~CalendarFieldsSet();
void clear();
void clear(UCalendarDateFields field);
void set(UCalendarDateFields field, int32_t amount);
UBool isSet(UCalendarDateFields field) const;
int32_t get(UCalendarDateFields field) const;
/**
* @param diffSet fillin to hold any fields different. Will have the calendar's value set on them.
* @return true if the calendar matches in these fields.
*/
UBool matches(Calendar *cal, CalendarFieldsSet &diffSet,
UErrorCode& status) const;
/**
* set the specified fields on this calendar. Doesn't clear first. Returns any errors the cale
*/
void setOnCalendar(Calendar *cal, UErrorCode& status) const;
/**
* @param "expected" set to match against
* @return a formatted string listing which fields are set in
* this, with the comparison made agaainst those fields in other.
*/
UnicodeString diffFrom(const CalendarFieldsSet& other) const;
/**
* parse from a string.
* @param str the string to parse
* @param inherit the CalendarFieldsSet to inherit any inherited items from, or NULL
* @param status error code
* @return the number of items successfully parsed
*/
int32_t parseFrom(const UnicodeString& str,
const CalendarFieldsSet* inheritFrom, UErrorCode& status);
int32_t parseFrom(const UnicodeString& str, UErrorCode& status);
private:
int32_t fValue[UDAT_FIELD_COUNT]; /** field values **/
UBool fIsSet[UDAT_FIELD_COUNT]; /** Is this field set? **/
};
CalendarFieldsSet::CalendarFieldsSet() {
clear();
}
CalendarFieldsSet::~CalendarFieldsSet() {
//
}
void CalendarFieldsSet::clear() {
for (int i=0; i<UDAT_FIELD_COUNT; i++) {
fValue[i]=-1;
fIsSet[i]=FALSE;
}
}
void CalendarFieldsSet::clear(UCalendarDateFields field) {
if (field<0|| field>=UCAL_FIELD_COUNT) {
return;
}
fValue[field] = -1;
fIsSet[field] = FALSE;
}
void CalendarFieldsSet::set(UCalendarDateFields field, int32_t amount) {
if (field<0|| field>=UCAL_FIELD_COUNT) {
return;
}
fValue[field] = amount;
fIsSet[field] = TRUE;
}
UBool CalendarFieldsSet::isSet(UCalendarDateFields field) const {
if (field<0|| field>=UCAL_FIELD_COUNT) {
return FALSE;
}
return fIsSet[field];
}
int32_t CalendarFieldsSet::get(UCalendarDateFields field) const {
if (field<0|| field>=UCAL_FIELD_COUNT) {
return -1;
}
return fValue[field];
}
/**
* set the specified fields on this calendar. Doesn't clear first. Returns any errors the caller
*/
void CalendarFieldsSet::setOnCalendar(Calendar *cal, UErrorCode& /*status*/) const {
for (int i=0; i<UDAT_FIELD_COUNT; i++) {
if (isSet((UCalendarDateFields)i)) {
int32_t value = get((UCalendarDateFields)i);
//fprintf(stderr, "Setting: %s#%d=%d\n",udbg_enumName(UDBG_UCalendarDateFields,i),i,value);
cal->set((UCalendarDateFields)i, value);
}
}
}
/**
* return true if the calendar matches in these fields
*/
UBool CalendarFieldsSet::matches(Calendar *cal, CalendarFieldsSet &diffSet,
UErrorCode& status) const {
UBool match = TRUE;
if (U_FAILURE(status))
return FALSE;
for (int i=0; i<UDAT_FIELD_COUNT; i++) {
if (isSet((UCalendarDateFields)i)) {
int32_t calVal = cal->get((UCalendarDateFields)i, status);
if (U_FAILURE(status))
return FALSE;
if (calVal != get((UCalendarDateFields)i)) {
match = FALSE;
diffSet.set((UCalendarDateFields)i, calVal);
//fprintf(stderr, "match failed: %s#%d=%d != %d\n",udbg_enumName(UDBG_UCalendarDateFields,i),i,cal->get((UCalendarDateFields)i,status), get((UCalendarDateFields)i));;
}
}
}
return match;
}
UnicodeString CalendarFieldsSet::diffFrom(const CalendarFieldsSet& other) const {
UnicodeString str;
for (int i=0; i<UDAT_FIELD_COUNT; i++) {
if (isSet((UCalendarDateFields)i)) {
int32_t myVal = get((UCalendarDateFields)i);
int32_t theirVal = other.get((UCalendarDateFields)i);
const UnicodeString& fieldName = udbg_enumString(
UDBG_UCalendarDateFields, i);
str = str + fieldName +"="+myVal+" not "+theirVal+", ";
}
}
return str;
}
int32_t CalendarFieldsSet::parseFrom(const UnicodeString& str,
UErrorCode& status) {
return parseFrom(str, NULL, status);
}
/**
* parse from a string.
* @param str the string to parse
* @param inherit the CalendarFieldsSet to inherit any inherited items from, or NULL
* @param status error code
* @return the number of items successfully parsed or -1 on error
*/
int32_t CalendarFieldsSet::parseFrom(const UnicodeString& str,
const CalendarFieldsSet* inheritFrom, UErrorCode& status) {
UnicodeString pattern(",", "");
RegexMatcher matcher(pattern, 0, status);
UnicodeString pattern2("=", "");
RegexMatcher matcher2(pattern2, 0, status);
if (U_FAILURE(status))
return -1;
UnicodeString dest[UDAT_FIELD_COUNT+10];
int32_t destCount = matcher.split(str, dest, sizeof(dest)/sizeof(dest[0]), status);
if(U_FAILURE(status)) return -1;
for(int i=0;i<destCount;i++) {
UnicodeString kv[2];
matcher2.split(dest[i],kv,2,status);
if(U_FAILURE(status)) {
fprintf(stderr, "Parse failed: splitting\n");
return -1;
}
int32_t field = udbg_enumByString(UDBG_UCalendarDateFields, kv[0]);
if(field == -1) {
char ch[256];
const UChar *u = kv[0].getBuffer();
int32_t len = kv[0].length();
u_UCharsToChars(u, ch, len);
ch[len] = 0; /* include terminating \0 */
fprintf(stderr,"Parse Failed: Unknown Field %s\n", ch);
status = U_ILLEGAL_ARGUMENT_ERROR;
return -1;
}
int value = -1;
if(kv[1].length()==0) {
// inherit
if((inheritFrom == NULL) || !inheritFrom->isSet((UCalendarDateFields)field)) {
// couldn't inherit from field
fprintf(stderr,"Parse Failed: Couldn't inherit field %d [%s]\n", field, udbg_enumName(UDBG_UCalendarDateFields, field));
status = U_ILLEGAL_ARGUMENT_ERROR;
return -1;
}
value = inheritFrom->get((UCalendarDateFields)field);
} else {
if(field==UCAL_MONTH) {
value = udbg_enumByString(UDBG_UCalendarMonths, kv[1]);
} // else, other types..
if(value==-1) {
// parse as decimal
value = udbg_stoi(kv[1]);
}
}
//fprintf(stderr, "Parsed: %s#%d=%d\n",udbg_enumName(UDBG_UCalendarDateFields,field),field,value);
set((UCalendarDateFields)field,value);
}
return -1;
}
DataDrivenCalendarTest::DataDrivenCalendarTest() {
UErrorCode status = U_ZERO_ERROR;
driver = TestDataModule::getTestDataModule("calendar", *this, status);
@ -275,7 +62,7 @@ void DataDrivenCalendarTest::runIndexedTest(int32_t index, UBool exec,
name = "";
}
} else {
errln("format/DataDrivenTest data (calendar.res) not initialized!");
errln("format/DataDriven*Test data (calendar.res) not initialized!");
name = "";
}
@ -413,7 +200,7 @@ void DataDrivenCalendarTest::testOps(TestData *testData,
diffSet.clear();
// Is the calendar sane after being set?
if (!fromSet.matches(fromCalendar, diffSet, status)) {
UnicodeString diffs = diffSet.diffFrom(fromSet);
UnicodeString diffs = diffSet.diffFrom(fromSet, status);
errln((UnicodeString)"FAIL: "+caseString
+", SET SOURCE calendar was not set: Differences: "+ diffs
+"', status: "+ u_errorName(status));
@ -453,7 +240,7 @@ void DataDrivenCalendarTest::testOps(TestData *testData,
diffSet.clear();
if (!toSet.matches(toCalendar, diffSet, status)) {
UnicodeString diffs = diffSet.diffFrom(toSet);
UnicodeString diffs = diffSet.diffFrom(toSet, status);
errln((UnicodeString)"FAIL: "+caseString+" - , "+caseContentsString
+" Differences: "+ diffs +"', status: "
+ u_errorName(status));
@ -489,7 +276,7 @@ void DataDrivenCalendarTest::testConvert(int32_t n,
diffSet.clear();
// Is the calendar sane at the first?
if (!fromSet.matches(fromCalendar, diffSet, status)) {
UnicodeString diffs = diffSet.diffFrom(fromSet);
UnicodeString diffs = diffSet.diffFrom(fromSet, status);
errln((UnicodeString)"FAIL: "+thisString
+", SOURCE calendar was not set: Differences: "+ diffs
+"', status: "+ u_errorName(status));
@ -511,7 +298,7 @@ void DataDrivenCalendarTest::testConvert(int32_t n,
diffSet.clear();
// Is the calendar sane after being set?
if (!fromSet.matches(fromCalendar, diffSet, status)) {
UnicodeString diffs = diffSet.diffFrom(fromSet);
UnicodeString diffs = diffSet.diffFrom(fromSet, status);
errln((UnicodeString)"FAIL: "+thisString
+", SET SOURCE calendar was not set: Differences: "+ diffs
+"', status: "+ u_errorName(status));
@ -531,7 +318,7 @@ void DataDrivenCalendarTest::testConvert(int32_t n,
diffSet.clear();
if (!toSet.matches(toCalendar, diffSet, status)) {
UnicodeString diffs = diffSet.diffFrom(toSet);
UnicodeString diffs = diffSet.diffFrom(toSet, status);
errln((UnicodeString)"FAIL: "+thisString+", Differences: "+ diffs
+"', status: "+ u_errorName(status));
SimpleDateFormat fmt(UnicodeString("EEE MMM dd yyyy G"), status);

View File

@ -20,6 +20,7 @@
#include "tsdate.h"
#include "uvector.h"
#include "unicode/calendar.h"
#include "fldset.h"
class TestDataModule;
class TestData;

View File

@ -0,0 +1,312 @@
/********************************************************************
* COPYRIGHT:
* Copyright (c) 1997-2007, International Business Machines Corporation and
* others. All Rights Reserved.
********************************************************************/
/***********************************************************************
* Modification history
* Date Name Description
* 07/09/2007 srl Copied from dadrcoll.cpp
***********************************************************************/
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#include "unicode/tstdtmod.h"
#include "tsdate.h"
#include "dadrfmt.h"
#include "unicode/calendar.h"
#include "intltest.h"
#include <string.h>
#include "unicode/schriter.h"
#include "unicode/regex.h"
#include "unicode/smpdtfmt.h"
#include "unicode/dbgutil.h"
#include "fldset.h"
#include <stdio.h>
DataDrivenFormatTest::DataDrivenFormatTest() {
UErrorCode status = U_ZERO_ERROR;
driver = TestDataModule::getTestDataModule("format", *this, status);
}
DataDrivenFormatTest::~DataDrivenFormatTest() {
delete driver;
}
void DataDrivenFormatTest::runIndexedTest(int32_t index, UBool exec,
const char* &name, char* /*par */) {
if (driver != NULL) {
if (exec) {
// logln("Begin ");
}
const DataMap *info= NULL;
UErrorCode status= U_ZERO_ERROR;
TestData *testData = driver->createTestData(index, status);
if (U_SUCCESS(status)) {
name = testData->getName();
if (testData->getInfo(info, status)) {
log(info->getString("Description", status));
}
if (exec) {
log(name);
logln("---");
logln("");
processTest(testData);
}
delete testData;
} else {
name = "";
}
} else {
errln("format/DataDriven*Test data (format.res) not initialized!");
name = "";
}
}
/*
* Headers { "locale","spec", "date", "str"}
// locale: locale including calendar type
// spec: either 'PATTERN=y mm h' etc, or 'DATE=SHORT,TIME=LONG'
// date: either an unsigned long (millis), or a calendar spec ERA=0,YEAR=1, etc.. applied to the calendar type specified by the locale
// str: the expected unicode string
Cases {
{
"en_US@calendar=gregorian",
"DATE=SHORT,TIME=SHORT",
"ERA=1,YEAR=2007,MONTH=AUGUST,DATE=8,HOUR=18,MINUTE=54,SECOND=12",
"8/8/2007 6:54pm"
},
* */
void DataDrivenFormatTest::testConvertDate(TestData *testData,
const DataMap */* settings */, UBool fmt) {
UnicodeString kPATTERN("PATTERN="); // TODO: static
UnicodeString kMILLIS("MILLIS="); // TODO: static
UErrorCode status = U_ZERO_ERROR;
SimpleDateFormat basicFmt(UnicodeString("EEE MMM dd yyyy / YYYY'-W'ww-ee"),
status);
if (U_FAILURE(status)) {
errln("FAIL: Couldn't create basic SimpleDateFormat: %s\n",
u_errorName(status));
return;
}
const DataMap *currentCase= NULL;
// Start the processing
int n = 0;
while (testData->nextCase(currentCase, status)) {
char calLoc[256] = "";
DateTimeStyleSet styleSet;
UnicodeString pattern;
UBool usePattern = FALSE;
CalendarFieldsSet fromSet;
UDate fromDate;
UBool useDate = FALSE;
++n;
char theCase[200];
sprintf(theCase, "case %d:", n);
UnicodeString caseString(theCase, "");
// load params
UnicodeString locale = currentCase->getString("locale", status);
if (U_FAILURE(status)) {
errln("case %d: No 'locale' line.", n);
continue;
}
UnicodeString spec = currentCase->getString("spec", status);
if(U_FAILURE(status)) {
errln("case %d: No 'spec' line.", n);
continue;
}
UnicodeString date = currentCase->getString("date", status);
if(U_FAILURE(status)) {
errln("case %d: No 'date' line.", n);
continue;
}
UnicodeString expectStr= currentCase->getString("str", status);
if(U_FAILURE(status)) {
errln("case %d: No 'str' line.", n);
continue;
}
DateFormat *format = NULL;
// Process: 'locale'
locale.extract(0, locale.length(), calLoc, (const char*)0); // default codepage. Invariant codepage doesn't have '@'!
Locale loc(calLoc);
if(spec.startsWith(kPATTERN)) {
pattern = UnicodeString(spec,kPATTERN.length());
usePattern = TRUE;
format = new SimpleDateFormat(pattern, loc, status);
if(U_FAILURE(status)) {
errln("case %d: could not create SimpleDateFormat from pattern: %s", n, u_errorName(status));
continue;
}
} else {
if(styleSet.parseFrom(spec, status)<0 || U_FAILURE(status)) {
errln("case %d: could not parse spec as style fields: %s", n, u_errorName(status));
continue;
}
format = DateFormat::createDateTimeInstance((DateFormat::EStyle)styleSet.getDateStyle(), (DateFormat::EStyle)styleSet.getTimeStyle(), loc);
if(format == NULL ) {
errln("case %d: could not create SimpleDateFormat from styles.", n);
continue;
}
}
// parse 'date'
if(date.startsWith(kMILLIS)) {
UnicodeString millis = UnicodeString(date, kMILLIS.length());
useDate = TRUE;
fromDate = udbg_stoi(millis);
} else {
if(fromSet.parseFrom(date, status)<0 || U_FAILURE(status)) {
errln("case %d: could not parse date as calendar fields: %s", n, u_errorName(status));
continue;
}
}
Calendar *cal = Calendar::createInstance(loc, status);
if(U_FAILURE(status)) {
errln("case %d: could not create calendar from %s", n, calLoc);
}
// now, do it.
if (fmt) {
FieldPosition pos;
// logln((UnicodeString)"#"+n+" "+locale+"/"+from+" >>> "+toCalLoc+"/"
// +to);
cal->clear();
UnicodeString output;
if(useDate) {
// cal->setTime(fromDate, status);
// if(U_FAILURE(status)) {
// errln("case %d: could not set time on calendar: %s", n, u_errorName(status));
// continue;
// }
format->format(fromDate, output, pos, status);
} else {
fromSet.setOnCalendar(cal, status);
if(U_FAILURE(status)) {
errln("case %d: could not set fields on calendar: %s", n, u_errorName(status));
continue;
}
format->format(*cal, output, pos);
}
// check erro result from 'format'
if(U_FAILURE(status)) {
errln("case %d: could not format(): %s", n, u_errorName(status)); // TODO: use 'pos'
}
// if(pos.getBeginIndex()==0 && pos.getEndIndex()==0) { // TODO: more precise error?
// errln("WARNING: case %d: format's pos returned (0,0) - error ??", n);
// }
if(output == expectStr) {
logln(caseString+": format: SUCCESS! "+UnicodeString("expect=output=")+output);
} else {
errln(caseString+": format: output!=expectStr, got " + output + " expected " + expectStr);
}
} else {
cal->clear();
ParsePosition pos;
format->parse(expectStr,*cal,pos);
if(useDate) {
UDate gotDate = cal->getTime(status);
if(U_FAILURE(status)) {
errln(caseString+": parse: could not get time on calendar: "+UnicodeString(u_errorName(status)));
continue;
}
if(gotDate == fromDate) {
logln(caseString+": parse: SUCCESS! "+UnicodeString("gotDate=parseDate=")+expectStr);
} else {
UnicodeString expectDateStr, gotDateStr;
basicFmt.format(fromDate,expectDateStr);
basicFmt.format(gotDate,gotDateStr);
errln(caseString+": parse: FAIL. parsed '"+expectStr+"' and got "+gotDateStr+", expected " + expectDateStr);
}
} else {
// Calendar *cal2 = cal->clone();
// cal2->clear();
// fromSet.setOnCalendar(cal2, status);
if(U_FAILURE(status)) {
errln("case %d: parse: could not set fields on calendar: %s", n, u_errorName(status));
continue;
}
CalendarFieldsSet diffSet;
// diffSet.clear();
if (!fromSet.matches(cal, diffSet, status)) {
UnicodeString diffs = diffSet.diffFrom(fromSet, status);
errln((UnicodeString)"FAIL: "+caseString
+", Differences: '"+ diffs
+"', status: "+ u_errorName(status));
} else if (U_FAILURE(status)) {
errln("FAIL: "+caseString+" parse SET SOURCE calendar Failed to match: "
+u_errorName(status));
} else {
logln("PASS: "+caseString+" parse.");
}
}
}
delete cal;
delete format;
}
// delete basicFmt;
}
void DataDrivenFormatTest::processTest(TestData *testData) {
//Format *cal= NULL;
//const UChar *arguments= NULL;
//int32_t argLen = 0;
char testType[256];
const DataMap *settings= NULL;
//const UChar *type= NULL;
UErrorCode status = U_ZERO_ERROR;
UnicodeString testSetting;
int n = 0;
while (testData->nextSettings(settings, status)) {
status = U_ZERO_ERROR;
// try to get a locale
testSetting = settings->getString("Type", status);
if (U_SUCCESS(status)) {
if ((++n)>0) {
logln("---");
}
logln(testSetting + "---");
testSetting.extract(0, testSetting.length(), testType, "");
} else {
errln("Unable to extract 'Type'. Skipping..");
continue;
}
if (!strcmp(testType, "date_format")) {
testConvertDate(testData, settings, true);
} else if (!strcmp(testType, "date_parse")) {
testConvertDate(testData, settings, false);
} else {
errln("Unknown type: %s", testType);
}
}
}
#endif

View File

@ -0,0 +1,52 @@
/********************************************************************
* COPYRIGHT:
* Copyright (c) 2007, International Business Machines Corporation and
* others. All Rights Reserved.
********************************************************************/
/**
* DataDrivenFormatTest is a test class that uses data stored in resource
* bundles to perform testing. For more details on data structure, see
* source/test/testdata/calendar.txt
*/
#ifndef _INTLTESTDATADRIVENFORMAT
#define _INTLTESTDATADRIVENFORMAT
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#include "tsdate.h"
#include "uvector.h"
#include "unicode/format.h"
//#include "fldset.h"
class TestDataModule;
class TestData;
class DataMap;
//class DateTimeStyle;
class DataDrivenFormatTest : public IntlTest {
void runIndexedTest(int32_t index, UBool exec, const char* &name,
char* par = NULL);
public:
DataDrivenFormatTest();
virtual ~DataDrivenFormatTest();
protected:
void DataDrivenTest(char *par);
void processTest(TestData *testData);
private:
void testConvertDate(TestData *testData, const DataMap *settings, UBool fmt);
// void testOps(TestData *testData, const DataMap *settings);
// void testConvert(int32_t n, const FormatFieldsSet &fromSet,
// Format *fromCal, const FormatFieldsSet &toSet, Format *toCal,
// UBool fwd);
private:
TestDataModule *driver;
};
#endif /* #if !UCONFIG_NO_COLLATION */
#endif

View File

@ -0,0 +1,315 @@
/*
************************************************************************
* Copyright (c) 2007, International Business Machines
* Corporation and others. All Rights Reserved.
************************************************************************
*/
#include "fldset.h"
#include <stdio.h>
#include "unicode/regex.h"
FieldsSet::FieldsSet() {
// NOTREACHED
}
FieldsSet::FieldsSet(int32_t fieldCount) {
construct((UDebugEnumType)-1, fieldCount);
}
FieldsSet::FieldsSet(UDebugEnumType field) {
construct(field, udbg_enumCount(field));
}
FieldsSet::~FieldsSet() {
}
int32_t FieldsSet::fieldCount() const {
return fFieldCount;
}
void FieldsSet::construct(UDebugEnumType field, int32_t fieldCount) {
fEnum = field;
if(fieldCount > U_FIELDS_SET_MAX) {
fieldCount = U_FIELDS_SET_MAX;
}
fFieldCount = fieldCount;
clear();
}
UnicodeString FieldsSet::diffFrom(const FieldsSet& other, UErrorCode& status) const {
UnicodeString str;
if(!isSameType(other)) {
status = U_ILLEGAL_ARGUMENT_ERROR;
return UnicodeString("U_ILLEGAL_ARGUMENT_ERROR: FieldsSet of a different type!");
}
for (int i=0; i<fieldCount(); i++) {
if (isSet((UCalendarDateFields)i)) {
int32_t myVal = get(i);
int32_t theirVal = other.get(i);
if(fEnum != -1) {
const UnicodeString& fieldName = udbg_enumString(
fEnum, i);
char aval[200];
char bval[200];
sprintf(aval,"%d",myVal);
sprintf(bval,"%d",theirVal);
str = str + fieldName +"="+aval+" not "+bval+", ";
} else {
str = str + UnicodeString("some field") + "=" + myVal+" not " + theirVal+", ";
}
}
}
return str;
}
int32_t FieldsSet::parseFrom(const UnicodeString& str, const
FieldsSet* inheritFrom, UErrorCode& status) {
int goodFields = 0;
UnicodeString pattern(",", "");
RegexMatcher matcher(pattern, 0, status);
UnicodeString pattern2("=", "");
RegexMatcher matcher2(pattern2, 0, status);
if (U_FAILURE(status))
return -1;
UnicodeString dest[U_FIELDS_SET_MAX+2]; // TODO: dynamicize
int32_t destCount = matcher.split(str, dest, sizeof(dest)/sizeof(dest[0]), status);
if(U_FAILURE(status)) return -1;
for(int i=0;i<destCount;i++) {
UnicodeString kv[2];
matcher2.split(dest[i],kv,2,status);
if(U_FAILURE(status)) {
fprintf(stderr, "Parse failed: splitting\n");
return -1;
}
int32_t field = handleParseName(inheritFrom, kv[0], kv[1], status);
if(U_FAILURE(status)) {
char ch[256];
const UChar *u = kv[0].getBuffer();
int32_t len = kv[0].length();
u_UCharsToChars(u, ch, len);
ch[len] = 0; /* include terminating \0 */
fprintf(stderr,"Parse Failed: Field %s, err %s\n", ch, u_errorName(status));
return -1;
}
if(field != -1) {
handleParseValue(inheritFrom, field, kv[1], status);
if(U_FAILURE(status)) {
char ch[256];
const UChar *u = kv[1].getBuffer();
int32_t len = kv[1].length();
u_UCharsToChars(u, ch, len);
ch[len] = 0; /* include terminating \0 */
fprintf(stderr,"Parse Failed: Value %s, err %s\n", ch, u_errorName(status));
return -1;
}
goodFields++;
}
}
return goodFields;
}
UBool FieldsSet::isSameType(const FieldsSet& other) const {
return((&other==this)||
((other.fFieldCount==fFieldCount) && (other.fEnum==fEnum)));
}
void FieldsSet::clear() {
for (int i=0; i<fieldCount(); i++) {
fValue[i]=-1;
fIsSet[i]=FALSE;
}
}
void FieldsSet::clear(int32_t field) {
if (field<0|| field>=fieldCount()) {
return;
}
fValue[field] = -1;
fIsSet[field] = FALSE;
}
void FieldsSet::set(int32_t field, int32_t amount) {
if (field<0|| field>=fieldCount()) {
return;
}
fValue[field] = amount;
fIsSet[field] = TRUE;
}
UBool FieldsSet::isSet(int32_t field) const {
if (field<0|| field>=fieldCount()) {
return FALSE;
}
return fIsSet[field];
}
int32_t FieldsSet::get(int32_t field) const {
if (field<0|| field>=fieldCount()) {
return -1;
}
return fValue[field];
}
int32_t FieldsSet::handleParseName(const FieldsSet* /* inheritFrom */, const UnicodeString& name, const UnicodeString& /* substr*/ , UErrorCode& status) {
if(fEnum > -1) {
return udbg_enumByString(fEnum, name);
} else {
status = U_UNSUPPORTED_ERROR;
return -1;
}
}
void FieldsSet::parseValueDefault(const FieldsSet* inheritFrom, int32_t field, const UnicodeString& substr, UErrorCode& status) {
int32_t value = -1;
if(substr.length()==0) { // inherit requested
// inherit
if((inheritFrom == NULL) || !inheritFrom->isSet((UCalendarDateFields)field)) {
// couldn't inherit from field
fprintf(stderr,"Parse Failed: Couldn't inherit field %d [%s]\n", field, udbg_enumName(fEnum, field));
status = U_ILLEGAL_ARGUMENT_ERROR;
return;
}
value = inheritFrom->get((UCalendarDateFields)field);
} else {
value = udbg_stoi(substr);
}
set(field, value);
}
void FieldsSet::parseValueEnum(UDebugEnumType type, const FieldsSet* inheritFrom, int32_t field, const UnicodeString& substr, UErrorCode& status) {
int32_t value = udbg_enumByString(type, substr);
if(value>=0) {
set(field, value);
} else {
// fallback
parseValueDefault(inheritFrom,field,substr,status);
}
}
void FieldsSet::handleParseValue(const FieldsSet* inheritFrom, int32_t field, const UnicodeString& substr, UErrorCode& status) {
parseValueDefault(inheritFrom, field, substr, status);
}
/// CAL FIELDS
CalendarFieldsSet::CalendarFieldsSet() :
FieldsSet(UDBG_UCalendarDateFields) {
// base class will call clear.
}
CalendarFieldsSet::~CalendarFieldsSet() {
}
void CalendarFieldsSet::handleParseValue(const FieldsSet* inheritFrom, int32_t field, const UnicodeString& substr, UErrorCode& status) {
if(field==UCAL_MONTH) {
parseValueEnum(UDBG_UCalendarMonths, inheritFrom, field, substr, status);
// will fallback to default.
} else {
parseValueDefault(inheritFrom, field, substr, status);
}
}
/**
* set the specified fields on this calendar. Doesn't clear first. Returns any errors the caller
*/
void CalendarFieldsSet::setOnCalendar(Calendar *cal, UErrorCode& /*status*/) const {
for (int i=0; i<UDAT_FIELD_COUNT; i++) {
if (isSet((UCalendarDateFields)i)) {
int32_t value = get((UCalendarDateFields)i);
//fprintf(stderr, "Setting: %s#%d=%d\n",udbg_enumName(UDBG_UCalendarDateFields,i),i,value);
cal->set((UCalendarDateFields)i, value);
}
}
}
/**
* return true if the calendar matches in these fields
*/
UBool CalendarFieldsSet::matches(Calendar *cal, CalendarFieldsSet &diffSet,
UErrorCode& status) const {
UBool match = TRUE;
if (U_FAILURE(status))
return FALSE;
for (int i=0; i<UDAT_FIELD_COUNT; i++) {
if (isSet((UCalendarDateFields)i)) {
int32_t calVal = cal->get((UCalendarDateFields)i, status);
if (U_FAILURE(status))
return FALSE;
if (calVal != get((UCalendarDateFields)i)) {
match = FALSE;
diffSet.set((UCalendarDateFields)i, calVal);
//fprintf(stderr, "match failed: %s#%d=%d != %d\n",udbg_enumName(UDBG_UCalendarDateFields,i),i,cal->get((UCalendarDateFields)i,status), get((UCalendarDateFields)i));;
}
}
}
return match;
}
enum {
DTS_DATE = 0,
DTS_TIME,
DTS_COUNT
};
/**
* DateTimeSet
* */
DateTimeStyleSet::DateTimeStyleSet() :
FieldsSet(DTS_COUNT) {
}
DateTimeStyleSet::~DateTimeStyleSet() {
}
UDateFormatStyle DateTimeStyleSet::getDateStyle() const {
if(!isSet(DTS_DATE)) {
return UDAT_NONE;
} else {
return (UDateFormatStyle)get(DTS_DATE);
}
}
UDateFormatStyle DateTimeStyleSet::getTimeStyle() const {
if(!isSet(DTS_TIME)) {
return UDAT_NONE;
} else {
return (UDateFormatStyle)get(DTS_TIME);
}
}
void DateTimeStyleSet::handleParseValue(const FieldsSet* inheritFrom, int32_t field, const UnicodeString& substr, UErrorCode& status) {
// int32_t value = udbg_enumByString(UDBG_UDateFormatStyle, substr);
// fprintf(stderr, " HPV: %d -> %d\n", field, value);
parseValueEnum(UDBG_UDateFormatStyle, inheritFrom, field, substr, status);
}
int32_t DateTimeStyleSet::handleParseName(const FieldsSet* /* inheritFrom */, const UnicodeString& name, const UnicodeString& /* substr */, UErrorCode& status) {
UnicodeString kDATE("DATE"); // TODO: static
UnicodeString kTIME("TIME"); // TODO: static
if(name == kDATE ) {
return DTS_DATE;
} else if(name == kTIME) {
return DTS_TIME;
} else {
status = U_ILLEGAL_ARGUMENT_ERROR;
return -1;
}
}

View File

@ -0,0 +1,184 @@
/*
************************************************************************
* Copyright (c) 2007, International Business Machines
* Corporation and others. All Rights Reserved.
************************************************************************
*/
#ifndef FLDSET_H_
#define FLDSET_H_
#include "unicode/utypes.h"
#include "unicode/calendar.h"
#include "unicode/ucal.h"
#include "unicode/udat.h"
#include "unicode/udbgutil.h"
#include "unicode/dbgutil.h"
#include "unicode/unistr.h"
#define U_FIELDS_SET_MAX 64
class FieldsSet {
protected:
/**
* subclass interface
* @param whichEnum which enumaration value goes with this set. Will be used to calculate str values and also enum size.
*/
FieldsSet(UDebugEnumType whichEnum);
/**
* subclass interface - no enum tie-in
* @param fieldCount how many fields this can hold.
*/
FieldsSet(int32_t fieldsCount);
public:
/**
* @param other "expected" set to match against
* @param status - will return invalid argument if sets are not the same size
* @return a formatted string listing which fields are set in
* this, with the comparison made agaainst those fields in other.
*/
UnicodeString diffFrom(const FieldsSet& other, UErrorCode &status) const;
public:
/**
* @param str string to parse
* @param status formatted string for status
*/
int32_t parseFrom(const UnicodeString& str, UErrorCode& status) { return parseFrom(str,NULL,status); }
public:
int32_t parseFrom(const UnicodeString& str, const FieldsSet& inheritFrom, UErrorCode& status) { return parseFrom(str, &inheritFrom, status); }
int32_t parseFrom(const UnicodeString& str, const
FieldsSet* inheritFrom, UErrorCode& status);
protected:
/**
* Callback interface for subclass.
* This function is called when parsing a field name, such as "MONTH" in "MONTH=4".
* Base implementation is to lookup the enum value using udbg_* utilities, or else as an integer if
* enum is not available.
*
* If there is a special directive, the implementer can catch it here and return -1 after special processing completes.
*
* @param inheritFrom the set inheriting from - may be null.
* @param name the field name (key side)
* @param substr the string in question (value side)
* @param status error status - set to error for failure.
* @return field number, or negative if field should be skipped.
*/
virtual int32_t handleParseName(const FieldsSet* inheritFrom, const UnicodeString& name, const UnicodeString& substr, UErrorCode& status);
/**
* Callback interface for subclass.
* Base implementation is to call parseValueDefault(...)
* @param inheritFrom the set inheriting from - may be null.
* @param field which field is being parsed
* @param substr the string in question (value side)
* @param status error status - set to error for failure.
* @see parseValueDefault
*/
virtual void handleParseValue(const FieldsSet* inheritFrom, int32_t field, const UnicodeString& substr, UErrorCode& status);
/**
* the default implementation for handleParseValue.
* Base implementation is to parse a decimal integer value, or inherit from inheritFrom if the string is 0-length.
* Implementations of this function should call set(field,...) on successful parse.
* @see handleParseValue
*/
void parseValueDefault(const FieldsSet* inheritFrom, int32_t field, const UnicodeString& substr, UErrorCode& status);
/**
* convenience implementation for handleParseValue
* attempt to load a value from an enum value using udbg_enumByString()
* if fails, will call parseValueDefault()
* @see handleParseValue
*/
void parseValueEnum(UDebugEnumType type, const FieldsSet* inheritFrom, int32_t field, const UnicodeString& substr, UErrorCode& status);
private:
FieldsSet();
void construct(UDebugEnumType whichEnum, int32_t fieldCount);
public:
virtual ~FieldsSet();
void clear();
void clear(int32_t field);
void set(int32_t field, int32_t amount);
UBool isSet(int field) const;
int32_t get(int field) const;
UBool isSameType(const FieldsSet& other) const;
int32_t fieldCount() const;
protected:
int32_t fValue[U_FIELDS_SET_MAX];
UBool fIsSet[U_FIELDS_SET_MAX];
protected:
int32_t fFieldCount;
UDebugEnumType fEnum;
};
/** ------- Calendar Fields Set -------- **/
class CalendarFieldsSet : public FieldsSet {
public:
CalendarFieldsSet();
virtual ~CalendarFieldsSet();
// void clear(UCalendarDateFields field) { clear((int32_t)field); }
// void set(UCalendarDateFields field, int32_t amount) { set ((int32_t)field, amount); }
// UBool isSet(UCalendarDateFields field) const { return isSet((int32_t)field); }
// int32_t get(UCalendarDateFields field) const { return get((int32_t)field); }
/**
* @param matches fillin to hold any fields different. Will have the calendar's value set on them.
* @return true if the calendar matches in these fields.
*/
UBool matches(Calendar *cal, CalendarFieldsSet &diffSet,
UErrorCode& status) const;
/**
* set the specified fields on this calendar. Doesn't clear first. Returns any errors the cale
*/
void setOnCalendar(Calendar *cal, UErrorCode& status) const;
protected:
void handleParseValue(const FieldsSet* inheritFrom, int32_t field, const UnicodeString& substr, UErrorCode& status);
};
/**
* This class simply implements a set of date and time styles
* such as DATE=SHORT or TIME=SHORT,DATE=LONG
*/
class DateTimeStyleSet : public FieldsSet {
public:
DateTimeStyleSet();
virtual ~DateTimeStyleSet();
/**
* @return the date style, or UDAT_NONE if not set
*/
UDateFormatStyle getDateStyle() const;
/**
* @return the time style, or UDAT_NONE if not set
*/
UDateFormatStyle getTimeStyle() const;
protected:
void handleParseValue(const FieldsSet* inheritFrom, int32_t field, const UnicodeString& substr, UErrorCode& status);
int32_t handleParseName(const FieldsSet* inheritFrom, const UnicodeString& name, const UnicodeString& substr, UErrorCode& status);
};
#endif /*FLDSET_H_*/

View File

@ -44,6 +44,7 @@
#include "calcasts.h" // CalendarCaseTest
#include "tzrulets.h" // TimeZoneRuleTest
#include "dadrcal.h" // DataDrivenCalendarTest
#include "dadrfmt.h" // DataDrivenFormatTest
#include "dtptngts.h" // IntlTestDateTimePatternGeneratorAPI
@ -107,7 +108,8 @@ void IntlTestFormat::runIndexedTest( int32_t index, UBool exec, const char* &nam
TESTCLASS(28,CalendarCaseTest);
TESTCLASS(29,TimeZoneRuleTest);
TESTCLASS(30,DataDrivenCalendarTest);
TESTCLASS(31,IntlTestDateTimePatternGeneratorAPI);
TESTCLASS(31,DataDrivenFormatTest);
TESTCLASS(32,IntlTestDateTimePatternGeneratorAPI);
default: name = ""; break; //needed to end loop

37
icu4c/source/test/testdata/format.txt vendored Normal file
View File

@ -0,0 +1,37 @@
// Copyright (c) 2007 International Business Machines
// Corporation and others. All Rights Reserved.
format:table(nofallback) {
Info {
Description { "These are the data driven format tests" }
LongDescription { "Data for data driven format tests." }
}
TestData {
TestDateFormatBasic {
Info {
Description { "Test data for format and parse :" }
}
Settings {
// options: 'format', or 'parse'. One can be omitted if this is a 1 way test.
{
Type { "date_format" }
},
{
Type { "date_parse" }
},
}
Headers { "locale","spec", "date", "str"}
// locale: locale including calendar type
// spec: either 'PATTERN=y mm h' etc, or 'DATE=SHORT,TIME=LONG'
// date: either 'MILLIS=####' where #### is an unsigned long (millis), or a calendar spec ERA=0,YEAR=1, etc.. applied to the calendar type specified by the locale
// str: the expected unicode string
Cases {
{
"en_US@calendar=gregorian",
"DATE=SHORT,TIME=SHORT",
"ERA=1,YEAR=2007,MONTH=AUGUST,DATE=8,HOUR_OF_DAY=18,MINUTE=54,SECOND=0",
"8/8/07 6:54 PM"
},
}
}
}
}

View File

@ -6,4 +6,5 @@
# Not everything has been moved to this file yet, as this is a new facility.
#
TEST_RES_SOURCE=DataDrivenCollationTest.txt calendar.txt
TEST_RES_SOURCE=DataDrivenCollationTest.txt calendar.txt format.txt

View File

@ -78,6 +78,27 @@ static const Field names_UCalendarMonths[] =
FIELD_NAME_STR( LEN_UCAL, UCAL_UNDECIMBER)
};
#include "unicode/udat.h"
#define LEN_UDAT 5 /* "UDAT_" */
static const int32_t count_UDateFormatStyle = UDAT_SHORT+1;
static const Field names_UDateFormatStyle[] =
{
FIELD_NAME_STR( LEN_UDAT, UDAT_FULL ),
FIELD_NAME_STR( LEN_UDAT, UDAT_LONG ),
FIELD_NAME_STR( LEN_UDAT, UDAT_MEDIUM ),
FIELD_NAME_STR( LEN_UDAT, UDAT_SHORT ),
/* end regular */
/*
* negative enums.. leave out for now.
FIELD_NAME_STR( LEN_UDAT, UDAT_NONE ),
FIELD_NAME_STR( LEN_UDAT, UDAT_IGNORE ),
*/
};
#endif
@ -90,6 +111,7 @@ static const Field names_UDebugEnumType[] =
FIELD_NAME_STR( LEN_UDBG, UDBG_UDebugEnumType ),
FIELD_NAME_STR( LEN_UDBG, UDBG_UCalendarDateFields ),
FIELD_NAME_STR( LEN_UDBG, UDBG_UCalendarMonths ),
FIELD_NAME_STR( LEN_UDBG, UDBG_UDateFormatStyle ),
};
@ -110,6 +132,7 @@ static int32_t _udbg_enumCount(UDebugEnumType type, UBool actual) {
COUNT_CASE(UDebugEnumType)
COUNT_CASE(UCalendarDateFields)
COUNT_CASE(UCalendarMonths)
COUNT_CASE(UDateFormatStyle)
// COUNT_FAIL_CASE(UNonExistentEnum)
default:
return -1;
@ -121,6 +144,7 @@ static const Field* _udbg_enumFields(UDebugEnumType type) {
FIELD_CASE(UDebugEnumType)
FIELD_CASE(UCalendarDateFields)
FIELD_CASE(UCalendarMonths)
FIELD_CASE(UDateFormatStyle)
// FIELD_FAIL_CASE(UNonExistentEnum)
default:
return NULL;

View File

@ -18,6 +18,7 @@ enum UDebugEnumType {
UDBG_UDebugEnumType = 0, /* Self-referential, strings for UDebugEnumType. Count=ENUM_COUNT. */
UDBG_UCalendarDateFields, /* UCalendarDateFields. Count=UCAL_FIELD_COUNT. Unsupported if UCONFIG_NO_FORMATTING. */
UDBG_UCalendarMonths, /* UCalendarMonths. Count= (UCAL_UNDECIMBER+1) */
UDBG_UDateFormatStyle, /* Count = UDAT_SHORT=1 */
UDBG_ENUM_COUNT
};