ICU-13754 Add a ListFormatter FieldPositionIterator format method (#109)
ICU-13754 Reapply PR#106 after sffc rewinding master it.
This commit is contained in:
parent
fcb82cb744
commit
00ccb44a30
@ -16,11 +16,16 @@
|
||||
* created by: Umesh P. Nair
|
||||
*/
|
||||
|
||||
#include "cmemory.h"
|
||||
#include "unicode/fpositer.h" // FieldPositionIterator
|
||||
#include "unicode/listformatter.h"
|
||||
#include "unicode/simpleformatter.h"
|
||||
#include "unicode/ulistformatter.h"
|
||||
#include "fphdlimp.h"
|
||||
#include "mutex.h"
|
||||
#include "hash.h"
|
||||
#include "cstring.h"
|
||||
#include "uarrsort.h"
|
||||
#include "ulocimp.h"
|
||||
#include "charstr.h"
|
||||
#include "ucln_in.h"
|
||||
@ -61,14 +66,14 @@ ListFormatInternal(const ListFormatInternal &other) :
|
||||
|
||||
|
||||
|
||||
static Hashtable* listPatternHash = NULL;
|
||||
static Hashtable* listPatternHash = nullptr;
|
||||
static UMutex listFormatterMutex = U_MUTEX_INITIALIZER;
|
||||
static const char STANDARD_STYLE[] = "standard";
|
||||
|
||||
U_CDECL_BEGIN
|
||||
static UBool U_CALLCONV uprv_listformatter_cleanup() {
|
||||
delete listPatternHash;
|
||||
listPatternHash = NULL;
|
||||
listPatternHash = nullptr;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -81,7 +86,7 @@ U_CDECL_END
|
||||
|
||||
ListFormatter::ListFormatter(const ListFormatter& other) :
|
||||
owned(other.owned), data(other.data) {
|
||||
if (other.owned != NULL) {
|
||||
if (other.owned != nullptr) {
|
||||
owned = new ListFormatInternal(*other.owned);
|
||||
data = owned;
|
||||
}
|
||||
@ -96,7 +101,7 @@ ListFormatter& ListFormatter::operator=(const ListFormatter& other) {
|
||||
owned = new ListFormatInternal(*other.owned);
|
||||
data = owned;
|
||||
} else {
|
||||
owned = NULL;
|
||||
owned = nullptr;
|
||||
data = other.data;
|
||||
}
|
||||
return *this;
|
||||
@ -108,7 +113,7 @@ void ListFormatter::initializeHash(UErrorCode& errorCode) {
|
||||
}
|
||||
|
||||
listPatternHash = new Hashtable();
|
||||
if (listPatternHash == NULL) {
|
||||
if (listPatternHash == nullptr) {
|
||||
errorCode = U_MEMORY_ALLOCATION_ERROR;
|
||||
return;
|
||||
}
|
||||
@ -121,40 +126,40 @@ void ListFormatter::initializeHash(UErrorCode& errorCode) {
|
||||
const ListFormatInternal* ListFormatter::getListFormatInternal(
|
||||
const Locale& locale, const char *style, UErrorCode& errorCode) {
|
||||
if (U_FAILURE(errorCode)) {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
CharString keyBuffer(locale.getName(), errorCode);
|
||||
keyBuffer.append(':', errorCode).append(style, errorCode);
|
||||
UnicodeString key(keyBuffer.data(), -1, US_INV);
|
||||
ListFormatInternal* result = NULL;
|
||||
ListFormatInternal* result = nullptr;
|
||||
{
|
||||
Mutex m(&listFormatterMutex);
|
||||
if (listPatternHash == NULL) {
|
||||
if (listPatternHash == nullptr) {
|
||||
initializeHash(errorCode);
|
||||
if (U_FAILURE(errorCode)) {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
result = static_cast<ListFormatInternal*>(listPatternHash->get(key));
|
||||
}
|
||||
if (result != NULL) {
|
||||
if (result != nullptr) {
|
||||
return result;
|
||||
}
|
||||
result = loadListFormatInternal(locale, style, errorCode);
|
||||
if (U_FAILURE(errorCode)) {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
{
|
||||
Mutex m(&listFormatterMutex);
|
||||
ListFormatInternal* temp = static_cast<ListFormatInternal*>(listPatternHash->get(key));
|
||||
if (temp != NULL) {
|
||||
if (temp != nullptr) {
|
||||
delete result;
|
||||
result = temp;
|
||||
} else {
|
||||
listPatternHash->put(key, result, errorCode);
|
||||
if (U_FAILURE(errorCode)) {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -235,11 +240,11 @@ ListFormatter::ListPatternsSink::~ListPatternsSink() {}
|
||||
|
||||
ListFormatInternal* ListFormatter::loadListFormatInternal(
|
||||
const Locale& locale, const char * style, UErrorCode& errorCode) {
|
||||
UResourceBundle* rb = ures_open(NULL, locale.getName(), &errorCode);
|
||||
UResourceBundle* rb = ures_open(nullptr, locale.getName(), &errorCode);
|
||||
rb = ures_getByKeyWithFallback(rb, "listPattern", rb, &errorCode);
|
||||
if (U_FAILURE(errorCode)) {
|
||||
ures_close(rb);
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
ListFormatter::ListPatternsSink sink;
|
||||
char currentStyle[kStyleLenMax+1];
|
||||
@ -255,20 +260,20 @@ ListFormatInternal* ListFormatter::loadListFormatInternal(
|
||||
}
|
||||
ures_close(rb);
|
||||
if (U_FAILURE(errorCode)) {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
if (sink.two.isEmpty() || sink.start.isEmpty() || sink.middle.isEmpty() || sink.end.isEmpty()) {
|
||||
errorCode = U_MISSING_RESOURCE_ERROR;
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
ListFormatInternal* result = new ListFormatInternal(sink.two, sink.start, sink.middle, sink.end, errorCode);
|
||||
if (result == NULL) {
|
||||
if (result == nullptr) {
|
||||
errorCode = U_MEMORY_ALLOCATION_ERROR;
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
if (U_FAILURE(errorCode)) {
|
||||
delete result;
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -286,12 +291,12 @@ ListFormatter* ListFormatter::createInstance(const Locale& locale, const char *s
|
||||
Locale tempLocale = locale;
|
||||
const ListFormatInternal* listFormatInternal = getListFormatInternal(tempLocale, style, errorCode);
|
||||
if (U_FAILURE(errorCode)) {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
ListFormatter* p = new ListFormatter(listFormatInternal);
|
||||
if (p == NULL) {
|
||||
if (p == nullptr) {
|
||||
errorCode = U_MEMORY_ALLOCATION_ERROR;
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
@ -301,7 +306,7 @@ ListFormatter::ListFormatter(const ListFormatData& listFormatData, UErrorCode &e
|
||||
data = owned;
|
||||
}
|
||||
|
||||
ListFormatter::ListFormatter(const ListFormatInternal* listFormatterInternal) : owned(NULL), data(listFormatterInternal) {
|
||||
ListFormatter::ListFormatter(const ListFormatInternal* listFormatterInternal) : owned(nullptr), data(listFormatterInternal) {
|
||||
}
|
||||
|
||||
ListFormatter::~ListFormatter() {
|
||||
@ -323,6 +328,8 @@ static void joinStringsAndReplace(
|
||||
UnicodeString &result,
|
||||
UBool recordOffset,
|
||||
int32_t &offset,
|
||||
int32_t *offsetFirst,
|
||||
int32_t *offsetSecond,
|
||||
UErrorCode& errorCode) {
|
||||
if (U_FAILURE(errorCode)) {
|
||||
return;
|
||||
@ -348,6 +355,8 @@ static void joinStringsAndReplace(
|
||||
} else if (offset >= 0) {
|
||||
offset += offsets[0];
|
||||
}
|
||||
if (offsetFirst != nullptr) *offsetFirst = offsets[0];
|
||||
if (offsetSecond != nullptr) *offsetSecond = offsets[1];
|
||||
}
|
||||
|
||||
UnicodeString& ListFormatter::format(
|
||||
@ -359,6 +368,17 @@ UnicodeString& ListFormatter::format(
|
||||
return format(items, nItems, appendTo, -1, offset, errorCode);
|
||||
}
|
||||
|
||||
UnicodeString& ListFormatter::format(
|
||||
const UnicodeString items[],
|
||||
int32_t nItems,
|
||||
UnicodeString & appendTo,
|
||||
FieldPositionIterator* posIter,
|
||||
UErrorCode& errorCode) const {
|
||||
int32_t offset;
|
||||
FieldPositionIteratorHandler handler(posIter, errorCode);
|
||||
return format_(items, nItems, appendTo, -1, offset, &handler, errorCode);
|
||||
};
|
||||
|
||||
UnicodeString& ListFormatter::format(
|
||||
const UnicodeString items[],
|
||||
int32_t nItems,
|
||||
@ -366,11 +386,22 @@ UnicodeString& ListFormatter::format(
|
||||
int32_t index,
|
||||
int32_t &offset,
|
||||
UErrorCode& errorCode) const {
|
||||
return format_(items, nItems, appendTo, index, offset, nullptr, errorCode);
|
||||
}
|
||||
|
||||
UnicodeString& ListFormatter::format_(
|
||||
const UnicodeString items[],
|
||||
int32_t nItems,
|
||||
UnicodeString& appendTo,
|
||||
int32_t index,
|
||||
int32_t &offset,
|
||||
FieldPositionHandler* handler,
|
||||
UErrorCode& errorCode) const {
|
||||
offset = -1;
|
||||
if (U_FAILURE(errorCode)) {
|
||||
return appendTo;
|
||||
}
|
||||
if (data == NULL) {
|
||||
if (data == nullptr) {
|
||||
errorCode = U_INVALID_STATE_ERROR;
|
||||
return appendTo;
|
||||
}
|
||||
@ -382,6 +413,11 @@ UnicodeString& ListFormatter::format(
|
||||
if (index == 0) {
|
||||
offset = appendTo.length();
|
||||
}
|
||||
if (handler != nullptr) {
|
||||
handler->addAttribute(ULISTFMT_ELEMENT_FIELD,
|
||||
appendTo.length(),
|
||||
appendTo.length() + items[0].length());
|
||||
}
|
||||
appendTo.append(items[0]);
|
||||
return appendTo;
|
||||
}
|
||||
@ -389,6 +425,12 @@ UnicodeString& ListFormatter::format(
|
||||
if (index == 0) {
|
||||
offset = 0;
|
||||
}
|
||||
int32_t offsetFirst;
|
||||
int32_t offsetSecond;
|
||||
int32_t prefixLength = 0;
|
||||
// for n items, there are 2 * (n + 1) boundary including 0 and the upper
|
||||
// edge.
|
||||
MaybeStackArray<int32_t, 10> offsets((handler != nullptr) ? 2 * (nItems + 1): 0);
|
||||
joinStringsAndReplace(
|
||||
nItems == 2 ? data->twoPattern : data->startPattern,
|
||||
result,
|
||||
@ -396,7 +438,14 @@ UnicodeString& ListFormatter::format(
|
||||
result,
|
||||
index == 1,
|
||||
offset,
|
||||
&offsetFirst,
|
||||
&offsetSecond,
|
||||
errorCode);
|
||||
if (handler != nullptr) {
|
||||
offsets[0] = 0;
|
||||
prefixLength += offsetFirst;
|
||||
offsets[1] = offsetSecond - prefixLength;
|
||||
}
|
||||
if (nItems > 2) {
|
||||
for (int32_t i = 2; i < nItems - 1; ++i) {
|
||||
joinStringsAndReplace(
|
||||
@ -406,7 +455,13 @@ UnicodeString& ListFormatter::format(
|
||||
result,
|
||||
index == i,
|
||||
offset,
|
||||
&offsetFirst,
|
||||
&offsetSecond,
|
||||
errorCode);
|
||||
if (handler != nullptr) {
|
||||
prefixLength += offsetFirst;
|
||||
offsets[i] = offsetSecond - prefixLength;
|
||||
}
|
||||
}
|
||||
joinStringsAndReplace(
|
||||
data->endPattern,
|
||||
@ -415,7 +470,45 @@ UnicodeString& ListFormatter::format(
|
||||
result,
|
||||
index == nItems - 1,
|
||||
offset,
|
||||
&offsetFirst,
|
||||
&offsetSecond,
|
||||
errorCode);
|
||||
if (handler != nullptr) {
|
||||
prefixLength += offsetFirst;
|
||||
offsets[nItems - 1] = offsetSecond - prefixLength;
|
||||
}
|
||||
}
|
||||
if (handler != nullptr) {
|
||||
// If there are already some data in appendTo, we need to adjust the index
|
||||
// by shifting that lenght while insert into handler.
|
||||
int32_t shift = appendTo.length() + prefixLength;
|
||||
// Output the ULISTFMT_ELEMENT_FIELD in the order of the input elements
|
||||
for (int32_t i = 0; i < nItems; ++i) {
|
||||
offsets[i + nItems] = offsets[i] + items[i].length() + shift;
|
||||
offsets[i] += shift;
|
||||
handler->addAttribute(
|
||||
ULISTFMT_ELEMENT_FIELD, // id
|
||||
offsets[i], // index
|
||||
offsets[i + nItems]); // limit
|
||||
}
|
||||
// The locale pattern may reorder the items (such as in ur-IN locale),
|
||||
// so we cannot assume the array is in accendning order.
|
||||
// To handle the edging case, just insert the two ends into the array
|
||||
// and sort. Then we output ULISTFMT_LITERAL_FIELD if the indecies
|
||||
// between the even and odd position are not the same in the sorted array.
|
||||
offsets[2 * nItems] = shift - prefixLength;
|
||||
offsets[2 * nItems + 1] = result.length() + shift - prefixLength;
|
||||
uprv_sortArray(offsets.getAlias(), 2 * (nItems + 1), sizeof(int32_t),
|
||||
uprv_int32Comparator, nullptr,
|
||||
false, &errorCode);
|
||||
for (int32_t i = 0; i <= nItems; ++i) {
|
||||
if (offsets[i * 2] != offsets[i * 2 + 1]) {
|
||||
handler->addAttribute(
|
||||
ULISTFMT_LITERAL_FIELD, // id
|
||||
offsets[i * 2], // index
|
||||
offsets[i * 2 + 1]); // limit
|
||||
}
|
||||
}
|
||||
}
|
||||
if (U_SUCCESS(errorCode)) {
|
||||
if (offset >= 0) {
|
||||
|
@ -26,6 +26,9 @@
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
class FieldPositionIterator;
|
||||
class FieldPositionHandler;
|
||||
|
||||
/** @internal */
|
||||
class Hashtable;
|
||||
|
||||
@ -137,6 +140,27 @@ class U_I18N_API ListFormatter : public UObject{
|
||||
UnicodeString& format(const UnicodeString items[], int32_t n_items,
|
||||
UnicodeString& appendTo, UErrorCode& errorCode) const;
|
||||
|
||||
#ifndef U_HIDE_DRAFT_API
|
||||
/**
|
||||
* Format a list of strings.
|
||||
*
|
||||
* @param items An array of strings to be combined and formatted.
|
||||
* @param n_items Length of the array items.
|
||||
* @param appendTo The string to which the formatted result will be
|
||||
* appended.
|
||||
* @param posIter On return, can be used to iterate over positions of
|
||||
* fields generated by this format call. Field values are
|
||||
* defined in UListFormatterField. Can be NULL.
|
||||
* @param status ICU error code returned here.
|
||||
* @return Formatted string combining the elements of items,
|
||||
* appended to appendTo.
|
||||
* @draft ICU 63
|
||||
*/
|
||||
UnicodeString& format(const UnicodeString items[], int32_t n_items,
|
||||
UnicodeString & appendTo, FieldPositionIterator* posIter,
|
||||
UErrorCode& errorCode) const;
|
||||
#endif /* U_HIDE_DRAFT_API */
|
||||
|
||||
#ifndef U_HIDE_INTERNAL_API
|
||||
/**
|
||||
@internal for MeasureFormat
|
||||
@ -164,6 +188,10 @@ class U_I18N_API ListFormatter : public UObject{
|
||||
struct ListPatternsSink;
|
||||
static ListFormatInternal* loadListFormatInternal(const Locale& locale, const char* style, UErrorCode& errorCode);
|
||||
|
||||
UnicodeString& format_(
|
||||
const UnicodeString items[], int32_t n_items, UnicodeString& appendTo,
|
||||
int32_t index, int32_t &offset, FieldPositionHandler* handler, UErrorCode& errorCode) const;
|
||||
|
||||
ListFormatter();
|
||||
|
||||
ListFormatInternal* owned;
|
||||
|
@ -33,6 +33,26 @@
|
||||
struct UListFormatter;
|
||||
typedef struct UListFormatter UListFormatter; /**< C typedef for struct UListFormatter. @stable ICU 55 */
|
||||
|
||||
#ifndef U_HIDE_DRAFT_API
|
||||
/**
|
||||
* FieldPosition and UFieldPosition selectors for format fields
|
||||
* defined by ListFormatter.
|
||||
* @draft ICU 63
|
||||
*/
|
||||
typedef enum UListFormatterField {
|
||||
/**
|
||||
* The literal text in the result which came from the resources.
|
||||
* @draft ICU 63
|
||||
*/
|
||||
ULISTFMT_LITERAL_FIELD,
|
||||
/**
|
||||
* The element text in the result which came from the input strings.
|
||||
* @draft ICU 63
|
||||
*/
|
||||
ULISTFMT_ELEMENT_FIELD
|
||||
} UListFormatterField;
|
||||
#endif // U_HIDE_DRAFT_API
|
||||
|
||||
/**
|
||||
* Open a new UListFormatter object using the rules for a given locale.
|
||||
* @param locale
|
||||
|
@ -17,8 +17,61 @@
|
||||
*/
|
||||
|
||||
#include "listformattertest.h"
|
||||
#include "unicode/ulistformatter.h"
|
||||
#include <string.h>
|
||||
|
||||
namespace {
|
||||
const char* attrString(int32_t attrId) {
|
||||
switch (attrId) {
|
||||
case ULISTFMT_LITERAL_FIELD: return "literal";
|
||||
case ULISTFMT_ELEMENT_FIELD: return "element";
|
||||
default: return "xxx";
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void ListFormatterTest::ExpectPositions(FieldPositionIterator& iter,
|
||||
int32_t *values, int32_t tupleCount) {
|
||||
UBool found[10];
|
||||
FieldPosition fp;
|
||||
if (tupleCount > 10) {
|
||||
assertTrue("internal error, tupleCount too large", FALSE);
|
||||
} else {
|
||||
for (int i = 0; i < tupleCount; ++i) {
|
||||
found[i] = FALSE;
|
||||
}
|
||||
}
|
||||
while (iter.next(fp)) {
|
||||
UBool ok = FALSE;
|
||||
int32_t id = fp.getField();
|
||||
int32_t start = fp.getBeginIndex();
|
||||
int32_t limit = fp.getEndIndex();
|
||||
char buf[128];
|
||||
sprintf(buf, "%24s %3d %3d %3d", attrString(id), id, start, limit);
|
||||
logln(buf);
|
||||
for (int i = 0; i < tupleCount; ++i) {
|
||||
if (found[i]) {
|
||||
continue;
|
||||
}
|
||||
if (values[i*3] == id && values[i*3+1] == start && values[i*3+2] == limit) {
|
||||
found[i] = ok = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertTrue((UnicodeString)"found [" + attrString(id) + "," + start + "," + limit + "]", ok);
|
||||
}
|
||||
// check that all were found
|
||||
UBool ok = TRUE;
|
||||
for (int i = 0; i < tupleCount; ++i) {
|
||||
if (!found[i]) {
|
||||
ok = FALSE;
|
||||
assertTrue((UnicodeString) "missing [" + attrString(values[i*3]) + "," + values[i*3+1] +
|
||||
"," + values[i*3+2] + "]", found[i]);
|
||||
}
|
||||
}
|
||||
assertTrue("no expected values were missing", ok);
|
||||
}
|
||||
|
||||
ListFormatterTest::ListFormatterTest() :
|
||||
prefix("Prefix: ", -1, US_INV),
|
||||
one("Alice", -1, US_INV), two("Bob", -1, US_INV),
|
||||
@ -26,9 +79,9 @@ ListFormatterTest::ListFormatterTest() :
|
||||
}
|
||||
|
||||
void ListFormatterTest::CheckFormatting(const ListFormatter* formatter, UnicodeString data[], int32_t dataSize,
|
||||
const UnicodeString& expected_result) {
|
||||
const UnicodeString& expected_result, const char* testName) {
|
||||
UnicodeString actualResult(prefix);
|
||||
UErrorCode errorCode = U_ZERO_ERROR;
|
||||
IcuTestErrorCode errorCode(*this, testName);
|
||||
formatter->format(data, dataSize, actualResult, errorCode);
|
||||
UnicodeString expectedStringWithPrefix = prefix + expected_result;
|
||||
if (expectedStringWithPrefix != actualResult) {
|
||||
@ -37,29 +90,29 @@ void ListFormatterTest::CheckFormatting(const ListFormatter* formatter, UnicodeS
|
||||
}
|
||||
|
||||
void ListFormatterTest::CheckFourCases(const char* locale_string, UnicodeString one, UnicodeString two,
|
||||
UnicodeString three, UnicodeString four, UnicodeString results[4]) {
|
||||
UErrorCode errorCode = U_ZERO_ERROR;
|
||||
UnicodeString three, UnicodeString four, UnicodeString results[4], const char* testName) {
|
||||
IcuTestErrorCode errorCode(*this, testName);
|
||||
LocalPointer<ListFormatter> formatter(ListFormatter::createInstance(Locale(locale_string), errorCode));
|
||||
if (U_FAILURE(errorCode)) {
|
||||
dataerrln("ListFormatter::createInstance(Locale(\"%s\"), errorCode) failed in CheckFourCases: %s", locale_string, u_errorName(errorCode));
|
||||
return;
|
||||
}
|
||||
UnicodeString input1[] = {one};
|
||||
CheckFormatting(formatter.getAlias(), input1, 1, results[0]);
|
||||
CheckFormatting(formatter.getAlias(), input1, 1, results[0], testName);
|
||||
|
||||
UnicodeString input2[] = {one, two};
|
||||
CheckFormatting(formatter.getAlias(), input2, 2, results[1]);
|
||||
CheckFormatting(formatter.getAlias(), input2, 2, results[1], testName);
|
||||
|
||||
UnicodeString input3[] = {one, two, three};
|
||||
CheckFormatting(formatter.getAlias(), input3, 3, results[2]);
|
||||
CheckFormatting(formatter.getAlias(), input3, 3, results[2], testName);
|
||||
|
||||
UnicodeString input4[] = {one, two, three, four};
|
||||
CheckFormatting(formatter.getAlias(), input4, 4, results[3]);
|
||||
CheckFormatting(formatter.getAlias(), input4, 4, results[3], testName);
|
||||
}
|
||||
|
||||
UBool ListFormatterTest::RecordFourCases(const Locale& locale, UnicodeString one, UnicodeString two,
|
||||
UnicodeString three, UnicodeString four, UnicodeString results[4]) {
|
||||
UErrorCode errorCode = U_ZERO_ERROR;
|
||||
UnicodeString three, UnicodeString four, UnicodeString results[4], const char* testName) {
|
||||
IcuTestErrorCode errorCode(*this, testName);
|
||||
LocalPointer<ListFormatter> formatter(ListFormatter::createInstance(locale, errorCode));
|
||||
if (U_FAILURE(errorCode)) {
|
||||
dataerrln("ListFormatter::createInstance(\"%s\", errorCode) failed in RecordFourCases: %s", locale.getName(), u_errorName(errorCode));
|
||||
@ -88,14 +141,14 @@ void ListFormatterTest::TestRoot() {
|
||||
one + ", " + two + ", " + three + ", " + four
|
||||
};
|
||||
|
||||
CheckFourCases("", one, two, three, four, results);
|
||||
CheckFourCases("", one, two, three, four, results, "TestRoot()");
|
||||
}
|
||||
|
||||
// Bogus locale should fallback to root.
|
||||
void ListFormatterTest::TestBogus() {
|
||||
UnicodeString results[4];
|
||||
if (RecordFourCases(Locale::getDefault(), one, two, three, four, results)) {
|
||||
CheckFourCases("ex_PY", one, two, three, four, results);
|
||||
if (RecordFourCases(Locale::getDefault(), one, two, three, four, results, "TestBogus()")) {
|
||||
CheckFourCases("ex_PY", one, two, three, four, results, "TestBogus()");
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,11 +162,11 @@ void ListFormatterTest::TestEnglish() {
|
||||
one + ", " + two + ", " + three + ", and " + four
|
||||
};
|
||||
|
||||
CheckFourCases("en", one, two, three, four, results);
|
||||
CheckFourCases("en", one, two, three, four, results, "TestEnglish()");
|
||||
}
|
||||
|
||||
void ListFormatterTest::Test9946() {
|
||||
UErrorCode errorCode = U_ZERO_ERROR;
|
||||
IcuTestErrorCode errorCode(*this, "Test9946()");
|
||||
LocalPointer<ListFormatter> formatter(ListFormatter::createInstance(Locale("en"), errorCode));
|
||||
if (U_FAILURE(errorCode)) {
|
||||
dataerrln(
|
||||
@ -144,7 +197,7 @@ void ListFormatterTest::TestEnglishUS() {
|
||||
one + ", " + two + ", " + three + ", and " + four
|
||||
};
|
||||
|
||||
CheckFourCases("en_US", one, two, three, four, results);
|
||||
CheckFourCases("en_US", one, two, three, four, results, "TestEnglishUS()");
|
||||
}
|
||||
|
||||
// Tests resource loading and inheritance when region sublocale
|
||||
@ -158,7 +211,231 @@ void ListFormatterTest::TestEnglishGB() {
|
||||
one + ", " + two + ", " + three + " and " + four
|
||||
};
|
||||
|
||||
CheckFourCases("en_GB", one, two, three, four, results);
|
||||
CheckFourCases("en_GB", one, two, three, four, results, "TestEnglishGB()");
|
||||
}
|
||||
|
||||
void ListFormatterTest::TestFieldPositionIteratorWontCrash() {
|
||||
IcuTestErrorCode errorCode(*this, "TestFieldPositionIteratorWontCrash()");
|
||||
LocalPointer<ListFormatter> formatter(
|
||||
ListFormatter::createInstance(Locale("en"), errorCode));
|
||||
if (U_FAILURE(errorCode)) {
|
||||
dataerrln(
|
||||
"ListFormatter::createInstance(Locale(\"en\"), errorCode) failed in "
|
||||
"TestFieldPositionIteratorWontCrash: %s",
|
||||
u_errorName(errorCode));
|
||||
return;
|
||||
}
|
||||
UnicodeString data[3] = {"a", "bbb", "cc"};
|
||||
UnicodeString actualResult;
|
||||
// make sure NULL as FieldPositionIterator won't caused crash.
|
||||
formatter->format(data, 3, actualResult, nullptr, errorCode);
|
||||
if (U_FAILURE(errorCode)) {
|
||||
dataerrln(
|
||||
"ListFormatter::format(data, 3, nullptr, errorCode) "
|
||||
"failed in TestFieldPositionIteratorWontCrash: %s",
|
||||
u_errorName(errorCode));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void ListFormatterTest::RunTestFieldPositionIteratorWithFormatter(
|
||||
ListFormatter* formatter,
|
||||
UnicodeString data[], int32_t n, int32_t expected[], int32_t tupleCount,
|
||||
UnicodeString& appendTo, const char16_t *expectedFormatted,
|
||||
const char* testName) {
|
||||
IcuTestErrorCode errorCode(*this, testName);
|
||||
FieldPositionIterator iter;
|
||||
formatter->format(data, n, appendTo, &iter, errorCode);
|
||||
if (U_FAILURE(errorCode)) {
|
||||
dataerrln(
|
||||
"ListFormatter::format(data, %d, &iter, errorCode) "
|
||||
"failed in %s: %s", n, testName, u_errorName(errorCode));
|
||||
return;
|
||||
}
|
||||
if (appendTo != expectedFormatted) {
|
||||
errln(UnicodeString("Expected: |") + expectedFormatted + "|, Actual: |" + appendTo + "|");
|
||||
}
|
||||
ExpectPositions(iter, expected, tupleCount);
|
||||
}
|
||||
|
||||
void ListFormatterTest::RunTestFieldPositionIteratorWithNItemsPatternShift(
|
||||
UnicodeString data[], int32_t n, int32_t expected[], int32_t tupleCount,
|
||||
UnicodeString& appendTo, const char16_t *expectedFormatted,
|
||||
const char* testName) {
|
||||
IcuTestErrorCode errorCode(*this, testName);
|
||||
LocalPointer<ListFormatter> formatter(
|
||||
ListFormatter::createInstance(Locale("ur", "IN"), "unit-narrow", errorCode));
|
||||
if (U_FAILURE(errorCode)) {
|
||||
dataerrln(
|
||||
"ListFormatter::createInstance(Locale(\"ur\", \"IN\"), \"unit-narrow\", errorCode) failed in "
|
||||
"%s: %s", testName, u_errorName(errorCode));
|
||||
return;
|
||||
}
|
||||
RunTestFieldPositionIteratorWithFormatter(
|
||||
formatter.getAlias(),
|
||||
data, n, expected, tupleCount, appendTo, expectedFormatted, testName);
|
||||
}
|
||||
|
||||
void ListFormatterTest::RunTestFieldPositionIteratorWithNItems(
|
||||
UnicodeString data[], int32_t n, int32_t expected[], int32_t tupleCount,
|
||||
UnicodeString& appendTo, const char16_t *expectedFormatted,
|
||||
const char* testName) {
|
||||
IcuTestErrorCode errorCode(*this, testName);
|
||||
LocalPointer<ListFormatter> formatter(
|
||||
ListFormatter::createInstance(Locale("en"), errorCode));
|
||||
if (U_FAILURE(errorCode)) {
|
||||
dataerrln(
|
||||
"ListFormatter::createInstance(Locale(\"en\"), errorCode) failed in "
|
||||
"%s: %s", testName, u_errorName(errorCode));
|
||||
return;
|
||||
}
|
||||
RunTestFieldPositionIteratorWithFormatter(
|
||||
formatter.getAlias(),
|
||||
data, n, expected, tupleCount, appendTo, expectedFormatted, testName);
|
||||
}
|
||||
|
||||
void ListFormatterTest::TestFieldPositionIteratorWith3ItemsAndDataBefore() {
|
||||
// 0 1 2
|
||||
// 0123456789012345678901234567
|
||||
// "Hello World: a, bbb, and cc"
|
||||
UnicodeString data[3] = {"a", "bbb", "cc"};
|
||||
int32_t expected[] = {
|
||||
ULISTFMT_ELEMENT_FIELD, 13, 14,
|
||||
ULISTFMT_LITERAL_FIELD, 14, 16,
|
||||
ULISTFMT_ELEMENT_FIELD, 16, 19,
|
||||
ULISTFMT_LITERAL_FIELD, 19, 25,
|
||||
ULISTFMT_ELEMENT_FIELD, 25, 27
|
||||
};
|
||||
int32_t tupleCount = sizeof(expected)/(3 * sizeof(*expected));
|
||||
UnicodeString appendTo(u"Hello World: ");
|
||||
RunTestFieldPositionIteratorWithNItems(
|
||||
data, 3, expected, tupleCount, appendTo,
|
||||
u"Hello World: a, bbb, and cc",
|
||||
"TestFieldPositionIteratorWith3ItemsAndDataBefore");
|
||||
}
|
||||
|
||||
void ListFormatterTest::TestFieldPositionIteratorWith3Items() {
|
||||
// 0 1
|
||||
// 012345678901234
|
||||
// "a, bbb, and cc"
|
||||
UnicodeString data[3] = {"a", "bbb", "cc"};
|
||||
int32_t expected[] = {
|
||||
ULISTFMT_ELEMENT_FIELD, 0, 1,
|
||||
ULISTFMT_LITERAL_FIELD, 1, 3,
|
||||
ULISTFMT_ELEMENT_FIELD, 3, 6,
|
||||
ULISTFMT_LITERAL_FIELD, 6, 12,
|
||||
ULISTFMT_ELEMENT_FIELD, 12, 14
|
||||
};
|
||||
int32_t tupleCount = sizeof(expected)/(3 * sizeof(*expected));
|
||||
UnicodeString appendTo;
|
||||
RunTestFieldPositionIteratorWithNItems(
|
||||
data, 3, expected, tupleCount, appendTo,
|
||||
u"a, bbb, and cc",
|
||||
"TestFieldPositionIteratorWith3Items");
|
||||
}
|
||||
|
||||
void ListFormatterTest::TestFieldPositionIteratorWith3ItemsPatternShift() {
|
||||
// 0 1
|
||||
// 012345678901234
|
||||
// "cc bbb a"
|
||||
UnicodeString data[3] = {"a", "bbb", "cc"};
|
||||
int32_t expected[] = {
|
||||
ULISTFMT_ELEMENT_FIELD, 7, 8,
|
||||
ULISTFMT_LITERAL_FIELD, 6, 7,
|
||||
ULISTFMT_ELEMENT_FIELD, 3, 6,
|
||||
ULISTFMT_LITERAL_FIELD, 2, 3,
|
||||
ULISTFMT_ELEMENT_FIELD, 0, 2
|
||||
};
|
||||
int32_t tupleCount = sizeof(expected)/(3 * sizeof(*expected));
|
||||
UnicodeString appendTo;
|
||||
RunTestFieldPositionIteratorWithNItemsPatternShift(
|
||||
data, 3, expected, tupleCount, appendTo,
|
||||
u"cc bbb a",
|
||||
"TestFieldPositionIteratorWith3ItemsPatternShift");
|
||||
}
|
||||
|
||||
void ListFormatterTest::TestFieldPositionIteratorWith2ItemsAndDataBefore() {
|
||||
// 0 1
|
||||
// 0123456789012345
|
||||
// "Foo: bbb and cc"
|
||||
UnicodeString data[2] = {"bbb", "cc"};
|
||||
int32_t expected[] = {
|
||||
ULISTFMT_ELEMENT_FIELD, 5, 8,
|
||||
ULISTFMT_LITERAL_FIELD, 8, 13,
|
||||
ULISTFMT_ELEMENT_FIELD, 13, 15
|
||||
};
|
||||
int32_t tupleCount = sizeof(expected)/(3 * sizeof(*expected));
|
||||
UnicodeString appendTo("Foo: ");
|
||||
RunTestFieldPositionIteratorWithNItems(
|
||||
data, 2, expected, tupleCount, appendTo,
|
||||
u"Foo: bbb and cc",
|
||||
"TestFieldPositionIteratorWith2ItemsAndDataBefore");
|
||||
}
|
||||
|
||||
void ListFormatterTest::TestFieldPositionIteratorWith2Items() {
|
||||
// 0 1
|
||||
// 01234567890
|
||||
// "bbb and cc"
|
||||
UnicodeString data[2] = {"bbb", "cc"};
|
||||
int32_t expected[] = {
|
||||
ULISTFMT_ELEMENT_FIELD, 0, 3,
|
||||
ULISTFMT_LITERAL_FIELD, 3, 8,
|
||||
ULISTFMT_ELEMENT_FIELD, 8, 10
|
||||
};
|
||||
int32_t tupleCount = sizeof(expected)/(3 * sizeof(*expected));
|
||||
UnicodeString appendTo;
|
||||
RunTestFieldPositionIteratorWithNItems(
|
||||
data, 2, expected, tupleCount, appendTo,
|
||||
u"bbb and cc",
|
||||
"TestFieldPositionIteratorWith2Items");
|
||||
}
|
||||
|
||||
void ListFormatterTest::TestFieldPositionIteratorWith2ItemsPatternShift() {
|
||||
// 0 1
|
||||
// 01234567890
|
||||
// "cc bbb"
|
||||
UnicodeString data[2] = {"bbb", "cc"};
|
||||
int32_t expected[] = {
|
||||
ULISTFMT_ELEMENT_FIELD, 3, 6,
|
||||
ULISTFMT_LITERAL_FIELD, 2, 3,
|
||||
ULISTFMT_ELEMENT_FIELD, 0, 2
|
||||
};
|
||||
int32_t tupleCount = sizeof(expected)/(3 * sizeof(*expected));
|
||||
UnicodeString appendTo;
|
||||
RunTestFieldPositionIteratorWithNItemsPatternShift(
|
||||
data, 2, expected, tupleCount, appendTo,
|
||||
u"cc bbb",
|
||||
"TestFieldPositionIteratorWith2ItemsPatternShift");
|
||||
}
|
||||
|
||||
void ListFormatterTest::TestFieldPositionIteratorWith1ItemAndDataBefore() {
|
||||
// 012345678
|
||||
// "Hello cc"
|
||||
UnicodeString data[1] = {"cc"};
|
||||
int32_t expected[] = {
|
||||
ULISTFMT_ELEMENT_FIELD, 6, 8
|
||||
};
|
||||
int32_t tupleCount = sizeof(expected)/(3 * sizeof(*expected));
|
||||
UnicodeString appendTo("Hello ");
|
||||
RunTestFieldPositionIteratorWithNItems(
|
||||
data, 1, expected, tupleCount, appendTo,
|
||||
u"Hello cc",
|
||||
"TestFieldPositionIteratorWith1ItemAndDataBefore");
|
||||
}
|
||||
|
||||
void ListFormatterTest::TestFieldPositionIteratorWith1Item() {
|
||||
// 012
|
||||
// "cc"
|
||||
UnicodeString data[1] = {"cc"};
|
||||
int32_t expected[] = {
|
||||
ULISTFMT_ELEMENT_FIELD, 0, 2
|
||||
};
|
||||
int32_t tupleCount = sizeof(expected)/(3 * sizeof(*expected));
|
||||
UnicodeString appendTo;
|
||||
RunTestFieldPositionIteratorWithNItems(
|
||||
data, 1, expected, tupleCount, appendTo,
|
||||
u"cc",
|
||||
"TestFieldPositionIteratorWith1Item");
|
||||
}
|
||||
|
||||
// Tests resource loading and inheritance when region sublocale
|
||||
@ -172,7 +449,7 @@ void ListFormatterTest::TestNynorsk() {
|
||||
one + ", " + two + ", " + three + " og " + four
|
||||
};
|
||||
|
||||
CheckFourCases("nn", one, two, three, four, results);
|
||||
CheckFourCases("nn", one, two, three, four, results, "TestNynorsk()");
|
||||
}
|
||||
|
||||
// Tests resource loading and inheritance when region sublocale
|
||||
@ -188,7 +465,7 @@ void ListFormatterTest::TestChineseTradHK() {
|
||||
one + comma_string + two + comma_string + three + and_string + four
|
||||
};
|
||||
|
||||
CheckFourCases("zh_Hant_HK", one, two, three, four, results);
|
||||
CheckFourCases("zh_Hant_HK", one, two, three, four, results, "TestChineseTradHK()");
|
||||
}
|
||||
|
||||
// Formatting in Russian.
|
||||
@ -202,7 +479,7 @@ void ListFormatterTest::TestRussian() {
|
||||
one + ", " + two + ", " + three + and_string + four
|
||||
};
|
||||
|
||||
CheckFourCases("ru", one, two, three, four, results);
|
||||
CheckFourCases("ru", one, two, three, four, results, "TestRussian()");
|
||||
}
|
||||
|
||||
// Formatting in Malayalam.
|
||||
@ -219,7 +496,7 @@ void ListFormatterTest::TestMalayalam() {
|
||||
one + ", " + two + ", " + three + ", " + four + total_string
|
||||
};
|
||||
|
||||
CheckFourCases("ml", one, two, three, four, results);
|
||||
CheckFourCases("ml", one, two, three, four, results, "TestMalayalam()");
|
||||
}
|
||||
|
||||
// Formatting in Zulu.
|
||||
@ -232,7 +509,7 @@ void ListFormatterTest::TestZulu() {
|
||||
one + ", " + two + ", " + three + ", ne-" + four
|
||||
};
|
||||
|
||||
CheckFourCases("zu", one, two, three, four, results);
|
||||
CheckFourCases("zu", one, two, three, four, results, "TestZulu()");
|
||||
}
|
||||
|
||||
void ListFormatterTest::TestOutOfOrderPatterns() {
|
||||
@ -243,22 +520,22 @@ void ListFormatterTest::TestOutOfOrderPatterns() {
|
||||
four + " in the last after " + three + " after " + two + " after the first " + one
|
||||
};
|
||||
|
||||
UErrorCode errorCode = U_ZERO_ERROR;
|
||||
IcuTestErrorCode errorCode(*this, "TestOutOfOrderPatterns()");
|
||||
ListFormatData data("{1} after {0}", "{1} after the first {0}",
|
||||
"{1} after {0}", "{1} in the last after {0}");
|
||||
ListFormatter formatter(data, errorCode);
|
||||
|
||||
UnicodeString input1[] = {one};
|
||||
CheckFormatting(&formatter, input1, 1, results[0]);
|
||||
CheckFormatting(&formatter, input1, 1, results[0], "TestOutOfOrderPatterns()");
|
||||
|
||||
UnicodeString input2[] = {one, two};
|
||||
CheckFormatting(&formatter, input2, 2, results[1]);
|
||||
CheckFormatting(&formatter, input2, 2, results[1], "TestOutOfOrderPatterns()");
|
||||
|
||||
UnicodeString input3[] = {one, two, three};
|
||||
CheckFormatting(&formatter, input3, 3, results[2]);
|
||||
CheckFormatting(&formatter, input3, 3, results[2], "TestOutOfOrderPatterns()");
|
||||
|
||||
UnicodeString input4[] = {one, two, three, four};
|
||||
CheckFormatting(&formatter, input4, 4, results[3]);
|
||||
CheckFormatting(&formatter, input4, 4, results[3], "TestOutOfOrderPatterns()");
|
||||
}
|
||||
|
||||
void ListFormatterTest::runIndexedTest(int32_t index, UBool exec,
|
||||
@ -276,7 +553,33 @@ void ListFormatterTest::runIndexedTest(int32_t index, UBool exec,
|
||||
case 9: name = "TestEnglishGB"; if (exec) TestEnglishGB(); break;
|
||||
case 10: name = "TestNynorsk"; if (exec) TestNynorsk(); break;
|
||||
case 11: name = "TestChineseTradHK"; if (exec) TestChineseTradHK(); break;
|
||||
|
||||
case 12: name = "TestFieldPositionIteratorWontCrash";
|
||||
if (exec) TestFieldPositionIteratorWontCrash();
|
||||
break;
|
||||
case 13: name = "TestFieldPositionIteratorWith1Item";
|
||||
if (exec) TestFieldPositionIteratorWith1Item();
|
||||
break;
|
||||
case 14: name = "TestFieldPositionIteratorWith1ItemAndDataBefore";
|
||||
if (exec) TestFieldPositionIteratorWith1ItemAndDataBefore();
|
||||
break;
|
||||
case 15: name = "TestFieldPositionIteratorWith2Items";
|
||||
if (exec) TestFieldPositionIteratorWith2Items();
|
||||
break;
|
||||
case 16: name = "TestFieldPositionIteratorWith2ItemsAndDataBefore";
|
||||
if (exec) TestFieldPositionIteratorWith2ItemsAndDataBefore();
|
||||
break;
|
||||
case 17: name = "TestFieldPositionIteratorWith2ItemsPatternShift";
|
||||
if (exec) TestFieldPositionIteratorWith2ItemsPatternShift();
|
||||
break;
|
||||
case 18: name = "TestFieldPositionIteratorWith3Items";
|
||||
if (exec) TestFieldPositionIteratorWith3Items();
|
||||
break;
|
||||
case 19: name = "TestFieldPositionIteratorWith3ItemsAndDataBefore";
|
||||
if (exec) TestFieldPositionIteratorWith3ItemsAndDataBefore();
|
||||
break;
|
||||
case 20: name = "TestFieldPositionIteratorWith3ItemsPatternShift";
|
||||
if (exec) TestFieldPositionIteratorWith3ItemsPatternShift();
|
||||
break;
|
||||
default: name = ""; break;
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
#ifndef __LISTFORMATTERTEST_H__
|
||||
#define __LISTFORMATTERTEST_H__
|
||||
|
||||
#include "unicode/fpositer.h"
|
||||
#include "unicode/listformatter.h"
|
||||
#include "intltest.h"
|
||||
|
||||
@ -41,23 +42,68 @@ class ListFormatterTest : public IntlTest {
|
||||
void TestZulu();
|
||||
void TestOutOfOrderPatterns();
|
||||
void Test9946();
|
||||
void TestFieldPositionIteratorWontCrash();
|
||||
void TestFieldPositionIteratorWith1Item();
|
||||
void TestFieldPositionIteratorWith2Items();
|
||||
void TestFieldPositionIteratorWith3Items();
|
||||
void TestFieldPositionIteratorWith1ItemAndDataBefore();
|
||||
void TestFieldPositionIteratorWith2ItemsAndDataBefore();
|
||||
void TestFieldPositionIteratorWith3ItemsAndDataBefore();
|
||||
void TestFieldPositionIteratorWith2ItemsPatternShift();
|
||||
void TestFieldPositionIteratorWith3ItemsPatternShift();
|
||||
|
||||
private:
|
||||
void CheckFormatting(const ListFormatter* formatter, UnicodeString data[], int32_t data_size, const UnicodeString& expected_result);
|
||||
void CheckFormatting(
|
||||
const ListFormatter* formatter,
|
||||
UnicodeString data[],
|
||||
int32_t data_size,
|
||||
const UnicodeString& expected_result,
|
||||
const char* testName);
|
||||
void ExpectPositions(
|
||||
FieldPositionIterator& iter,
|
||||
int32_t *values,
|
||||
int32_t tupleCount);
|
||||
void RunTestFieldPositionIteratorWithNItems(
|
||||
UnicodeString *data,
|
||||
int32_t n,
|
||||
int32_t *values,
|
||||
int32_t tupleCount,
|
||||
UnicodeString& appendTo,
|
||||
const char16_t *expectedFormatted,
|
||||
const char* testName);
|
||||
void RunTestFieldPositionIteratorWithNItemsPatternShift(
|
||||
UnicodeString *data,
|
||||
int32_t n,
|
||||
int32_t *values,
|
||||
int32_t tupleCount,
|
||||
UnicodeString& appendTo,
|
||||
const char16_t *expectedFormatted,
|
||||
const char* testName);
|
||||
void RunTestFieldPositionIteratorWithFormatter(
|
||||
ListFormatter* formatter,
|
||||
UnicodeString *data,
|
||||
int32_t n,
|
||||
int32_t *values,
|
||||
int32_t tupleCount,
|
||||
UnicodeString& appendTo,
|
||||
const char16_t *expectedFormatted,
|
||||
const char* testName);
|
||||
void CheckFourCases(
|
||||
const char* locale_string,
|
||||
UnicodeString one,
|
||||
UnicodeString two,
|
||||
UnicodeString three,
|
||||
UnicodeString four,
|
||||
UnicodeString results[4]);
|
||||
UnicodeString results[4],
|
||||
const char* testName);
|
||||
UBool RecordFourCases(
|
||||
const Locale& locale,
|
||||
UnicodeString one,
|
||||
UnicodeString two,
|
||||
UnicodeString three,
|
||||
UnicodeString four,
|
||||
UnicodeString results[4]);
|
||||
UnicodeString results[4],
|
||||
const char* testName);
|
||||
|
||||
private:
|
||||
// Reused test data.
|
||||
|
Loading…
Reference in New Issue
Block a user