1 /********************************************************************
2 * Copyright (c) 1997-2007, International Business Machines
3 * Corporation and others. All Rights Reserved.
4 ********************************************************************
5 * File TMSGFMT.CPP
6 *
7 * Modification History:
8 *
9 * Date Name Description
10 * 03/24/97 helena Converted from Java.
11 * 07/11/97 helena Updated to work on AIX.
12 * 08/04/97 jfitz Updated to intltest
13 *******************************************************************/
14
15 #include "unicode/utypes.h"
16
17 #if !UCONFIG_NO_FORMATTING
18
19 #include "tmsgfmt.h"
20
21 #include "unicode/format.h"
22 #include "unicode/decimfmt.h"
23 #include "unicode/locid.h"
24 #include "unicode/msgfmt.h"
25 #include "unicode/numfmt.h"
26 #include "unicode/choicfmt.h"
27 #include "unicode/gregocal.h"
28 #include <stdio.h>
29
30 void
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)31 TestMessageFormat::runIndexedTest(int32_t index, UBool exec,
32 const char* &name, char* /*par*/) {
33 switch (index) {
34 TESTCASE(0,testBug1);
35 TESTCASE(1,testBug2);
36 TESTCASE(2,sample);
37 TESTCASE(3,PatternTest);
38 TESTCASE(4,testStaticFormat);
39 TESTCASE(5,testSimpleFormat);
40 TESTCASE(6,testMsgFormatChoice);
41 TESTCASE(7,testCopyConstructor);
42 TESTCASE(8,testAssignment);
43 TESTCASE(9,testClone);
44 TESTCASE(10,testEquals);
45 TESTCASE(11,testNotEquals);
46 TESTCASE(12,testSetLocale);
47 TESTCASE(13,testFormat);
48 TESTCASE(14,testParse);
49 TESTCASE(15,testAdopt);
50 TESTCASE(16,testCopyConstructor2);
51 TESTCASE(17,TestUnlimitedArgsAndSubformats);
52 TESTCASE(18,TestRBNF);
53 TESTCASE(19,TestTurkishCasing);
54 TESTCASE(20,testAutoQuoteApostrophe);
55 default: name = ""; break;
56 }
57 }
58
testBug3()59 void TestMessageFormat::testBug3()
60 {
61 double myNumber = -123456;
62 DecimalFormat *form = 0;
63 Locale locale[] = {
64 Locale("ar", "", ""),
65 Locale("be", "", ""),
66 Locale("bg", "", ""),
67 Locale("ca", "", ""),
68 Locale("cs", "", ""),
69 Locale("da", "", ""),
70 Locale("de", "", ""),
71 Locale("de", "AT", ""),
72 Locale("de", "CH", ""),
73 Locale("el", "", ""), // 10
74 Locale("en", "CA", ""),
75 Locale("en", "GB", ""),
76 Locale("en", "IE", ""),
77 Locale("en", "US", ""),
78 Locale("es", "", ""),
79 Locale("et", "", ""),
80 Locale("fi", "", ""),
81 Locale("fr", "", ""),
82 Locale("fr", "BE", ""),
83 Locale("fr", "CA", ""), // 20
84 Locale("fr", "CH", ""),
85 Locale("he", "", ""),
86 Locale("hr", "", ""),
87 Locale("hu", "", ""),
88 Locale("is", "", ""),
89 Locale("it", "", ""),
90 Locale("it", "CH", ""),
91 Locale("ja", "", ""),
92 Locale("ko", "", ""),
93 Locale("lt", "", ""), // 30
94 Locale("lv", "", ""),
95 Locale("mk", "", ""),
96 Locale("nl", "", ""),
97 Locale("nl", "BE", ""),
98 Locale("no", "", ""),
99 Locale("pl", "", ""),
100 Locale("pt", "", ""),
101 Locale("ro", "", ""),
102 Locale("ru", "", ""),
103 Locale("sh", "", ""), // 40
104 Locale("sk", "", ""),
105 Locale("sl", "", ""),
106 Locale("sq", "", ""),
107 Locale("sr", "", ""),
108 Locale("sv", "", ""),
109 Locale("tr", "", ""),
110 Locale("uk", "", ""),
111 Locale("zh", "", ""),
112 Locale("zh", "TW", "") // 49
113 };
114 int32_t i;
115 for (i= 0; i < 49; i++) {
116 UnicodeString buffer;
117 logln(locale[i].getDisplayName(buffer));
118 UErrorCode success = U_ZERO_ERROR;
119 // form = (DecimalFormat*)NumberFormat::createCurrencyInstance(locale[i], success);
120 form = (DecimalFormat*)NumberFormat::createInstance(locale[i], success);
121 if (U_FAILURE(success)) {
122 errln("Err: Number Format ");
123 logln("Number format creation failed.");
124 continue;
125 }
126 Formattable result;
127 FieldPosition pos(0);
128 buffer.remove();
129 form->format(myNumber, buffer, pos);
130 success = U_ZERO_ERROR;
131 ParsePosition parsePos;
132 form->parse(buffer, result, parsePos);
133 logln(UnicodeString(" -> ") /* + << dec*/ + toString(result) + UnicodeString("[supposed output for result]"));
134 if (U_FAILURE(success)) {
135 errln("Err: Number Format parse");
136 logln("Number format parse failed.");
137 }
138 delete form;
139 }
140 }
141
testBug1()142 void TestMessageFormat::testBug1()
143 {
144 const double limit[] = {0.0, 1.0, 2.0};
145 const UnicodeString formats[] = {"0.0<=Arg<1.0",
146 "1.0<=Arg<2.0",
147 "2.0<-Arg"};
148 ChoiceFormat *cf = new ChoiceFormat(limit, formats, 3);
149 FieldPosition status(0);
150 UnicodeString toAppendTo;
151 cf->format((int32_t)1, toAppendTo, status);
152 if (toAppendTo != "1.0<=Arg<2.0") {
153 errln("ChoiceFormat cmp in testBug1");
154 }
155 logln(toAppendTo);
156 delete cf;
157 }
158
testBug2()159 void TestMessageFormat::testBug2()
160 {
161 UErrorCode status = U_ZERO_ERROR;
162 UnicodeString result;
163 // {sfb} use double format in pattern, so result will match (not strictly necessary)
164 const UnicodeString pattern = "There {0,choice,0.0#are no files|1.0#is one file|1.0<are {0, number} files} on disk {1}. ";
165 logln("The input pattern : " + pattern);
166 MessageFormat *fmt = new MessageFormat(pattern, status);
167 if (U_FAILURE(status)) {
168 errln("MessageFormat pattern creation failed.");
169 return;
170 }
171 logln("The output pattern is : " + fmt->toPattern(result));
172 if (pattern != result) {
173 errln("MessageFormat::toPattern() failed.");
174 }
175 delete fmt;
176 }
177
178 #if 0
179 #if defined(_DEBUG) && U_IOSTREAM_SOURCE!=0
180 //----------------------------------------------------
181 // console I/O
182 //----------------------------------------------------
183
184 #if U_IOSTREAM_SOURCE >= 199711
185 # include <iostream>
186 std::ostream& operator<<(std::ostream& stream, const Formattable& obj);
187 #elif U_IOSTREAM_SOURCE >= 198506
188 # include <iostream.h>
189 ostream& operator<<(ostream& stream, const Formattable& obj);
190 #endif
191
192 #include "unicode/datefmt.h"
193 #include <stdlib.h>
194 #include <string.h>
195
196 IntlTest&
197 operator<<( IntlTest& stream,
198 const Formattable& obj)
199 {
200 static DateFormat *defDateFormat = 0;
201
202 UnicodeString buffer;
203 switch(obj.getType()) {
204 case Formattable::kDate :
205 if (defDateFormat == 0) {
206 defDateFormat = DateFormat::createInstance();
207 }
208 defDateFormat->format(obj.getDate(), buffer);
209 stream << buffer;
210 break;
211 case Formattable::kDouble :
212 char convert[20];
213 sprintf( convert, "%lf", obj.getDouble() );
214 stream << convert << "D";
215 break;
216 case Formattable::kLong :
217 stream << obj.getLong() << "L";
218 break;
219 case Formattable::kString:
220 stream << "\"" << obj.getString(buffer) << "\"";
221 break;
222 case Formattable::kArray:
223 int32_t i, count;
224 const Formattable* array;
225 array = obj.getArray(count);
226 stream << "[";
227 for (i=0; i<count; ++i) stream << array[i] << ( (i==(count-1)) ? "" : ", " );
228 stream << "]";
229 break;
230 default:
231 stream << "INVALID_Formattable";
232 }
233 return stream;
234 }
235 #endif /* defined(_DEBUG) && U_IOSTREAM_SOURCE!=0 */
236 #endif
237
PatternTest()238 void TestMessageFormat::PatternTest()
239 {
240 Formattable testArgs[] = {
241 Formattable(double(1)), Formattable(double(3456)),
242 Formattable("Disk"), Formattable(UDate((int32_t)1000000000L), Formattable::kIsDate)
243 };
244 UnicodeString testCases[] = {
245 "Quotes '', '{', 'a' {0} '{0}'",
246 "Quotes '', '{', 'a' {0,number} '{0}'",
247 "'{'1,number,'#',##} {1,number,'#',##}",
248 "There are {1} files on {2} at {3}.",
249 "On {2}, there are {1} files, with {0,number,currency}.",
250 "'{1,number,percent}', {1,number,percent},",
251 "'{1,date,full}', {1,date,full},",
252 "'{3,date,full}', {3,date,full},",
253 "'{1,number,#,##}' {1,number,#,##}",
254 };
255
256 UnicodeString testResultPatterns[] = {
257 "Quotes '', '{', a {0} '{'0}",
258 "Quotes '', '{', a {0,number} '{'0}",
259 "'{'1,number,#,##} {1,number,'#'#,##}",
260 "There are {1} files on {2} at {3}.",
261 "On {2}, there are {1} files, with {0,number,currency}.",
262 "'{'1,number,percent}, {1,number,percent},",
263 "'{'1,date,full}, {1,date,full},",
264 "'{'3,date,full}, {3,date,full},",
265 "'{'1,number,#,##} {1,number,#,##}"
266 };
267
268 UnicodeString testResultStrings[] = {
269 "Quotes ', {, a 1 {0}",
270 "Quotes ', {, a 1 {0}",
271 "{1,number,#,##} #34,56",
272 "There are 3,456 files on Disk at 1/12/70 5:46 AM.",
273 "On Disk, there are 3,456 files, with $1.00.",
274 "{1,number,percent}, 345,600%,",
275 "{1,date,full}, Wednesday, December 31, 1969,",
276 "{3,date,full}, Monday, January 12, 1970,",
277 "{1,number,#,##} 34,56"
278 };
279
280
281 for (int32_t i = 0; i < 9; ++i) {
282 //it_out << "\nPat in: " << testCases[i]);
283
284 MessageFormat *form = 0;
285 UErrorCode success = U_ZERO_ERROR;
286 UnicodeString buffer;
287 form = new MessageFormat(testCases[i], Locale::getUS(), success);
288 if (U_FAILURE(success)) {
289 errln("MessageFormat creation failed.#1");
290 logln(((UnicodeString)"MessageFormat for ") + testCases[i] + " creation failed.\n");
291 continue;
292 }
293 if (form->toPattern(buffer) != testResultPatterns[i]) {
294 errln(UnicodeString("TestMessageFormat::PatternTest failed test #2, i = ") + i);
295 //form->toPattern(buffer);
296 errln(((UnicodeString)" Orig: ") + testCases[i]);
297 errln(((UnicodeString)" Exp: ") + testResultPatterns[i]);
298 errln(((UnicodeString)" Got: ") + buffer);
299 }
300
301 //it_out << "Pat out: " << form->toPattern(buffer));
302 UnicodeString result;
303 int32_t count = 4;
304 FieldPosition fieldpos(0);
305 form->format(testArgs, count, result, fieldpos, success);
306 if (U_FAILURE(success)) {
307 errln("MessageFormat failed test #3");
308 logln("TestMessageFormat::PatternTest failed test #3");
309 continue;
310 }
311 if (result != testResultStrings[i]) {
312 errln("TestMessageFormat::PatternTest failed test #4");
313 logln("TestMessageFormat::PatternTest failed #4.");
314 logln(UnicodeString(" Result: ") + result );
315 logln(UnicodeString(" Expected: ") + testResultStrings[i] );
316 }
317
318
319 //it_out << "Result: " << result);
320 #if 0
321 /* TODO: Look at this test and see if this is still a valid test */
322 logln("---------------- test parse ----------------");
323
324 form->toPattern(buffer);
325 logln("MSG pattern for parse: " + buffer);
326
327 int32_t parseCount = 0;
328 Formattable* values = form->parse(result, parseCount, success);
329 if (U_FAILURE(success)) {
330 errln("MessageFormat failed test #5");
331 logln(UnicodeString("MessageFormat failed test #5 with error code ")+(int32_t)success);
332 } else if (parseCount != count) {
333 errln("MSG count not %d as expected. Got %d", count, parseCount);
334 }
335 UBool failed = FALSE;
336 for (int32_t j = 0; j < parseCount; ++j) {
337 if (values == 0 || testArgs[j] != values[j]) {
338 errln(((UnicodeString)"MSG testargs[") + j + "]: " + toString(testArgs[j]));
339 errln(((UnicodeString)"MSG values[") + j + "] : " + toString(values[j]));
340 failed = TRUE;
341 }
342 }
343 if (failed)
344 errln("MessageFormat failed test #6");
345 #endif
346 delete form;
347 }
348 }
349
sample()350 void TestMessageFormat::sample()
351 {
352 MessageFormat *form = 0;
353 UnicodeString buffer1, buffer2;
354 UErrorCode success = U_ZERO_ERROR;
355 form = new MessageFormat("There are {0} files on {1}", success);
356 if (U_FAILURE(success)) {
357 errln("Err: Message format creation failed");
358 logln("Sample message format creation failed.");
359 return;
360 }
361 UnicodeString abc("abc");
362 UnicodeString def("def");
363 Formattable testArgs1[] = { abc, def };
364 FieldPosition fieldpos(0);
365 assertEquals("format",
366 "There are abc files on def",
367 form->format(testArgs1, 2, buffer2, fieldpos, success));
368 assertSuccess("format", success);
369 delete form;
370 }
371
testStaticFormat()372 void TestMessageFormat::testStaticFormat()
373 {
374 UErrorCode err = U_ZERO_ERROR;
375 Formattable arguments[] = {
376 (int32_t)7,
377 Formattable(UDate(8.71068e+011), Formattable::kIsDate),
378 "a disturbance in the Force"
379 };
380
381 UnicodeString result;
382 result = MessageFormat::format(
383 "At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.",
384 arguments,
385 3,
386 result,
387 err);
388
389 if (U_FAILURE(err)) {
390 errln("TestMessageFormat::testStaticFormat #1");
391 logln(UnicodeString("TestMessageFormat::testStaticFormat failed test #1 with error code ")+(int32_t)err);
392 return;
393 }
394
395 const UnicodeString expected(
396 "At 12:20:00 PM on Aug 8, 1997, there was a disturbance in the Force on planet 7.", "");
397 if (result != expected) {
398 errln("TestMessageFormat::testStaticFormat failed on test");
399 logln( UnicodeString(" Result: ") + result );
400 logln( UnicodeString(" Expected: ") + expected );
401 }
402 }
403
404 /* When the default locale is tr, make sure that the pattern can still be parsed. */
TestTurkishCasing()405 void TestMessageFormat::TestTurkishCasing()
406 {
407 UErrorCode err = U_ZERO_ERROR;
408 Locale saveDefaultLocale;
409 Locale::setDefault( Locale("tr"), err );
410
411 Formattable arguments[] = {
412 (int32_t)7,
413 Formattable(UDate(8.71068e+011), Formattable::kIsDate),
414 "a disturbance in the Force"
415 };
416
417 UnicodeString result;
418 result = MessageFormat::format(
419 "At {1,TIME} on {1,DATE,SHORT}, there was {2} on planet {0,NUMBER,INTEGER}.",
420 arguments,
421 3,
422 result,
423 err);
424
425 if (U_FAILURE(err)) {
426 errln("TestTurkishCasing #1 with error code %s", u_errorName(err));
427 return;
428 }
429
430 const UnicodeString expected(
431 "At 12:20:00 on 08.08.1997, there was a disturbance in the Force on planet 7.", "");
432 if (result != expected) {
433 errln("TestTurkishCasing failed on test");
434 errln( UnicodeString(" Result: ") + result );
435 errln( UnicodeString(" Expected: ") + expected );
436 }
437 Locale::setDefault( saveDefaultLocale, err );
438 }
439
testSimpleFormat()440 void TestMessageFormat::testSimpleFormat(/* char* par */)
441 {
442 logln("running TestMessageFormat::testSimpleFormat");
443
444 UErrorCode err = U_ZERO_ERROR;
445
446 Formattable testArgs1[] = {(int32_t)0, "MyDisk"};
447 Formattable testArgs2[] = {(int32_t)1, "MyDisk"};
448 Formattable testArgs3[] = {(int32_t)12, "MyDisk"};
449
450 MessageFormat* form = new MessageFormat(
451 "The disk \"{1}\" contains {0} file(s).", err);
452
453 UnicodeString string;
454 FieldPosition ignore(FieldPosition::DONT_CARE);
455 form->format(testArgs1, 2, string, ignore, err);
456 if (U_FAILURE(err) || string != "The disk \"MyDisk\" contains 0 file(s).") {
457 errln(UnicodeString("TestMessageFormat::testSimpleFormat failed on test #1"));
458 }
459
460 ignore.setField(FieldPosition::DONT_CARE);
461 string.remove();
462 form->format(testArgs2, 2, string, ignore, err);
463 if (U_FAILURE(err) || string != "The disk \"MyDisk\" contains 1 file(s).") {
464 logln(string);
465 errln(UnicodeString("TestMessageFormat::testSimpleFormat failed on test #2")+string);
466 }
467
468 ignore.setField(FieldPosition::DONT_CARE);
469 string.remove();
470 form->format(testArgs3, 2, string, ignore, err);
471 if (U_FAILURE(err) || string != "The disk \"MyDisk\" contains 12 file(s).") {
472 errln(UnicodeString("TestMessageFormat::testSimpleFormat failed on test #3")+string);
473 }
474
475 delete form;
476 }
477
testMsgFormatChoice()478 void TestMessageFormat::testMsgFormatChoice(/* char* par */)
479 {
480 logln("running TestMessageFormat::testMsgFormatChoice");
481
482 UErrorCode err = U_ZERO_ERROR;
483
484 MessageFormat* form = new MessageFormat("The disk \"{1}\" contains {0}.", err);
485 double filelimits[] = {0,1,2};
486 UnicodeString filepart[] = {"no files","one file","{0,number} files"};
487 ChoiceFormat* fileform = new ChoiceFormat(filelimits, filepart, 3);
488 form->setFormat(1,*fileform); // NOT zero, see below
489 //is the format adopted?
490
491 FieldPosition ignore(FieldPosition::DONT_CARE);
492 UnicodeString string;
493 Formattable testArgs1[] = {(int32_t)0, "MyDisk"};
494 form->format(testArgs1, 2, string, ignore, err);
495 if (string != "The disk \"MyDisk\" contains no files.") {
496 errln("TestMessageFormat::testMsgFormatChoice failed on test #1");
497 }
498
499 ignore.setField(FieldPosition::DONT_CARE);
500 string.remove();
501 Formattable testArgs2[] = {(int32_t)1, "MyDisk"};
502 form->format(testArgs2, 2, string, ignore, err);
503 if (string != "The disk \"MyDisk\" contains one file.") {
504 errln("TestMessageFormat::testMsgFormatChoice failed on test #2");
505 }
506
507 ignore.setField(FieldPosition::DONT_CARE);
508 string.remove();
509 Formattable testArgs3[] = {(int32_t)1273, "MyDisk"};
510 form->format(testArgs3, 2, string, ignore, err);
511 if (string != "The disk \"MyDisk\" contains 1,273 files.") {
512 errln("TestMessageFormat::testMsgFormatChoice failed on test #3");
513 }
514
515 delete form;
516 delete fileform;
517 }
518
519
520 //---------------------------------
521 // API Tests
522 //---------------------------------
523
testCopyConstructor()524 void TestMessageFormat::testCopyConstructor()
525 {
526 UErrorCode success = U_ZERO_ERROR;
527 MessageFormat *x = new MessageFormat("There are {0} files on {1}", success);
528 MessageFormat *z = new MessageFormat("There are {0} files on {1} created", success);
529 MessageFormat *y = 0;
530 y = new MessageFormat(*x);
531 if ( (*x == *y) &&
532 (*x != *z) &&
533 (*y != *z) )
534 logln("First test (operator ==): Passed!");
535 else {
536 errln("TestMessageFormat::testCopyConstructor failed #1");
537 logln("First test (operator ==): Failed!");
538 }
539 if ( ((*x == *y) && (*y == *x)) &&
540 ((*x != *z) && (*z != *x)) &&
541 ((*y != *z) && (*z != *y)) )
542 logln("Second test (equals): Passed!");
543 else {
544 errln("TestMessageFormat::testCopyConstructor failed #2");
545 logln("Second test (equals): Failed!");
546 }
547
548 delete x;
549 delete y;
550 delete z;
551 }
552
553
testAssignment()554 void TestMessageFormat::testAssignment()
555 {
556 UErrorCode success = U_ZERO_ERROR;
557 MessageFormat *x = new MessageFormat("There are {0} files on {1}", success);
558 MessageFormat *z = new MessageFormat("There are {0} files on {1} created", success);
559 MessageFormat *y = new MessageFormat("There are {0} files on {1} created", success);
560 *y = *x;
561 if ( (*x == *y) &&
562 (*x != *z) &&
563 (*y != *z) )
564 logln("First test (operator ==): Passed!");
565 else {
566 errln( "TestMessageFormat::testAssignment failed #1");
567 logln("First test (operator ==): Failed!");
568 }
569 if ( ((*x == *y) && (*y == *x)) &&
570 ((*x != *z) && (*z != *x)) &&
571 ((*y != *z) && (*z != *y)) )
572 logln("Second test (equals): Passed!");
573 else {
574 errln("TestMessageFormat::testAssignment failed #2");
575 logln("Second test (equals): Failed!");
576 }
577
578 delete x;
579 delete y;
580 delete z;
581 }
582
testClone()583 void TestMessageFormat::testClone()
584 {
585 UErrorCode success = U_ZERO_ERROR;
586 MessageFormat *x = new MessageFormat("There are {0} files on {1}", success);
587 MessageFormat *z = new MessageFormat("There are {0} files on {1} created", success);
588 MessageFormat *y = 0;
589 y = (MessageFormat*)x->clone();
590 if ( (*x == *y) &&
591 (*x != *z) &&
592 (*y != *z) )
593 logln("First test (operator ==): Passed!");
594 else {
595 errln("TestMessageFormat::testClone failed #1");
596 logln("First test (operator ==): Failed!");
597 }
598 if ( ((*x == *y) && (*y == *x)) &&
599 ((*x != *z) && (*z != *x)) &&
600 ((*y != *z) && (*z != *y)) )
601 logln("Second test (equals): Passed!");
602 else {
603 errln("TestMessageFormat::testClone failed #2");
604 logln("Second test (equals): Failed!");
605 }
606
607 delete x;
608 delete y;
609 delete z;
610 }
611
testEquals()612 void TestMessageFormat::testEquals()
613 {
614 UErrorCode success = U_ZERO_ERROR;
615 MessageFormat x("There are {0} files on {1}", success);
616 MessageFormat y("There are {0} files on {1}", success);
617 if (!(x == y)) {
618 errln( "TestMessageFormat::testEquals failed #1");
619 logln("First test (operator ==): Failed!");
620 }
621
622 }
623
testNotEquals()624 void TestMessageFormat::testNotEquals()
625 {
626 UErrorCode success = U_ZERO_ERROR;
627 MessageFormat x("There are {0} files on {1}", success);
628 MessageFormat y(x);
629 y.setLocale(Locale("fr"));
630 if (!(x != y)) {
631 errln( "TestMessageFormat::testEquals failed #1");
632 logln("First test (operator !=): Failed!");
633 }
634 y = x;
635 y.applyPattern("There are {0} files on {1} the disk", success);
636 if (!(x != y)) {
637 errln( "TestMessageFormat::testEquals failed #1");
638 logln("Second test (operator !=): Failed!");
639 }
640 }
641
642
testSetLocale()643 void TestMessageFormat::testSetLocale()
644 {
645 UErrorCode err = U_ZERO_ERROR;
646 GregorianCalendar cal(err);
647 Formattable arguments[] = {
648 456.83,
649 Formattable(UDate(8.71068e+011), Formattable::kIsDate),
650 "deposit"
651 };
652
653 UnicodeString result;
654
655 //UnicodeString formatStr = "At {1,time} on {1,date}, you made a {2} of {0,number,currency}.";
656 UnicodeString formatStr = "At <time> on {1,date}, you made a {2} of {0,number,currency}.";
657 // {sfb} to get $, would need Locale::US, not Locale::ENGLISH
658 // Just use unlocalized currency symbol.
659 //UnicodeString compareStrEng = "At <time> on Aug 8, 1997, you made a deposit of $456.83.";
660 UnicodeString compareStrEng = "At <time> on Aug 8, 1997, you made a deposit of ";
661 compareStrEng += (UChar) 0x00a4;
662 compareStrEng += "456.83.";
663 // {sfb} to get DM, would need Locale::GERMANY, not Locale::GERMAN
664 // Just use unlocalized currency symbol.
665 //UnicodeString compareStrGer = "At <time> on 08.08.1997, you made a deposit of 456,83 DM.";
666 UnicodeString compareStrGer = "At <time> on 08.08.1997, you made a deposit of ";
667 compareStrGer += "456,83 ";
668 compareStrGer += (UChar) 0x00a4;
669 compareStrGer += ".";
670
671 MessageFormat msg( formatStr, err);
672 result = "";
673 FieldPosition pos(0);
674 result = msg.format(
675 arguments,
676 3,
677 result,
678 pos,
679 err);
680
681 logln(result);
682 if (result != compareStrEng) {
683 errln("*** MSG format err.");
684 }
685
686 msg.setLocale(Locale::getEnglish());
687 UBool getLocale_ok = TRUE;
688 if (msg.getLocale() != Locale::getEnglish()) {
689 errln("*** MSG getLocal err.");
690 getLocale_ok = FALSE;
691 }
692
693 msg.setLocale(Locale::getGerman());
694
695 if (msg.getLocale() != Locale::getGerman()) {
696 errln("*** MSG getLocal err.");
697 getLocale_ok = FALSE;
698 }
699
700 msg.applyPattern( formatStr, err);
701
702 pos.setField(0);
703 result = "";
704 result = msg.format(
705 arguments,
706 3,
707 result,
708 pos,
709 err);
710
711 logln(result);
712 if (result == compareStrGer) {
713 logln("MSG setLocale tested.");
714 }else{
715 errln( "*** MSG setLocale err.");
716 }
717
718 if (getLocale_ok) {
719 logln("MSG getLocale tested.");
720 }
721 }
722
testFormat()723 void TestMessageFormat::testFormat()
724 {
725 UErrorCode err = U_ZERO_ERROR;
726 GregorianCalendar cal(err);
727
728 const Formattable ftarray[] =
729 {
730 Formattable( UDate(8.71068e+011), Formattable::kIsDate )
731 };
732 const int32_t ft_cnt = sizeof(ftarray) / sizeof(Formattable);
733 Formattable ft_arr( ftarray, ft_cnt );
734
735 Formattable* fmt = new Formattable(UDate(8.71068e+011), Formattable::kIsDate);
736
737 UnicodeString result;
738
739 //UnicodeString formatStr = "At {1,time} on {1,date}, you made a {2} of {0,number,currency}.";
740 UnicodeString formatStr = "On {0,date}, it began.";
741 UnicodeString compareStr = "On Aug 8, 1997, it began.";
742
743 err = U_ZERO_ERROR;
744 MessageFormat msg( formatStr, err);
745 FieldPosition fp(0);
746
747 result = "";
748 fp = 0;
749 result = msg.format(
750 *fmt,
751 result,
752 //FieldPosition(0),
753 fp,
754 err);
755
756 if (err != U_ILLEGAL_ARGUMENT_ERROR) {
757 errln("*** MSG format without expected error code.");
758 }
759 err = U_ZERO_ERROR;
760
761 result = "";
762 fp = 0;
763 result = msg.format(
764 ft_arr,
765 result,
766 //FieldPosition(0),
767 fp,
768 err);
769
770 logln("MSG format( Formattable&, ... ) expected:" + compareStr);
771 logln("MSG format( Formattable&, ... ) result:" + result);
772 if (result != compareStr) {
773 errln("*** MSG format( Formattable&, .... ) err.");
774 }else{
775 logln("MSG format( Formattable&, ... ) tested.");
776 }
777
778 delete fmt;
779
780 }
781
testParse()782 void TestMessageFormat::testParse()
783 {
784 UErrorCode err = U_ZERO_ERROR;
785 int32_t count;
786 UnicodeString msgFormatString = "{0} =sep= {1}";
787 MessageFormat msg( msgFormatString, err);
788 UnicodeString source = "abc =sep= def";
789 UnicodeString tmp1, tmp2;
790
791 Formattable* fmt_arr = msg.parse( source, count, err );
792 if (U_FAILURE(err) || (!fmt_arr)) {
793 errln("*** MSG parse (ustring, count, err) error.");
794 }else{
795 logln("MSG parse -- count: %d", count);
796 if (count != 2) {
797 errln("*** MSG parse (ustring, count, err) count err.");
798 }else{
799 if ((fmt_arr[0].getType() == Formattable::kString)
800 && (fmt_arr[1].getType() == Formattable::kString)
801 && (fmt_arr[0].getString(tmp1) == "abc")
802 && (fmt_arr[1].getString(tmp2) == "def")) {
803 logln("MSG parse (ustring, count, err) tested.");
804 }else{
805 errln("*** MSG parse (ustring, count, err) result err.");
806 }
807 }
808 }
809 delete[] fmt_arr;
810
811 ParsePosition pp(0);
812
813 fmt_arr = msg.parse( source, pp, count );
814 if ((pp == 0) || (!fmt_arr)) {
815 errln("*** MSG parse (ustring, parsepos., count) error.");
816 }else{
817 logln("MSG parse -- count: %d", count);
818 if (count != 2) {
819 errln("*** MSG parse (ustring, parsepos., count) count err.");
820 }else{
821 if ((fmt_arr[0].getType() == Formattable::kString)
822 && (fmt_arr[1].getType() == Formattable::kString)
823 && (fmt_arr[0].getString(tmp1) == "abc")
824 && (fmt_arr[1].getString(tmp2) == "def")) {
825 logln("MSG parse (ustring, parsepos., count) tested.");
826 }else{
827 errln("*** MSG parse (ustring, parsepos., count) result err.");
828 }
829 }
830 }
831 delete[] fmt_arr;
832
833 pp = 0;
834 Formattable fmta;
835
836 msg.parseObject( source, fmta, pp );
837 if (pp == 0) {
838 errln("*** MSG parse (ustring, Formattable, parsepos ) error.");
839 }else{
840 logln("MSG parse -- count: %d", count);
841 fmta.getArray(count);
842 if (count != 2) {
843 errln("*** MSG parse (ustring, Formattable, parsepos ) count err.");
844 }else{
845 if ((fmta[0].getType() == Formattable::kString)
846 && (fmta[1].getType() == Formattable::kString)
847 && (fmta[0].getString(tmp1) == "abc")
848 && (fmta[1].getString(tmp2) == "def")) {
849 logln("MSG parse (ustring, Formattable, parsepos ) tested.");
850 }else{
851 errln("*** MSG parse (ustring, Formattable, parsepos ) result err.");
852 }
853 }
854 }
855 }
856
857
testAdopt()858 void TestMessageFormat::testAdopt()
859 {
860 UErrorCode err = U_ZERO_ERROR;
861
862 UnicodeString formatStr("{0,date},{1},{2,number}", "");
863 UnicodeString formatStrChange("{0,number},{1,number},{2,date}", "");
864 err = U_ZERO_ERROR;
865 MessageFormat msg( formatStr, err);
866 MessageFormat msgCmp( formatStr, err);
867 int32_t count, countCmp;
868 const Format** formats = msg.getFormats(count);
869 const Format** formatsCmp = msgCmp.getFormats(countCmp);
870 const Format** formatsChg = 0;
871 const Format** formatsAct = 0;
872 int32_t countAct;
873 const Format* a;
874 const Format* b;
875 UnicodeString patCmp;
876 UnicodeString patAct;
877 Format** formatsToAdopt;
878
879 if (!formats || !formatsCmp || (count <= 0) || (count != countCmp)) {
880 errln("Error getting Formats");
881 return;
882 }
883
884 int32_t i;
885
886 for (i = 0; i < count; i++) {
887 a = formats[i];
888 b = formatsCmp[i];
889 if ((a != NULL) && (b != NULL)) {
890 if (*a != *b) {
891 errln("a != b");
892 return;
893 }
894 }else if ((a != NULL) || (b != NULL)) {
895 errln("(a != NULL) || (b != NULL)");
896 return;
897 }
898 }
899
900 msg.applyPattern( formatStrChange, err ); //set msg formats to something different
901 int32_t countChg;
902 formatsChg = msg.getFormats(countChg); // tested function
903 if (!formatsChg || (countChg != count)) {
904 errln("Error getting Formats");
905 return;
906 }
907
908 UBool diff;
909 diff = TRUE;
910 for (i = 0; i < count; i++) {
911 a = formatsChg[i];
912 b = formatsCmp[i];
913 if ((a != NULL) && (b != NULL)) {
914 if (*a == *b) {
915 logln("formatsChg == formatsCmp at index %d", i);
916 diff = FALSE;
917 }
918 }
919 }
920 if (!diff) {
921 errln("*** MSG getFormats diff err.");
922 return;
923 }
924
925 logln("MSG getFormats tested.");
926
927 msg.setFormats( formatsCmp, countCmp ); //tested function
928
929 formatsAct = msg.getFormats(countAct);
930 if (!formatsAct || (countAct <=0) || (countAct != countCmp)) {
931 errln("Error getting Formats");
932 return;
933 }
934
935 assertEquals("msgCmp.toPattern()", formatStr, msgCmp.toPattern(patCmp.remove()));
936 assertEquals("msg.toPattern()", formatStr, msg.toPattern(patAct.remove()));
937
938 for (i = 0; i < countAct; i++) {
939 a = formatsAct[i];
940 b = formatsCmp[i];
941 if ((a != NULL) && (b != NULL)) {
942 if (*a != *b) {
943 logln("formatsAct != formatsCmp at index %d", i);
944 errln("a != b");
945 return;
946 }
947 }else if ((a != NULL) || (b != NULL)) {
948 errln("(a != NULL) || (b != NULL)");
949 return;
950 }
951 }
952 logln("MSG setFormats tested.");
953
954 //----
955
956 msg.applyPattern( formatStrChange, err ); //set msg formats to something different
957
958 formatsToAdopt = new Format* [countCmp];
959 if (!formatsToAdopt) {
960 errln("memory allocation error");
961 return;
962 }
963
964 for (i = 0; i < countCmp; i++) {
965 if (formatsCmp[i] == NULL) {
966 formatsToAdopt[i] = NULL;
967 }else{
968 formatsToAdopt[i] = formatsCmp[i]->clone();
969 if (!formatsToAdopt[i]) {
970 errln("Can't clone format at index %d", i);
971 return;
972 }
973 }
974 }
975 msg.adoptFormats( formatsToAdopt, countCmp ); // function to test
976 delete[] formatsToAdopt;
977
978 assertEquals("msgCmp.toPattern()", formatStr, msgCmp.toPattern(patCmp.remove()));
979 assertEquals("msg.toPattern()", formatStr, msg.toPattern(patAct.remove()));
980
981 formatsAct = msg.getFormats(countAct);
982 if (!formatsAct || (countAct <=0) || (countAct != countCmp)) {
983 errln("Error getting Formats");
984 return;
985 }
986
987 for (i = 0; i < countAct; i++) {
988 a = formatsAct[i];
989 b = formatsCmp[i];
990 if ((a != NULL) && (b != NULL)) {
991 if (*a != *b) {
992 errln("a != b");
993 return;
994 }
995 }else if ((a != NULL) || (b != NULL)) {
996 errln("(a != NULL) || (b != NULL)");
997 return;
998 }
999 }
1000 logln("MSG adoptFormats tested.");
1001
1002 //---- adoptFormat
1003
1004 msg.applyPattern( formatStrChange, err ); //set msg formats to something different
1005
1006 formatsToAdopt = new Format* [countCmp];
1007 if (!formatsToAdopt) {
1008 errln("memory allocation error");
1009 return;
1010 }
1011
1012 for (i = 0; i < countCmp; i++) {
1013 if (formatsCmp[i] == NULL) {
1014 formatsToAdopt[i] = NULL;
1015 }else{
1016 formatsToAdopt[i] = formatsCmp[i]->clone();
1017 if (!formatsToAdopt[i]) {
1018 errln("Can't clone format at index %d", i);
1019 return;
1020 }
1021 }
1022 }
1023
1024 for ( i = 0; i < countCmp; i++ ) {
1025 msg.adoptFormat( i, formatsToAdopt[i] ); // function to test
1026 }
1027 delete[] formatsToAdopt; // array itself not needed in this case;
1028
1029 assertEquals("msgCmp.toPattern()", formatStr, msgCmp.toPattern(patCmp.remove()));
1030 assertEquals("msg.toPattern()", formatStr, msg.toPattern(patAct.remove()));
1031
1032 formatsAct = msg.getFormats(countAct);
1033 if (!formatsAct || (countAct <=0) || (countAct != countCmp)) {
1034 errln("Error getting Formats");
1035 return;
1036 }
1037
1038 for (i = 0; i < countAct; i++) {
1039 a = formatsAct[i];
1040 b = formatsCmp[i];
1041 if ((a != NULL) && (b != NULL)) {
1042 if (*a != *b) {
1043 errln("a != b");
1044 return;
1045 }
1046 }else if ((a != NULL) || (b != NULL)) {
1047 errln("(a != NULL) || (b != NULL)");
1048 return;
1049 }
1050 }
1051 logln("MSG adoptFormat tested.");
1052 }
1053
1054 // This test is a regression test for a fixed bug in the copy constructor.
1055 // It is kept as a global function rather than as a method since the test depends on memory values.
1056 // (At least before the bug was fixed, whether it showed up or not depended on memory contents,
1057 // which is probably why it didn't show up in the regular test for the copy constructor.)
1058 // For this reason, the test isn't changed even though it contains function calls whose results are
1059 // not tested and had no problems. Actually, the test failed by *crashing*.
_testCopyConstructor2()1060 static void _testCopyConstructor2()
1061 {
1062 UErrorCode status = U_ZERO_ERROR;
1063 UnicodeString formatStr("Hello World on {0,date,full}", "");
1064 UnicodeString resultStr(" ", "");
1065 UnicodeString result;
1066 FieldPosition fp(0);
1067 UDate d = Calendar::getNow();
1068 const Formattable fargs( d, Formattable::kIsDate );
1069
1070 MessageFormat* fmt1 = new MessageFormat( formatStr, status );
1071 MessageFormat* fmt2 = new MessageFormat( *fmt1 );
1072 MessageFormat* fmt3;
1073 MessageFormat* fmt4;
1074
1075 if (fmt1 == NULL) it_err("testCopyConstructor2: (fmt1 != NULL)");
1076
1077 result = fmt1->format( &fargs, 1, resultStr, fp, status );
1078
1079 if (fmt2 == NULL) it_err("testCopyConstructor2: (fmt2 != NULL)");
1080
1081 fmt3 = (MessageFormat*) fmt1->clone();
1082 fmt4 = (MessageFormat*) fmt2->clone();
1083
1084 if (fmt3 == NULL) it_err("testCopyConstructor2: (fmt3 != NULL)");
1085 if (fmt4 == NULL) it_err("testCopyConstructor2: (fmt4 != NULL)");
1086
1087 result = fmt1->format( &fargs, 1, resultStr, fp, status );
1088 result = fmt2->format( &fargs, 1, resultStr, fp, status );
1089 result = fmt3->format( &fargs, 1, resultStr, fp, status );
1090 result = fmt4->format( &fargs, 1, resultStr, fp, status );
1091 delete fmt1;
1092 delete fmt2;
1093 delete fmt3;
1094 delete fmt4;
1095 }
1096
testCopyConstructor2()1097 void TestMessageFormat::testCopyConstructor2() {
1098 _testCopyConstructor2();
1099 }
1100
1101 /**
1102 * Verify that MessageFormat accomodates more than 10 arguments and
1103 * more than 10 subformats.
1104 */
TestUnlimitedArgsAndSubformats()1105 void TestMessageFormat::TestUnlimitedArgsAndSubformats() {
1106 UErrorCode ec = U_ZERO_ERROR;
1107 const UnicodeString pattern =
1108 "On {0,date} (aka {0,date,short}, aka {0,date,long}) "
1109 "at {0,time} (aka {0,time,short}, aka {0,time,long}) "
1110 "there were {1,number} werjes "
1111 "(a {3,number,percent} increase over {2,number}) "
1112 "despite the {4}''s efforts "
1113 "and to delight of {5}, {6}, {7}, {8}, {9}, and {10} {11}.";
1114 MessageFormat msg(pattern, ec);
1115 if (U_FAILURE(ec)) {
1116 errln("FAIL: constructor failed");
1117 return;
1118 }
1119
1120 const Formattable ARGS[] = {
1121 Formattable(UDate(1e13), Formattable::kIsDate),
1122 Formattable((int32_t)1303),
1123 Formattable((int32_t)1202),
1124 Formattable(1303.0/1202 - 1),
1125 Formattable("Glimmung"),
1126 Formattable("the printers"),
1127 Formattable("Nick"),
1128 Formattable("his father"),
1129 Formattable("his mother"),
1130 Formattable("the spiddles"),
1131 Formattable("of course"),
1132 Formattable("Horace"),
1133 };
1134 const int32_t ARGS_LENGTH = sizeof(ARGS) / sizeof(ARGS[0]);
1135 Formattable ARGS_OBJ(ARGS, ARGS_LENGTH);
1136
1137 UnicodeString expected =
1138 "On Nov 20, 2286 (aka 11/20/86, aka November 20, 2286) "
1139 "at 9:46:40 AM (aka 9:46 AM, aka 9:46:40 AM PST) "
1140 "there were 1,303 werjes "
1141 "(a 8% increase over 1,202) "
1142 "despite the Glimmung's efforts "
1143 "and to delight of the printers, Nick, his father, "
1144 "his mother, the spiddles, and of course Horace.";
1145 UnicodeString result;
1146 msg.format(ARGS_OBJ, result, ec);
1147 if (result == expected) {
1148 logln(result);
1149 } else {
1150 errln((UnicodeString)"FAIL: Got " + result +
1151 ", expected " + expected);
1152 }
1153 }
1154
1155 // test RBNF extensions to message format
TestRBNF(void)1156 void TestMessageFormat::TestRBNF(void) {
1157 // WARNING: this depends on the RBNF formats for en_US
1158 Locale locale("en", "US", "");
1159
1160 UErrorCode ec = U_ZERO_ERROR;
1161
1162 UnicodeString values[] = {
1163 // decimal values do not format completely for ordinal or duration, and
1164 // do not always parse, so do not include them
1165 "0", "1", "12", "100", "123", "1001", "123,456", "-17",
1166 };
1167 int32_t values_count = sizeof(values)/sizeof(values[0]);
1168
1169 UnicodeString formats[] = {
1170 "There are {0,spellout} files to search.",
1171 "There are {0,spellout,%simplified} files to search.",
1172 "The bogus spellout {0,spellout,%BOGUS} files behaves like the default.",
1173 "This is the {0,ordinal} file to search.", // TODO fix bug, ordinal does not parse
1174 "Searching this file will take {0,duration} to complete.",
1175 "Searching this file will take {0,duration,%with-words} to complete.",
1176 };
1177 int32_t formats_count = sizeof(formats)/sizeof(formats[0]);
1178
1179 Formattable args[1];
1180
1181 NumberFormat* numFmt = NumberFormat::createInstance(locale, ec);
1182 if (U_FAILURE(ec)) {
1183 dataerrln("Error calling NumberFormat::createInstance()");
1184 return;
1185 }
1186
1187 for (int i = 0; i < formats_count; ++i) {
1188 MessageFormat* fmt = new MessageFormat(formats[i], locale, ec);
1189 logln((UnicodeString)"Testing format pattern: '" + formats[i] + "'");
1190
1191 for (int j = 0; j < values_count; ++j) {
1192 ec = U_ZERO_ERROR;
1193 numFmt->parse(values[j], args[0], ec);
1194 if (U_FAILURE(ec)) {
1195 errln((UnicodeString)"Failed to parse test argument " + values[j]);
1196 } else {
1197 FieldPosition fp(0);
1198 UnicodeString result;
1199 fmt->format(args, 1, result, fp, ec);
1200 logln((UnicodeString)"value: " + toString(args[0]) + " --> " + result + UnicodeString(" ec: ") + u_errorName(ec));
1201
1202 if (i != 3) { // TODO: fix this, for now skip ordinal parsing (format string at index 3)
1203 int32_t count = 0;
1204 Formattable* parseResult = fmt->parse(result, count, ec);
1205 if (count != 1) {
1206 errln((UnicodeString)"parse returned " + count + " args");
1207 } else if (parseResult[0] != args[0]) {
1208 errln((UnicodeString)"parsed argument " + toString(parseResult[0]) + " != " + toString(args[0]));
1209 }
1210 delete []parseResult;
1211 }
1212 }
1213 }
1214 delete fmt;
1215 }
1216 delete numFmt;
1217 }
1218
testAutoQuoteApostrophe(void)1219 void TestMessageFormat::testAutoQuoteApostrophe(void) {
1220 const char* patterns[] = { // pattern, expected pattern
1221 "'", "''",
1222 "''", "''",
1223 "'{", "'{'",
1224 "' {", "'' {",
1225 "'a", "''a",
1226 "'{'a", "'{'a",
1227 "'{a'", "'{a'",
1228 "'{}", "'{}'",
1229 "{'", "{'",
1230 "{'a", "{'a",
1231 "{'a{}'a}'a", "{'a{}'a}''a",
1232 "'}'", "'}'",
1233 "'} '{'}'", "'} '{'}''",
1234 "'} {{{''", "'} {{{'''",
1235 };
1236 int32_t pattern_count = sizeof(patterns)/sizeof(patterns[0]);
1237
1238 for (int i = 0; i < pattern_count; i += 2) {
1239 UErrorCode status = U_ZERO_ERROR;
1240 UnicodeString result = MessageFormat::autoQuoteApostrophe(patterns[i], status);
1241 UnicodeString target(patterns[i+1]);
1242 if (target != result) {
1243 const int BUF2_LEN = 64;
1244 char buf[256];
1245 char buf2[BUF2_LEN];
1246 int32_t len = result.extract(0, result.length(), buf2, BUF2_LEN);
1247 if (len >= BUF2_LEN) {
1248 buf2[BUF2_LEN-1] = 0;
1249 }
1250 sprintf(buf, "[%2d] test \"%s\": target (\"%s\") != result (\"%s\")\n", i/2, patterns[i], patterns[i+1], buf2);
1251 errln(buf);
1252 }
1253 }
1254 }
1255
1256 #endif /* #if !UCONFIG_NO_FORMATTING */
1257