• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
isCROrLF(UChar c)16 static UBool isCROrLF(UChar c) { return c == 0xa || c == 0xd; }
isSpace(UChar c)17 static UBool isSpace(UChar c) { return c == 9 || c == 0x20 || c == 0x3000; }
18 
run(const char * fileName,UBool runAllTests)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 
~DataDrivenNumberFormatTestSuite()104 DataDrivenNumberFormatTestSuite::~DataDrivenNumberFormatTestSuite() {
105     for (int32_t i = 0; i < UPRV_LENGTHOF(fPreviousFormatters); ++i) {
106         delete fPreviousFormatters[i];
107     }
108 }
109 
breaksC()110 UBool DataDrivenNumberFormatTestSuite::breaksC() {
111     return (NFTT_GET_FIELD(fTuple, breaks, "").toUpper().indexOf(0x43) != -1);
112 }
113 
setTupleField(UErrorCode & status)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
splitBy(UnicodeString * columnValues,int32_t columnValuesCount,UChar delimiter)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 
showLineInfo()155 void DataDrivenNumberFormatTestSuite::showLineInfo() {
156     UnicodeString indent("    ");
157     infoln(indent + fFileTestName);
158     infoln(indent + fFileLine);
159 }
160 
showError(const char * message)161 void DataDrivenNumberFormatTestSuite::showError(const char *message) {
162     errln("line %d: %s", (int) fFileLineNumber, message);
163     showLineInfo();
164 }
165 
showFailure(const UnicodeString & message)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 
readLine(UCHARBUF * f,UErrorCode & status)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 
isPass(const NumberFormatTestTuple & tuple,UnicodeString & appendErrorMessage,UErrorCode & status)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 
isFormatPass(const NumberFormatTestTuple &,UnicodeString &,UErrorCode & status)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 
isFormatPass(const NumberFormatTestTuple & tuple,UObject *,UnicodeString & appendErrorMessage,UErrorCode & status)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 
newFormatter(UErrorCode &)259 UObject *DataDrivenNumberFormatTestSuite::newFormatter(
260         UErrorCode & /*status*/) {
261     return NULL;
262 }
263 
isToPatternPass(const NumberFormatTestTuple &,UnicodeString &,UErrorCode & status)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 
isParsePass(const NumberFormatTestTuple &,UnicodeString &,UErrorCode & status)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 
isParseCurrencyPass(const NumberFormatTestTuple &,UnicodeString &,UErrorCode & status)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 
isSelectPass(const NumberFormatTestTuple &,UnicodeString &,UErrorCode & status)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