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