1 // © 2017 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 #include "unicode/utypes.h"
6 #if !UCONFIG_NO_FORMATTING
8 #include "unicode/dcfmtsym.h"
11 #include "numbertest.h"
12 #include "number_utils.h"
13 #include "number_skeletons.h"
16 using namespace icu::number::impl
;
19 void NumberSkeletonTest::runIndexedTest(int32_t index
, UBool exec
, const char*& name
, char*) {
21 logln("TestSuite AffixUtilsTest: ");
24 TESTCASE_AUTO(validTokens
);
25 TESTCASE_AUTO(invalidTokens
);
26 TESTCASE_AUTO(unknownTokens
);
27 TESTCASE_AUTO(unexpectedTokens
);
28 TESTCASE_AUTO(duplicateValues
);
29 TESTCASE_AUTO(stemsRequiringOption
);
30 TESTCASE_AUTO(defaultTokens
);
31 TESTCASE_AUTO(flexibleSeparators
);
35 void NumberSkeletonTest::validTokens() {
36 IcuTestErrorCode
status(*this, "validTokens");
38 // This tests only if the tokens are valid, not their behavior.
39 // Most of these are from the design doc.
40 static const char16_t* cases
[] = {
42 u
"precision-unlimited",
52 u
"precision-increment/3.14",
53 u
"precision-currency-standard",
54 u
"precision-integer rounding-mode-half-up",
55 u
".00# rounding-mode-ceiling",
56 u
".00/@@+ rounding-mode-floor",
59 u
"scientific/sign-always",
60 u
"scientific/+ee/sign-always",
61 u
"scientific/sign-always/+ee",
62 u
"scientific/sign-except-zero",
70 u
"measure-unit/length-meter",
71 u
"measure-unit/area-square-meter",
72 u
"measure-unit/energy-joule per-measure-unit/length-meter",
88 u
"sign-accounting-always",
90 u
"sign-accounting-except-zero",
93 u
"unit-width-iso-code",
94 u
"unit-width-full-name",
104 u
"numbering-system/arab",
105 u
"numbering-system/latn",
106 u
"precision-integer/@##",
107 u
"precision-integer rounding-mode-ceiling",
108 u
"precision-currency-cash rounding-mode-ceiling"};
110 for (auto& cas
: cases
) {
111 UnicodeString
skeletonString(cas
);
112 status
.setScope(skeletonString
);
113 NumberFormatter::forSkeleton(skeletonString
, status
);
114 assertSuccess(CStr(skeletonString
)(), status
, true);
115 status
.errIfFailureAndReset();
119 void NumberSkeletonTest::invalidTokens() {
120 static const char16_t* cases
[] = {
134 u
".00/floor/@@+", // wrong order
135 u
"precision-increment/français", // non-invariant characters for C++
137 u
"precision-increment/xxx",
138 u
"precision-increment/NaN",
139 u
"precision-increment/0.1.2",
143 u
"scale/français", // non-invariant characters for C++
145 u
"currency/ççç", // three characters but not ASCII
147 u
"integer-width/xxx",
149 u
"integer-width/+0#",
152 expectedErrorSkeleton(cases
, UPRV_LENGTHOF(cases
));
155 void NumberSkeletonTest::unknownTokens() {
156 static const char16_t* cases
[] = {
158 u
"measure-unit/foo-bar",
159 u
"numbering-system/dummy",
161 u
"measure-unit/français-français", // non-invariant characters for C++
162 u
"numbering-system/français", // non-invariant characters for C++
165 expectedErrorSkeleton(cases
, UPRV_LENGTHOF(cases
));
168 void NumberSkeletonTest::unexpectedTokens() {
169 static const char16_t* cases
[] = {
170 u
"group-thousands/foo",
171 u
"precision-integer//@## group-off",
172 u
"precision-integer//@## group-off",
173 u
"precision-integer/ group-off",
174 u
"precision-integer// group-off"};
176 expectedErrorSkeleton(cases
, UPRV_LENGTHOF(cases
));
179 void NumberSkeletonTest::duplicateValues() {
180 static const char16_t* cases
[] = {
181 u
"precision-integer precision-integer",
182 u
"precision-integer .00+",
183 u
"precision-integer precision-unlimited",
184 u
"precision-integer @@@",
185 u
"scientific engineering",
186 u
"engineering compact-long",
187 u
"sign-auto sign-always"};
189 expectedErrorSkeleton(cases
, UPRV_LENGTHOF(cases
));
192 void NumberSkeletonTest::stemsRequiringOption() {
193 static const char16_t* stems
[] = {
194 u
"precision-increment",
201 static const char16_t* suffixes
[] = {u
"", u
"/@##", u
" scientific", u
"/@## scientific"};
203 for (auto& stem
: stems
) {
204 for (auto& suffix
: suffixes
) {
205 UnicodeString skeletonString
= UnicodeString(stem
) + suffix
;
206 UErrorCode status
= U_ZERO_ERROR
;
207 NumberFormatter::forSkeleton(skeletonString
, status
);
208 assertEquals(skeletonString
, U_NUMBER_SKELETON_SYNTAX_ERROR
, status
);
213 void NumberSkeletonTest::defaultTokens() {
214 IcuTestErrorCode
status(*this, "defaultTokens");
216 static const char16_t* cases
[] = {
225 for (auto& cas
: cases
) {
226 UnicodeString
skeletonString(cas
);
227 status
.setScope(skeletonString
);
228 UnicodeString normalized
= NumberFormatter::forSkeleton(
229 skeletonString
, status
).toSkeleton(status
);
230 // Skeleton should become empty when normalized
231 assertEquals(skeletonString
, u
"", normalized
);
232 status
.errIfFailureAndReset();
236 void NumberSkeletonTest::flexibleSeparators() {
237 IcuTestErrorCode
status(*this, "flexibleSeparators");
239 static struct TestCase
{
240 const char16_t* skeleton
;
241 const char16_t* expected
;
242 } cases
[] = {{u
"precision-integer group-off", u
"5142"},
243 {u
"precision-integer group-off", u
"5142"},
244 {u
"precision-integer/@## group-off", u
"5140"},
245 {u
"precision-integer/@## group-off", u
"5140"}};
247 for (auto& cas
: cases
) {
248 UnicodeString
skeletonString(cas
.skeleton
);
249 UnicodeString
expected(cas
.expected
);
250 status
.setScope(skeletonString
);
251 UnicodeString actual
= NumberFormatter::forSkeleton(skeletonString
, status
).locale("en")
252 .formatDouble(5142.3, status
)
254 if (!status
.errDataIfFailureAndReset()) {
255 assertEquals(skeletonString
, expected
, actual
);
257 status
.errIfFailureAndReset();
261 // In C++, there is no distinguishing between "invalid", "unknown", and "unexpected" tokens.
262 void NumberSkeletonTest::expectedErrorSkeleton(const char16_t** cases
, int32_t casesLen
) {
263 for (int32_t i
= 0; i
< casesLen
; i
++) {
264 UnicodeString
skeletonString(cases
[i
]);
265 UErrorCode status
= U_ZERO_ERROR
;
266 NumberFormatter::forSkeleton(skeletonString
, status
);
267 assertEquals(skeletonString
, U_NUMBER_SKELETON_SYNTAX_ERROR
, status
);
272 #endif /* #if !UCONFIG_NO_FORMATTING */