1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /********************************************************************
5 * Copyright (c) 2015, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 ********************************************************************/
9 #include "datadrivennumberformattestsuite.h"
11 #if !UCONFIG_NO_FORMATTING
15 #include "unicode/localpointer.h"
18 static UBool
isCROrLF(UChar c
) { return c
== 0xa || c
== 0xd; }
19 static UBool
isSpace(UChar c
) { return c
== 9 || c
== 0x20 || c
== 0x3000; }
21 void DataDrivenNumberFormatTestSuite::run(const char *fileName
, UBool runAllTests
) {
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
);
29 if (!assertSuccess("Can't create previous formatters", status
)) {
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
)) {
39 UnicodeString columnValues
[kNumberFormatTestTupleFieldCount
];
40 ENumberFormatTestTupleField columnTypes
[kNumberFormatTestTupleFieldCount
];
41 int32_t columnCount
= 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) {
52 if (fFileLine
.startsWith("//")) {
56 // Initial setup of test.
58 if (fFileLine
.startsWith(UNICODE_STRING("test ", 5))) {
59 fFileTestName
= fFileLine
;
61 } else if(fFileLine
.startsWith(UNICODE_STRING("set ", 4))) {
62 setTupleField(status
);
63 } else if(fFileLine
.startsWith(UNICODE_STRING("begin", 5))) {
66 showError("Unrecognized verb.");
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(
75 if (columnTypes
[i
] == kNumberFormatTestTupleFieldCount
) {
76 showError("Unrecognized field name.");
83 int32_t columnsInThisRow
= splitBy(columnValues
, columnCount
, 0x9);
84 for (int32_t i
= 0; i
< columnsInThisRow
; ++i
) {
86 columnTypes
[i
], columnValues
[i
].unescape(), status
);
88 for (int32_t i
= columnsInThisRow
; i
< columnCount
; ++i
) {
89 fTuple
.clearField(columnTypes
[i
], status
);
91 if (U_FAILURE(status
)) {
92 showError("Invalid column values");
95 if (runAllTests
|| !breaksC()) {
96 UnicodeString errorMessage
;
97 UBool shouldFail
= (NFTT_GET_FIELD(fTuple
, output
, "") == "fail")
100 UBool actualSuccess
= isPass(fTuple
, errorMessage
, status
);
101 if (shouldFail
&& actualSuccess
) {
102 showFailure("Expected failure, but passed: " + errorMessage
);
104 } else if (!shouldFail
&& !actualSuccess
) {
105 showFailure(errorMessage
);
108 status
= U_ZERO_ERROR
;
115 DataDrivenNumberFormatTestSuite::~DataDrivenNumberFormatTestSuite() {
116 for (int32_t i
= 0; i
< UPRV_LENGTHOF(fPreviousFormatters
); ++i
) {
117 delete fPreviousFormatters
[i
];
121 UBool
DataDrivenNumberFormatTestSuite::breaksC() {
122 return (NFTT_GET_FIELD(fTuple
, breaks
, "").toUpper().indexOf((UChar
)0x43) != -1);
125 void DataDrivenNumberFormatTestSuite::setTupleField(UErrorCode
&status
) {
126 if (U_FAILURE(status
)) {
129 UnicodeString parts
[3];
130 int32_t partCount
= splitBy(parts
, UPRV_LENGTHOF(parts
), 0x20);
132 showError("Set expects 2 parameters");
133 status
= U_PARSE_ERROR
;
136 if (!fTuple
.setField(
137 NumberFormatTestTuple::getFieldByName(parts
[1]),
140 showError("Invalid field value");
146 DataDrivenNumberFormatTestSuite::splitBy(
147 UnicodeString
*columnValues
,
148 int32_t columnValuesCount
,
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
);
161 columnValues
[colIdx
++] =
162 fFileLine
.tempSubString(colStart
, len
- colStart
);
166 void DataDrivenNumberFormatTestSuite::showLineInfo() {
167 UnicodeString
indent(" ");
168 infoln(indent
+ fFileTestName
);
169 infoln(indent
+ fFileLine
);
172 void DataDrivenNumberFormatTestSuite::showError(const char *message
) {
173 errln("line %d: %s", (int) fFileLineNumber
, message
);
177 void DataDrivenNumberFormatTestSuite::showFailure(const UnicodeString
&message
) {
180 lineStr
, UPRV_LENGTHOF(lineStr
), (uint32_t) fFileLineNumber
, 10, 1);
181 UnicodeString
fullMessage("line ");
182 dataerrln(fullMessage
.append(lineStr
).append(": ")
183 .append(prettify(message
)));
187 UBool
DataDrivenNumberFormatTestSuite::readLine(
188 UCHARBUF
*f
, UErrorCode
&status
) {
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.");
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) {
209 UBool
DataDrivenNumberFormatTestSuite::isPass(
210 const NumberFormatTestTuple
&tuple
,
211 UnicodeString
&appendErrorMessage
,
212 UErrorCode
&status
) {
213 if (U_FAILURE(status
)) {
216 UBool result
= FALSE
;
217 if (tuple
.formatFlag
&& tuple
.outputFlag
) {
219 result
= isFormatPass(
222 fFormatTestNumber
% UPRV_LENGTHOF(fPreviousFormatters
)],
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
);
231 } else if (tuple
.parseFlag
&& tuple
.outputFlag
) {
232 result
= isParsePass(tuple
, appendErrorMessage
, status
);
233 } else if (tuple
.pluralFlag
) {
234 result
= isSelectPass(tuple
, appendErrorMessage
, status
);
236 appendErrorMessage
.append("Unrecognized test type.");
237 status
= U_ILLEGAL_ARGUMENT_ERROR
;
240 if (appendErrorMessage
.length() > 0) {
241 appendErrorMessage
.append(": ");
243 if (U_FAILURE(status
)) {
244 appendErrorMessage
.append(u_errorName(status
));
245 appendErrorMessage
.append(": ");
247 tuple
.toString(appendErrorMessage
);
252 UBool
DataDrivenNumberFormatTestSuite::isFormatPass(
253 const NumberFormatTestTuple
& /* tuple */,
254 UnicodeString
& /*appendErrorMessage*/,
255 UErrorCode
&status
) {
256 if (U_FAILURE(status
)) {
262 UBool
DataDrivenNumberFormatTestSuite::isFormatPass(
263 const NumberFormatTestTuple
&tuple
,
264 UObject
* /* somePreviousFormatter */,
265 UnicodeString
&appendErrorMessage
,
266 UErrorCode
&status
) {
267 return isFormatPass(tuple
, appendErrorMessage
, status
);
270 UObject
*DataDrivenNumberFormatTestSuite::newFormatter(
271 UErrorCode
& /*status*/) {
275 UBool
DataDrivenNumberFormatTestSuite::isToPatternPass(
276 const NumberFormatTestTuple
& /* tuple */,
277 UnicodeString
& /*appendErrorMessage*/,
278 UErrorCode
&status
) {
279 if (U_FAILURE(status
)) {
285 UBool
DataDrivenNumberFormatTestSuite::isParsePass(
286 const NumberFormatTestTuple
& /* tuple */,
287 UnicodeString
& /*appendErrorMessage*/,
288 UErrorCode
&status
) {
289 if (U_FAILURE(status
)) {
295 UBool
DataDrivenNumberFormatTestSuite::isParseCurrencyPass(
296 const NumberFormatTestTuple
& /* tuple */,
297 UnicodeString
& /*appendErrorMessage*/,
298 UErrorCode
&status
) {
299 if (U_FAILURE(status
)) {
305 UBool
DataDrivenNumberFormatTestSuite::isSelectPass(
306 const NumberFormatTestTuple
& /* tuple */,
307 UnicodeString
& /*appendErrorMessage*/,
308 UErrorCode
&status
) {
309 if (U_FAILURE(status
)) {
314 #endif /* !UCONFIG_NO_FORMATTING */