• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 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 
isCROrLF(UChar c)18 static UBool isCROrLF(UChar c) { return c == 0xa || c == 0xd; }
isSpace(UChar c)19 static UBool isSpace(UChar c) { return c == 9 || c == 0x20 || c == 0x3000; }
20 
run(const char * fileName,UBool runAllTests)21 void 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 (!breaksC() || runAllTests) {
96                 UnicodeString errorMessage;
97                 if (!isPass(fTuple, errorMessage, status)) {
98                     showFailure(errorMessage);
99                 }
100             }
101         }
102         fFileLine.remove();
103     }
104 }
105 
~DataDrivenNumberFormatTestSuite()106 DataDrivenNumberFormatTestSuite::~DataDrivenNumberFormatTestSuite() {
107     for (int32_t i = 0; i < UPRV_LENGTHOF(fPreviousFormatters); ++i) {
108         delete fPreviousFormatters[i];
109     }
110 }
111 
breaksC()112 UBool DataDrivenNumberFormatTestSuite::breaksC() {
113     return (NFTT_GET_FIELD(fTuple, breaks, "").toUpper().indexOf((UChar)0x43) != -1);
114 }
115 
setTupleField(UErrorCode & status)116 void DataDrivenNumberFormatTestSuite::setTupleField(UErrorCode &status) {
117     if (U_FAILURE(status)) {
118         return;
119     }
120     UnicodeString parts[3];
121     int32_t partCount = splitBy(parts, UPRV_LENGTHOF(parts), 0x20);
122     if (partCount < 3) {
123         showError("Set expects 2 parameters");
124         status = U_PARSE_ERROR;
125         return;
126     }
127     if (!fTuple.setField(
128             NumberFormatTestTuple::getFieldByName(parts[1]),
129             parts[2].unescape(),
130             status)) {
131         showError("Invalid field value");
132     }
133 }
134 
135 
136 int32_t
splitBy(UnicodeString * columnValues,int32_t columnValuesCount,UChar delimiter)137 DataDrivenNumberFormatTestSuite::splitBy(
138         UnicodeString *columnValues,
139         int32_t columnValuesCount,
140         UChar delimiter) {
141     int32_t colIdx = 0;
142     int32_t colStart = 0;
143     int32_t len = fFileLine.length();
144     for (int32_t idx = 0; colIdx < columnValuesCount - 1 && idx < len; ++idx) {
145         UChar ch = fFileLine.charAt(idx);
146         if (ch == delimiter) {
147             columnValues[colIdx++] =
148                     fFileLine.tempSubString(colStart, idx - colStart);
149             colStart = idx + 1;
150         }
151     }
152     columnValues[colIdx++] =
153             fFileLine.tempSubString(colStart, len - colStart);
154     return colIdx;
155 }
156 
showLineInfo()157 void DataDrivenNumberFormatTestSuite::showLineInfo() {
158     UnicodeString indent("    ");
159     infoln(indent + fFileTestName);
160     infoln(indent + fFileLine);
161 }
162 
showError(const char * message)163 void DataDrivenNumberFormatTestSuite::showError(const char *message) {
164     errln("line %d: %s", (int) fFileLineNumber, message);
165     showLineInfo();
166 }
167 
showFailure(const UnicodeString & message)168 void DataDrivenNumberFormatTestSuite::showFailure(const UnicodeString &message) {
169     UChar lineStr[20];
170     uprv_itou(
171             lineStr, UPRV_LENGTHOF(lineStr), (uint32_t) fFileLineNumber, 10, 1);
172     UnicodeString fullMessage("line ");
173     dataerrln(fullMessage.append(lineStr).append(": ")
174             .append(prettify(message)));
175     showLineInfo();
176 }
177 
readLine(UCHARBUF * f,UErrorCode & status)178 UBool DataDrivenNumberFormatTestSuite::readLine(
179         UCHARBUF *f, UErrorCode &status) {
180     int32_t lineLength;
181     const UChar *line = ucbuf_readline(f, &lineLength, &status);
182     if(line == NULL || U_FAILURE(status)) {
183         if (U_FAILURE(status)) {
184             errln("Error reading line from file.");
185         }
186         fFileLine.remove();
187         return FALSE;
188     }
189     ++fFileLineNumber;
190     // Strip trailing CR/LF, comments, and spaces.
191     while(lineLength > 0 && isCROrLF(line[lineLength - 1])) { --lineLength; }
192     fFileLine.setTo(FALSE, line, lineLength);
193     while(lineLength > 0 && isSpace(line[lineLength - 1])) { --lineLength; }
194     if (lineLength == 0) {
195         fFileLine.remove();
196     }
197     return TRUE;
198 }
199 
isPass(const NumberFormatTestTuple & tuple,UnicodeString & appendErrorMessage,UErrorCode & status)200 UBool DataDrivenNumberFormatTestSuite::isPass(
201         const NumberFormatTestTuple &tuple,
202         UnicodeString &appendErrorMessage,
203         UErrorCode &status) {
204     if (U_FAILURE(status)) {
205         return FALSE;
206     }
207     UBool result = FALSE;
208     if (tuple.formatFlag && tuple.outputFlag) {
209         ++fFormatTestNumber;
210         result = isFormatPass(
211                 tuple,
212                 fPreviousFormatters[
213                         fFormatTestNumber % UPRV_LENGTHOF(fPreviousFormatters)],
214                 appendErrorMessage,
215                 status);
216     }
217     else if (tuple.toPatternFlag || tuple.toLocalizedPatternFlag) {
218         result = isToPatternPass(tuple, appendErrorMessage, status);
219     } else if (tuple.parseFlag && tuple.outputFlag && tuple.outputCurrencyFlag) {
220         result = isParseCurrencyPass(tuple, appendErrorMessage, status);
221 
222     } else if (tuple.parseFlag && tuple.outputFlag) {
223         result = isParsePass(tuple, appendErrorMessage, status);
224     } else if (tuple.pluralFlag) {
225         result = isSelectPass(tuple, appendErrorMessage, status);
226     } else {
227         appendErrorMessage.append("Unrecognized test type.");
228         status = U_ILLEGAL_ARGUMENT_ERROR;
229     }
230     if (!result) {
231         if (appendErrorMessage.length() > 0) {
232             appendErrorMessage.append(": ");
233         }
234         if (U_FAILURE(status)) {
235             appendErrorMessage.append(u_errorName(status));
236             appendErrorMessage.append(": ");
237         }
238         tuple.toString(appendErrorMessage);
239     }
240     return result;
241 }
242 
isFormatPass(const NumberFormatTestTuple &,UnicodeString &,UErrorCode & status)243 UBool DataDrivenNumberFormatTestSuite::isFormatPass(
244         const NumberFormatTestTuple & /* tuple */,
245         UnicodeString & /*appendErrorMessage*/,
246         UErrorCode &status) {
247     if (U_FAILURE(status)) {
248         return FALSE;
249     }
250     return TRUE;
251 }
252 
isFormatPass(const NumberFormatTestTuple & tuple,UObject *,UnicodeString & appendErrorMessage,UErrorCode & status)253 UBool DataDrivenNumberFormatTestSuite::isFormatPass(
254         const NumberFormatTestTuple &tuple,
255         UObject * /* somePreviousFormatter */,
256         UnicodeString &appendErrorMessage,
257         UErrorCode &status) {
258     return isFormatPass(tuple, appendErrorMessage, status);
259 }
260 
newFormatter(UErrorCode &)261 UObject *DataDrivenNumberFormatTestSuite::newFormatter(
262         UErrorCode & /*status*/) {
263     return NULL;
264 }
265 
isToPatternPass(const NumberFormatTestTuple &,UnicodeString &,UErrorCode & status)266 UBool DataDrivenNumberFormatTestSuite::isToPatternPass(
267         const NumberFormatTestTuple & /* tuple */,
268         UnicodeString & /*appendErrorMessage*/,
269         UErrorCode &status) {
270     if (U_FAILURE(status)) {
271         return FALSE;
272     }
273     return TRUE;
274 }
275 
isParsePass(const NumberFormatTestTuple &,UnicodeString &,UErrorCode & status)276 UBool DataDrivenNumberFormatTestSuite::isParsePass(
277         const NumberFormatTestTuple & /* tuple */,
278         UnicodeString & /*appendErrorMessage*/,
279         UErrorCode &status) {
280     if (U_FAILURE(status)) {
281         return FALSE;
282     }
283     return TRUE;
284 }
285 
isParseCurrencyPass(const NumberFormatTestTuple &,UnicodeString &,UErrorCode & status)286 UBool DataDrivenNumberFormatTestSuite::isParseCurrencyPass(
287         const NumberFormatTestTuple & /* tuple */,
288         UnicodeString & /*appendErrorMessage*/,
289         UErrorCode &status) {
290     if (U_FAILURE(status)) {
291         return FALSE;
292     }
293     return TRUE;
294 }
295 
isSelectPass(const NumberFormatTestTuple &,UnicodeString &,UErrorCode & status)296 UBool DataDrivenNumberFormatTestSuite::isSelectPass(
297         const NumberFormatTestTuple & /* tuple */,
298         UnicodeString & /*appendErrorMessage*/,
299         UErrorCode &status) {
300     if (U_FAILURE(status)) {
301         return FALSE;
302     }
303     return TRUE;
304 }
305 #endif /* !UCONFIG_NO_FORMATTING */
306