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