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