1 // Copyright (C) 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /********************************************************************
4 * COPYRIGHT:
5 * Copyright (c) 1997-2016, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 ********************************************************************
8 * File TMSGFMT.CPP
9 *
10 * Modification History:
11 *
12 * Date Name Description
13 * 03/24/97 helena Converted from Java.
14 * 07/11/97 helena Updated to work on AIX.
15 * 08/04/97 jfitz Updated to intltest
16 *******************************************************************/
17
18 #include "unicode/utypes.h"
19
20 #if !UCONFIG_NO_FORMATTING
21
22 #include "tmsgfmt.h"
23 #include "cmemory.h"
24
25 #include "unicode/format.h"
26 #include "unicode/decimfmt.h"
27 #include "unicode/localpointer.h"
28 #include "unicode/locid.h"
29 #include "unicode/msgfmt.h"
30 #include "unicode/numfmt.h"
31 #include "unicode/choicfmt.h"
32 #include "unicode/messagepattern.h"
33 #include "unicode/selfmt.h"
34 #include "unicode/gregocal.h"
35 #include <stdio.h>
36
37 void
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)38 TestMessageFormat::runIndexedTest(int32_t index, UBool exec,
39 const char* &name, char* /*par*/) {
40 TESTCASE_AUTO_BEGIN;
41 TESTCASE_AUTO(testBug1);
42 TESTCASE_AUTO(testBug2);
43 TESTCASE_AUTO(sample);
44 TESTCASE_AUTO(PatternTest);
45 TESTCASE_AUTO(testStaticFormat);
46 TESTCASE_AUTO(testSimpleFormat);
47 TESTCASE_AUTO(testMsgFormatChoice);
48 TESTCASE_AUTO(testCopyConstructor);
49 TESTCASE_AUTO(testAssignment);
50 TESTCASE_AUTO(testClone);
51 TESTCASE_AUTO(testEquals);
52 TESTCASE_AUTO(testNotEquals);
53 TESTCASE_AUTO(testSetLocale);
54 TESTCASE_AUTO(testFormat);
55 TESTCASE_AUTO(testParse);
56 TESTCASE_AUTO(testAdopt);
57 TESTCASE_AUTO(testCopyConstructor2);
58 TESTCASE_AUTO(TestUnlimitedArgsAndSubformats);
59 TESTCASE_AUTO(TestRBNF);
60 TESTCASE_AUTO(TestTurkishCasing);
61 TESTCASE_AUTO(testAutoQuoteApostrophe);
62 TESTCASE_AUTO(testMsgFormatPlural);
63 TESTCASE_AUTO(testMsgFormatSelect);
64 TESTCASE_AUTO(testApostropheInPluralAndSelect);
65 TESTCASE_AUTO(TestApostropheMode);
66 TESTCASE_AUTO(TestCompatibleApostrophe);
67 TESTCASE_AUTO(testCoverage);
68 TESTCASE_AUTO(testGetFormatNames);
69 TESTCASE_AUTO(TestTrimArgumentName);
70 TESTCASE_AUTO(TestSelectOrdinal);
71 TESTCASE_AUTO(TestDecimals);
72 TESTCASE_AUTO(TestArgIsPrefixOfAnother);
73 TESTCASE_AUTO_END;
74 }
75
testBug3()76 void TestMessageFormat::testBug3()
77 {
78 double myNumber = -123456;
79 DecimalFormat *form = 0;
80 Locale locale[] = {
81 Locale("ar", "", ""),
82 Locale("be", "", ""),
83 Locale("bg", "", ""),
84 Locale("ca", "", ""),
85 Locale("cs", "", ""),
86 Locale("da", "", ""),
87 Locale("de", "", ""),
88 Locale("de", "AT", ""),
89 Locale("de", "CH", ""),
90 Locale("el", "", ""), // 10
91 Locale("en", "CA", ""),
92 Locale("en", "GB", ""),
93 Locale("en", "IE", ""),
94 Locale("en", "US", ""),
95 Locale("es", "", ""),
96 Locale("et", "", ""),
97 Locale("fi", "", ""),
98 Locale("fr", "", ""),
99 Locale("fr", "BE", ""),
100 Locale("fr", "CA", ""), // 20
101 Locale("fr", "CH", ""),
102 Locale("he", "", ""),
103 Locale("hr", "", ""),
104 Locale("hu", "", ""),
105 Locale("is", "", ""),
106 Locale("it", "", ""),
107 Locale("it", "CH", ""),
108 Locale("ja", "", ""),
109 Locale("ko", "", ""),
110 Locale("lt", "", ""), // 30
111 Locale("lv", "", ""),
112 Locale("mk", "", ""),
113 Locale("nl", "", ""),
114 Locale("nl", "BE", ""),
115 Locale("no", "", ""),
116 Locale("pl", "", ""),
117 Locale("pt", "", ""),
118 Locale("ro", "", ""),
119 Locale("ru", "", ""),
120 Locale("sh", "", ""), // 40
121 Locale("sk", "", ""),
122 Locale("sl", "", ""),
123 Locale("sq", "", ""),
124 Locale("sr", "", ""),
125 Locale("sv", "", ""),
126 Locale("tr", "", ""),
127 Locale("uk", "", ""),
128 Locale("zh", "", ""),
129 Locale("zh", "TW", "") // 49
130 };
131 int32_t i;
132 for (i= 0; i < 49; i++) {
133 UnicodeString buffer;
134 logln(locale[i].getDisplayName(buffer));
135 UErrorCode success = U_ZERO_ERROR;
136 // form = (DecimalFormat*)NumberFormat::createCurrencyInstance(locale[i], success);
137 form = (DecimalFormat*)NumberFormat::createInstance(locale[i], success);
138 if (U_FAILURE(success)) {
139 errln("Err: Number Format ");
140 logln("Number format creation failed.");
141 continue;
142 }
143 Formattable result;
144 FieldPosition pos(FieldPosition::DONT_CARE);
145 buffer.remove();
146 form->format(myNumber, buffer, pos);
147 success = U_ZERO_ERROR;
148 ParsePosition parsePos;
149 form->parse(buffer, result, parsePos);
150 logln(UnicodeString(" -> ") /* + << dec*/ + toString(result) + UnicodeString("[supposed output for result]"));
151 if (U_FAILURE(success)) {
152 errln("Err: Number Format parse");
153 logln("Number format parse failed.");
154 }
155 delete form;
156 }
157 }
158
testBug1()159 void TestMessageFormat::testBug1()
160 {
161 const double limit[] = {0.0, 1.0, 2.0};
162 const UnicodeString formats[] = {"0.0<=Arg<1.0",
163 "1.0<=Arg<2.0",
164 "2.0<-Arg"};
165 ChoiceFormat *cf = new ChoiceFormat(limit, formats, 3);
166 FieldPosition status(FieldPosition::DONT_CARE);
167 UnicodeString toAppendTo;
168 cf->format((int32_t)1, toAppendTo, status);
169 if (toAppendTo != "1.0<=Arg<2.0") {
170 errln("ChoiceFormat cmp in testBug1");
171 }
172 logln(toAppendTo);
173 delete cf;
174 }
175
testBug2()176 void TestMessageFormat::testBug2()
177 {
178 UErrorCode status = U_ZERO_ERROR;
179 UnicodeString result;
180 // {sfb} use double format in pattern, so result will match (not strictly necessary)
181 const UnicodeString pattern = "There {0,choice,0#are no files|1#is one file|1<are {0, number} files} on disk {1}. ";
182 logln("The input pattern : " + pattern);
183 MessageFormat *fmt = new MessageFormat(pattern, status);
184 if (U_FAILURE(status)) {
185 dataerrln("MessageFormat pattern creation failed. - %s", u_errorName(status));
186 return;
187 }
188 logln("The output pattern is : " + fmt->toPattern(result));
189 if (pattern != result) {
190 errln("MessageFormat::toPattern() failed.");
191 }
192 delete fmt;
193 }
194
195 #if 0
196 #if defined(_DEBUG) && U_IOSTREAM_SOURCE >= 199711
197 //----------------------------------------------------
198 // console I/O
199 //----------------------------------------------------
200
201 #include <iostream>
202 std::ostream& operator<<(std::ostream& stream, const Formattable& obj);
203
204 #include "unicode/datefmt.h"
205 #include <stdlib.h>
206 #include <string.h>
207
208 IntlTest&
209 operator<<( IntlTest& stream,
210 const Formattable& obj)
211 {
212 static DateFormat *defDateFormat = 0;
213
214 UnicodeString buffer;
215 switch(obj.getType()) {
216 case Formattable::kDate :
217 if (defDateFormat == 0) {
218 defDateFormat = DateFormat::createInstance();
219 }
220 defDateFormat->format(obj.getDate(), buffer);
221 stream << buffer;
222 break;
223 case Formattable::kDouble :
224 char convert[20];
225 sprintf( convert, "%lf", obj.getDouble() );
226 stream << convert << "D";
227 break;
228 case Formattable::kLong :
229 stream << obj.getLong() << "L";
230 break;
231 case Formattable::kString:
232 stream << "\"" << obj.getString(buffer) << "\"";
233 break;
234 case Formattable::kArray:
235 int32_t i, count;
236 const Formattable* array;
237 array = obj.getArray(count);
238 stream << "[";
239 for (i=0; i<count; ++i) stream << array[i] << ( (i==(count-1)) ? "" : ", " );
240 stream << "]";
241 break;
242 default:
243 stream << "INVALID_Formattable";
244 }
245 return stream;
246 }
247 #endif /* defined(_DEBUG) && U_IOSTREAM_SOURCE >= 199711 */
248 #endif
249
PatternTest()250 void TestMessageFormat::PatternTest()
251 {
252 Formattable testArgs[] = {
253 Formattable(double(1)), Formattable(double(3456)),
254 Formattable("Disk"), Formattable(UDate((int32_t)1000000000L), Formattable::kIsDate)
255 };
256 UnicodeString testCases[] = {
257 "Quotes '', '{', 'a' {0} '{0}'",
258 "Quotes '', '{', 'a' {0,number} '{0}'",
259 "'{'1,number,'#',##} {1,number,'#',##}",
260 "There are {1} files on {2} at {3}.",
261 "On {2}, there are {1} files, with {0,number,currency}.",
262 "'{1,number,percent}', {1,number,percent},",
263 "'{1,date,full}', {1,date,full},",
264 "'{3,date,full}', {3,date,full},",
265 "'{1,number,#,##}' {1,number,#,##}",
266 };
267
268 // ICU 4.8 returns the original pattern (testCases),
269 // rather than toPattern() reconstituting a new, equivalent pattern string (testResultPatterns).
270 /*UnicodeString testResultPatterns[] = {
271 "Quotes '', '{', a {0} '{'0}",
272 "Quotes '', '{', a {0,number} '{'0}",
273 "'{'1,number,#,##} {1,number,'#'#,##}",
274 "There are {1} files on {2} at {3}.",
275 "On {2}, there are {1} files, with {0,number,currency}.",
276 "'{'1,number,percent}, {1,number,percent},",
277 "'{'1,date,full}, {1,date,full},",
278 "'{'3,date,full}, {3,date,full},",
279 "'{'1,number,#,##} {1,number,#,##}"
280 };*/
281
282 UnicodeString testResultStrings[] = {
283 "Quotes ', {, 'a' 1 {0}",
284 "Quotes ', {, 'a' 1 {0}",
285 "{1,number,'#',##} #34,56",
286 "There are 3,456 files on Disk at 1/12/70, 5:46 AM.",
287 "On Disk, there are 3,456 files, with $1.00.",
288 "{1,number,percent}, 345,600%,",
289 "{1,date,full}, Wednesday, December 31, 1969,",
290 "{3,date,full}, Monday, January 12, 1970,",
291 "{1,number,#,##} 34,56"
292 };
293
294
295 for (int32_t i = 0; i < 9; ++i) {
296 //it_out << "\nPat in: " << testCases[i]);
297
298 MessageFormat *form = 0;
299 UErrorCode success = U_ZERO_ERROR;
300 UnicodeString buffer;
301 form = new MessageFormat(testCases[i], Locale::getUS(), success);
302 if (U_FAILURE(success)) {
303 dataerrln("MessageFormat creation failed.#1 - %s", u_errorName(success));
304 logln(((UnicodeString)"MessageFormat for ") + testCases[i] + " creation failed.\n");
305 continue;
306 }
307 // ICU 4.8 returns the original pattern (testCases),
308 // rather than toPattern() reconstituting a new, equivalent pattern string (testResultPatterns).
309 if (form->toPattern(buffer) != testCases[i]) {
310 // Note: An alternative test would be to build MessagePattern objects for
311 // both the input and output patterns and compare them, taking SKIP_SYNTAX etc.
312 // into account.
313 // (Too much trouble...)
314 errln(UnicodeString("TestMessageFormat::PatternTest failed test #2, i = ") + i);
315 //form->toPattern(buffer);
316 errln(((UnicodeString)" Orig: ") + testCases[i]);
317 errln(((UnicodeString)" Exp: ") + testCases[i]);
318 errln(((UnicodeString)" Got: ") + buffer);
319 }
320
321 //it_out << "Pat out: " << form->toPattern(buffer));
322 UnicodeString result;
323 int32_t count = 4;
324 FieldPosition fieldpos(FieldPosition::DONT_CARE);
325 form->format(testArgs, count, result, fieldpos, success);
326 if (U_FAILURE(success)) {
327 dataerrln("MessageFormat failed test #3 - %s", u_errorName(success));
328 logln("TestMessageFormat::PatternTest failed test #3");
329 continue;
330 }
331 if (result != testResultStrings[i]) {
332 errln("TestMessageFormat::PatternTest failed test #4");
333 logln("TestMessageFormat::PatternTest failed #4.");
334 logln(UnicodeString(" Result: ") + result );
335 logln(UnicodeString(" Expected: ") + testResultStrings[i] );
336 }
337
338
339 //it_out << "Result: " << result);
340 #if 0
341 /* TODO: Look at this test and see if this is still a valid test */
342 logln("---------------- test parse ----------------");
343
344 form->toPattern(buffer);
345 logln("MSG pattern for parse: " + buffer);
346
347 int32_t parseCount = 0;
348 Formattable* values = form->parse(result, parseCount, success);
349 if (U_FAILURE(success)) {
350 errln("MessageFormat failed test #5");
351 logln(UnicodeString("MessageFormat failed test #5 with error code ")+(int32_t)success);
352 } else if (parseCount != count) {
353 errln("MSG count not %d as expected. Got %d", count, parseCount);
354 }
355 UBool failed = FALSE;
356 for (int32_t j = 0; j < parseCount; ++j) {
357 if (values == 0 || testArgs[j] != values[j]) {
358 errln(((UnicodeString)"MSG testargs[") + j + "]: " + toString(testArgs[j]));
359 errln(((UnicodeString)"MSG values[") + j + "] : " + toString(values[j]));
360 failed = TRUE;
361 }
362 }
363 if (failed)
364 errln("MessageFormat failed test #6");
365 #endif
366 delete form;
367 }
368 }
369
sample()370 void TestMessageFormat::sample()
371 {
372 MessageFormat *form = 0;
373 UnicodeString buffer1, buffer2;
374 UErrorCode success = U_ZERO_ERROR;
375 form = new MessageFormat("There are {0} files on {1}", success);
376 if (U_FAILURE(success)) {
377 errln("Err: Message format creation failed");
378 logln("Sample message format creation failed.");
379 return;
380 }
381 UnicodeString abc("abc");
382 UnicodeString def("def");
383 Formattable testArgs1[] = { abc, def };
384 FieldPosition fieldpos(FieldPosition::DONT_CARE);
385 assertEquals("format",
386 "There are abc files on def",
387 form->format(testArgs1, 2, buffer2, fieldpos, success));
388 assertSuccess("format", success);
389 delete form;
390 }
391
testStaticFormat()392 void TestMessageFormat::testStaticFormat()
393 {
394 UErrorCode err = U_ZERO_ERROR;
395 Formattable arguments[] = {
396 (int32_t)7,
397 Formattable(UDate(8.71068e+011), Formattable::kIsDate),
398 "a disturbance in the Force"
399 };
400
401 UnicodeString result;
402 result = MessageFormat::format(
403 "At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.",
404 arguments,
405 3,
406 result,
407 err);
408
409 if (U_FAILURE(err)) {
410 dataerrln("TestMessageFormat::testStaticFormat #1 - %s", u_errorName(err));
411 logln(UnicodeString("TestMessageFormat::testStaticFormat failed test #1 with error code ")+(int32_t)err);
412 return;
413 }
414
415 const UnicodeString expected(
416 "At 12:20:00 PM on Aug 8, 1997, there was a disturbance in the Force on planet 7.", "");
417 if (result != expected) {
418 errln("TestMessageFormat::testStaticFormat failed on test");
419 logln( UnicodeString(" Result: ") + result );
420 logln( UnicodeString(" Expected: ") + expected );
421 }
422 }
423
424 /* When the default locale is tr, make sure that the pattern can still be parsed. */
TestTurkishCasing()425 void TestMessageFormat::TestTurkishCasing()
426 {
427 UErrorCode err = U_ZERO_ERROR;
428 Locale saveDefaultLocale;
429 Locale::setDefault( Locale("tr"), err );
430
431 Formattable arguments[] = {
432 (int32_t)7,
433 Formattable(UDate(8.71068e+011), Formattable::kIsDate),
434 "a disturbance in the Force"
435 };
436
437 UnicodeString result;
438 result = MessageFormat::format(
439 "At {1,TIME} on {1,DATE,SHORT}, there was {2} on planet {0,NUMBER,INTEGER}.",
440 arguments,
441 3,
442 result,
443 err);
444
445 if (U_FAILURE(err)) {
446 dataerrln("TestTurkishCasing #1 with error code %s", u_errorName(err));
447 return;
448 }
449
450 const UnicodeString expected(
451 "At 12:20:00 on 8.08.1997, there was a disturbance in the Force on planet 7.", "");
452 if (result != expected) {
453 errln("TestTurkishCasing failed on test");
454 errln( UnicodeString(" Result: ") + result );
455 errln( UnicodeString(" Expected: ") + expected );
456 }
457 Locale::setDefault( saveDefaultLocale, err );
458 }
459
testSimpleFormat()460 void TestMessageFormat::testSimpleFormat(/* char* par */)
461 {
462 logln("running TestMessageFormat::testSimpleFormat");
463
464 UErrorCode err = U_ZERO_ERROR;
465
466 Formattable testArgs1[] = {(int32_t)0, "MyDisk"};
467 Formattable testArgs2[] = {(int32_t)1, "MyDisk"};
468 Formattable testArgs3[] = {(int32_t)12, "MyDisk"};
469
470 MessageFormat* form = new MessageFormat(
471 "The disk \"{1}\" contains {0} file(s).", err);
472
473 UnicodeString string;
474 FieldPosition ignore(FieldPosition::DONT_CARE);
475 form->format(testArgs1, 2, string, ignore, err);
476 if (U_FAILURE(err) || string != "The disk \"MyDisk\" contains 0 file(s).") {
477 dataerrln(UnicodeString("TestMessageFormat::testSimpleFormat failed on test #1 - ") + u_errorName(err));
478 }
479
480 ignore.setField(FieldPosition::DONT_CARE);
481 string.remove();
482 form->format(testArgs2, 2, string, ignore, err);
483 if (U_FAILURE(err) || string != "The disk \"MyDisk\" contains 1 file(s).") {
484 logln(string);
485 dataerrln(UnicodeString("TestMessageFormat::testSimpleFormat failed on test #2")+string + " - " + u_errorName(err));
486 }
487
488 ignore.setField(FieldPosition::DONT_CARE);
489 string.remove();
490 form->format(testArgs3, 2, string, ignore, err);
491 if (U_FAILURE(err) || string != "The disk \"MyDisk\" contains 12 file(s).") {
492 dataerrln(UnicodeString("TestMessageFormat::testSimpleFormat failed on test #3")+string + " - " + u_errorName(err));
493 }
494
495 delete form;
496 }
497
testMsgFormatChoice()498 void TestMessageFormat::testMsgFormatChoice(/* char* par */)
499 {
500 logln("running TestMessageFormat::testMsgFormatChoice");
501
502 UErrorCode err = U_ZERO_ERROR;
503
504 MessageFormat* form = new MessageFormat("The disk \"{1}\" contains {0}.", err);
505 double filelimits[] = {0,1,2};
506 UnicodeString filepart[] = {"no files","one file","{0,number} files"};
507 ChoiceFormat* fileform = new ChoiceFormat(filelimits, filepart, 3);
508 form->setFormat(1,*fileform); // NOT zero, see below
509 //is the format adopted?
510
511 FieldPosition ignore(FieldPosition::DONT_CARE);
512 UnicodeString string;
513 Formattable testArgs1[] = {(int32_t)0, "MyDisk"};
514 form->format(testArgs1, 2, string, ignore, err);
515 if (string != "The disk \"MyDisk\" contains no files.") {
516 errln("TestMessageFormat::testMsgFormatChoice failed on test #1");
517 }
518
519 ignore.setField(FieldPosition::DONT_CARE);
520 string.remove();
521 Formattable testArgs2[] = {(int32_t)1, "MyDisk"};
522 form->format(testArgs2, 2, string, ignore, err);
523 if (string != "The disk \"MyDisk\" contains one file.") {
524 errln("TestMessageFormat::testMsgFormatChoice failed on test #2");
525 }
526
527 ignore.setField(FieldPosition::DONT_CARE);
528 string.remove();
529 Formattable testArgs3[] = {(int32_t)1273, "MyDisk"};
530 form->format(testArgs3, 2, string, ignore, err);
531 if (string != "The disk \"MyDisk\" contains 1,273 files.") {
532 dataerrln("TestMessageFormat::testMsgFormatChoice failed on test #3 - %s", u_errorName(err));
533 }
534
535 delete form;
536 delete fileform;
537 }
538
539
testMsgFormatPlural()540 void TestMessageFormat::testMsgFormatPlural(/* char* par */)
541 {
542 logln("running TestMessageFormat::testMsgFormatPlural");
543
544 UErrorCode err = U_ZERO_ERROR;
545 UnicodeString t1("{0, plural, one{C''est # fichier} other{Ce sont # fichiers}} dans la liste.");
546 UnicodeString t2("{argument, plural, one{C''est # fichier} other {Ce sont # fichiers}} dans la liste.");
547 UnicodeString t3("There {0, plural, one{is # zavod}few{are {0, number,###.0} zavoda} other{are # zavodov}} in the directory.");
548 UnicodeString t4("There {argument, plural, one{is # zavod}few{are {argument, number,###.0} zavoda} other{are #zavodov}} in the directory.");
549 UnicodeString t5("{0, plural, one {{0, number,C''est #,##0.0# fichier}} other {Ce sont # fichiers}} dans la liste.");
550 MessageFormat* mfNum = new MessageFormat(t1, Locale("fr"), err);
551 if (U_FAILURE(err)) {
552 dataerrln("TestMessageFormat::testMsgFormatPlural #1 - argumentIndex - %s", u_errorName(err));
553 logln(UnicodeString("TestMessageFormat::testMsgFormatPlural #1 with error code ")+(int32_t)err);
554 return;
555 }
556 Formattable testArgs1((int32_t)0);
557 FieldPosition ignore(FieldPosition::DONT_CARE);
558 UnicodeString numResult1;
559 mfNum->format(&testArgs1, 1, numResult1, ignore, err);
560
561 MessageFormat* mfAlpha = new MessageFormat(t2, Locale("fr"), err);
562 UnicodeString argName[] = {UnicodeString("argument")};
563 UnicodeString argNameResult;
564 mfAlpha->format(argName, &testArgs1, 1, argNameResult, err);
565 if (U_FAILURE(err)) {
566 dataerrln("TestMessageFormat::testMsgFormatPlural #1 - argumentName - %s", u_errorName(err));
567 logln(UnicodeString("TestMessageFormat::testMsgFormatPlural #1 with error code ")+(int32_t)err);
568 delete mfNum;
569 return;
570 }
571 if ( numResult1 != argNameResult){
572 errln("TestMessageFormat::testMsgFormatPlural #1");
573 logln(UnicodeString("The results of argumentName and argumentIndex are not the same."));
574 }
575 if ( numResult1 != UnicodeString("C\'est 0 fichier dans la liste.")) {
576 errln("TestMessageFormat::testMsgFormatPlural #1");
577 logln(UnicodeString("The results of argumentName and argumentIndex are not the same."));
578 }
579 err = U_ZERO_ERROR;
580
581 delete mfNum;
582 delete mfAlpha;
583
584 MessageFormat* mfNum2 = new MessageFormat(t3, Locale("uk"), err);
585 numResult1.remove();
586 Formattable testArgs2((int32_t)4);
587 mfNum2->format(&testArgs2, 1, numResult1, ignore, err);
588 MessageFormat* mfAlpha2 = new MessageFormat(t4, Locale("uk"), err);
589 argNameResult.remove();
590 mfAlpha2->format(argName, &testArgs2, 1, argNameResult, err);
591
592 if (U_FAILURE(err)) {
593 errln("TestMessageFormat::testMsgFormatPlural #2 - argumentName");
594 logln(UnicodeString("TestMessageFormat::testMsgFormatPlural #2 with error code ")+(int32_t)err);
595 delete mfNum2;
596 return;
597 }
598 if ( numResult1 != argNameResult){
599 errln("TestMessageFormat::testMsgFormatPlural #2");
600 logln(UnicodeString("The results of argumentName and argumentIndex are not the same."));
601 }
602 if ( numResult1 != UnicodeString("There are 4,0 zavoda in the directory.")) {
603 errln("TestMessageFormat::testMsgFormatPlural #2");
604 logln(UnicodeString("The results of argumentName and argumentIndex are not the same."));
605 }
606
607 delete mfNum2;
608 delete mfAlpha2;
609
610 // nested formats
611 err = U_ZERO_ERROR;
612 MessageFormat* msgFmt = new MessageFormat(t5, Locale("fr"), err);
613 if (U_FAILURE(err)) {
614 errln("TestMessageFormat::test nested PluralFormat with argumentName");
615 logln(UnicodeString("TestMessageFormat::test nested PluralFormat with error code ")+(int32_t)err);
616 delete msgFmt;
617 return;
618 }
619 Formattable testArgs3((int32_t)0);
620 argNameResult.remove();
621 msgFmt->format(&testArgs3, 1, argNameResult, ignore, err);
622 if (U_FAILURE(err)) {
623 errln("TestMessageFormat::test nested PluralFormat with argumentName");
624 }
625 if ( argNameResult!= UnicodeString("C'est 0,0 fichier dans la liste.")) {
626 errln(UnicodeString("TestMessageFormat::test nested named PluralFormat: ") + argNameResult);
627 logln(UnicodeString("The unexpected nested named PluralFormat."));
628 }
629 delete msgFmt;
630 }
631
testApostropheInPluralAndSelect()632 void TestMessageFormat::testApostropheInPluralAndSelect() {
633 UErrorCode errorCode = U_ZERO_ERROR;
634 MessageFormat msgFmt(UNICODE_STRING_SIMPLE(
635 "abc_{0,plural,other{#'#'#'{'#''}}_def_{1,select,other{sel'}'ect''}}_xyz"),
636 Locale::getEnglish(),
637 errorCode);
638 if (U_FAILURE(errorCode)) {
639 errln("MessageFormat constructor failed - %s\n", u_errorName(errorCode));
640 return;
641 }
642 UnicodeString expected = UNICODE_STRING_SIMPLE("abc_3#3{3'_def_sel}ect'_xyz");
643 Formattable args[] = { (int32_t)3, UNICODE_STRING_SIMPLE("x") };
644 internalFormat(
645 &msgFmt, args, 2, expected,
646 "MessageFormat with apostrophes in plural/select arguments failed:\n");
647 }
648
internalFormat(MessageFormat * msgFmt,Formattable * args,int32_t numOfArgs,UnicodeString expected,const char * errMsg)649 void TestMessageFormat::internalFormat(MessageFormat* msgFmt ,
650 Formattable* args , int32_t numOfArgs ,
651 UnicodeString expected, const char* errMsg)
652 {
653 UnicodeString result;
654 FieldPosition ignore(FieldPosition::DONT_CARE);
655 UErrorCode status = U_ZERO_ERROR;
656
657 //Format with passed arguments
658 msgFmt->format( args , numOfArgs , result, ignore, status);
659 if (U_FAILURE(status)) {
660 dataerrln( "%s error while formatting with ErrorCode as %s" ,errMsg, u_errorName(status) );
661 }
662 //Compare expected with obtained result
663 if ( result!= expected ) {
664 UnicodeString err = UnicodeString(errMsg);
665 err+= UnicodeString(":Unexpected Result \n Expected: " + expected + "\n Obtained: " + result + "\n");
666 dataerrln(err);
667 }
668 }
669
internalCreate(UnicodeString pattern,Locale locale,UErrorCode & status,char * errMsg)670 MessageFormat* TestMessageFormat::internalCreate(
671 UnicodeString pattern ,Locale locale ,UErrorCode &status , char* errMsg)
672 {
673 //Create the MessageFormat with simple SelectFormat
674 MessageFormat* msgFmt = new MessageFormat(pattern, locale, status);
675 if (U_FAILURE(status)) {
676 dataerrln( "%s error while constructing with ErrorCode as %s" ,errMsg, u_errorName(status) );
677 logln(UnicodeString("TestMessageFormat::testMsgFormatSelect #1 with error code ")+(int32_t)status);
678 return NULL;
679 }
680 return msgFmt;
681 }
682
testMsgFormatSelect()683 void TestMessageFormat::testMsgFormatSelect(/* char* par */)
684 {
685 logln("running TestMessageFormat::testMsgFormatSelect");
686
687 UErrorCode err = U_ZERO_ERROR;
688 //French Pattern
689 UnicodeString t1("{0} est {1, select, female {all\\u00E9e} other {all\\u00E9}} \\u00E0 Paris.");
690
691 err = U_ZERO_ERROR;
692 //Create the MessageFormat with simple French pattern
693 MessageFormat* msgFmt1 = internalCreate(t1.unescape(), Locale("fr"),err,(char*)"From TestMessageFormat::TestSelectFormat create t1");
694 if (!U_FAILURE(err)) {
695 //Arguments
696 Formattable testArgs10[] = {"Kirti","female"};
697 Formattable testArgs11[] = {"Victor","other"};
698 Formattable testArgs12[] = {"Ash","unknown"};
699 Formattable* testArgs[] = {testArgs10,testArgs11,testArgs12};
700 UnicodeString exp[] = {
701 "Kirti est all\\u00E9e \\u00E0 Paris." ,
702 "Victor est all\\u00E9 \\u00E0 Paris.",
703 "Ash est all\\u00E9 \\u00E0 Paris."};
704 //Format
705 for( int i=0; i< 3; i++){
706 internalFormat( msgFmt1 , testArgs[i], 2, exp[i].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t1");
707 }
708 }
709 delete msgFmt1;
710
711 //Quoted French Pattern
712 UnicodeString t2("{0} est {1, select, female {all\\u00E9e c''est} other {all\\u00E9 c''est}} \\u00E0 Paris.");
713 err = U_ZERO_ERROR;
714 //Create the MessageFormat with Quoted French pattern
715 MessageFormat* msgFmt2 = internalCreate(t2.unescape(), Locale("fr"),err,(char*)"From TestMessageFormat::TestSelectFormat create t2");
716 if (!U_FAILURE(err)) {
717 //Arguments
718 Formattable testArgs10[] = {"Kirti","female"};
719 Formattable testArgs11[] = {"Victor","other"};
720 Formattable testArgs12[] = {"Ash","male"};
721 Formattable* testArgs[] = {testArgs10,testArgs11,testArgs12};
722 UnicodeString exp[] = {
723 "Kirti est all\\u00E9e c'est \\u00E0 Paris." ,
724 "Victor est all\\u00E9 c'est \\u00E0 Paris.",
725 "Ash est all\\u00E9 c'est \\u00E0 Paris."};
726 //Format
727 for( int i=0; i< 3; i++){
728 internalFormat( msgFmt2 , testArgs[i], 2, exp[i].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t2");
729 }
730 }
731 delete msgFmt2;
732
733 //English Pattern
734 UnicodeString t3("{0, select , male {MALE FR company} female {FEMALE FR company} other {FR otherValue}} published new books.");
735 err = U_ZERO_ERROR;
736 //Create the MessageFormat with English pattern
737 MessageFormat* msgFmt3 = internalCreate(t3, Locale("en"),err,(char*)"From TestMessageFormat::TestSelectFormat create t3");
738 if (!U_FAILURE(err)) {
739 //Arguments
740 Formattable testArgs10[] = {"female"};
741 Formattable testArgs11[] = {"other"};
742 Formattable testArgs12[] = {"male"};
743 Formattable* testArgs[] = {testArgs10,testArgs11,testArgs12};
744 UnicodeString exp[] = {
745 "FEMALE FR company published new books." ,
746 "FR otherValue published new books.",
747 "MALE FR company published new books."};
748 //Format
749 for( int i=0; i< 3; i++){
750 internalFormat( msgFmt3 , testArgs[i], 1, exp[i] ,(char*)"From TestMessageFormat::testSelectFormat format t3");
751 }
752 }
753 delete msgFmt3;
754
755 //Nested patterns with plural, number ,choice ,select format etc.
756 //Select Format with embedded number format
757 UnicodeString t4("{0} est {1, select, female {{2,number,integer} all\\u00E9e} other {all\\u00E9}} \\u00E0 Paris.");
758 err = U_ZERO_ERROR;
759 //Create the MessageFormat with Select Format with embedded number format (nested pattern)
760 MessageFormat* msgFmt4 = internalCreate(t4.unescape(), Locale("fr"),err,(char*)"From TestMessageFormat::TestSelectFormat create t4");
761 if (!U_FAILURE(err)) {
762 //Arguments
763 Formattable testArgs10[] = {"Kirti","female",(int32_t)6};
764 Formattable testArgs11[] = {"Kirti","female",100.100};
765 Formattable testArgs12[] = {"Kirti","other",(int32_t)6};
766 Formattable* testArgs[] = {testArgs10,testArgs11,testArgs12};
767 UnicodeString exp[] = {
768 "Kirti est 6 all\\u00E9e \\u00E0 Paris." ,
769 "Kirti est 100 all\\u00E9e \\u00E0 Paris.",
770 "Kirti est all\\u00E9 \\u00E0 Paris."};
771 //Format
772 for( int i=0; i< 3; i++){
773 internalFormat( msgFmt4 , testArgs[i], 3, exp[i].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t4");
774 }
775 }
776 delete msgFmt4;
777
778 //Plural format with embedded select format
779 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.");
780 err = U_ZERO_ERROR;
781 //Create the MessageFormat with Plural format with embedded select format(nested pattern)
782 MessageFormat* msgFmt5 = internalCreate(t5.unescape(), Locale("fr"),err,(char*)"From TestMessageFormat::TestSelectFormat create t5");
783 if (!U_FAILURE(err)) {
784 //Arguments
785 Formattable testArgs10[] = {"Kirti",(int32_t)6,"female"};
786 Formattable testArgs11[] = {"Kirti",(int32_t)1,"female"};
787 Formattable testArgs12[] = {"Ash",(int32_t)1,"other"};
788 Formattable testArgs13[] = {"Ash",(int32_t)5,"other"};
789 Formattable* testArgs[] = {testArgs10,testArgs11,testArgs12,testArgs13};
790 UnicodeString exp[] = {
791 "Kirti sont all\\u00E9es \\u00E0 Paris." ,
792 "Kirti est all\\u00E9e \\u00E0 Paris.",
793 "Ash est all\\u00E9 \\u00E0 Paris.",
794 "Ash sont all\\u00E9s \\u00E0 Paris."};
795 //Format
796 for( int i=0; i< 4; i++){
797 internalFormat( msgFmt5 , testArgs[i], 3, exp[i].unescape() ,(char*)"From TestMessageFormat::testSelectFormat format t5");
798 }
799 }
800 delete msgFmt5;
801
802 err = U_ZERO_ERROR;
803 //Select, plural, and number formats heavily nested
804 UnicodeString t6("{0} und {1, select, female {{2, plural, one {{3, select, female {ihre Freundin} other {ihr Freund}} } other {ihre {2, number, integer} {3, select, female {Freundinnen} other {Freunde}} } }} other{{2, plural, one {{3, select, female {seine Freundin} other {sein Freund}}} other {seine {2, number, integer} {3, select, female {Freundinnen} other {Freunde}}}}} } gingen nach Paris.");
805 //Create the MessageFormat with Select, plural, and number formats heavily nested
806 MessageFormat* msgFmt6 = internalCreate(t6, Locale("de"),err,(char*)"From TestMessageFormat::TestSelectFormat create t6");
807 if (!U_FAILURE(err)) {
808 //Arguments
809 Formattable testArgs10[] = {"Kirti","other",(int32_t)1,"other"};
810 Formattable testArgs11[] = {"Kirti","other",(int32_t)6,"other"};
811 Formattable testArgs12[] = {"Kirti","other",(int32_t)1,"female"};
812 Formattable testArgs13[] = {"Kirti","other",(int32_t)3,"female"};
813 Formattable testArgs14[] = {"Kirti","female",(int32_t)1,"female"};
814 Formattable testArgs15[] = {"Kirti","female",(int32_t)5,"female"};
815 Formattable testArgs16[] = {"Kirti","female",(int32_t)1,"other"};
816 Formattable testArgs17[] = {"Kirti","female",(int32_t)5,"other"};
817 Formattable testArgs18[] = {"Kirti","mixed",(int32_t)1,"mixed"};
818 Formattable testArgs19[] = {"Kirti","mixed",(int32_t)1,"other"};
819 Formattable testArgs20[] = {"Kirti","female",(int32_t)1,"mixed"};
820 Formattable testArgs21[] = {"Kirti","mixed",(int32_t)5,"mixed"};
821 Formattable testArgs22[] = {"Kirti","mixed",(int32_t)5,"other"};
822 Formattable testArgs23[] = {"Kirti","female",(int32_t)5,"mixed"};
823 Formattable* testArgs[] = {testArgs10,testArgs11,testArgs12,testArgs13,
824 testArgs14,testArgs15,testArgs16,testArgs17,
825 testArgs18,testArgs19,testArgs20,testArgs21,
826 testArgs22,testArgs23 };
827 UnicodeString exp[] = {
828 "Kirti und sein Freund gingen nach Paris." ,
829 "Kirti und seine 6 Freunde gingen nach Paris." ,
830 "Kirti und seine Freundin gingen nach Paris.",
831 "Kirti und seine 3 Freundinnen gingen nach Paris.",
832 "Kirti und ihre Freundin gingen nach Paris.",
833 "Kirti und ihre 5 Freundinnen gingen nach Paris.",
834 "Kirti und ihr Freund gingen nach Paris.",
835 "Kirti und ihre 5 Freunde gingen nach Paris.",
836 "Kirti und sein Freund gingen nach Paris.",
837 "Kirti und sein Freund gingen nach Paris.",
838 "Kirti und ihr Freund gingen nach Paris.",
839 "Kirti und seine 5 Freunde gingen nach Paris." ,
840 "Kirti und seine 5 Freunde gingen nach Paris." ,
841 "Kirti und ihre 5 Freunde gingen nach Paris."
842 };
843 //Format
844 for( int i=0; i< 14; i++){
845 internalFormat( msgFmt6 , testArgs[i], 4, exp[i] ,(char*)"From TestMessageFormat::testSelectFormat format t6");
846 }
847 }
848 delete msgFmt6;
849 }
850
851 //---------------------------------
852 // API Tests
853 //---------------------------------
854
testCopyConstructor()855 void TestMessageFormat::testCopyConstructor()
856 {
857 UErrorCode success = U_ZERO_ERROR;
858 MessageFormat *x = new MessageFormat("There are {0} files on {1}", success);
859 MessageFormat *z = new MessageFormat("There are {0} files on {1} created", success);
860 MessageFormat *y = 0;
861 y = new MessageFormat(*x);
862 if ( (*x == *y) &&
863 (*x != *z) &&
864 (*y != *z) )
865 logln("First test (operator ==): Passed!");
866 else {
867 errln("TestMessageFormat::testCopyConstructor failed #1");
868 logln("First test (operator ==): Failed!");
869 }
870 if ( ((*x == *y) && (*y == *x)) &&
871 ((*x != *z) && (*z != *x)) &&
872 ((*y != *z) && (*z != *y)) )
873 logln("Second test (equals): Passed!");
874 else {
875 errln("TestMessageFormat::testCopyConstructor failed #2");
876 logln("Second test (equals): Failed!");
877 }
878
879 delete x;
880 delete y;
881 delete z;
882 }
883
884
testAssignment()885 void TestMessageFormat::testAssignment()
886 {
887 UErrorCode success = U_ZERO_ERROR;
888 MessageFormat *x = new MessageFormat("There are {0} files on {1}", success);
889 MessageFormat *z = new MessageFormat("There are {0} files on {1} created", success);
890 MessageFormat *y = new MessageFormat("There are {0} files on {1} created", success);
891 *y = *x;
892 if ( (*x == *y) &&
893 (*x != *z) &&
894 (*y != *z) )
895 logln("First test (operator ==): Passed!");
896 else {
897 errln( "TestMessageFormat::testAssignment failed #1");
898 logln("First test (operator ==): Failed!");
899 }
900 if ( ((*x == *y) && (*y == *x)) &&
901 ((*x != *z) && (*z != *x)) &&
902 ((*y != *z) && (*z != *y)) )
903 logln("Second test (equals): Passed!");
904 else {
905 errln("TestMessageFormat::testAssignment failed #2");
906 logln("Second test (equals): Failed!");
907 }
908
909 delete x;
910 delete y;
911 delete z;
912 }
913
testClone()914 void TestMessageFormat::testClone()
915 {
916 UErrorCode success = U_ZERO_ERROR;
917 MessageFormat *x = new MessageFormat("There are {0} files on {1}", success);
918 MessageFormat *z = new MessageFormat("There are {0} files on {1} created", success);
919 MessageFormat *y = 0;
920 y = (MessageFormat*)x->clone();
921 if ( (*x == *y) &&
922 (*x != *z) &&
923 (*y != *z) )
924 logln("First test (operator ==): Passed!");
925 else {
926 errln("TestMessageFormat::testClone failed #1");
927 logln("First test (operator ==): Failed!");
928 }
929 if ( ((*x == *y) && (*y == *x)) &&
930 ((*x != *z) && (*z != *x)) &&
931 ((*y != *z) && (*z != *y)) )
932 logln("Second test (equals): Passed!");
933 else {
934 errln("TestMessageFormat::testClone failed #2");
935 logln("Second test (equals): Failed!");
936 }
937
938 delete x;
939 delete y;
940 delete z;
941 }
942
testEquals()943 void TestMessageFormat::testEquals()
944 {
945 UErrorCode success = U_ZERO_ERROR;
946 MessageFormat x("There are {0} files on {1}", success);
947 MessageFormat y("There are {0} files on {1}", success);
948 if (!(x == y)) {
949 errln( "TestMessageFormat::testEquals failed #1");
950 logln("First test (operator ==): Failed!");
951 }
952
953 }
954
testNotEquals()955 void TestMessageFormat::testNotEquals()
956 {
957 UErrorCode success = U_ZERO_ERROR;
958 MessageFormat x("There are {0} files on {1}", success);
959 MessageFormat y(x);
960 y.setLocale(Locale("fr"));
961 if (!(x != y)) {
962 errln( "TestMessageFormat::testEquals failed #1");
963 logln("First test (operator !=): Failed!");
964 }
965 y = x;
966 y.applyPattern("There are {0} files on {1} the disk", success);
967 if (!(x != y)) {
968 errln( "TestMessageFormat::testEquals failed #1");
969 logln("Second test (operator !=): Failed!");
970 }
971 }
972
973
testSetLocale()974 void TestMessageFormat::testSetLocale()
975 {
976 UErrorCode err = U_ZERO_ERROR;
977 GregorianCalendar cal(err);
978 Formattable arguments[] = {
979 456.83,
980 Formattable(UDate(8.71068e+011), Formattable::kIsDate),
981 "deposit"
982 };
983
984 UnicodeString result;
985
986 //UnicodeString formatStr = "At {1,time} on {1,date}, you made a {2} of {0,number,currency}.";
987 UnicodeString formatStr = "At <time> on {1,date}, you made a {2} of {0,number,currency}.";
988 // {sfb} to get $, would need Locale::US, not Locale::ENGLISH
989 // Just use unlocalized currency symbol.
990 //UnicodeString compareStrEng = "At <time> on Aug 8, 1997, you made a deposit of $456.83.";
991 UnicodeString compareStrEng = "At <time> on Aug 8, 1997, you made a deposit of ";
992 compareStrEng += (UChar) 0x00a4;
993 compareStrEng += "456.83.";
994 // {sfb} to get DM, would need Locale::GERMANY, not Locale::GERMAN
995 // Just use unlocalized currency symbol.
996 //UnicodeString compareStrGer = "At <time> on 08.08.1997, you made a deposit of 456,83 DM.";
997 UnicodeString compareStrGer = "At <time> on 08.08.1997, you made a deposit of ";
998 compareStrGer += "456,83";
999 compareStrGer += (UChar) 0x00a0;
1000 compareStrGer += (UChar) 0x00a4;
1001 compareStrGer += ".";
1002
1003 MessageFormat msg( formatStr, err);
1004 result = "";
1005 FieldPosition pos(FieldPosition::DONT_CARE);
1006 result = msg.format(
1007 arguments,
1008 3,
1009 result,
1010 pos,
1011 err);
1012
1013 logln(result);
1014 if (result != compareStrEng) {
1015 dataerrln("*** MSG format err. - %s", u_errorName(err));
1016 }
1017
1018 msg.setLocale(Locale::getEnglish());
1019 UBool getLocale_ok = TRUE;
1020 if (msg.getLocale() != Locale::getEnglish()) {
1021 errln("*** MSG getLocal err.");
1022 getLocale_ok = FALSE;
1023 }
1024
1025 msg.setLocale(Locale::getGerman());
1026
1027 if (msg.getLocale() != Locale::getGerman()) {
1028 errln("*** MSG getLocal err.");
1029 getLocale_ok = FALSE;
1030 }
1031
1032 msg.applyPattern( formatStr, err);
1033
1034 pos.setField(0);
1035 result = "";
1036 result = msg.format(
1037 arguments,
1038 3,
1039 result,
1040 pos,
1041 err);
1042
1043 logln(result);
1044 if (result == compareStrGer) {
1045 logln("MSG setLocale tested.");
1046 }else{
1047 dataerrln( "*** MSG setLocale err. - %s", u_errorName(err));
1048 }
1049
1050 if (getLocale_ok) {
1051 logln("MSG getLocale tested.");
1052 }
1053 }
1054
testFormat()1055 void TestMessageFormat::testFormat()
1056 {
1057 UErrorCode err = U_ZERO_ERROR;
1058 GregorianCalendar cal(err);
1059
1060 const Formattable ftarray[] =
1061 {
1062 Formattable( UDate(8.71068e+011), Formattable::kIsDate )
1063 };
1064 const int32_t ft_cnt = UPRV_LENGTHOF(ftarray);
1065 Formattable ft_arr( ftarray, ft_cnt );
1066
1067 Formattable* fmt = new Formattable(UDate(8.71068e+011), Formattable::kIsDate);
1068
1069 UnicodeString result;
1070
1071 //UnicodeString formatStr = "At {1,time} on {1,date}, you made a {2} of {0,number,currency}.";
1072 UnicodeString formatStr = "On {0,date}, it began.";
1073 UnicodeString compareStr = "On Aug 8, 1997, it began.";
1074
1075 err = U_ZERO_ERROR;
1076 MessageFormat msg( formatStr, err);
1077 FieldPosition fp(FieldPosition::DONT_CARE);
1078
1079 result = "";
1080 fp = 0;
1081 result = msg.format(
1082 *fmt,
1083 result,
1084 //FieldPosition(0),
1085 fp,
1086 err);
1087
1088 if (err != U_ILLEGAL_ARGUMENT_ERROR) {
1089 dataerrln("*** MSG format without expected error code. - %s", u_errorName(err));
1090 }
1091 err = U_ZERO_ERROR;
1092
1093 result = "";
1094 fp = 0;
1095 result = msg.format(
1096 ft_arr,
1097 result,
1098 //FieldPosition(0),
1099 fp,
1100 err);
1101
1102 logln("MSG format( Formattable&, ... ) expected:" + compareStr);
1103 logln("MSG format( Formattable&, ... ) result:" + result);
1104 if (result != compareStr) {
1105 dataerrln("*** MSG format( Formattable&, .... ) err. - %s", u_errorName(err));
1106 }else{
1107 logln("MSG format( Formattable&, ... ) tested.");
1108 }
1109
1110 delete fmt;
1111
1112 }
1113
testParse()1114 void TestMessageFormat::testParse()
1115 {
1116 UErrorCode err = U_ZERO_ERROR;
1117 int32_t count;
1118 UnicodeString msgFormatString = "{0} =sep= {1}";
1119 MessageFormat msg( msgFormatString, err);
1120 UnicodeString source = "abc =sep= def";
1121 UnicodeString tmp1, tmp2;
1122
1123 Formattable* fmt_arr = msg.parse( source, count, err );
1124 if (U_FAILURE(err) || (!fmt_arr)) {
1125 errln("*** MSG parse (ustring, count, err) error.");
1126 }else{
1127 logln("MSG parse -- count: %d", count);
1128 if (count != 2) {
1129 errln("*** MSG parse (ustring, count, err) count err.");
1130 }else{
1131 if ((fmt_arr[0].getType() == Formattable::kString)
1132 && (fmt_arr[1].getType() == Formattable::kString)
1133 && (fmt_arr[0].getString(tmp1) == "abc")
1134 && (fmt_arr[1].getString(tmp2) == "def")) {
1135 logln("MSG parse (ustring, count, err) tested.");
1136 }else{
1137 errln("*** MSG parse (ustring, count, err) result err.");
1138 }
1139 }
1140 }
1141 delete[] fmt_arr;
1142
1143 ParsePosition pp(0);
1144
1145 fmt_arr = msg.parse( source, pp, count );
1146 if ((pp == 0) || (!fmt_arr)) {
1147 errln("*** MSG parse (ustring, parsepos., count) error.");
1148 }else{
1149 logln("MSG parse -- count: %d", count);
1150 if (count != 2) {
1151 errln("*** MSG parse (ustring, parsepos., count) count err.");
1152 }else{
1153 if ((fmt_arr[0].getType() == Formattable::kString)
1154 && (fmt_arr[1].getType() == Formattable::kString)
1155 && (fmt_arr[0].getString(tmp1) == "abc")
1156 && (fmt_arr[1].getString(tmp2) == "def")) {
1157 logln("MSG parse (ustring, parsepos., count) tested.");
1158 }else{
1159 errln("*** MSG parse (ustring, parsepos., count) result err.");
1160 }
1161 }
1162 }
1163 delete[] fmt_arr;
1164
1165 pp = 0;
1166 Formattable fmta;
1167
1168 msg.parseObject( source, fmta, pp );
1169 if (pp == 0) {
1170 errln("*** MSG parse (ustring, Formattable, parsepos ) error.");
1171 }else{
1172 logln("MSG parse -- count: %d", count);
1173 fmta.getArray(count);
1174 if (count != 2) {
1175 errln("*** MSG parse (ustring, Formattable, parsepos ) count err.");
1176 }else{
1177 if ((fmta[0].getType() == Formattable::kString)
1178 && (fmta[1].getType() == Formattable::kString)
1179 && (fmta[0].getString(tmp1) == "abc")
1180 && (fmta[1].getString(tmp2) == "def")) {
1181 logln("MSG parse (ustring, Formattable, parsepos ) tested.");
1182 }else{
1183 errln("*** MSG parse (ustring, Formattable, parsepos ) result err.");
1184 }
1185 }
1186 }
1187 }
1188
1189
testAdopt()1190 void TestMessageFormat::testAdopt()
1191 {
1192 UErrorCode err = U_ZERO_ERROR;
1193
1194 UnicodeString formatStr("{0,date},{1},{2,number}", "");
1195 UnicodeString formatStrChange("{0,number},{1,number},{2,date}", "");
1196 err = U_ZERO_ERROR;
1197 MessageFormat msg( formatStr, err);
1198 MessageFormat msgCmp( formatStr, err);
1199 if (U_FAILURE(err)) {
1200 dataerrln("Unable to instantiate MessageFormat - %s", u_errorName(err));
1201 return;
1202 }
1203 int32_t count, countCmp;
1204 const Format** formats = msg.getFormats(count);
1205 const Format** formatsCmp = msgCmp.getFormats(countCmp);
1206 const Format** formatsChg = 0;
1207 const Format** formatsAct = 0;
1208 int32_t countAct;
1209 const Format* a;
1210 const Format* b;
1211 UnicodeString patCmp;
1212 UnicodeString patAct;
1213 Format** formatsToAdopt;
1214
1215 if (!formats || !formatsCmp || (count <= 0) || (count != countCmp)) {
1216 dataerrln("Error getting Formats");
1217 return;
1218 }
1219
1220 int32_t i;
1221
1222 for (i = 0; i < count; i++) {
1223 a = formats[i];
1224 b = formatsCmp[i];
1225 if ((a != NULL) && (b != NULL)) {
1226 if (*a != *b) {
1227 errln("a != b");
1228 return;
1229 }
1230 }else if ((a != NULL) || (b != NULL)) {
1231 errln("(a != NULL) || (b != NULL)");
1232 return;
1233 }
1234 }
1235
1236 msg.applyPattern( formatStrChange, err ); //set msg formats to something different
1237 int32_t countChg;
1238 formatsChg = msg.getFormats(countChg); // tested function
1239 if (!formatsChg || (countChg != count)) {
1240 errln("Error getting Formats");
1241 return;
1242 }
1243
1244 UBool diff;
1245 diff = TRUE;
1246 for (i = 0; i < count; i++) {
1247 a = formatsChg[i];
1248 b = formatsCmp[i];
1249 if ((a != NULL) && (b != NULL)) {
1250 if (*a == *b) {
1251 logln("formatsChg == formatsCmp at index %d", i);
1252 diff = FALSE;
1253 }
1254 }
1255 }
1256 if (!diff) {
1257 errln("*** MSG getFormats diff err.");
1258 return;
1259 }
1260
1261 logln("MSG getFormats tested.");
1262
1263 msg.setFormats( formatsCmp, countCmp ); //tested function
1264
1265 formatsAct = msg.getFormats(countAct);
1266 if (!formatsAct || (countAct <=0) || (countAct != countCmp)) {
1267 errln("Error getting Formats");
1268 return;
1269 }
1270
1271 assertEquals("msgCmp.toPattern()", formatStr, msgCmp.toPattern(patCmp.remove()));
1272 // ICU 4.8 does not support toPattern() when there are custom formats (from setFormat() etc.).
1273 // assertEquals("msg.toPattern()", formatStr, msg.toPattern(patAct.remove()));
1274 msg.toPattern(patCmp.remove());
1275 if (!patCmp.isBogus()) {
1276 errln("msg.setFormat().toPattern() succeeds.");
1277 }
1278
1279 for (i = 0; i < countAct; i++) {
1280 a = formatsAct[i];
1281 b = formatsCmp[i];
1282 if ((a != NULL) && (b != NULL)) {
1283 if (*a != *b) {
1284 logln("formatsAct != formatsCmp at index %d", i);
1285 errln("a != b");
1286 return;
1287 }
1288 }else if ((a != NULL) || (b != NULL)) {
1289 errln("(a != NULL) || (b != NULL)");
1290 return;
1291 }
1292 }
1293 logln("MSG setFormats tested.");
1294
1295 //----
1296
1297 msg.applyPattern( formatStrChange, err ); //set msg formats to something different
1298
1299 formatsToAdopt = new Format* [countCmp];
1300 if (!formatsToAdopt) {
1301 errln("memory allocation error");
1302 return;
1303 }
1304
1305 for (i = 0; i < countCmp; i++) {
1306 if (formatsCmp[i] == NULL) {
1307 formatsToAdopt[i] = NULL;
1308 }else{
1309 formatsToAdopt[i] = formatsCmp[i]->clone();
1310 if (!formatsToAdopt[i]) {
1311 errln("Can't clone format at index %d", i);
1312 return;
1313 }
1314 }
1315 }
1316 msg.adoptFormats( formatsToAdopt, countCmp ); // function to test
1317 delete[] formatsToAdopt;
1318
1319 assertEquals("msgCmp.toPattern()", formatStr, msgCmp.toPattern(patCmp.remove()));
1320 // ICU 4.8 does not support toPattern() when there are custom formats (from setFormat() etc.).
1321 // assertEquals("msg.toPattern()", formatStr, msg.toPattern(patAct.remove()));
1322
1323 formatsAct = msg.getFormats(countAct);
1324 if (!formatsAct || (countAct <=0) || (countAct != countCmp)) {
1325 errln("Error getting Formats");
1326 return;
1327 }
1328
1329 for (i = 0; i < countAct; i++) {
1330 a = formatsAct[i];
1331 b = formatsCmp[i];
1332 if ((a != NULL) && (b != NULL)) {
1333 if (*a != *b) {
1334 errln("a != b");
1335 return;
1336 }
1337 }else if ((a != NULL) || (b != NULL)) {
1338 errln("(a != NULL) || (b != NULL)");
1339 return;
1340 }
1341 }
1342 logln("MSG adoptFormats tested.");
1343
1344 //---- adoptFormat
1345
1346 msg.applyPattern( formatStrChange, err ); //set msg formats to something different
1347
1348 formatsToAdopt = new Format* [countCmp];
1349 if (!formatsToAdopt) {
1350 errln("memory allocation error");
1351 return;
1352 }
1353
1354 for (i = 0; i < countCmp; i++) {
1355 if (formatsCmp[i] == NULL) {
1356 formatsToAdopt[i] = NULL;
1357 }else{
1358 formatsToAdopt[i] = formatsCmp[i]->clone();
1359 if (!formatsToAdopt[i]) {
1360 errln("Can't clone format at index %d", i);
1361 return;
1362 }
1363 }
1364 }
1365
1366 for ( i = 0; i < countCmp; i++ ) {
1367 msg.adoptFormat( i, formatsToAdopt[i] ); // function to test
1368 }
1369 delete[] formatsToAdopt; // array itself not needed in this case;
1370
1371 assertEquals("msgCmp.toPattern()", formatStr, msgCmp.toPattern(patCmp.remove()));
1372 // ICU 4.8 does not support toPattern() when there are custom formats (from setFormat() etc.).
1373 // assertEquals("msg.toPattern()", formatStr, msg.toPattern(patAct.remove()));
1374
1375 formatsAct = msg.getFormats(countAct);
1376 if (!formatsAct || (countAct <=0) || (countAct != countCmp)) {
1377 errln("Error getting Formats");
1378 return;
1379 }
1380
1381 for (i = 0; i < countAct; i++) {
1382 a = formatsAct[i];
1383 b = formatsCmp[i];
1384 if ((a != NULL) && (b != NULL)) {
1385 if (*a != *b) {
1386 errln("a != b");
1387 return;
1388 }
1389 }else if ((a != NULL) || (b != NULL)) {
1390 errln("(a != NULL) || (b != NULL)");
1391 return;
1392 }
1393 }
1394 logln("MSG adoptFormat tested.");
1395 }
1396
1397 // This test is a regression test for a fixed bug in the copy constructor.
1398 // It is kept as a global function rather than as a method since the test depends on memory values.
1399 // (At least before the bug was fixed, whether it showed up or not depended on memory contents,
1400 // which is probably why it didn't show up in the regular test for the copy constructor.)
1401 // For this reason, the test isn't changed even though it contains function calls whose results are
1402 // not tested and had no problems. Actually, the test failed by *crashing*.
_testCopyConstructor2()1403 static void _testCopyConstructor2()
1404 {
1405 UErrorCode status = U_ZERO_ERROR;
1406 UnicodeString formatStr("Hello World on {0,date,full}", "");
1407 UnicodeString resultStr(" ", "");
1408 UnicodeString result;
1409 FieldPosition fp(FieldPosition::DONT_CARE);
1410 UDate d = Calendar::getNow();
1411 const Formattable fargs( d, Formattable::kIsDate );
1412
1413 MessageFormat* fmt1 = new MessageFormat( formatStr, status );
1414 MessageFormat* fmt2 = NULL;
1415 MessageFormat* fmt3 = NULL;
1416 MessageFormat* fmt4 = NULL;
1417
1418 if (fmt1 == NULL) {
1419 it_err("testCopyConstructor2: (fmt1 != NULL)");
1420 goto cleanup;
1421 }
1422
1423 fmt2 = new MessageFormat( *fmt1 );
1424 result = fmt1->format( &fargs, 1, resultStr, fp, status );
1425
1426 if (fmt2 == NULL) {
1427 it_err("testCopyConstructor2: (fmt2 != NULL)");
1428 goto cleanup;
1429 }
1430
1431 fmt3 = (MessageFormat*) fmt1->clone();
1432 fmt4 = (MessageFormat*) fmt2->clone();
1433
1434 if (fmt3 == NULL) {
1435 it_err("testCopyConstructor2: (fmt3 != NULL)");
1436 goto cleanup;
1437 }
1438 if (fmt4 == NULL) {
1439 it_err("testCopyConstructor2: (fmt4 != NULL)");
1440 goto cleanup;
1441 }
1442
1443 result = fmt1->format( &fargs, 1, resultStr, fp, status );
1444 result = fmt2->format( &fargs, 1, resultStr, fp, status );
1445 result = fmt3->format( &fargs, 1, resultStr, fp, status );
1446 result = fmt4->format( &fargs, 1, resultStr, fp, status );
1447
1448 cleanup:
1449 delete fmt1;
1450 delete fmt2;
1451 delete fmt3;
1452 delete fmt4;
1453 }
1454
testCopyConstructor2()1455 void TestMessageFormat::testCopyConstructor2() {
1456 _testCopyConstructor2();
1457 }
1458
1459 /**
1460 * Verify that MessageFormat accomodates more than 10 arguments and
1461 * more than 10 subformats.
1462 */
TestUnlimitedArgsAndSubformats()1463 void TestMessageFormat::TestUnlimitedArgsAndSubformats() {
1464 UErrorCode ec = U_ZERO_ERROR;
1465 const UnicodeString pattern =
1466 "On {0,date} (aka {0,date,short}, aka {0,date,long}) "
1467 "at {0,time} (aka {0,time,short}, aka {0,time,long}) "
1468 "there were {1,number} werjes "
1469 "(a {3,number,percent} increase over {2,number}) "
1470 "despite the {4}''s efforts "
1471 "and to delight of {5}, {6}, {7}, {8}, {9}, and {10} {11}.";
1472 MessageFormat msg(pattern, ec);
1473 if (U_FAILURE(ec)) {
1474 dataerrln("FAIL: constructor failed - %s", u_errorName(ec));
1475 return;
1476 }
1477
1478 const Formattable ARGS[] = {
1479 Formattable(UDate(1e13), Formattable::kIsDate),
1480 Formattable((int32_t)1303),
1481 Formattable((int32_t)1202),
1482 Formattable(1303.0/1202 - 1),
1483 Formattable("Glimmung"),
1484 Formattable("the printers"),
1485 Formattable("Nick"),
1486 Formattable("his father"),
1487 Formattable("his mother"),
1488 Formattable("the spiddles"),
1489 Formattable("of course"),
1490 Formattable("Horace"),
1491 };
1492 const int32_t ARGS_LENGTH = UPRV_LENGTHOF(ARGS);
1493 Formattable ARGS_OBJ(ARGS, ARGS_LENGTH);
1494
1495 UnicodeString expected =
1496 "On Nov 20, 2286 (aka 11/20/86, aka November 20, 2286) "
1497 "at 9:46:40 AM (aka 9:46 AM, aka 9:46:40 AM PST) "
1498 "there were 1,303 werjes "
1499 "(a 8% increase over 1,202) "
1500 "despite the Glimmung's efforts "
1501 "and to delight of the printers, Nick, his father, "
1502 "his mother, the spiddles, and of course Horace.";
1503 UnicodeString result;
1504 msg.format(ARGS_OBJ, result, ec);
1505 if (result == expected) {
1506 logln(result);
1507 } else {
1508 errln((UnicodeString)"FAIL: Got " + result +
1509 ", expected " + expected);
1510 }
1511 }
1512
1513 // test RBNF extensions to message format
TestRBNF(void)1514 void TestMessageFormat::TestRBNF(void) {
1515 // WARNING: this depends on the RBNF formats for en_US
1516 Locale locale("en", "US", "");
1517
1518 UErrorCode ec = U_ZERO_ERROR;
1519
1520 UnicodeString values[] = {
1521 // decimal values do not format completely for ordinal or duration, and
1522 // do not always parse, so do not include them
1523 "0", "1", "12", "100", "123", "1001", "123,456", "-17",
1524 };
1525 int32_t values_count = UPRV_LENGTHOF(values);
1526
1527 UnicodeString formats[] = {
1528 "There are {0,spellout} files to search.",
1529 "There are {0,spellout,%simplified} files to search.",
1530 "The bogus spellout {0,spellout,%BOGUS} files behaves like the default.",
1531 "This is the {0,ordinal} file to search.",
1532 "Searching this file will take {0,duration} to complete.",
1533 "Searching this file will take {0,duration,%with-words} to complete.",
1534 };
1535 int32_t formats_count = UPRV_LENGTHOF(formats);
1536
1537 Formattable args[1];
1538
1539 NumberFormat* numFmt = NumberFormat::createInstance(locale, ec);
1540 if (U_FAILURE(ec)) {
1541 dataerrln("Error calling NumberFormat::createInstance()");
1542 return;
1543 }
1544
1545 for (int i = 0; i < formats_count; ++i) {
1546 MessageFormat* fmt = new MessageFormat(formats[i], locale, ec);
1547 logln((UnicodeString)"Testing format pattern: '" + formats[i] + "'");
1548
1549 for (int j = 0; j < values_count; ++j) {
1550 ec = U_ZERO_ERROR;
1551 numFmt->parse(values[j], args[0], ec);
1552 if (U_FAILURE(ec)) {
1553 errln((UnicodeString)"Failed to parse test argument " + values[j]);
1554 } else {
1555 FieldPosition fp(FieldPosition::DONT_CARE);
1556 UnicodeString result;
1557 fmt->format(args, 1, result, fp, ec);
1558 logln((UnicodeString)"value: " + toString(args[0]) + " --> " + result + UnicodeString(" ec: ") + u_errorName(ec));
1559
1560 int32_t count = 0;
1561 Formattable* parseResult = fmt->parse(result, count, ec);
1562 if (count != 1) {
1563 errln((UnicodeString)"parse returned " + count + " args");
1564 } else if (parseResult[0] != args[0]) {
1565 errln((UnicodeString)"parsed argument " + toString(parseResult[0]) + " != " + toString(args[0]));
1566 }
1567 delete []parseResult;
1568 }
1569 }
1570 delete fmt;
1571 }
1572 delete numFmt;
1573 }
1574
GetPatternAndSkipSyntax(const MessagePattern & pattern)1575 UnicodeString TestMessageFormat::GetPatternAndSkipSyntax(const MessagePattern& pattern) {
1576 UnicodeString us(pattern.getPatternString());
1577 int count = pattern.countParts();
1578 for (int i = count; i > 0;) {
1579 const MessagePattern::Part& part = pattern.getPart(--i);
1580 if (part.getType() == UMSGPAT_PART_TYPE_SKIP_SYNTAX) {
1581 us.remove(part.getIndex(), part.getLimit() - part.getIndex());
1582 }
1583 }
1584 return us;
1585 }
1586
TestApostropheMode()1587 void TestMessageFormat::TestApostropheMode() {
1588 UErrorCode status = U_ZERO_ERROR;
1589 MessagePattern *ado_mp = new MessagePattern(UMSGPAT_APOS_DOUBLE_OPTIONAL, status);
1590 MessagePattern *adr_mp = new MessagePattern(UMSGPAT_APOS_DOUBLE_REQUIRED, status);
1591 if (ado_mp->getApostropheMode() != UMSGPAT_APOS_DOUBLE_OPTIONAL) {
1592 errln("wrong value from ado_mp->getApostropheMode().");
1593 }
1594 if (adr_mp->getApostropheMode() != UMSGPAT_APOS_DOUBLE_REQUIRED) {
1595 errln("wrong value from adr_mp->getApostropheMode().");
1596 }
1597
1598
1599 UnicodeString tuples[] = {
1600 // Desired output
1601 // DOUBLE_OPTIONAL pattern
1602 // DOUBLE_REQUIRED pattern (empty=same as DOUBLE_OPTIONAL)
1603 "I see {many}", "I see '{many}'", "",
1604 "I said {'Wow!'}", "I said '{''Wow!''}'", "",
1605 "I dont know", "I dont know", "I don't know",
1606 "I don't know", "I don't know", "I don''t know",
1607 "I don't know", "I don''t know", "I don''t know"
1608 };
1609 int32_t tuples_count = UPRV_LENGTHOF(tuples);
1610
1611 for (int i = 0; i < tuples_count; i += 3) {
1612 UnicodeString& desired = tuples[i];
1613 UnicodeString& ado_pattern = tuples[i + 1];
1614 UErrorCode status = U_ZERO_ERROR;
1615 assertEquals("DOUBLE_OPTIONAL failure",
1616 desired,
1617 GetPatternAndSkipSyntax(ado_mp->parse(ado_pattern, NULL, status)));
1618 UnicodeString& adr_pattern = tuples[i + 2].isEmpty() ? ado_pattern : tuples[i + 2];
1619 assertEquals("DOUBLE_REQUIRED failure", desired,
1620 GetPatternAndSkipSyntax(adr_mp->parse(adr_pattern, NULL, status)));
1621 }
1622 delete adr_mp;
1623 delete ado_mp;
1624 }
1625
1626
1627 // Compare behavior of DOUBLE_OPTIONAL (new default) and DOUBLE_REQUIRED JDK-compatibility mode.
TestCompatibleApostrophe()1628 void TestMessageFormat::TestCompatibleApostrophe() {
1629 // Message with choice argument which does not contain another argument.
1630 // The JDK performs only one apostrophe-quoting pass on this pattern.
1631 UnicodeString pattern = "ab{0,choice,0#1'2''3'''4''''.}yz";
1632
1633 UErrorCode ec = U_ZERO_ERROR;
1634 MessageFormat compMsg("", Locale::getUS(), ec);
1635 compMsg.applyPattern(pattern, UMSGPAT_APOS_DOUBLE_REQUIRED, NULL, ec);
1636 if (compMsg.getApostropheMode() != UMSGPAT_APOS_DOUBLE_REQUIRED) {
1637 errln("wrong value from compMsg.getApostropheMode().");
1638 }
1639
1640 MessageFormat icuMsg("", Locale::getUS(), ec);
1641 icuMsg.applyPattern(pattern, UMSGPAT_APOS_DOUBLE_OPTIONAL, NULL, ec);
1642 if (icuMsg.getApostropheMode() != UMSGPAT_APOS_DOUBLE_OPTIONAL) {
1643 errln("wrong value from icuMsg.getApostropheMode().");
1644 }
1645
1646 Formattable zero0[] = { (int32_t)0 };
1647 FieldPosition fieldpos(FieldPosition::DONT_CARE);
1648 UnicodeString buffer1, buffer2;
1649 assertEquals("incompatible ICU MessageFormat compatibility-apostrophe behavior",
1650 "ab12'3'4''.yz",
1651 compMsg.format(zero0, 1, buffer1, fieldpos, ec));
1652 assertEquals("unexpected ICU MessageFormat double-apostrophe-optional behavior",
1653 "ab1'2'3''4''.yz",
1654 icuMsg.format(zero0, 1, buffer2, fieldpos, ec));
1655
1656 // Message with choice argument which contains a nested simple argument.
1657 // The DOUBLE_REQUIRED version performs two apostrophe-quoting passes.
1658 buffer1.remove();
1659 buffer2.remove();
1660 pattern = "ab{0,choice,0#1'2''3'''4''''.{0,number,'#x'}}yz";
1661 compMsg.applyPattern(pattern, ec);
1662 icuMsg.applyPattern(pattern, ec);
1663 if (U_FAILURE(ec)) {
1664 dataerrln("Unable to applyPattern - %s", u_errorName(ec));
1665 } else {
1666 assertEquals("incompatible ICU MessageFormat compatibility-apostrophe behavior",
1667 "ab1234'.0xyz",
1668 compMsg.format(zero0, 1, buffer1, fieldpos, ec));
1669 assertEquals("unexpected ICU MessageFormat double-apostrophe-optional behavior",
1670 "ab1'2'3''4''.#x0yz",
1671 icuMsg.format(zero0, 1, buffer2, fieldpos, ec));
1672 }
1673
1674 // This part is copied over from Java tests but cannot be properly tested here
1675 // because we do not have a live reference implementation with JDK behavior.
1676 // The JDK ChoiceFormat itself always performs one apostrophe-quoting pass.
1677 /*
1678 ChoiceFormat choice = new ChoiceFormat("0#1'2''3'''4''''.");
1679 assertEquals("unexpected JDK ChoiceFormat apostrophe behavior",
1680 "12'3'4''.",
1681 choice.format(0));
1682 choice.applyPattern("0#1'2''3'''4''''.{0,number,'#x'}");
1683 assertEquals("unexpected JDK ChoiceFormat apostrophe behavior",
1684 "12'3'4''.{0,number,#x}",
1685 choice.format(0));
1686 */
1687 }
1688
testAutoQuoteApostrophe(void)1689 void TestMessageFormat::testAutoQuoteApostrophe(void) {
1690 const char* patterns[] = { // pattern, expected pattern
1691 "'", "''",
1692 "''", "''",
1693 "'{", "'{'",
1694 "' {", "'' {",
1695 "'a", "''a",
1696 "'{'a", "'{'a",
1697 "'{a'", "'{a'",
1698 "'{}", "'{}'",
1699 "{'", "{'",
1700 "{'a", "{'a",
1701 "{'a{}'a}'a", "{'a{}'a}''a",
1702 "'}'", "'}'",
1703 "'} '{'}'", "'} '{'}''",
1704 "'} {{{''", "'} {{{'''",
1705 };
1706 int32_t pattern_count = UPRV_LENGTHOF(patterns);
1707
1708 for (int i = 0; i < pattern_count; i += 2) {
1709 UErrorCode status = U_ZERO_ERROR;
1710 UnicodeString result = MessageFormat::autoQuoteApostrophe(patterns[i], status);
1711 UnicodeString target(patterns[i+1]);
1712 if (target != result) {
1713 const int BUF2_LEN = 64;
1714 char buf[256];
1715 char buf2[BUF2_LEN];
1716 int32_t len = result.extract(0, result.length(), buf2, BUF2_LEN);
1717 if (len >= BUF2_LEN) {
1718 buf2[BUF2_LEN-1] = 0;
1719 }
1720 sprintf(buf, "[%2d] test \"%s\": target (\"%s\") != result (\"%s\")\n", i/2, patterns[i], patterns[i+1], buf2);
1721 errln(buf);
1722 }
1723 }
1724 }
1725
testCoverage(void)1726 void TestMessageFormat::testCoverage(void) {
1727 UErrorCode status = U_ZERO_ERROR;
1728 UnicodeString testformat("{argument, plural, one{C''est # fichier} other {Ce sont # fichiers}} dans la liste.");
1729 MessageFormat *msgfmt = new MessageFormat(testformat, Locale("fr"), status);
1730 if (msgfmt == NULL || U_FAILURE(status)) {
1731 dataerrln("FAIL: Unable to create MessageFormat.: %s", u_errorName(status));
1732 return;
1733 }
1734 if (!msgfmt->usesNamedArguments()) {
1735 errln("FAIL: Unable to detect usage of named arguments.");
1736 }
1737 const double limit[] = {0.0, 1.0, 2.0};
1738 const UnicodeString formats[] = {"0.0<=Arg<1.0",
1739 "1.0<=Arg<2.0",
1740 "2.0<-Arg"};
1741 ChoiceFormat cf(limit, formats, 3);
1742
1743 msgfmt->setFormat("set", cf, status);
1744
1745 StringEnumeration *en = msgfmt->getFormatNames(status);
1746 if (en == NULL || U_FAILURE(status)) {
1747 errln("FAIL: Unable to get format names enumeration.");
1748 } else {
1749 int32_t count = 0;
1750 en->reset(status);
1751 count = en->count(status);
1752 if (U_FAILURE(status)) {
1753 errln("FAIL: Unable to get format name enumeration count.");
1754 } else {
1755 for (int32_t i = 0; i < count; i++) {
1756 en->snext(status);
1757 if (U_FAILURE(status)) {
1758 errln("FAIL: Error enumerating through names.");
1759 break;
1760 }
1761 }
1762 }
1763 }
1764
1765 // adoptFormat() takes ownership of the input Format object.
1766 // We need to clone the stack-allocated cf so that we do not attempt to delete cf.
1767 Format *cfClone = cf.clone();
1768 msgfmt->adoptFormat("adopt", cfClone, status);
1769
1770 delete en;
1771 delete msgfmt;
1772
1773 msgfmt = new MessageFormat("'", status);
1774 if (msgfmt == NULL || U_FAILURE(status)) {
1775 errln("FAIL: Unable to create MessageFormat.");
1776 return;
1777 }
1778 if (msgfmt->usesNamedArguments()) {
1779 errln("FAIL: Unable to detect usage of named arguments.");
1780 }
1781
1782 // Starting with ICU 4.8, we support setFormat(name, ...) and getFormatNames()
1783 // on a MessageFormat without named arguments.
1784 msgfmt->setFormat("formatName", cf, status);
1785 if (U_FAILURE(status)) {
1786 errln("FAIL: Should work to setFormat(name, ...) regardless of pattern.");
1787 }
1788 status = U_ZERO_ERROR;
1789 en = msgfmt->getFormatNames(status);
1790 if (U_FAILURE(status)) {
1791 errln("FAIL: Should work to get format names enumeration regardless of pattern.");
1792 }
1793
1794 delete en;
1795 delete msgfmt;
1796 }
1797
testGetFormatNames()1798 void TestMessageFormat::testGetFormatNames() {
1799 IcuTestErrorCode errorCode(*this, "testGetFormatNames");
1800 MessageFormat msgfmt("Hello, {alice,number} {oops,date,full} {zip,spellout} World.", Locale::getRoot(), errorCode);
1801 if(errorCode.logDataIfFailureAndReset("MessageFormat() failed")) {
1802 return;
1803 }
1804 LocalPointer<StringEnumeration> names(msgfmt.getFormatNames(errorCode));
1805 if(errorCode.logIfFailureAndReset("msgfmt.getFormatNames() failed")) {
1806 return;
1807 }
1808 const UnicodeString *name;
1809 name = names->snext(errorCode);
1810 if (name == NULL || errorCode.isFailure()) {
1811 errln("msgfmt.getFormatNames()[0] failed: %s", errorCode.errorName());
1812 errorCode.reset();
1813 return;
1814 }
1815 if (!assertEquals("msgfmt.getFormatNames()[0]", UNICODE_STRING_SIMPLE("alice"), *name)) {
1816 return;
1817 }
1818 name = names->snext(errorCode);
1819 if (name == NULL || errorCode.isFailure()) {
1820 errln("msgfmt.getFormatNames()[1] failed: %s", errorCode.errorName());
1821 errorCode.reset();
1822 return;
1823 }
1824 if (!assertEquals("msgfmt.getFormatNames()[1]", UNICODE_STRING_SIMPLE("oops"), *name)) {
1825 return;
1826 }
1827 name = names->snext(errorCode);
1828 if (name == NULL || errorCode.isFailure()) {
1829 errln("msgfmt.getFormatNames()[2] failed: %s", errorCode.errorName());
1830 errorCode.reset();
1831 return;
1832 }
1833 if (!assertEquals("msgfmt.getFormatNames()[2]", UNICODE_STRING_SIMPLE("zip"), *name)) {
1834 return;
1835 }
1836 name = names->snext(errorCode);
1837 if (name != NULL) {
1838 errln(UnicodeString("msgfmt.getFormatNames()[3] should be NULL but is: ") + *name);
1839 return;
1840 }
1841 }
1842
TestTrimArgumentName()1843 void TestMessageFormat::TestTrimArgumentName() {
1844 // ICU 4.8 allows and ignores white space around argument names and numbers.
1845 IcuTestErrorCode errorCode(*this, "TestTrimArgumentName");
1846 MessageFormat m("a { 0 , number , '#,#'#.0 } z", Locale::getEnglish(), errorCode);
1847 if (errorCode.logDataIfFailureAndReset("Unable to instantiate MessageFormat")) {
1848 return;
1849 }
1850 Formattable args[1] = { (int32_t)2 };
1851 FieldPosition ignore(FieldPosition::DONT_CARE);
1852 UnicodeString result;
1853 assertEquals("trim-numbered-arg format() failed", "a #,#2.0 z",
1854 m.format(args, 1, result, ignore, errorCode));
1855
1856 m.applyPattern("x { _oOo_ , number , integer } y", errorCode);
1857 UnicodeString argName = UNICODE_STRING_SIMPLE("_oOo_");
1858 args[0].setLong(3);
1859 result.remove();
1860 assertEquals("trim-named-arg format() failed", "x 3 y",
1861 m.format(&argName, args, 1, result, errorCode));
1862 }
1863
TestSelectOrdinal()1864 void TestMessageFormat::TestSelectOrdinal() {
1865 IcuTestErrorCode errorCode(*this, "TestSelectOrdinal");
1866 // Test plural & ordinal together,
1867 // to make sure that we get the correct cached PluralSelector for each.
1868 MessageFormat m(
1869 "{0,plural,one{1 file}other{# files}}, "
1870 "{0,selectordinal,one{#st file}two{#nd file}few{#rd file}other{#th file}}",
1871 Locale::getEnglish(), errorCode);
1872 if (errorCode.logDataIfFailureAndReset("Unable to instantiate MessageFormat")) {
1873 return;
1874 }
1875 Formattable args[1] = { (int32_t)21 };
1876 FieldPosition ignore(FieldPosition::DONT_CARE);
1877 UnicodeString result;
1878 assertEquals("plural-and-ordinal format(21) failed", "21 files, 21st file",
1879 m.format(args, 1, result, ignore, errorCode), TRUE);
1880
1881 args[0].setLong(2);
1882 assertEquals("plural-and-ordinal format(2) failed", "2 files, 2nd file",
1883 m.format(args, 1, result.remove(), ignore, errorCode), TRUE);
1884
1885 args[0].setLong(1);
1886 assertEquals("plural-and-ordinal format(1) failed", "1 file, 1st file",
1887 m.format(args, 1, result.remove(), ignore, errorCode), TRUE);
1888
1889 args[0].setLong(3);
1890 assertEquals("plural-and-ordinal format(3) failed", "3 files, 3rd file",
1891 m.format(args, 1, result.remove(), ignore, errorCode), TRUE);
1892
1893 errorCode.logDataIfFailureAndReset("");
1894 }
1895
TestDecimals()1896 void TestMessageFormat::TestDecimals() {
1897 IcuTestErrorCode errorCode(*this, "TestDecimals");
1898 // Simple number replacement.
1899 MessageFormat m(
1900 "{0,plural,one{one meter}other{# meters}}",
1901 Locale::getEnglish(), errorCode);
1902 Formattable args[1] = { (int32_t)1 };
1903 FieldPosition ignore;
1904 UnicodeString result;
1905 assertEquals("simple format(1)", "one meter",
1906 m.format(args, 1, result, ignore, errorCode), TRUE);
1907
1908 args[0] = (double)1.5;
1909 result.remove();
1910 assertEquals("simple format(1.5)", "1.5 meters",
1911 m.format(args, 1, result, ignore, errorCode), TRUE);
1912
1913 // Simple but explicit.
1914 MessageFormat m0(
1915 "{0,plural,one{one meter}other{{0} meters}}",
1916 Locale::getEnglish(), errorCode);
1917 args[0] = (int32_t)1;
1918 result.remove();
1919 assertEquals("explicit format(1)", "one meter",
1920 m0.format(args, 1, result, ignore, errorCode), TRUE);
1921
1922 args[0] = (double)1.5;
1923 result.remove();
1924 assertEquals("explicit format(1.5)", "1.5 meters",
1925 m0.format(args, 1, result, ignore, errorCode), TRUE);
1926
1927 // With offset and specific simple format with optional decimals.
1928 MessageFormat m1(
1929 "{0,plural,offset:1 one{another meter}other{{0,number,00.#} meters}}",
1930 Locale::getEnglish(), errorCode);
1931 args[0] = (int32_t)1;
1932 result.remove();
1933 assertEquals("offset format(1)", "01 meters",
1934 m1.format(args, 1, result, ignore, errorCode), TRUE);
1935
1936 args[0] = (int32_t)2;
1937 result.remove();
1938 assertEquals("offset format(1)", "another meter",
1939 m1.format(args, 1, result, ignore, errorCode), TRUE);
1940
1941 args[0] = (double)2.5;
1942 result.remove();
1943 assertEquals("offset format(1)", "02.5 meters",
1944 m1.format(args, 1, result, ignore, errorCode), TRUE);
1945
1946 // With offset and specific simple format with forced decimals.
1947 MessageFormat m2(
1948 "{0,plural,offset:1 one{another meter}other{{0,number,0.0} meters}}",
1949 Locale::getEnglish(), errorCode);
1950 args[0] = (int32_t)1;
1951 result.remove();
1952 assertEquals("offset-decimals format(1)", "1.0 meters",
1953 m2.format(args, 1, result, ignore, errorCode), TRUE);
1954
1955 args[0] = (int32_t)2;
1956 result.remove();
1957 assertEquals("offset-decimals format(1)", "2.0 meters",
1958 m2.format(args, 1, result, ignore, errorCode), TRUE);
1959
1960 args[0] = (double)2.5;
1961 result.remove();
1962 assertEquals("offset-decimals format(1)", "2.5 meters",
1963 m2.format(args, 1, result, ignore, errorCode), TRUE);
1964 errorCode.reset();
1965 }
1966
TestArgIsPrefixOfAnother()1967 void TestMessageFormat::TestArgIsPrefixOfAnother() {
1968 IcuTestErrorCode errorCode(*this, "TestArgIsPrefixOfAnother");
1969 // Ticket #11952
1970 MessageFormat mf1("{0,select,a{A}ab{AB}abc{ABC}other{?}}", Locale::getEnglish(), errorCode);
1971 Formattable args[3];
1972 FieldPosition ignore;
1973 UnicodeString result;
1974 args[0].setString("a");
1975 assertEquals("a", "A", mf1.format(args, 1, result, ignore, errorCode));
1976 args[0].setString("ab");
1977 assertEquals("ab", "AB", mf1.format(args, 1, result.remove(), ignore, errorCode));
1978 args[0].setString("abc");
1979 assertEquals("abc", "ABC", mf1.format(args, 1, result.remove(), ignore, errorCode));
1980
1981 // Ticket #12172
1982 MessageFormat mf2("{a} {aa} {aaa}", Locale::getEnglish(), errorCode);
1983 UnicodeString argNames[3] = { "a", "aa", "aaa" };
1984 args[0].setString("A");
1985 args[1].setString("AB");
1986 args[2].setString("ABC");
1987 assertEquals("a aa aaa", "A AB ABC", mf2.format(argNames, args, 3, result.remove(), errorCode));
1988
1989 // Ticket #12172
1990 MessageFormat mf3("{aa} {aaa}", Locale::getEnglish(), errorCode);
1991 assertEquals("aa aaa", "AB ABC", mf3.format(argNames + 1, args + 1, 2, result.remove(), errorCode));
1992 }
1993
1994 #endif /* #if !UCONFIG_NO_FORMATTING */
1995