1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3
4 #include "unicode/utypes.h"
5
6 #if !UCONFIG_NO_FORMATTING
7
8 #include <set>
9
10 #include "unicode/formattedvalue.h"
11 #include "unicode/unum.h"
12 #include "unicode/udat.h"
13 #include "intltest.h"
14 #include "itformat.h"
15
16
17 class FormattedValueTest : public IntlTest {
18 public:
19 void runIndexedTest(int32_t index, UBool exec, const char*& name, char* par = nullptr) override;
20
21 private:
22 void testBasic();
23 void testSetters();
24 void testLocalPointer();
25
26 void assertAllPartsEqual(
27 UnicodeString messagePrefix,
28 const ConstrainedFieldPosition& cfpos,
29 int32_t matching,
30 UFieldCategory category,
31 int32_t field,
32 int32_t start,
33 int32_t limit,
34 int64_t context);
35 };
36
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)37 void FormattedValueTest::runIndexedTest(int32_t index, UBool exec, const char *&name, char *) {
38 if (exec) {
39 logln("TestSuite FormattedValueTest: ");
40 }
41 TESTCASE_AUTO_BEGIN;
42 TESTCASE_AUTO(testBasic);
43 TESTCASE_AUTO(testSetters);
44 TESTCASE_AUTO(testLocalPointer);
45 TESTCASE_AUTO_END;
46 }
47
48
testBasic()49 void FormattedValueTest::testBasic() {
50 IcuTestErrorCode status(*this, "testBasic");
51 ConstrainedFieldPosition cfpos;
52 assertAllPartsEqual(
53 u"basic",
54 cfpos,
55 7,
56 UFIELD_CATEGORY_UNDEFINED,
57 0,
58 0,
59 0,
60 0LL);
61 }
62
testSetters()63 void FormattedValueTest::testSetters() {
64 IcuTestErrorCode status(*this, "testSetters");
65 ConstrainedFieldPosition cfpos;
66
67 cfpos.constrainCategory(UFIELD_CATEGORY_DATE);
68 assertAllPartsEqual(
69 u"setters 0",
70 cfpos,
71 4,
72 UFIELD_CATEGORY_DATE,
73 0,
74 0,
75 0,
76 0LL);
77
78 cfpos.constrainField(UFIELD_CATEGORY_NUMBER, UNUM_COMPACT_FIELD);
79 assertAllPartsEqual(
80 u"setters 1",
81 cfpos,
82 2,
83 UFIELD_CATEGORY_NUMBER,
84 UNUM_COMPACT_FIELD,
85 0,
86 0,
87 0LL);
88
89 cfpos.setInt64IterationContext(42424242424242LL);
90 assertAllPartsEqual(
91 u"setters 2",
92 cfpos,
93 2,
94 UFIELD_CATEGORY_NUMBER,
95 UNUM_COMPACT_FIELD,
96 0,
97 0,
98 42424242424242LL);
99
100 cfpos.setState(UFIELD_CATEGORY_NUMBER, UNUM_COMPACT_FIELD, 5, 10);
101 assertAllPartsEqual(
102 u"setters 3",
103 cfpos,
104 2,
105 UFIELD_CATEGORY_NUMBER,
106 UNUM_COMPACT_FIELD,
107 5,
108 10,
109 42424242424242LL);
110
111 cfpos.reset();
112 assertAllPartsEqual(
113 u"setters 4",
114 cfpos,
115 7,
116 UFIELD_CATEGORY_UNDEFINED,
117 0,
118 0,
119 0,
120 0LL);
121 }
122
testLocalPointer()123 void FormattedValueTest::testLocalPointer() {
124 UErrorCode status = U_ZERO_ERROR;
125 LocalUConstrainedFieldPositionPointer ucfpos(ucfpos_open(&status));
126 assertSuccess("Openining LocalUConstrainedFieldPositionPointer", status);
127 assertEquals(u"Test that object is valid",
128 0LL,
129 ucfpos_getInt64IterationContext(ucfpos.getAlias(), &status));
130 assertSuccess("Using LocalUConstrainedFieldPositionPointer", status);
131 }
132
133 /** For matching, turn on these bits:
134 *
135 * 1 = UNUM_INTEGER_FIELD
136 * 2 = UNUM_COMPACT_FIELD
137 * 4 = UDAT_AM_PM_FIELD
138 */
assertAllPartsEqual(UnicodeString messagePrefix,const ConstrainedFieldPosition & cfpos,int32_t matching,UFieldCategory category,int32_t field,int32_t start,int32_t limit,int64_t context)139 void FormattedValueTest::assertAllPartsEqual(
140 UnicodeString messagePrefix,
141 const ConstrainedFieldPosition& cfpos,
142 int32_t matching,
143 UFieldCategory category,
144 int32_t field,
145 int32_t start,
146 int32_t limit,
147 int64_t context) {
148 assertEquals(messagePrefix + u": category",
149 category, cfpos.getCategory());
150 assertEquals(messagePrefix + u": field",
151 field, cfpos.getField());
152 assertEquals(messagePrefix + u": start",
153 start, cfpos.getStart());
154 assertEquals(messagePrefix + u": limit",
155 limit, cfpos.getLimit());
156 assertEquals(messagePrefix + u": context",
157 context, cfpos.getInt64IterationContext());
158
159 assertEquals(messagePrefix + u": integer field",
160 static_cast<UBool>((matching & 1) != 0), cfpos.matchesField(UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD));
161 assertEquals(messagePrefix + u": compact field",
162 static_cast<UBool>((matching & 2) != 0), cfpos.matchesField(UFIELD_CATEGORY_NUMBER, UNUM_COMPACT_FIELD));
163 assertEquals(messagePrefix + u": date field",
164 static_cast<UBool>((matching & 4) != 0), cfpos.matchesField(UFIELD_CATEGORY_DATE, UDAT_AM_PM_FIELD));
165 }
166
167
checkFormattedValue(const char16_t * message,const FormattedValue & fv,UnicodeString expectedString,UFieldCategory expectedCategory,const UFieldPosition * expectedFieldPositions,int32_t length)168 void IntlTestWithFieldPosition::checkFormattedValue(
169 const char16_t* message,
170 const FormattedValue& fv,
171 UnicodeString expectedString,
172 UFieldCategory expectedCategory,
173 const UFieldPosition* expectedFieldPositions,
174 int32_t length) {
175 LocalArray<UFieldPositionWithCategory> converted(new UFieldPositionWithCategory[length]);
176 for (int32_t i=0; i<length; i++) {
177 converted[i].category = expectedCategory;
178 converted[i].field = expectedFieldPositions[i].field;
179 converted[i].beginIndex = expectedFieldPositions[i].beginIndex;
180 converted[i].endIndex = expectedFieldPositions[i].endIndex;
181 }
182 checkMixedFormattedValue(message, fv, expectedString, converted.getAlias(), length);
183 }
184
185
CFPosToUnicodeString(const ConstrainedFieldPosition & cfpos)186 UnicodeString CFPosToUnicodeString(const ConstrainedFieldPosition& cfpos) {
187 UnicodeString sb;
188 sb.append(u"CFPos[");
189 sb.append(Int64ToUnicodeString(cfpos.getStart()));
190 sb.append(u'-');
191 sb.append(Int64ToUnicodeString(cfpos.getLimit()));
192 sb.append(u' ');
193 sb.append(Int64ToUnicodeString(cfpos.getCategory()));
194 sb.append(u':');
195 sb.append(Int64ToUnicodeString(cfpos.getField()));
196 sb.append(u']');
197 return sb;
198 }
199
200
checkMixedFormattedValue(const char16_t * message,const FormattedValue & fv,UnicodeString expectedString,const UFieldPositionWithCategory * expectedFieldPositions,int32_t length)201 void IntlTestWithFieldPosition::checkMixedFormattedValue(
202 const char16_t* message,
203 const FormattedValue& fv,
204 UnicodeString expectedString,
205 const UFieldPositionWithCategory* expectedFieldPositions,
206 int32_t length) {
207 IcuTestErrorCode status(*this, "checkMixedFormattedValue");
208 UnicodeString baseMessage = UnicodeString(message) + u": " + fv.toString(status) + u": ";
209
210 // Check string values
211 assertEquals(baseMessage + u"string", expectedString, fv.toString(status));
212 assertEquals(baseMessage + u"temp string", expectedString, fv.toTempString(status));
213
214 // The temp string is guaranteed to be NUL-terminated
215 UnicodeString readOnlyAlias = fv.toTempString(status);
216 if (!status.errIfFailureAndReset()) {
217 assertEquals(baseMessage + u"NUL-terminated",
218 0, readOnlyAlias.getBuffer()[readOnlyAlias.length()]);
219 }
220
221 // Check nextPosition over all fields
222 ConstrainedFieldPosition cfpos;
223 for (int32_t i = 0; i < length; i++) {
224 assertTrue(baseMessage + u"A has next position @ " + Int64ToUnicodeString(i),
225 fv.nextPosition(cfpos, status));
226 int32_t expectedCategory = expectedFieldPositions[i].category;
227 int32_t expectedField = expectedFieldPositions[i].field;
228 int32_t expectedStart = expectedFieldPositions[i].beginIndex;
229 int32_t expectedLimit = expectedFieldPositions[i].endIndex;
230 assertEquals(baseMessage + u"A category @ " + Int64ToUnicodeString(i),
231 expectedCategory, cfpos.getCategory());
232 assertEquals(baseMessage + u"A field @ " + Int64ToUnicodeString(i),
233 expectedField, cfpos.getField());
234 assertEquals(baseMessage + u"A start @ " + Int64ToUnicodeString(i),
235 expectedStart, cfpos.getStart());
236 assertEquals(baseMessage + u"A limit @ " + Int64ToUnicodeString(i),
237 expectedLimit, cfpos.getLimit());
238 }
239 UBool afterLoopResult = fv.nextPosition(cfpos, status);
240 assertFalse(baseMessage + u"A after loop: " + CFPosToUnicodeString(cfpos), afterLoopResult);
241 afterLoopResult = fv.nextPosition(cfpos, status);
242 assertFalse(baseMessage + u"A after loop again: " + CFPosToUnicodeString(cfpos), afterLoopResult);
243
244 // Check nextPosition constrained over each category one at a time
245 for (int32_t category=0; category<UFIELD_CATEGORY_COUNT+1; category++) {
246 if (category == UFIELD_CATEGORY_COUNT) {
247 category = UFIELD_CATEGORY_LIST_SPAN;
248 }
249 cfpos.reset();
250 cfpos.constrainCategory(static_cast<UFieldCategory>(category));
251 for (int32_t i = 0; i < length; i++) {
252 if (expectedFieldPositions[i].category != category) {
253 continue;
254 }
255 assertTrue(baseMessage + u"B has next position @ " + Int64ToUnicodeString(i),
256 fv.nextPosition(cfpos, status));
257 int32_t expectedCategory = expectedFieldPositions[i].category;
258 int32_t expectedField = expectedFieldPositions[i].field;
259 int32_t expectedStart = expectedFieldPositions[i].beginIndex;
260 int32_t expectedLimit = expectedFieldPositions[i].endIndex;
261 assertEquals(baseMessage + u"B category @ " + Int64ToUnicodeString(i),
262 expectedCategory, cfpos.getCategory());
263 assertEquals(baseMessage + u"B field @ " + Int64ToUnicodeString(i),
264 expectedField, cfpos.getField());
265 assertEquals(baseMessage + u"B start @ " + Int64ToUnicodeString(i),
266 expectedStart, cfpos.getStart());
267 assertEquals(baseMessage + u"B limit @ " + Int64ToUnicodeString(i),
268 expectedLimit, cfpos.getLimit());
269 }
270 UBool afterLoopResult = fv.nextPosition(cfpos, status);
271 assertFalse(baseMessage + u"B after loop @ " + CFPosToUnicodeString(cfpos), afterLoopResult);
272 afterLoopResult = fv.nextPosition(cfpos, status);
273 assertFalse(baseMessage + u"B after loop again @ " + CFPosToUnicodeString(cfpos), afterLoopResult);
274 }
275
276 // Check nextPosition constrained over each field one at a time
277 std::set<std::pair<UFieldCategory, int32_t>> uniqueFields;
278 for (int32_t i = 0; i < length; i++) {
279 uniqueFields.insert({expectedFieldPositions[i].category, expectedFieldPositions[i].field});
280 }
281 for (std::pair<UFieldCategory, int32_t> categoryAndField : uniqueFields) {
282 cfpos.reset();
283 cfpos.constrainField(categoryAndField.first, categoryAndField.second);
284 for (int32_t i = 0; i < length; i++) {
285 if (expectedFieldPositions[i].category != categoryAndField.first) {
286 continue;
287 }
288 if (expectedFieldPositions[i].field != categoryAndField.second) {
289 continue;
290 }
291 assertTrue(baseMessage + u"C has next position @ " + Int64ToUnicodeString(i),
292 fv.nextPosition(cfpos, status));
293 int32_t expectedCategory = expectedFieldPositions[i].category;
294 int32_t expectedField = expectedFieldPositions[i].field;
295 int32_t expectedStart = expectedFieldPositions[i].beginIndex;
296 int32_t expectedLimit = expectedFieldPositions[i].endIndex;
297 assertEquals(baseMessage + u"C category @ " + Int64ToUnicodeString(i),
298 expectedCategory, cfpos.getCategory());
299 assertEquals(baseMessage + u"C field @ " + Int64ToUnicodeString(i),
300 expectedField, cfpos.getField());
301 assertEquals(baseMessage + u"C start @ " + Int64ToUnicodeString(i),
302 expectedStart, cfpos.getStart());
303 assertEquals(baseMessage + u"C limit @ " + Int64ToUnicodeString(i),
304 expectedLimit, cfpos.getLimit());
305 }
306 UBool afterLoopResult = fv.nextPosition(cfpos, status);
307 assertFalse(baseMessage + u"C after loop: " + CFPosToUnicodeString(cfpos), afterLoopResult);
308 afterLoopResult = fv.nextPosition(cfpos, status);
309 assertFalse(baseMessage + u"C after loop again: " + CFPosToUnicodeString(cfpos), afterLoopResult);
310 }
311 }
312
313
createFormattedValueTest()314 extern IntlTest *createFormattedValueTest() {
315 return new FormattedValueTest();
316 }
317
318 #endif /* !UCONFIG_NO_FORMATTING */
319