X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/4388f060552cc537e71e957d32f35e9d75a61233..ef6cf650f4a75c3f97de06b51fa104f2069b9ea2:/icuSources/test/intltest/tmsgfmt.cpp diff --git a/icuSources/test/intltest/tmsgfmt.cpp b/icuSources/test/intltest/tmsgfmt.cpp index 236313fc..df018940 100644 --- a/icuSources/test/intltest/tmsgfmt.cpp +++ b/icuSources/test/intltest/tmsgfmt.cpp @@ -1,6 +1,6 @@ /******************************************************************** * COPYRIGHT: - * Copyright (c) 1997-2011, International Business Machines Corporation and + * Copyright (c) 1997-2016, International Business Machines Corporation and * others. All Rights Reserved. ******************************************************************** * File TMSGFMT.CPP @@ -18,9 +18,11 @@ #if !UCONFIG_NO_FORMATTING #include "tmsgfmt.h" +#include "cmemory.h" #include "unicode/format.h" #include "unicode/decimfmt.h" +#include "unicode/localpointer.h" #include "unicode/locid.h" #include "unicode/msgfmt.h" #include "unicode/numfmt.h" @@ -30,8 +32,6 @@ #include "unicode/gregocal.h" #include -#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0])) - void TestMessageFormat::runIndexedTest(int32_t index, UBool exec, const char* &name, char* /*par*/) { @@ -63,7 +63,11 @@ TestMessageFormat::runIndexedTest(int32_t index, UBool exec, TESTCASE_AUTO(TestApostropheMode); TESTCASE_AUTO(TestCompatibleApostrophe); TESTCASE_AUTO(testCoverage); + TESTCASE_AUTO(testGetFormatNames); TESTCASE_AUTO(TestTrimArgumentName); + TESTCASE_AUTO(TestSelectOrdinal); + TESTCASE_AUTO(TestDecimals); + TESTCASE_AUTO(TestArgIsPrefixOfAnother); TESTCASE_AUTO_END; } @@ -277,7 +281,7 @@ void TestMessageFormat::PatternTest() "Quotes ', {, 'a' 1 {0}", "Quotes ', {, 'a' 1 {0}", "{1,number,'#',##} #34,56", - "There are 3,456 files on Disk at 1/12/70 5:46 AM.", + "There are 3,456 files on Disk at 1/12/70, 5:46 AM.", "On Disk, there are 3,456 files, with $1.00.", "{1,number,percent}, 345,600%,", "{1,date,full}, Wednesday, December 31, 1969,", @@ -442,7 +446,7 @@ void TestMessageFormat::TestTurkishCasing() } const UnicodeString expected( - "At 12:20:00 on 08.08.1997, there was a disturbance in the Force on planet 7.", ""); + "At 12:20:00 on 8.08.1997, there was a disturbance in the Force on planet 7.", ""); if (result != expected) { errln("TestTurkishCasing failed on test"); errln( UnicodeString(" Result: ") + result ); @@ -575,11 +579,11 @@ void TestMessageFormat::testMsgFormatPlural(/* char* par */) delete mfNum; delete mfAlpha; - MessageFormat* mfNum2 = new MessageFormat(t3, Locale("ru"), err); + MessageFormat* mfNum2 = new MessageFormat(t3, Locale("uk"), err); numResult1.remove(); Formattable testArgs2((int32_t)4); mfNum2->format(&testArgs2, 1, numResult1, ignore, err); - MessageFormat* mfAlpha2 = new MessageFormat(t4, Locale("ru"), err); + MessageFormat* mfAlpha2 = new MessageFormat(t4, Locale("uk"), err); argNameResult.remove(); mfAlpha2->format(argName, &testArgs2, 1, argNameResult, err); @@ -651,7 +655,7 @@ void TestMessageFormat::internalFormat(MessageFormat* msgFmt , //Format with passed arguments msgFmt->format( args , numOfArgs , result, ignore, status); if (U_FAILURE(status)) { - dataerrln( "%serror while formatting with ErrorCode as %s" ,errMsg, u_errorName(status) ); + dataerrln( "%s error while formatting with ErrorCode as %s" ,errMsg, u_errorName(status) ); } //Compare expected with obtained result if ( result!= expected ) { @@ -667,7 +671,7 @@ MessageFormat* TestMessageFormat::internalCreate( //Create the MessageFormat with simple SelectFormat MessageFormat* msgFmt = new MessageFormat(pattern, locale, status); if (U_FAILURE(status)) { - dataerrln( "%serror while constructing with ErrorCode as %s" ,errMsg, u_errorName(status) ); + dataerrln( "%s error while constructing with ErrorCode as %s" ,errMsg, u_errorName(status) ); logln(UnicodeString("TestMessageFormat::testMsgFormatSelect #1 with error code ")+(int32_t)status); return NULL; } @@ -749,6 +753,7 @@ void TestMessageFormat::testMsgFormatSelect(/* char* par */) //Nested patterns with plural, number ,choice ,select format etc. //Select Format with embedded number format UnicodeString t4("{0} est {1, select, female {{2,number,integer} all\\u00E9e} other {all\\u00E9}} \\u00E0 Paris."); + err = U_ZERO_ERROR; //Create the MessageFormat with Select Format with embedded number format (nested pattern) MessageFormat* msgFmt4 = internalCreate(t4.unescape(), Locale("fr"),err,(char*)"From TestMessageFormat::TestSelectFormat create t4"); if (!U_FAILURE(err)) { @@ -768,7 +773,6 @@ void TestMessageFormat::testMsgFormatSelect(/* char* par */) } delete msgFmt4; - err = U_ZERO_ERROR; //Plural format with embedded select format UnicodeString t5("{0} {1, plural, one {est {2, select, female {all\\u00E9e} other {all\\u00E9}}} other {sont {2, select, female {all\\u00E9es} other {all\\u00E9s}}}} \\u00E0 Paris."); err = U_ZERO_ERROR; @@ -1055,7 +1059,7 @@ void TestMessageFormat::testFormat() { Formattable( UDate(8.71068e+011), Formattable::kIsDate ) }; - const int32_t ft_cnt = sizeof(ftarray) / sizeof(Formattable); + const int32_t ft_cnt = UPRV_LENGTHOF(ftarray); Formattable ft_arr( ftarray, ft_cnt ); Formattable* fmt = new Formattable(UDate(8.71068e+011), Formattable::kIsDate); @@ -1483,7 +1487,7 @@ void TestMessageFormat::TestUnlimitedArgsAndSubformats() { Formattable("of course"), Formattable("Horace"), }; - const int32_t ARGS_LENGTH = sizeof(ARGS) / sizeof(ARGS[0]); + const int32_t ARGS_LENGTH = UPRV_LENGTHOF(ARGS); Formattable ARGS_OBJ(ARGS, ARGS_LENGTH); UnicodeString expected = @@ -1516,17 +1520,17 @@ void TestMessageFormat::TestRBNF(void) { // do not always parse, so do not include them "0", "1", "12", "100", "123", "1001", "123,456", "-17", }; - int32_t values_count = sizeof(values)/sizeof(values[0]); + int32_t values_count = UPRV_LENGTHOF(values); UnicodeString formats[] = { "There are {0,spellout} files to search.", "There are {0,spellout,%simplified} files to search.", "The bogus spellout {0,spellout,%BOGUS} files behaves like the default.", - "This is the {0,ordinal} file to search.", // TODO fix bug, ordinal does not parse + "This is the {0,ordinal} file to search.", "Searching this file will take {0,duration} to complete.", "Searching this file will take {0,duration,%with-words} to complete.", }; - int32_t formats_count = sizeof(formats)/sizeof(formats[0]); + int32_t formats_count = UPRV_LENGTHOF(formats); Formattable args[1]; @@ -1551,16 +1555,14 @@ void TestMessageFormat::TestRBNF(void) { fmt->format(args, 1, result, fp, ec); logln((UnicodeString)"value: " + toString(args[0]) + " --> " + result + UnicodeString(" ec: ") + u_errorName(ec)); - if (i != 3) { // TODO: fix this, for now skip ordinal parsing (format string at index 3) - int32_t count = 0; - Formattable* parseResult = fmt->parse(result, count, ec); - if (count != 1) { - errln((UnicodeString)"parse returned " + count + " args"); - } else if (parseResult[0] != args[0]) { - errln((UnicodeString)"parsed argument " + toString(parseResult[0]) + " != " + toString(args[0])); - } - delete []parseResult; + int32_t count = 0; + Formattable* parseResult = fmt->parse(result, count, ec); + if (count != 1) { + errln((UnicodeString)"parse returned " + count + " args"); + } else if (parseResult[0] != args[0]) { + errln((UnicodeString)"parsed argument " + toString(parseResult[0]) + " != " + toString(args[0])); } + delete []parseResult; } } delete fmt; @@ -1602,7 +1604,7 @@ void TestMessageFormat::TestApostropheMode() { "I don't know", "I don't know", "I don''t know", "I don't know", "I don''t know", "I don''t know" }; - int32_t tuples_count = LENGTHOF(tuples); + int32_t tuples_count = UPRV_LENGTHOF(tuples); for (int i = 0; i < tuples_count; i += 3) { UnicodeString& desired = tuples[i]; @@ -1699,7 +1701,7 @@ void TestMessageFormat::testAutoQuoteApostrophe(void) { "'} '{'}'", "'} '{'}''", "'} {{{''", "'} {{{'''", }; - int32_t pattern_count = sizeof(patterns)/sizeof(patterns[0]); + int32_t pattern_count = UPRV_LENGTHOF(patterns); for (int i = 0; i < pattern_count; i += 2) { UErrorCode status = U_ZERO_ERROR; @@ -1791,6 +1793,51 @@ void TestMessageFormat::testCoverage(void) { delete msgfmt; } +void TestMessageFormat::testGetFormatNames() { + IcuTestErrorCode errorCode(*this, "testGetFormatNames"); + MessageFormat msgfmt("Hello, {alice,number} {oops,date,full} {zip,spellout} World.", Locale::getRoot(), errorCode); + if(errorCode.logDataIfFailureAndReset("MessageFormat() failed")) { + return; + } + LocalPointer names(msgfmt.getFormatNames(errorCode)); + if(errorCode.logIfFailureAndReset("msgfmt.getFormatNames() failed")) { + return; + } + const UnicodeString *name; + name = names->snext(errorCode); + if (name == NULL || errorCode.isFailure()) { + errln("msgfmt.getFormatNames()[0] failed: %s", errorCode.errorName()); + errorCode.reset(); + return; + } + if (!assertEquals("msgfmt.getFormatNames()[0]", UNICODE_STRING_SIMPLE("alice"), *name)) { + return; + } + name = names->snext(errorCode); + if (name == NULL || errorCode.isFailure()) { + errln("msgfmt.getFormatNames()[1] failed: %s", errorCode.errorName()); + errorCode.reset(); + return; + } + if (!assertEquals("msgfmt.getFormatNames()[1]", UNICODE_STRING_SIMPLE("oops"), *name)) { + return; + } + name = names->snext(errorCode); + if (name == NULL || errorCode.isFailure()) { + errln("msgfmt.getFormatNames()[2] failed: %s", errorCode.errorName()); + errorCode.reset(); + return; + } + if (!assertEquals("msgfmt.getFormatNames()[2]", UNICODE_STRING_SIMPLE("zip"), *name)) { + return; + } + name = names->snext(errorCode); + if (name != NULL) { + errln(UnicodeString("msgfmt.getFormatNames()[3] should be NULL but is: ") + *name); + return; + } +} + void TestMessageFormat::TestTrimArgumentName() { // ICU 4.8 allows and ignores white space around argument names and numbers. IcuTestErrorCode errorCode(*this, "TestTrimArgumentName"); @@ -1812,4 +1859,134 @@ void TestMessageFormat::TestTrimArgumentName() { m.format(&argName, args, 1, result, errorCode)); } +void TestMessageFormat::TestSelectOrdinal() { + IcuTestErrorCode errorCode(*this, "TestSelectOrdinal"); + // Test plural & ordinal together, + // to make sure that we get the correct cached PluralSelector for each. + MessageFormat m( + "{0,plural,one{1 file}other{# files}}, " + "{0,selectordinal,one{#st file}two{#nd file}few{#rd file}other{#th file}}", + Locale::getEnglish(), errorCode); + if (errorCode.logDataIfFailureAndReset("Unable to instantiate MessageFormat")) { + return; + } + Formattable args[1] = { (int32_t)21 }; + FieldPosition ignore(0); + UnicodeString result; + assertEquals("plural-and-ordinal format(21) failed", "21 files, 21st file", + m.format(args, 1, result, ignore, errorCode), TRUE); + + args[0].setLong(2); + assertEquals("plural-and-ordinal format(2) failed", "2 files, 2nd file", + m.format(args, 1, result.remove(), ignore, errorCode), TRUE); + + args[0].setLong(1); + assertEquals("plural-and-ordinal format(1) failed", "1 file, 1st file", + m.format(args, 1, result.remove(), ignore, errorCode), TRUE); + + args[0].setLong(3); + assertEquals("plural-and-ordinal format(3) failed", "3 files, 3rd file", + m.format(args, 1, result.remove(), ignore, errorCode), TRUE); + + errorCode.logDataIfFailureAndReset(""); +} + +void TestMessageFormat::TestDecimals() { + IcuTestErrorCode errorCode(*this, "TestDecimals"); + // Simple number replacement. + MessageFormat m( + "{0,plural,one{one meter}other{# meters}}", + Locale::getEnglish(), errorCode); + Formattable args[1] = { (int32_t)1 }; + FieldPosition ignore; + UnicodeString result; + assertEquals("simple format(1)", "one meter", + m.format(args, 1, result, ignore, errorCode), TRUE); + + args[0] = (double)1.5; + result.remove(); + assertEquals("simple format(1.5)", "1.5 meters", + m.format(args, 1, result, ignore, errorCode), TRUE); + + // Simple but explicit. + MessageFormat m0( + "{0,plural,one{one meter}other{{0} meters}}", + Locale::getEnglish(), errorCode); + args[0] = (int32_t)1; + result.remove(); + assertEquals("explicit format(1)", "one meter", + m0.format(args, 1, result, ignore, errorCode), TRUE); + + args[0] = (double)1.5; + result.remove(); + assertEquals("explicit format(1.5)", "1.5 meters", + m0.format(args, 1, result, ignore, errorCode), TRUE); + + // With offset and specific simple format with optional decimals. + MessageFormat m1( + "{0,plural,offset:1 one{another meter}other{{0,number,00.#} meters}}", + Locale::getEnglish(), errorCode); + args[0] = (int32_t)1; + result.remove(); + assertEquals("offset format(1)", "01 meters", + m1.format(args, 1, result, ignore, errorCode), TRUE); + + args[0] = (int32_t)2; + result.remove(); + assertEquals("offset format(1)", "another meter", + m1.format(args, 1, result, ignore, errorCode), TRUE); + + args[0] = (double)2.5; + result.remove(); + assertEquals("offset format(1)", "02.5 meters", + m1.format(args, 1, result, ignore, errorCode), TRUE); + + // With offset and specific simple format with forced decimals. + MessageFormat m2( + "{0,plural,offset:1 one{another meter}other{{0,number,0.0} meters}}", + Locale::getEnglish(), errorCode); + args[0] = (int32_t)1; + result.remove(); + assertEquals("offset-decimals format(1)", "1.0 meters", + m2.format(args, 1, result, ignore, errorCode), TRUE); + + args[0] = (int32_t)2; + result.remove(); + assertEquals("offset-decimals format(1)", "2.0 meters", + m2.format(args, 1, result, ignore, errorCode), TRUE); + + args[0] = (double)2.5; + result.remove(); + assertEquals("offset-decimals format(1)", "2.5 meters", + m2.format(args, 1, result, ignore, errorCode), TRUE); + errorCode.reset(); +} + +void TestMessageFormat::TestArgIsPrefixOfAnother() { + IcuTestErrorCode errorCode(*this, "TestArgIsPrefixOfAnother"); + // Ticket #11952 + MessageFormat mf1("{0,select,a{A}ab{AB}abc{ABC}other{?}}", Locale::getEnglish(), errorCode); + Formattable args[3]; + FieldPosition ignore; + UnicodeString result; + args[0].setString("a"); + assertEquals("a", "A", mf1.format(args, 1, result, ignore, errorCode)); + args[0].setString("ab"); + assertEquals("ab", "AB", mf1.format(args, 1, result.remove(), ignore, errorCode)); + args[0].setString("abc"); + assertEquals("abc", "ABC", mf1.format(args, 1, result.remove(), ignore, errorCode)); + + // Ticket #12172 + MessageFormat mf2("{a} {aa} {aaa}", Locale::getEnglish(), errorCode); + UnicodeString argNames[3] = { "a", "aa", "aaa" }; + args[0].setString("A"); + args[1].setString("AB"); + args[2].setString("ABC"); + assertEquals("a aa aaa", "A AB ABC", mf2.format(argNames, args, 3, result.remove(), errorCode)); + + // Ticket #12172 + MessageFormat mf3("{aa} {aaa}", Locale::getEnglish(), errorCode); + assertEquals("aa aaa", "AB ABC", mf3.format(argNames + 1, args + 1, 2, result.remove(), errorCode)); +} + #endif /* #if !UCONFIG_NO_FORMATTING */