Home | History | Annotate | Download | only in intltest
      1 /********************************************************************
      2  * COPYRIGHT:
      3  * Copyright (c) 2015, International Business Machines Corporation and
      4  * others. All Rights Reserved.
      5  ********************************************************************/
      6 
      7 #include "datadrivennumberformattestsuite.h"
      8 
      9 #if !UCONFIG_NO_FORMATTING
     10 
     11 #include "charstr.h"
     12 #include "ucbuf.h"
     13 #include "unicode/localpointer.h"
     14 #include "ustrfmt.h"
     15 
     16 static UBool isCROrLF(UChar c) { return c == 0xa || c == 0xd; }
     17 static UBool isSpace(UChar c) { return c == 9 || c == 0x20 || c == 0x3000; }
     18 
     19 void DataDrivenNumberFormatTestSuite::run(const char *fileName, UBool runAllTests) {
     20     fFileLineNumber = 0;
     21     fFormatTestNumber = 0;
     22     UErrorCode status = U_ZERO_ERROR;
     23     for (int32_t i = 0; i < UPRV_LENGTHOF(fPreviousFormatters); ++i) {
     24         delete fPreviousFormatters[i];
     25         fPreviousFormatters[i] = newFormatter(status);
     26     }
     27     if (!assertSuccess("Can't create previous formatters", status)) {
     28         return;
     29     }
     30     CharString path(getSourceTestData(status), status);
     31     path.appendPathPart(fileName, status);
     32     const char *codePage = "UTF-8";
     33     LocalUCHARBUFPointer f(ucbuf_open(path.data(), &codePage, TRUE, FALSE, &status));
     34     if (!assertSuccess("Can't open data file", status)) {
     35         return;
     36     }
     37     UnicodeString columnValues[kNumberFormatTestTupleFieldCount];
     38     ENumberFormatTestTupleField columnTypes[kNumberFormatTestTupleFieldCount];
     39     int32_t columnCount;
     40     int32_t state = 0;
     41     while(U_SUCCESS(status)) {
     42         // Read a new line if necessary.
     43         if(fFileLine.isEmpty()) {
     44             if(!readLine(f.getAlias(), status)) { break; }
     45             if (fFileLine.isEmpty() && state == 2) {
     46                 state = 0;
     47             }
     48             continue;
     49         }
     50         if (fFileLine.startsWith("//")) {
     51             fFileLine.remove();
     52             continue;
     53         }
     54         // Initial setup of test.
     55         if (state == 0) {
     56             if (fFileLine.startsWith(UNICODE_STRING("test ", 5))) {
     57                 fFileTestName = fFileLine;
     58                 fTuple.clear();
     59             } else if(fFileLine.startsWith(UNICODE_STRING("set ", 4))) {
     60                 setTupleField(status);
     61             } else if(fFileLine.startsWith(UNICODE_STRING("begin", 5))) {
     62                 state = 1;
     63             } else {
     64                 showError("Unrecognized verb.");
     65                 return;
     66             }
     67         // column specification
     68         } else if (state == 1) {
     69             columnCount = splitBy(columnValues, UPRV_LENGTHOF(columnValues), 0x9);
     70             for (int32_t i = 0; i < columnCount; ++i) {
     71                 columnTypes[i] = NumberFormatTestTuple::getFieldByName(
     72                     columnValues[i]);
     73                 if (columnTypes[i] == kNumberFormatTestTupleFieldCount) {
     74                     showError("Unrecognized field name.");
     75                     return;
     76                 }
     77             }
     78             state = 2;
     79         // run the tests
     80         } else {
     81             int32_t columnsInThisRow = splitBy(columnValues, columnCount, 0x9);
     82             for (int32_t i = 0; i < columnsInThisRow; ++i) {
     83                 fTuple.setField(
     84                         columnTypes[i], columnValues[i].unescape(), status);
     85             }
     86             for (int32_t i = columnsInThisRow; i < columnCount; ++i) {
     87                 fTuple.clearField(columnTypes[i], status);
     88             }
     89             if (U_FAILURE(status)) {
     90                 showError("Invalid column values");
     91                 return;
     92             }
     93             if (!breaksC() || runAllTests) {
     94                 UnicodeString errorMessage;
     95                 if (!isPass(fTuple, errorMessage, status)) {
     96                     showFailure(errorMessage);
     97                 }
     98             }
     99         }
    100         fFileLine.remove();
    101     }
    102 }
    103 
    104 DataDrivenNumberFormatTestSuite::~DataDrivenNumberFormatTestSuite() {
    105     for (int32_t i = 0; i < UPRV_LENGTHOF(fPreviousFormatters); ++i) {
    106         delete fPreviousFormatters[i];
    107     }
    108 }
    109 
    110 UBool DataDrivenNumberFormatTestSuite::breaksC() {
    111     return (NFTT_GET_FIELD(fTuple, breaks, "").toUpper().indexOf(0x43) != -1);
    112 }
    113 
    114 void DataDrivenNumberFormatTestSuite::setTupleField(UErrorCode &status) {
    115     if (U_FAILURE(status)) {
    116         return;
    117     }
    118     UnicodeString parts[3];
    119     int32_t partCount = splitBy(parts, UPRV_LENGTHOF(parts), 0x20);
    120     if (partCount < 3) {
    121         showError("Set expects 2 parameters");
    122         status = U_PARSE_ERROR;
    123         return;
    124     }
    125     if (!fTuple.setField(
    126             NumberFormatTestTuple::getFieldByName(parts[1]),
    127             parts[2].unescape(),
    128             status)) {
    129         showError("Invalid field value");
    130     }
    131 }
    132 
    133 
    134 int32_t
    135 DataDrivenNumberFormatTestSuite::splitBy(
    136         UnicodeString *columnValues,
    137         int32_t columnValuesCount,
    138         UChar delimiter) {
    139     int32_t colIdx = 0;
    140     int32_t colStart = 0;
    141     int32_t len = fFileLine.length();
    142     for (int32_t idx = 0; colIdx < columnValuesCount - 1 && idx < len; ++idx) {
    143         UChar ch = fFileLine.charAt(idx);
    144         if (ch == delimiter) {
    145             columnValues[colIdx++] =
    146                     fFileLine.tempSubString(colStart, idx - colStart);
    147             colStart = idx + 1;
    148         }
    149     }
    150     columnValues[colIdx++] =
    151             fFileLine.tempSubString(colStart, len - colStart);
    152     return colIdx;
    153 }
    154 
    155 void DataDrivenNumberFormatTestSuite::showLineInfo() {
    156     UnicodeString indent("    ");
    157     infoln(indent + fFileTestName);
    158     infoln(indent + fFileLine);
    159 }
    160 
    161 void DataDrivenNumberFormatTestSuite::showError(const char *message) {
    162     errln("line %d: %s", (int) fFileLineNumber, message);
    163     showLineInfo();
    164 }
    165 
    166 void DataDrivenNumberFormatTestSuite::showFailure(const UnicodeString &message) {
    167     UChar lineStr[20];
    168     uprv_itou(
    169             lineStr, UPRV_LENGTHOF(lineStr), (uint32_t) fFileLineNumber, 10, 1);
    170     UnicodeString fullMessage("line ");
    171     dataerrln(fullMessage.append(lineStr).append(": ")
    172             .append(prettify(message)));
    173     showLineInfo();
    174 }
    175 
    176 UBool DataDrivenNumberFormatTestSuite::readLine(
    177         UCHARBUF *f, UErrorCode &status) {
    178     int32_t lineLength;
    179     const UChar *line = ucbuf_readline(f, &lineLength, &status);
    180     if(line == NULL || U_FAILURE(status)) {
    181         if (U_FAILURE(status)) {
    182             errln("Error reading line from file.");
    183         }
    184         fFileLine.remove();
    185         return FALSE;
    186     }
    187     ++fFileLineNumber;
    188     // Strip trailing CR/LF, comments, and spaces.
    189     while(lineLength > 0 && isCROrLF(line[lineLength - 1])) { --lineLength; }
    190     fFileLine.setTo(FALSE, line, lineLength);
    191     while(lineLength > 0 && isSpace(line[lineLength - 1])) { --lineLength; }
    192     if (lineLength == 0) {
    193         fFileLine.remove();
    194     }
    195     return TRUE;
    196 }
    197 
    198 UBool DataDrivenNumberFormatTestSuite::isPass(
    199         const NumberFormatTestTuple &tuple,
    200         UnicodeString &appendErrorMessage,
    201         UErrorCode &status) {
    202     if (U_FAILURE(status)) {
    203         return FALSE;
    204     }
    205     UBool result = FALSE;
    206     if (tuple.formatFlag && tuple.outputFlag) {
    207         ++fFormatTestNumber;
    208         result = isFormatPass(
    209                 tuple,
    210                 fPreviousFormatters[
    211                         fFormatTestNumber % UPRV_LENGTHOF(fPreviousFormatters)],
    212                 appendErrorMessage,
    213                 status);
    214     }
    215     else if (tuple.toPatternFlag || tuple.toLocalizedPatternFlag) {
    216         result = isToPatternPass(tuple, appendErrorMessage, status);
    217     } else if (tuple.parseFlag && tuple.outputFlag && tuple.outputCurrencyFlag) {
    218         result = isParseCurrencyPass(tuple, appendErrorMessage, status);
    219 
    220     } else if (tuple.parseFlag && tuple.outputFlag) {
    221         result = isParsePass(tuple, appendErrorMessage, status);
    222     } else if (tuple.pluralFlag) {
    223         result = isSelectPass(tuple, appendErrorMessage, status);
    224     } else {
    225         appendErrorMessage.append("Unrecognized test type.");
    226         status = U_ILLEGAL_ARGUMENT_ERROR;
    227     }
    228     if (!result) {
    229         if (appendErrorMessage.length() > 0) {
    230             appendErrorMessage.append(": ");
    231         }
    232         if (U_FAILURE(status)) {
    233             appendErrorMessage.append(u_errorName(status));
    234             appendErrorMessage.append(": ");
    235         }
    236         tuple.toString(appendErrorMessage);
    237     }
    238     return result;
    239 }
    240 
    241 UBool DataDrivenNumberFormatTestSuite::isFormatPass(
    242         const NumberFormatTestTuple & /* tuple */,
    243         UnicodeString & /*appendErrorMessage*/,
    244         UErrorCode &status) {
    245     if (U_FAILURE(status)) {
    246         return FALSE;
    247     }
    248     return TRUE;
    249 }
    250 
    251 UBool DataDrivenNumberFormatTestSuite::isFormatPass(
    252         const NumberFormatTestTuple &tuple,
    253         UObject * /* somePreviousFormatter */,
    254         UnicodeString &appendErrorMessage,
    255         UErrorCode &status) {
    256     return isFormatPass(tuple, appendErrorMessage, status);
    257 }
    258 
    259 UObject *DataDrivenNumberFormatTestSuite::newFormatter(
    260         UErrorCode & /*status*/) {
    261     return NULL;
    262 }
    263 
    264 UBool DataDrivenNumberFormatTestSuite::isToPatternPass(
    265         const NumberFormatTestTuple & /* tuple */,
    266         UnicodeString & /*appendErrorMessage*/,
    267         UErrorCode &status) {
    268     if (U_FAILURE(status)) {
    269         return FALSE;
    270     }
    271     return TRUE;
    272 }
    273 
    274 UBool DataDrivenNumberFormatTestSuite::isParsePass(
    275         const NumberFormatTestTuple & /* tuple */,
    276         UnicodeString & /*appendErrorMessage*/,
    277         UErrorCode &status) {
    278     if (U_FAILURE(status)) {
    279         return FALSE;
    280     }
    281     return TRUE;
    282 }
    283 
    284 UBool DataDrivenNumberFormatTestSuite::isParseCurrencyPass(
    285         const NumberFormatTestTuple & /* tuple */,
    286         UnicodeString & /*appendErrorMessage*/,
    287         UErrorCode &status) {
    288     if (U_FAILURE(status)) {
    289         return FALSE;
    290     }
    291     return TRUE;
    292 }
    293 
    294 UBool DataDrivenNumberFormatTestSuite::isSelectPass(
    295         const NumberFormatTestTuple & /* tuple */,
    296         UnicodeString & /*appendErrorMessage*/,
    297         UErrorCode &status) {
    298     if (U_FAILURE(status)) {
    299         return FALSE;
    300     }
    301     return TRUE;
    302 }
    303 #endif /* !UCONFIG_NO_FORMATTING */
    304