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