- Adds test infra for multi-category formatted values.
- Adds helper method ConstrainedFieldPosition#matchesField, currently internal.
fLimit = limit;
}
+UBool ConstrainedFieldPosition::matchesField(UFieldCategory category, int32_t field) {
+ switch (fConstraint) {
+ case UCFPOS_CONSTRAINT_NONE:
+ return TRUE;
+ case UCFPOS_CONSTRAINT_CATEGORY:
+ return fCategory == category;
+ case UCFPOS_CONSTRAINT_FIELD:
+ return fCategory == category && fField == field;
+ default:
+ UPRV_UNREACHABLE;
+ }
+}
+
FormattedValue::~FormattedValue() = default;
}
+U_DRAFT UBool U_EXPORT2
+ufmtval_nextPosition(
+ const UFormattedValue* ufmtval,
+ UConstrainedFieldPosition* ucfpos,
+ UErrorCode* ec) {
+ const auto* fmtval = number::impl::UFormattedValueApiHelper::validate(ufmtval, *ec);
+ auto* cfpos = UConstrainedFieldPositionImpl::validate(ucfpos, *ec);
+ if (U_FAILURE(*ec)) {
+ return FALSE;
+ }
+ return fmtval->fFormattedValue->nextPosition(cfpos->fImpl, *ec);
+}
+
+
U_NAMESPACE_END
#endif /* #if !UCONFIG_NO_FORMATTING */
int32_t start,
int32_t limit);
+ /** @internal */
+ UBool matchesField(UFieldCategory category, int32_t field);
+
private:
int64_t fContext = 0LL;
int32_t fField = 0;
*/
UFIELD_CATEGORY_LIST,
+#ifndef U_HIDE_INTERNAL_API
+ /** @internal */
+ UFIELD_CATEGORY_COUNT
+#endif
+
} UFieldCategory;
UChar* myDateFormat(UDateFormat *dat, UDate d);
-// The following is implemented in uformattedvaluetest.c
-// TODO: When needed, add overload with a different category for each position
+typedef struct UFieldPositionWithCategory {
+ UFieldCategory category;
+ int32_t field;
+ int32_t beginIndex;
+ int32_t endIndex;
+} UFieldPositionWithCategory;
+
+// The following are implemented in uformattedvaluetest.c
void checkFormattedValue(
const char* message,
const UFormattedValue* fv,
const UFieldPosition* expectedFieldPositions,
int32_t expectedFieldPositionsLength);
+void checkMixedFormattedValue(
+ const char* message,
+ const UFormattedValue* fv,
+ const UChar* expectedString,
+ const UFieldPositionWithCategory* expectedFieldPositions,
+ int32_t length);
+
#endif /* #if !UCONFIG_NO_FORMATTING */
}
-// Declared in cformtst.h
-void checkFormattedValue(
+static void checkFormattedValueString(
const char* message,
const UFormattedValue* fv,
const UChar* expectedString,
- UFieldCategory expectedCategory,
- const UFieldPosition* expectedFieldPositions,
- int32_t expectedFieldPositionsLength) {
- UErrorCode status = U_ZERO_ERROR;
+ UErrorCode* ec) {
int32_t length;
- const UChar* actualString = ufmtval_getString(fv, &length, &status);
- assertSuccess(message, &status);
+ const UChar* actualString = ufmtval_getString(fv, &length, ec);
+ assertSuccess(message, ec);
// The string is guaranteed to be NUL-terminated.
int32_t actualLength = u_strlen(actualString);
assertIntEquals(message, actualLength, length);
assertUEquals(message, expectedString, actualString);
}
+// Declared in cformtst.h
+void checkFormattedValue(
+ const char* message,
+ const UFormattedValue* fv,
+ const UChar* expectedString,
+ UFieldCategory expectedCategory,
+ const UFieldPosition* expectedFieldPositions,
+ int32_t expectedFieldPositionsLength) {
+ UErrorCode ec = U_ZERO_ERROR;
+ checkFormattedValueString(message, fv, expectedString, &ec);
+ if (U_FAILURE(ec)) { return; }
+
+ // Basic loop over the fields (more rigorous testing in C++)
+ UConstrainedFieldPosition* ucfpos = ucfpos_open(&ec);
+ int32_t i = 0;
+ while (ufmtval_nextPosition(fv, ucfpos, &ec)) {
+ assertIntEquals("category",
+ expectedCategory, ucfpos_getCategory(ucfpos, &ec));
+ assertIntEquals("field",
+ expectedFieldPositions[i].field, ucfpos_getField(ucfpos, &ec));
+ int32_t start, limit;
+ ucfpos_getIndexes(ucfpos, &start, &limit, &ec);
+ assertIntEquals("start",
+ expectedFieldPositions[i].beginIndex, start);
+ assertIntEquals("limit",
+ expectedFieldPositions[i].endIndex, limit);
+ i++;
+ }
+ assertTrue("After loop", !ufmtval_nextPosition(fv, ucfpos, &ec));
+ assertSuccess("After loop", &ec);
+ ucfpos_close(ucfpos);
+}
+
+void checkMixedFormattedValue(
+ const char* message,
+ const UFormattedValue* fv,
+ const UChar* expectedString,
+ const UFieldPositionWithCategory* expectedFieldPositions,
+ int32_t length) {
+ UErrorCode ec = U_ZERO_ERROR;
+ checkFormattedValueString(message, fv, expectedString, &ec);
+ if (U_FAILURE(ec)) { return; }
+
+ // Basic loop over the fields (more rigorous testing in C++)
+ UConstrainedFieldPosition* ucfpos = ucfpos_open(&ec);
+ int32_t i = 0;
+ while (ufmtval_nextPosition(fv, ucfpos, &ec)) {
+ assertIntEquals("category",
+ expectedFieldPositions[i].category, ucfpos_getCategory(ucfpos, &ec));
+ assertIntEquals("field",
+ expectedFieldPositions[i].field, ucfpos_getField(ucfpos, &ec));
+ int32_t start, limit;
+ ucfpos_getIndexes(ucfpos, &start, &limit, &ec);
+ assertIntEquals("start",
+ expectedFieldPositions[i].beginIndex, start);
+ assertIntEquals("limit",
+ expectedFieldPositions[i].endIndex, limit);
+ i++;
+ }
+ assertTrue("After loop", !ufmtval_nextPosition(fv, ucfpos, &ec));
+ assertSuccess("After loop", &ec);
+ ucfpos_close(ucfpos);
+}
+
#endif /* #if !UCONFIG_NO_FORMATTING */
assertSuccess("Should convert without error", &ec);
static const UFieldPosition expectedFieldPositions[] = {
// field, begin index, end index
- {UNUM_GROUPING_SEPARATOR_FIELD, 2, 3},
- {UNUM_GROUPING_SEPARATOR_FIELD, 6, 7},
- {UNUM_INTEGER_FIELD, 0, 10},
- {UNUM_GROUPING_SEPARATOR_FIELD, 13, 14},
- {UNUM_GROUPING_SEPARATOR_FIELD, 17, 18},
- {UNUM_INTEGER_FIELD, 11, 21}};
+ {UNUM_INTEGER_FIELD, 0, 2},
+ {UNUM_DECIMAL_SEPARATOR_FIELD, 2, 3},
+ {UNUM_FRACTION_FIELD, 3, 5},
+ {UNUM_COMPACT_FIELD, 5, 6}};
checkFormattedValue(
"FormattedNumber as FormattedValue",
fv,
UFieldCategory expectedCategory,
const UFieldPosition* expectedFieldPositions,
int32_t length) {
- IcuTestErrorCode status(*this, "checkFormattedValue");
+ LocalArray<UFieldPositionWithCategory> converted(new UFieldPositionWithCategory[length]);
+ for (int32_t i=0; i<length; i++) {
+ converted[i].category = expectedCategory;
+ converted[i].field = expectedFieldPositions[i].field;
+ converted[i].beginIndex = expectedFieldPositions[i].beginIndex;
+ converted[i].endIndex = expectedFieldPositions[i].endIndex;
+ }
+ checkMixedFormattedValue(message, fv, expectedString, converted.getAlias(), length);
+}
+
+
+UnicodeString CFPosToUnicodeString(const ConstrainedFieldPosition& cfpos) {
+ UnicodeString sb;
+ sb.append(u"CFPos[");
+ sb.append(Int64ToUnicodeString(cfpos.getStart()));
+ sb.append(u'-');
+ sb.append(Int64ToUnicodeString(cfpos.getLimit()));
+ sb.append(u' ');
+ sb.append(Int64ToUnicodeString(cfpos.getCategory()));
+ sb.append(u':');
+ sb.append(Int64ToUnicodeString(cfpos.getField()));
+ sb.append(u']');
+ return sb;
+}
+
+
+void IntlTestWithFieldPosition::checkMixedFormattedValue(
+ const char16_t* message,
+ const FormattedValue& fv,
+ UnicodeString expectedString,
+ const UFieldPositionWithCategory* expectedFieldPositions,
+ int32_t length) {
+ IcuTestErrorCode status(*this, "checkMixedFormattedValue");
UnicodeString baseMessage = UnicodeString(message) + u": " + fv.toString(status) + u": ";
// Check string values
// Check nextPosition over all fields
ConstrainedFieldPosition cfpos;
- cfpos.constrainCategory(expectedCategory);
for (int32_t i = 0; i < length; i++) {
assertTrue(baseMessage + i, fv.nextPosition(cfpos, status));
+ int32_t expectedCategory = expectedFieldPositions[i].category;
int32_t expectedField = expectedFieldPositions[i].field;
int32_t expectedStart = expectedFieldPositions[i].beginIndex;
int32_t expectedLimit = expectedFieldPositions[i].endIndex;
- assertEquals(baseMessage + u"category " + Int64ToUnicodeString(i),
+ assertEquals(baseMessage + u"A category " + Int64ToUnicodeString(i),
expectedCategory, cfpos.getCategory());
- assertEquals(baseMessage + u"field " + Int64ToUnicodeString(i),
+ assertEquals(baseMessage + u"A field " + Int64ToUnicodeString(i),
expectedField, cfpos.getField());
- assertEquals(baseMessage + u"start " + Int64ToUnicodeString(i),
+ assertEquals(baseMessage + u"A start " + Int64ToUnicodeString(i),
expectedStart, cfpos.getStart());
- assertEquals(baseMessage + u"limit " + Int64ToUnicodeString(i),
+ assertEquals(baseMessage + u"A limit " + Int64ToUnicodeString(i),
expectedLimit, cfpos.getLimit());
}
- assertFalse(baseMessage + u"after loop", fv.nextPosition(cfpos, status));
+ UBool afterLoopResult = fv.nextPosition(cfpos, status);
+ assertFalse(baseMessage + u"A after loop: " + CFPosToUnicodeString(cfpos), afterLoopResult);
+
+ // Check nextPosition constrained over each category one at a time
+ for (int32_t category=0; category<UFIELD_CATEGORY_COUNT; category++) {
+ cfpos.reset();
+ cfpos.constrainCategory(static_cast<UFieldCategory>(category));
+ for (int32_t i = 0; i < length; i++) {
+ if (expectedFieldPositions[i].category != category) {
+ continue;
+ }
+ assertTrue(baseMessage + i, fv.nextPosition(cfpos, status));
+ int32_t expectedCategory = expectedFieldPositions[i].category;
+ int32_t expectedField = expectedFieldPositions[i].field;
+ int32_t expectedStart = expectedFieldPositions[i].beginIndex;
+ int32_t expectedLimit = expectedFieldPositions[i].endIndex;
+ assertEquals(baseMessage + u"B category " + Int64ToUnicodeString(i),
+ expectedCategory, cfpos.getCategory());
+ assertEquals(baseMessage + u"B field " + Int64ToUnicodeString(i),
+ expectedField, cfpos.getField());
+ assertEquals(baseMessage + u"B start " + Int64ToUnicodeString(i),
+ expectedStart, cfpos.getStart());
+ assertEquals(baseMessage + u"B limit " + Int64ToUnicodeString(i),
+ expectedLimit, cfpos.getLimit());
+ }
+ UBool afterLoopResult = fv.nextPosition(cfpos, status);
+ assertFalse(baseMessage + u"B after loop: " + CFPosToUnicodeString(cfpos), afterLoopResult);
+ }
// Check nextPosition constrained over each field one at a time
- std::set<int32_t> uniqueFields;
+ std::set<std::pair<UFieldCategory, int32_t>> uniqueFields;
for (int32_t i = 0; i < length; i++) {
- uniqueFields.insert(expectedFieldPositions[i].field);
+ uniqueFields.insert({expectedFieldPositions[i].category, expectedFieldPositions[i].field});
}
- for (int32_t field : uniqueFields) {
+ for (std::pair<UFieldCategory, int32_t> categoryAndField : uniqueFields) {
cfpos.reset();
- cfpos.constrainField(expectedCategory, field);
+ cfpos.constrainField(categoryAndField.first, categoryAndField.second);
for (int32_t i = 0; i < length; i++) {
- if (expectedFieldPositions[i].field != field) {
+ if (expectedFieldPositions[i].category != categoryAndField.first) {
+ continue;
+ }
+ if (expectedFieldPositions[i].field != categoryAndField.second) {
continue;
}
assertTrue(baseMessage + i, fv.nextPosition(cfpos, status));
+ int32_t expectedCategory = expectedFieldPositions[i].category;
int32_t expectedField = expectedFieldPositions[i].field;
int32_t expectedStart = expectedFieldPositions[i].beginIndex;
int32_t expectedLimit = expectedFieldPositions[i].endIndex;
- assertEquals(baseMessage + u"category " + Int64ToUnicodeString(i),
+ assertEquals(baseMessage + u"C category " + Int64ToUnicodeString(i),
expectedCategory, cfpos.getCategory());
- assertEquals(baseMessage + u"field " + Int64ToUnicodeString(i),
+ assertEquals(baseMessage + u"C field " + Int64ToUnicodeString(i),
expectedField, cfpos.getField());
- assertEquals(baseMessage + u"start " + Int64ToUnicodeString(i),
+ assertEquals(baseMessage + u"C start " + Int64ToUnicodeString(i),
expectedStart, cfpos.getStart());
- assertEquals(baseMessage + u"limit " + Int64ToUnicodeString(i),
+ assertEquals(baseMessage + u"C limit " + Int64ToUnicodeString(i),
expectedLimit, cfpos.getLimit());
}
- assertFalse(baseMessage + u"after loop", fv.nextPosition(cfpos, status));
+ UBool afterLoopResult = fv.nextPosition(cfpos, status);
+ assertFalse(baseMessage + u"C after loop: " + CFPosToUnicodeString(cfpos), afterLoopResult);
}
}
};
+typedef struct UFieldPositionWithCategory {
+ UFieldCategory category;
+ int32_t field;
+ int32_t beginIndex;
+ int32_t endIndex;
+} UFieldPositionWithCategory;
+
class IntlTestWithFieldPosition : public IntlTest {
public:
- // TODO: When needed, add overload with a different category for each position
void checkFormattedValue(
const char16_t* message,
const FormattedValue& fv,
UFieldCategory expectedCategory,
const UFieldPosition* expectedFieldPositions,
int32_t length);
+
+ void checkMixedFormattedValue(
+ const char16_t* message,
+ const FormattedValue& fv,
+ UnicodeString expectedString,
+ const UFieldPositionWithCategory* expectedFieldPositions,
+ int32_t length);
};
expectedFieldPositions,
length);
- // Check no field positions in an unrelated category
- checkFormattedValue(
- message,
- static_cast<const FormattedValue&>(formattedNumber),
- formattedNumber.toString(status),
- UFIELD_CATEGORY_DATE,
- nullptr,
- 0);
-
// Check FormattedNumber-specific functions
UnicodeString baseMessage = UnicodeString(message) + u": " + formattedNumber.toString(status) + u": ";
FieldPositionIterator fpi;
fLimit = limit;
}
+ /** @internal */
+ public boolean matchesField(Field field) {
+ // If this method ever becomes public, change assert to throw IllegalArgumentException
+ assert field != null;
+ switch (fConstraint) {
+ case NONE:
+ return true;
+ case CLASS:
+ return fClassConstraint.isAssignableFrom(field.getClass());
+ case FIELD:
+ return fField == field;
+ default:
+ throw new AssertionError();
+ }
+ }
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
assertEquals(baseMessage + "limit " + i, expectedLimit, cfpos.getLimit());
i++;
}
- assertFalse(baseMessage + "after loop", fv.nextPosition(cfpos));
+ boolean afterLoopResult = fv.nextPosition(cfpos);
+ assertFalse(baseMessage + "after loop: " + cfpos, afterLoopResult);
// Check nextPosition constrained over each class one at a time
for (Class<?> classConstraint : uniqueFieldClasses) {
assertEquals(baseMessage + "limit " + i, expectedLimit, cfpos.getLimit());
i++;
}
- assertFalse(baseMessage + "after loop", fv.nextPosition(cfpos));
+ afterLoopResult = fv.nextPosition(cfpos);
+ assertFalse(baseMessage + "after loop: " + cfpos, afterLoopResult);
}
// Check nextPosition constrained over an unrelated class
assertEquals(baseMessage + "limit " + i, expectedLimit, cfpos.getLimit());
i++;
}
- assertFalse(baseMessage + "after loop", fv.nextPosition(cfpos));
+ afterLoopResult = fv.nextPosition(cfpos);
+ assertFalse(baseMessage + "after loop: " + cfpos, afterLoopResult);
}
}