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
10 #include "number_stringbuilder.h"
11 #include "number_modifiers.h"
12 #include "numbertest.h"
14 void ModifiersTest::runIndexedTest(int32_t index
, UBool exec
, const char *&name
, char *) {
16 logln("TestSuite ModifiersTest: ");
19 TESTCASE_AUTO(testConstantAffixModifier
);
20 TESTCASE_AUTO(testConstantMultiFieldModifier
);
21 TESTCASE_AUTO(testSimpleModifier
);
22 TESTCASE_AUTO(testCurrencySpacingEnabledModifier
);
26 void ModifiersTest::testConstantAffixModifier() {
27 UErrorCode status
= U_ZERO_ERROR
;
28 ConstantAffixModifier
mod0(u
"", u
"", UNUM_PERCENT_FIELD
, true);
29 assertModifierEquals(mod0
, 0, true, u
"|", u
"n", status
);
30 assertSuccess("Spot 1", status
);
32 ConstantAffixModifier
mod1(u
"a📻", u
"b", UNUM_PERCENT_FIELD
, true);
33 assertModifierEquals(mod1
, 3, true, u
"a📻|b", u
"%%%n%", status
);
34 assertSuccess("Spot 2", status
);
37 void ModifiersTest::testConstantMultiFieldModifier() {
38 UErrorCode status
= U_ZERO_ERROR
;
39 NumberStringBuilder prefix
;
40 NumberStringBuilder suffix
;
41 ConstantMultiFieldModifier
mod1(prefix
, suffix
, false, true);
42 assertModifierEquals(mod1
, 0, true, u
"|", u
"n", status
);
43 assertSuccess("Spot 1", status
);
45 prefix
.append(u
"a📻", UNUM_PERCENT_FIELD
, status
);
46 suffix
.append(u
"b", UNUM_CURRENCY_FIELD
, status
);
47 ConstantMultiFieldModifier
mod2(prefix
, suffix
, false, true);
48 assertModifierEquals(mod2
, 3, true, u
"a📻|b", u
"%%%n$", status
);
49 assertSuccess("Spot 2", status
);
51 // Make sure the first modifier is still the same (that it stayed constant)
52 assertModifierEquals(mod1
, 0, true, u
"|", u
"n", status
);
53 assertSuccess("Spot 3", status
);
56 void ModifiersTest::testSimpleModifier() {
57 static const int32_t NUM_CASES
= 5;
58 static const int32_t NUM_OUTPUTS
= 4;
59 static const char16_t *patterns
[] = {u
"{0}", u
"X{0}Y", u
"XX{0}YYY", u
"{0}YY", u
"XX📺XX{0}"};
61 const char16_t *baseString
;
64 } outputs
[NUM_OUTPUTS
] = {{u
"", 0, 0}, {u
"a📻bcde", 0, 0}, {u
"a📻bcde", 4, 4}, {u
"a📻bcde", 3, 5}};
65 static const int32_t prefixLens
[] = {0, 1, 2, 0, 6};
66 static const char16_t *expectedCharFields
[][2] = {{u
"|", u
"n"},
68 {u
"XX|YYY", u
"%%n%%%"},
70 {u
"XX📺XX|", u
"%%%%%%n"}};
71 static const char16_t *expecteds
[][NUM_CASES
] = // force auto-format line break
73 u
"", u
"XY", u
"XXYYY", u
"YY", u
"XX📺XX"}, {
74 u
"a📻bcde", u
"XYa📻bcde", u
"XXYYYa📻bcde", u
"YYa📻bcde", u
"XX📺XXa📻bcde"}, {
75 u
"a📻bcde", u
"a📻bXYcde", u
"a📻bXXYYYcde", u
"a📻bYYcde", u
"a📻bXX📺XXcde"}, {
76 u
"a📻bcde", u
"a📻XbcYde", u
"a📻XXbcYYYde", u
"a📻bcYYde", u
"a📻XX📺XXbcde"}};
78 UErrorCode status
= U_ZERO_ERROR
;
79 for (int32_t i
= 0; i
< NUM_CASES
; i
++) {
80 const UnicodeString
pattern(patterns
[i
]);
81 SimpleFormatter
compiledFormatter(pattern
, 1, 1, status
);
82 assertSuccess("Spot 1", status
);
83 SimpleModifier
mod(compiledFormatter
, UNUM_PERCENT_FIELD
, false);
85 mod
, prefixLens
[i
], false, expectedCharFields
[i
][0], expectedCharFields
[i
][1], status
);
86 assertSuccess("Spot 2", status
);
88 // Test strange insertion positions
89 for (int32_t j
= 0; j
< NUM_OUTPUTS
; j
++) {
90 NumberStringBuilder output
;
91 output
.append(outputs
[j
].baseString
, UNUM_FIELD_COUNT
, status
);
92 mod
.apply(output
, outputs
[j
].leftIndex
, outputs
[j
].rightIndex
, status
);
93 UnicodeString expected
= expecteds
[j
][i
];
94 UnicodeString actual
= output
.toUnicodeString();
95 assertEquals("Strange insertion position", expected
, actual
);
96 assertSuccess("Spot 3", status
);
101 void ModifiersTest::testCurrencySpacingEnabledModifier() {
102 UErrorCode status
= U_ZERO_ERROR
;
103 DecimalFormatSymbols
symbols(Locale("en"), status
);
104 if (!assertSuccess("Spot 1", status
, true)) {
108 NumberStringBuilder prefix
;
109 NumberStringBuilder suffix
;
110 CurrencySpacingEnabledModifier
mod1(prefix
, suffix
, false, true, symbols
, status
);
111 assertSuccess("Spot 2", status
);
112 assertModifierEquals(mod1
, 0, true, u
"|", u
"n", status
);
113 assertSuccess("Spot 3", status
);
115 prefix
.append(u
"USD", UNUM_CURRENCY_FIELD
, status
);
116 assertSuccess("Spot 4", status
);
117 CurrencySpacingEnabledModifier
mod2(prefix
, suffix
, false, true, symbols
, status
);
118 assertSuccess("Spot 5", status
);
119 assertModifierEquals(mod2
, 3, true, u
"USD|", u
"$$$n", status
);
120 assertSuccess("Spot 6", status
);
122 // Test the default currency spacing rules
123 NumberStringBuilder sb
;
124 sb
.append("123", UNUM_INTEGER_FIELD
, status
);
125 assertSuccess("Spot 7", status
);
126 NumberStringBuilder
sb1(sb
);
127 assertModifierEquals(mod2
, sb1
, 3, true, u
"USD\u00A0123", u
"$$$niii", status
);
128 assertSuccess("Spot 8", status
);
130 // Compare with the unsafe code path
131 NumberStringBuilder
sb2(sb
);
132 sb2
.insert(0, "USD", UNUM_CURRENCY_FIELD
, status
);
133 assertSuccess("Spot 9", status
);
134 CurrencySpacingEnabledModifier::applyCurrencySpacing(sb2
, 0, 3, 6, 0, symbols
, status
);
135 assertSuccess("Spot 10", status
);
136 assertTrue(sb1
.toDebugString() + " vs " + sb2
.toDebugString(), sb1
.contentEquals(sb2
));
138 // Test custom patterns
139 // The following line means that the last char of the number should be a | (rather than a digit)
140 symbols
.setPatternForCurrencySpacing(UNUM_CURRENCY_SURROUNDING_MATCH
, true, u
"[|]");
141 suffix
.append("XYZ", UNUM_CURRENCY_FIELD
, status
);
142 assertSuccess("Spot 11", status
);
143 CurrencySpacingEnabledModifier
mod3(prefix
, suffix
, false, true, symbols
, status
);
144 assertSuccess("Spot 12", status
);
145 assertModifierEquals(mod3
, 3, true, u
"USD|\u00A0XYZ", u
"$$$nn$$$", status
);
146 assertSuccess("Spot 13", status
);
149 void ModifiersTest::assertModifierEquals(const Modifier
&mod
, int32_t expectedPrefixLength
,
150 bool expectedStrong
, UnicodeString expectedChars
,
151 UnicodeString expectedFields
, UErrorCode
&status
) {
152 NumberStringBuilder sb
;
153 sb
.appendCodePoint('|', UNUM_FIELD_COUNT
, status
);
154 assertModifierEquals(
155 mod
, sb
, expectedPrefixLength
, expectedStrong
, expectedChars
, expectedFields
, status
);
159 void ModifiersTest::assertModifierEquals(const Modifier
&mod
, NumberStringBuilder
&sb
,
160 int32_t expectedPrefixLength
, bool expectedStrong
,
161 UnicodeString expectedChars
, UnicodeString expectedFields
,
162 UErrorCode
&status
) {
163 int32_t oldCount
= sb
.codePointCount();
164 mod
.apply(sb
, 0, sb
.length(), status
);
165 assertEquals("Prefix length", expectedPrefixLength
, mod
.getPrefixLength(status
));
166 assertEquals("Strong", expectedStrong
, mod
.isStrong());
167 if (dynamic_cast<const CurrencySpacingEnabledModifier
*>(&mod
) == nullptr) {
168 // i.e., if mod is not a CurrencySpacingEnabledModifier
169 assertEquals("Code point count equals actual code point count",
170 sb
.codePointCount() - oldCount
, mod
.getCodePointCount(status
));
173 UnicodeString debugString
;
174 debugString
.append(u
"<NumberStringBuilder [");
175 debugString
.append(expectedChars
);
176 debugString
.append(u
"] [");
177 debugString
.append(expectedFields
);
178 debugString
.append(u
"]>");
179 assertEquals("Debug string", debugString
, sb
.toDebugString());
182 #endif /* #if !UCONFIG_NO_FORMATTING */