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