]>
Commit | Line | Data |
---|---|---|
f3c0d7a5 A |
1 | // © 2016 and later: Unicode, Inc. and others. |
2 | // License & terms of use: http://www.unicode.org/copyright.html | |
2ca993e8 A |
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 | ||
18 | static UBool isCROrLF(UChar c) { return c == 0xa || c == 0xd; } | |
19 | static UBool isSpace(UChar c) { return c == 9 || c == 0x20 || c == 0x3000; } | |
20 | ||
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]; | |
340931cb | 41 | int32_t columnCount = 0; |
2ca993e8 A |
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 | } | |
0f5d89e8 | 95 | if (runAllTests || !breaksC()) { |
2ca993e8 | 96 | UnicodeString errorMessage; |
0f5d89e8 A |
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: " + errorMessage); | |
103 | break; | |
104 | } else if (!shouldFail && !actualSuccess) { | |
2ca993e8 | 105 | showFailure(errorMessage); |
0f5d89e8 | 106 | break; |
2ca993e8 | 107 | } |
0f5d89e8 | 108 | status = U_ZERO_ERROR; |
2ca993e8 A |
109 | } |
110 | } | |
111 | fFileLine.remove(); | |
112 | } | |
113 | } | |
114 | ||
115 | DataDrivenNumberFormatTestSuite::~DataDrivenNumberFormatTestSuite() { | |
116 | for (int32_t i = 0; i < UPRV_LENGTHOF(fPreviousFormatters); ++i) { | |
117 | delete fPreviousFormatters[i]; | |
118 | } | |
119 | } | |
120 | ||
121 | UBool DataDrivenNumberFormatTestSuite::breaksC() { | |
f3c0d7a5 | 122 | return (NFTT_GET_FIELD(fTuple, breaks, "").toUpper().indexOf((UChar)0x43) != -1); |
2ca993e8 A |
123 | } |
124 | ||
125 | void 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 | ||
145 | int32_t | |
146 | DataDrivenNumberFormatTestSuite::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 | ||
166 | void DataDrivenNumberFormatTestSuite::showLineInfo() { | |
167 | UnicodeString indent(" "); | |
168 | infoln(indent + fFileTestName); | |
169 | infoln(indent + fFileLine); | |
170 | } | |
171 | ||
172 | void DataDrivenNumberFormatTestSuite::showError(const char *message) { | |
173 | errln("line %d: %s", (int) fFileLineNumber, message); | |
174 | showLineInfo(); | |
175 | } | |
176 | ||
177 | void 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 | ||
187 | UBool 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 | ||
209 | UBool 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 | ||
252 | UBool 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 | ||
262 | UBool DataDrivenNumberFormatTestSuite::isFormatPass( | |
263 | const NumberFormatTestTuple &tuple, | |
264 | UObject * /* somePreviousFormatter */, | |
265 | UnicodeString &appendErrorMessage, | |
266 | UErrorCode &status) { | |
267 | return isFormatPass(tuple, appendErrorMessage, status); | |
268 | } | |
269 | ||
270 | UObject *DataDrivenNumberFormatTestSuite::newFormatter( | |
271 | UErrorCode & /*status*/) { | |
272 | return NULL; | |
273 | } | |
274 | ||
275 | UBool 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 | ||
285 | UBool 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 | ||
295 | UBool 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 | ||
305 | UBool 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 */ |