1 /* GENERATED SOURCE. DO NOT MODIFY. */ 2 // 2016 and later: Unicode, Inc. and others. 3 // License & terms of use: http://www.unicode.org/copyright.html#License 4 /* 5 ********************************************************************** 6 * Copyright (c) 2004-2016, International Business Machines 7 * Corporation and others. All Rights Reserved. 8 ********************************************************************** 9 * Author: Alan Liu 10 * Created: April 6, 2004 11 * Since: ICU 3.0 12 ********************************************************************** 13 */ 14 package android.icu.dev.test.format; 15 16 import java.text.AttributedCharacterIterator; 17 import java.text.AttributedString; 18 import java.text.ChoiceFormat; 19 import java.text.FieldPosition; 20 import java.text.Format; 21 import java.text.ParseException; 22 import java.text.ParsePosition; 23 import java.util.Date; 24 import java.util.HashMap; 25 import java.util.Iterator; 26 import java.util.Locale; 27 import java.util.Map; 28 import java.util.Set; 29 import java.util.TreeMap; 30 31 import org.junit.Test; 32 33 import android.icu.text.DateFormat; 34 import android.icu.text.DecimalFormat; 35 import android.icu.text.DecimalFormatSymbols; 36 import android.icu.text.MessageFormat; 37 import android.icu.text.MessagePattern; 38 import android.icu.text.NumberFormat; 39 import android.icu.text.SimpleDateFormat; 40 import android.icu.text.UFormat; 41 import android.icu.util.TimeZone; 42 import android.icu.util.ULocale; 43 44 public class TestMessageFormat extends android.icu.dev.test.TestFmwk { 45 @Test 46 public void TestBug3() 47 { 48 double myNumber = -123456; 49 DecimalFormat form = null; 50 Locale locale[] = { 51 new Locale("ar", "", ""), 52 new Locale("be", "", ""), 53 new Locale("bg", "", ""), 54 new Locale("ca", "", ""), 55 new Locale("cs", "", ""), 56 new Locale("da", "", ""), 57 new Locale("de", "", ""), 58 new Locale("de", "AT", ""), 59 new Locale("de", "CH", ""), 60 new Locale("el", "", ""), // 10 61 new Locale("en", "CA", ""), 62 new Locale("en", "GB", ""), 63 new Locale("en", "IE", ""), 64 new Locale("en", "US", ""), 65 new Locale("es", "", ""), 66 new Locale("et", "", ""), 67 new Locale("fi", "", ""), 68 new Locale("fr", "", ""), 69 new Locale("fr", "BE", ""), 70 new Locale("fr", "CA", ""), // 20 71 new Locale("fr", "CH", ""), 72 new Locale("he", "", ""), 73 new Locale("hr", "", ""), 74 new Locale("hu", "", ""), 75 new Locale("is", "", ""), 76 new Locale("it", "", ""), 77 new Locale("it", "CH", ""), 78 new Locale("ja", "", ""), 79 new Locale("ko", "", ""), 80 new Locale("lt", "", ""), // 30 81 new Locale("lv", "", ""), 82 new Locale("mk", "", ""), 83 new Locale("nl", "", ""), 84 new Locale("nl", "BE", ""), 85 new Locale("no", "", ""), 86 new Locale("pl", "", ""), 87 new Locale("pt", "", ""), 88 new Locale("ro", "", ""), 89 new Locale("ru", "", ""), 90 new Locale("sh", "", ""), // 40 91 new Locale("sk", "", ""), 92 new Locale("sl", "", ""), 93 new Locale("sq", "", ""), 94 new Locale("sr", "", ""), 95 new Locale("sv", "", ""), 96 new Locale("tr", "", ""), 97 new Locale("uk", "", ""), 98 new Locale("zh", "", ""), 99 new Locale("zh", "TW", "") // 49 100 }; 101 StringBuffer buffer = new StringBuffer(); 102 ParsePosition parsePos = new ParsePosition(0); 103 int i; 104 for (i= 0; i < 49; i++) { 105 // form = (DecimalFormat)NumberFormat.getCurrencyInstance(locale[i]); 106 form = (DecimalFormat)NumberFormat.getInstance(locale[i]); 107 if (form == null) { 108 errln("Number format creation failed for " + locale[i].getDisplayName()); 109 continue; 110 } 111 FieldPosition pos = new FieldPosition(0); 112 buffer.setLength(0); 113 form.format(myNumber, buffer, pos); 114 parsePos.setIndex(0); 115 Object result = form.parse(buffer.toString(), parsePos); 116 logln(locale[i].getDisplayName() + " -> " + result); 117 if (parsePos.getIndex() != buffer.length()) { 118 errln("Number format parse failed."); 119 } 120 } 121 } 122 123 @Test 124 public void TestBug1() 125 { 126 final double limit[] = {0.0, 1.0, 2.0}; 127 final String formats[] = {"0.0<=Arg<1.0", 128 "1.0<=Arg<2.0", 129 "2.0<-Arg"}; 130 ChoiceFormat cf = new ChoiceFormat(limit, formats); 131 assertEquals("ChoiceFormat.format", formats[1], cf.format(1)); 132 } 133 134 @Test 135 public void TestBug2() 136 { 137 // {sfb} use double format in pattern, so result will match (not strictly necessary) 138 final String pattern = "There {0,choice,0.0#are no files|1.0#is one file|1.0<are {0, number} files} on disk {1}. "; 139 logln("The input pattern : " + pattern); 140 try { 141 MessageFormat fmt = new MessageFormat(pattern); 142 assertEquals("toPattern", pattern, fmt.toPattern()); 143 } catch (IllegalArgumentException e) { 144 errln("MessageFormat pattern creation failed."); 145 } 146 } 147 148 @Test 149 public void TestPattern() // aka PatternTest() 150 { 151 Object testArgs[] = { 152 new Double(1), new Double(3456), 153 "Disk", new Date(1000000000L) 154 }; 155 String testCases[] = { 156 "Quotes '', '{', 'a' {0} '{0}'", 157 "Quotes '', '{', 'a' {0,number} '{0}'", 158 "'{'1,number,'#',##} {1,number,'#',##}", 159 "There are {1} files on {2} at {3}.", 160 "On {2}, there are {1} files, with {0,number,currency}.", 161 "'{1,number,percent}', {1,number,percent},", 162 "'{1,date,full}', {1,date,full},", 163 "'{3,date,full}', {3,date,full},", 164 "'{1,number,#,##}' {1,number,#,##}", 165 }; 166 167 // ICU 4.8 returns the original pattern (testCases) 168 // rather than toPattern() reconstituting a new, equivalent pattern string (testResultPatterns). 169 /*String testResultPatterns[] = { 170 "Quotes '', '{', a {0} '{'0}", 171 "Quotes '', '{', a {0,number} '{'0}", 172 "'{'1,number,#,##} {1,number,'#'#,##}", 173 "There are {1} files on {2} at {3}.", 174 "On {2}, there are {1} files, with {0,number,currency}.", 175 "'{'1,number,percent}, {1,number,percent},", 176 "'{'1,date,full}, {1,date,full},", 177 "'{'3,date,full}, {3,date,full},", 178 "'{'1,number,#,##} {1,number,#,##}" 179 };*/ 180 181 String testResultStrings[] = { 182 "Quotes ', {, 'a' 1 {0}", 183 "Quotes ', {, 'a' 1 {0}", 184 "{1,number,'#',##} #34,56", 185 "There are 3,456 files on Disk at 1/12/70, 5:46 AM.", 186 "On Disk, there are 3,456 files, with $1.00.", 187 "{1,number,percent}, 345,600%,", 188 "{1,date,full}, Wednesday, December 31, 1969,", 189 "{3,date,full}, Monday, January 12, 1970,", 190 "{1,number,#,##} 34,56" 191 }; 192 193 for (int i = 0; i < 9; ++i) { 194 //it_out << "\nPat in: " << testCases[i]); 195 196 //String buffer; 197 MessageFormat form = null; 198 try { 199 form = new MessageFormat(testCases[i], Locale.US); 200 } catch (IllegalArgumentException e1) { 201 errln("MessageFormat for " + testCases[i] + " creation failed."); 202 continue; 203 } 204 // ICU 4.8 returns the original pattern (testCases) 205 // rather than toPattern() reconstituting a new, equivalent pattern string (testResultPatterns). 206 // assertEquals("\"" + testCases[i] + "\".toPattern()", testResultPatterns[i], form.toPattern()); 207 assertEquals("\"" + testCases[i] + "\".toPattern()", testCases[i], form.toPattern()); 208 // Note: An alternative test would be to build MessagePattern objects for 209 // both the input and output patterns and compare them, taking SKIP_SYNTAX etc. 210 // into account. 211 // (Too much trouble...) 212 213 //it_out << "Pat out: " << form.toPattern(buffer)); 214 StringBuffer result = new StringBuffer(); 215 FieldPosition fieldpos = new FieldPosition(0); 216 form.format(testArgs, result, fieldpos); 217 assertEquals("format", testResultStrings[i], result.toString()); 218 219 //it_out << "Result: " << result); 220 // /* TODO: Look at this test and see if this is still a valid test */ 221 // logln("---------------- test parse ----------------"); 222 // 223 // int count = 4; 224 // form.toPattern(buffer); 225 // logln("MSG pattern for parse: " + buffer); 226 // 227 // int parseCount = 0; 228 // Formattable* values = form.parse(result, parseCount, success); 229 // if (U_FAILURE(success)) { 230 // errln("MessageFormat failed test #5"); 231 // logln(String("MessageFormat failed test #5 with error code ")+(int)success); 232 // } else if (parseCount != count) { 233 // errln("MSG count not %d as expected. Got %d", count, parseCount); 234 // } 235 // UBool failed = FALSE; 236 // for (int j = 0; j < parseCount; ++j) { 237 // if (values == 0 || testArgs[j] != values[j]) { 238 // errln(((String)"MSG testargs[") + j + "]: " + toString(testArgs[j])); 239 // errln(((String)"MSG values[") + j + "] : " + toString(values[j])); 240 // failed = TRUE; 241 // } 242 // } 243 // if (failed) 244 // errln("MessageFormat failed test #6"); 245 } 246 } 247 248 @Test 249 public void TestSample() // aka sample() 250 { 251 MessageFormat form = null; 252 StringBuffer buffer2 = new StringBuffer(); 253 try { 254 form = new MessageFormat("There are {0} files on {1}"); 255 } catch (IllegalArgumentException e1) { 256 errln("Sample message format creation failed."); 257 return; 258 } 259 Object testArgs1[] = { "abc", "def" }; 260 FieldPosition fieldpos = new FieldPosition(0); 261 assertEquals("format", 262 "There are abc files on def", 263 form.format(testArgs1, buffer2, fieldpos).toString()); 264 } 265 266 @Test 267 public void TestStaticFormat() 268 { 269 Object arguments[] = { 270 new Integer(7), 271 new Date(871068000000L), 272 "a disturbance in the Force" 273 }; 274 275 assertEquals("format", 276 "At 12:20:00 PM on Aug 8, 1997, there was a disturbance in the Force on planet 7.", 277 MessageFormat.format("At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.", 278 arguments)); 279 } 280 281 static final int FieldPosition_DONT_CARE = -1; 282 283 @Test 284 public void TestSimpleFormat() 285 { 286 Object testArgs1[] = {new Integer(0), "MyDisk"}; 287 Object testArgs2[] = {new Integer(1), "MyDisk"}; 288 Object testArgs3[] = {new Integer(12), "MyDisk"}; 289 290 MessageFormat form = new MessageFormat( 291 "The disk \"{1}\" contains {0} file(s)."); 292 293 StringBuffer string = new StringBuffer(); 294 FieldPosition ignore = new FieldPosition(FieldPosition_DONT_CARE); 295 form.format(testArgs1, string, ignore); 296 assertEquals("format", 297 "The disk \"MyDisk\" contains 0 file(s).", 298 string.toString()); 299 300 string.setLength(0); 301 form.format(testArgs2, string, ignore); 302 assertEquals("format", 303 "The disk \"MyDisk\" contains 1 file(s).", 304 string.toString()); 305 306 string.setLength(0); 307 form.format(testArgs3, string, ignore); 308 assertEquals("format", 309 "The disk \"MyDisk\" contains 12 file(s).", 310 string.toString()); 311 } 312 313 @Test 314 public void TestMsgFormatChoice() 315 { 316 MessageFormat form = new MessageFormat("The disk \"{1}\" contains {0}."); 317 double filelimits[] = {0,1,2}; 318 String filepart[] = {"no files","one file","{0,number} files"}; 319 ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart); 320 form.setFormat(1, fileform); // NOT zero, see below 321 322 FieldPosition ignore = new FieldPosition(FieldPosition_DONT_CARE); 323 StringBuffer string = new StringBuffer(); 324 Object testArgs1[] = {new Integer(0), "MyDisk"}; 325 form.format(testArgs1, string, ignore); 326 assertEquals("format#1", 327 "The disk \"MyDisk\" contains no files.", 328 string.toString()); 329 330 string.setLength(0); 331 Object testArgs2[] = {new Integer(1), "MyDisk"}; 332 form.format(testArgs2, string, ignore); 333 assertEquals("format#2", 334 "The disk \"MyDisk\" contains one file.", 335 string.toString()); 336 337 string.setLength(0); 338 Object testArgs3[] = {new Integer(1273), "MyDisk"}; 339 form.format(testArgs3, string, ignore); 340 assertEquals("format#3", 341 "The disk \"MyDisk\" contains 1,273 files.", 342 string.toString()); 343 } 344 345 //--------------------------------- 346 // API Tests 347 //--------------------------------- 348 349 @Test 350 public void TestClone() 351 { 352 MessageFormat x = new MessageFormat("There are {0} files on {1}"); 353 MessageFormat z = new MessageFormat("There are {0} files on {1} created"); 354 MessageFormat y = null; 355 y = (MessageFormat)x.clone(); 356 if (x.equals(y) && 357 !x.equals(z) && 358 !y.equals(z) ) 359 logln("First test (operator ==): Passed!"); 360 else { 361 errln("First test (operator ==): Failed!"); 362 } 363 if ((x.equals(y) && y.equals(x)) && 364 (!x.equals(z) && !z.equals(x)) && 365 (!y.equals(z) && !z.equals(y)) ) 366 logln("Second test (equals): Passed!"); 367 else { 368 errln("Second test (equals): Failed!"); 369 } 370 371 } 372 373 @Test 374 public void TestEquals() 375 { 376 MessageFormat x = new MessageFormat("There are {0} files on {1}"); 377 MessageFormat y = new MessageFormat("There are {0} files on {1}"); 378 if (!x.equals(y)) { 379 errln("First test (operator ==): Failed!"); 380 } 381 382 } 383 384 @Test 385 public void TestNotEquals() 386 { 387 MessageFormat x = new MessageFormat("There are {0} files on {1}"); 388 MessageFormat y = new MessageFormat("There are {0} files on {1}"); 389 y.setLocale(Locale.FRENCH); 390 if (x.equals(y)) { 391 errln("First test (operator !=): Failed!"); 392 } 393 y = new MessageFormat("There are {0} files on {1}"); 394 y.applyPattern("There are {0} files on {1} the disk"); 395 if (x.equals(y)) { 396 errln("Second test (operator !=): Failed!"); 397 } 398 } 399 400 @Test 401 public void TestHashCode() 402 { 403 ULocale save = ULocale.getDefault(); 404 ULocale.setDefault(ULocale.US); 405 406 MessageFormat x = new MessageFormat("There are {0} files on {1}"); 407 MessageFormat z = new MessageFormat("There are {0} files on {1}"); 408 MessageFormat y = null; 409 y = (MessageFormat)x.clone(); 410 if (x.hashCode() != y.hashCode()) 411 errln("FAIL: identical objects have different hashcodes"); 412 if (x.hashCode() != z.hashCode()) 413 errln("FAIL: identical objects have different hashcodes"); 414 415 /* These are not errors 416 y.setLocale(ULocale.FRENCH); 417 if (x.hashCode() == y.hashCode()) 418 errln("FAIL: different objects have same hashcodes. Locale ignored"); 419 420 z.applyPattern("There are {0} files on {1} the disk"); 421 if (x.hashCode() == z.hashCode()) 422 errln("FAIL: different objects have same hashcodes. Pattern ignored"); 423 */ 424 425 ULocale.setDefault(save); 426 } 427 428 @Test 429 public void TestSetLocale() 430 { 431 Object arguments[] = { 432 new Double(456.83), 433 new Date(871068000000L), 434 "deposit" 435 }; 436 437 StringBuffer result = new StringBuffer(); 438 439 //String formatStr = "At {1,time} on {1,date}, you made a {2} of {0,number,currency}."; 440 String formatStr = "At <time> on {1,date}, you made a {2} of {0,number,currency}."; 441 // {sfb} to get $, would need Locale::US, not Locale::ENGLISH 442 // Just use unlocalized currency symbol. 443 //String compareStrEng = "At <time> on Aug 8, 1997, you made a deposit of $456.83."; 444 String compareStrEng = "At <time> on Aug 8, 1997, you made a deposit of "; 445 compareStrEng += '\u00a4'; 446 compareStrEng += "456.83."; 447 // {sfb} to get DM, would need Locale::GERMANY, not Locale::GERMAN 448 // Just use unlocalized currency symbol. 449 //String compareStrGer = "At <time> on 08.08.1997, you made a deposit of 456,83 DM."; 450 String compareStrGer = "At <time> on 08.08.1997, you made a deposit of "; 451 compareStrGer += "456,83\u00a0"; 452 compareStrGer += '\u00a4'; 453 compareStrGer += "."; 454 455 MessageFormat msg = new MessageFormat(formatStr, Locale.ENGLISH); 456 result.setLength(0); 457 FieldPosition pos = new FieldPosition(0); 458 result = msg.format( 459 arguments, 460 result, 461 pos); 462 assertEquals("format", compareStrEng, result.toString()); 463 464 msg.setLocale(Locale.ENGLISH); 465 assertEquals("getLocale", Locale.ENGLISH, msg.getLocale()); 466 467 msg.setLocale(Locale.GERMAN); 468 assertEquals("getLocale", Locale.GERMAN, msg.getLocale()); 469 470 msg.applyPattern(formatStr); 471 result.setLength(0); 472 result = msg.format( 473 arguments, 474 result, 475 pos); 476 assertEquals("format", compareStrGer, result.toString()); 477 478 //Cover getULocale() 479 logln("Testing set/get ULocale ..."); 480 msg.setLocale(ULocale.ENGLISH); 481 assertEquals("getULocale", ULocale.ENGLISH, msg.getULocale()); 482 483 msg.setLocale(ULocale.GERMAN); 484 assertEquals("getULocale", ULocale.GERMAN, msg.getULocale()); 485 486 msg.applyPattern(formatStr); 487 result.setLength(0); 488 result = msg.format( 489 arguments, 490 result, 491 pos); 492 assertEquals("format", compareStrGer, result.toString()); 493 } 494 495 @SuppressWarnings("static-access") 496 @Test 497 public void TestFormat() 498 { 499 final Object ft_arr[] = 500 { 501 new Date(871068000000L) 502 }; 503 504 StringBuffer result = new StringBuffer(); 505 506 //String formatStr = "At {1,time} on {1,date}, you made a {2} of {0,number,currency}."; 507 String formatStr = "On {0,date}, it began."; 508 String compareStr = "On Aug 8, 1997, it began."; 509 510 MessageFormat msg = new MessageFormat(formatStr); 511 FieldPosition fp = new FieldPosition(0); 512 513 try { 514 msg.format(new Date(871068000000L), 515 result, 516 fp); 517 errln("*** MSG format without expected error code."); 518 } catch (Exception e1) { 519 } 520 521 result.setLength(0); 522 result = msg.format( 523 ft_arr, 524 result, 525 fp); 526 assertEquals("format", compareStr, result.toString()); 527 528 Map<String,Object> map = new HashMap<String,Object>(); 529 try{ 530 msg.format("", map); 531 } catch(Exception e){ 532 errln("MessageFormat.format(String,Map) was not suppose to return " + 533 "an exception."); 534 } 535 } 536 537 @Test 538 public void TestParse() 539 { 540 String msgFormatString = "{0} =sep= {1}"; 541 MessageFormat msg = new MessageFormat(msgFormatString); 542 String source = "abc =sep= def"; 543 544 try { 545 Object[] fmt_arr = msg.parse(source); 546 if (fmt_arr.length != 2) { 547 errln("*** MSG parse (ustring, count, err) count err."); 548 } else { 549 // TODO: This if statement seems to be redundant. [tschumann] 550 if (fmt_arr.length != 2) { 551 errln("*** MSG parse (ustring, parsepos., count) count err."); 552 } else { 553 assertEquals("parse()[0]", "abc", fmt_arr[0]); 554 assertEquals("parse()[1]", "def", fmt_arr[1]); 555 } 556 } 557 } catch (ParseException e1) { 558 errln("*** MSG parse (ustring, count, err) error."); 559 } 560 561 ParsePosition pp = new ParsePosition(0); 562 563 Object[] fmt_arr = msg.parse(source, pp); 564 if (pp.getIndex()==0 || fmt_arr==null) { 565 errln("*** MSG parse (ustring, parsepos., count) error."); 566 } else { 567 if (fmt_arr.length != 2) { 568 errln("*** MSG parse (ustring, parsepos., count) count err."); 569 } else { 570 assertEquals("parse()[0]", "abc", fmt_arr[0]); 571 assertEquals("parse()[1]", "def", fmt_arr[1]); 572 } 573 } 574 575 pp.setIndex(0); 576 Object[] fmta; 577 578 fmta = (Object[]) msg.parseObject( source, pp ); 579 if (pp.getIndex() == 0) { 580 errln("*** MSG parse (ustring, Object, parsepos ) error."); 581 } else { 582 if (fmta.length != 2) { 583 errln("*** MSG parse (ustring, count, err) count err."); 584 } else { 585 // TODO: Don't we want to check fmta? 586 // In this case this if statement would be redundant, too. 587 // [tschumann] 588 if (fmt_arr.length != 2) { 589 errln("*** MSG parse (ustring, parsepos., count) count err."); 590 } else { 591 // TODO: Don't we want to check fmta? [tschumann] 592 assertEquals("parse()[0]", "abc", fmt_arr[0]); 593 assertEquals("parse()[1]", "def", fmt_arr[1]); 594 } 595 } 596 } 597 } 598 599 /** 600 * Of course, in Java there is no adopt, but we retain the same 601 * method name. [alan] 602 */ 603 @Test 604 public void TestAdopt() 605 { 606 String formatStr = "{0,date},{1},{2,number}"; 607 String formatStrChange = "{0,number},{1,number},{2,date}"; 608 MessageFormat msg = new MessageFormat(formatStr); 609 MessageFormat msgCmp = new MessageFormat(formatStr); 610 Format[] formats = msg.getFormats(); 611 Format[] formatsCmp = msgCmp.getFormats(); 612 Format[] formatsChg = null; 613 Format[] formatsAct = null; 614 Format a = null; 615 Format b = null; 616 Format[] formatsToAdopt = null; 617 618 if (formats==null || formatsCmp==null || (formats.length <= 0) || (formats.length != formatsCmp.length)) { 619 errln("Error getting Formats"); 620 return; 621 } 622 623 int i; 624 625 for (i = 0; i < formats.length; i++) { 626 a = formats[i]; 627 b = formatsCmp[i]; 628 if ((a != null) && (b != null)) { 629 if (!a.equals(b)) { 630 errln("a != b"); 631 return; 632 } 633 } else if ((a != null) || (b != null)) { 634 errln("(a != null) || (b != null)"); 635 return; 636 } 637 } 638 639 msg.applyPattern( formatStrChange ); //set msg formats to something different 640 formatsChg = msg.getFormats(); // tested function 641 if (formatsChg==null || (formatsChg.length != formats.length)) { 642 errln("Error getting Formats"); 643 return; 644 } 645 646 boolean diff; 647 diff = true; 648 for (i = 0; i < formats.length; i++) { 649 a = formatsChg[i]; 650 b = formatsCmp[i]; 651 if ((a != null) && (b != null)) { 652 if (a.equals(b)) { 653 logln("formatsChg == formatsCmp at index " + i); 654 diff = false; 655 } 656 } 657 } 658 if (!diff) { 659 errln("*** MSG getFormats diff err."); 660 return; 661 } 662 663 logln("MSG getFormats tested."); 664 665 msg.setFormats( formatsCmp ); //tested function 666 667 formatsAct = msg.getFormats(); 668 if (formatsAct==null || (formatsAct.length <=0) || (formatsAct.length != formatsCmp.length)) { 669 errln("Error getting Formats"); 670 return; 671 } 672 673 assertEquals("msgCmp.toPattern()", formatStr, msgCmp.toPattern()); 674 // ICU 4.8 does not support toPattern() when there are custom formats (from setFormat() etc.). 675 // assertEquals("msg.toPattern()", formatStr, msg.toPattern()); 676 try { 677 msg.toPattern(); 678 errln("msg.setFormat().toPattern() does not throw an IllegalStateException"); 679 } catch(IllegalStateException e) { 680 // ok 681 } 682 683 for (i = 0; i < formatsAct.length; i++) { 684 a = formatsAct[i]; 685 b = formatsCmp[i]; 686 if ((a != null) && (b != null)) { 687 if (!a.equals(b)) { 688 errln("formatsAct != formatsCmp at index " + i); 689 return; 690 } 691 } else if ((a != null) || (b != null)) { 692 errln("(a != null) || (b != null)"); 693 return; 694 } 695 } 696 logln("MSG setFormats tested."); 697 698 //---- 699 700 msg.applyPattern( formatStrChange ); //set msg formats to something different 701 702 formatsToAdopt = new Format[formatsCmp.length]; 703 if (formatsToAdopt==null) { 704 errln("memory allocation error"); 705 return; 706 } 707 708 for (i = 0; i < formatsCmp.length; i++) { 709 if (formatsCmp[i] == null) { 710 formatsToAdopt[i] = null; 711 } else { 712 formatsToAdopt[i] = (Format) formatsCmp[i].clone(); 713 if (formatsToAdopt[i]==null) { 714 errln("Can't clone format at index " + i); 715 return; 716 } 717 } 718 } 719 msg.setFormats( formatsToAdopt ); // function to test 720 721 assertEquals("msgCmp.toPattern()", formatStr, msgCmp.toPattern()); 722 // ICU 4.8 does not support toPattern() when there are custom formats (from setFormat() etc.). 723 // assertEquals("msg.toPattern()", formatStr, msg.toPattern()); 724 725 formatsAct = msg.getFormats(); 726 if (formatsAct==null || (formatsAct.length <=0) || (formatsAct.length != formatsCmp.length)) { 727 errln("Error getting Formats"); 728 return; 729 } 730 731 for (i = 0; i < formatsAct.length; i++) { 732 a = formatsAct[i]; 733 b = formatsCmp[i]; 734 if ((a != null) && (b != null)) { 735 if (!a.equals(b)) { 736 errln("a != b"); 737 return; 738 } 739 } else if ((a != null) || (b != null)) { 740 errln("(a != null) || (b != null)"); 741 return; 742 } 743 } 744 logln("MSG adoptFormats tested."); 745 746 //---- adoptFormat 747 748 msg.applyPattern( formatStrChange ); //set msg formats to something different 749 750 formatsToAdopt = new Format[formatsCmp.length]; 751 if (formatsToAdopt==null) { 752 errln("memory allocation error"); 753 return; 754 } 755 756 for (i = 0; i < formatsCmp.length; i++) { 757 if (formatsCmp[i] == null) { 758 formatsToAdopt[i] = null; 759 } else { 760 formatsToAdopt[i] = (Format) formatsCmp[i].clone(); 761 if (formatsToAdopt[i]==null) { 762 errln("Can't clone format at index " + i); 763 return; 764 } 765 } 766 } 767 768 for ( i = 0; i < formatsCmp.length; i++ ) { 769 msg.setFormat( i, formatsToAdopt[i] ); // function to test 770 } 771 772 assertEquals("msgCmp.toPattern()", formatStr, msgCmp.toPattern()); 773 // ICU 4.8 does not support toPattern() when there are custom formats (from setFormat() etc.). 774 // assertEquals("msg.toPattern()", formatStr, msg.toPattern()); 775 776 formatsAct = msg.getFormats(); 777 if (formatsAct==null || (formatsAct.length <=0) || (formatsAct.length != formatsCmp.length)) { 778 errln("Error getting Formats"); 779 return; 780 } 781 782 for (i = 0; i < formatsAct.length; i++) { 783 a = formatsAct[i]; 784 b = formatsCmp[i]; 785 if ((a != null) && (b != null)) { 786 if (!a.equals(b)) { 787 errln("a != b"); 788 return; 789 } 790 } else if ((a != null) || (b != null)) { 791 errln("(a != null) || (b != null)"); 792 return; 793 } 794 } 795 logln("MSG adoptFormat tested."); 796 } 797 798 /** 799 * Verify that MessageFormat accomodates more than 10 arguments and 800 * more than 10 subformats. 801 */ 802 @Test 803 public void TestUnlimitedArgsAndSubformats() { 804 final String pattern = 805 "On {0,date} (aka {0,date,short}, aka {0,date,long}) "+ 806 "at {0,time} (aka {0,time,short}, aka {0,time,long}) "+ 807 "there were {1,number} werjes "+ 808 "(a {3,number,percent} increase over {2,number}) "+ 809 "despite the {4}''s efforts "+ 810 "and to delight of {5}, {6}, {7}, {8}, {9}, and {10} {11}."; 811 try { 812 MessageFormat msg = new MessageFormat(pattern); 813 814 final Object ARGS[] = { 815 new Date(10000000000000L), 816 new Integer(1303), 817 new Integer(1202), 818 new Double(1303.0/1202 - 1), 819 "Glimmung", 820 "the printers", 821 "Nick", 822 "his father", 823 "his mother", 824 "the spiddles", 825 "of course", 826 "Horace" 827 }; 828 829 String expected = 830 "On Nov 20, 2286 (aka 11/20/86, aka November 20, 2286) "+ 831 "at 9:46:40 AM (aka 9:46 AM, aka 9:46:40 AM PST) "+ 832 "there were 1,303 werjes "+ 833 "(a 8% increase over 1,202) "+ 834 "despite the Glimmung's efforts "+ 835 "and to delight of the printers, Nick, his father, "+ 836 "his mother, the spiddles, and of course Horace."; 837 assertEquals("format", expected, msg.format(ARGS)); 838 } catch (IllegalArgumentException e1) { 839 errln("FAIL: constructor failed"); 840 } 841 } 842 843 // test RBNF extensions to message format 844 @Test 845 public void TestRBNF() { 846 // WARNING: this depends on the RBNF formats for en_US 847 Locale locale = Locale.US; 848 String[] values = { 849 // decimal values do not format completely for ordinal or duration, and 850 // do not always parse, so do not include them 851 "0", "1", "12", "100", "123", "1001", "123,456", "-17", 852 }; 853 String[] formats = { 854 "There are {0,spellout} files to search.", 855 "There are {0,spellout,%simplified} files to search.", 856 "The bogus spellout {0,spellout,%BOGUS} files behaves like the default.", 857 "This is the {0,ordinal} file to search.", // TODO fix bug, ordinal does not parse 858 "Searching this file will take {0,duration} to complete.", 859 "Searching this file will take {0,duration,%with-words} to complete.", 860 }; 861 final NumberFormat numFmt = NumberFormat.getInstance(locale); 862 Object[] args = new Object[1]; 863 Number num = null; 864 for (int i = 0; i < formats.length; ++i) { 865 MessageFormat fmt = new MessageFormat(formats[i], locale); 866 logln("Testing format pattern: '" + formats[i] + "'"); 867 for (int j = 0; j < values.length; ++j) { 868 try { 869 num = numFmt.parse(values[j]); 870 } 871 catch (Exception e) { 872 throw new IllegalStateException("failed to parse test argument"); 873 } 874 args[0] = num; 875 String result = fmt.format(args); 876 logln("value: " + num + " --> " + result); 877 878 if (i != 3) { // TODO: fix this, for now skip ordinal parsing (format string at index 3) 879 try { 880 Object[] parsedArgs = fmt.parse(result); 881 if (parsedArgs.length != 1) { 882 errln("parse returned " + parsedArgs.length + " args"); 883 } else if (!parsedArgs[0].equals(num)) { 884 errln("parsed argument " + parsedArgs[0] + " != " + num); 885 } 886 } 887 catch (Exception e) { 888 errln("parse of '" + result + " returned exception: " + e.getMessage()); 889 } 890 } 891 } 892 } 893 } 894 895 @Test 896 public void TestSetGetFormats() 897 { 898 Object arguments[] = { 899 new Double(456.83), 900 new Date(871068000000L), 901 "deposit" 902 }; 903 904 StringBuffer result = new StringBuffer(); 905 906 String formatStr = "At <time> on {1,date}, you made a {2} of {0,number,currency}."; 907 // original expected format result 908 String compareStr = "At <time> on Aug 8, 1997, you made a deposit of $456.83."; 909 // the date being German-style, but the currency being English-style 910 String compareStr2 = "At <time> on 08.08.1997, you made a deposit of "; 911 compareStr2 += '\u00a4'; 912 compareStr2 += "456.83."; 913 // both date and currency formats are German-style 914 String compareStr3 = "At <time> on 08.08.1997, you made a deposit of "; 915 compareStr3 += "456,83\u00a0"; 916 compareStr3 += '\u00a4'; 917 compareStr3 += "."; 918 919 MessageFormat msg = new MessageFormat(formatStr, ULocale.US); 920 result.setLength(0); 921 FieldPosition pos = new FieldPosition(0); 922 result = msg.format( 923 arguments, 924 result, 925 pos); 926 assertEquals("format", compareStr, result.toString()); 927 928 // constructs a Format array with a English-style Currency formatter 929 // and a German-style Date formatter 930 // might not meaningful, just for testing setFormatsByArgIndex 931 Format[] fmts = new Format[] { 932 NumberFormat.getCurrencyInstance(ULocale.ENGLISH), 933 DateFormat.getDateInstance(DateFormat.DEFAULT, ULocale.GERMAN) 934 }; 935 936 msg.setFormatsByArgumentIndex(fmts); 937 result.setLength(0); 938 pos = new FieldPosition(0); 939 result = msg.format( 940 arguments, 941 result, 942 pos); 943 assertEquals("format", compareStr2, result.toString()); 944 945 // Construct a German-style Currency formatter, replace the corresponding one 946 // Thus both formatters should format objects with German-style 947 Format newFmt = NumberFormat.getCurrencyInstance(ULocale.GERMAN); 948 msg.setFormatByArgumentIndex(0, newFmt); 949 result.setLength(0); 950 pos = new FieldPosition(0); 951 result = msg.format( 952 arguments, 953 result, 954 pos); 955 assertEquals("format", compareStr3, result.toString()); 956 957 // verify getFormatsByArgumentIndex 958 // you should got three formats by that 959 // - DecimalFormat locale: de 960 // - SimpleDateFormat locale: de 961 // - null 962 Format[] fmts2 = msg.getFormatsByArgumentIndex(); 963 assertEquals("1st subformmater: Format Class", "android.icu.text.DecimalFormat", fmts2[0].getClass().getName()); 964 assertEquals("1st subformmater: its Locale", ULocale.GERMAN, ((UFormat)fmts2[0]).getLocale(ULocale.VALID_LOCALE)); 965 assertEquals("2nd subformatter: Format Class", "android.icu.text.SimpleDateFormat", fmts2[1].getClass().getName()); 966 assertEquals("2nd subformmater: its Locale", ULocale.GERMAN, ((UFormat)fmts2[1]).getLocale(ULocale.VALID_LOCALE)); 967 assertTrue("The third subFormatter is null", null == fmts2[2]); 968 } 969 970 // Test the fix pattern api 971 @Test 972 public void TestAutoQuoteApostrophe() { 973 final String[] patterns = { // new pattern, expected pattern 974 "'", "''", 975 "''", "''", 976 "'{", "'{'", 977 "' {", "'' {", 978 "'a", "''a", 979 "'{'a", "'{'a", 980 "'{a'", "'{a'", 981 "'{}", "'{}'", 982 "{'", "{'", 983 "{'a", "{'a", 984 "{'a{}'a}'a", "{'a{}'a}''a", 985 "'}'", "'}'", 986 "'} '{'}'", "'} '{'}''", 987 "'} {{{''", "'} {{{'''", 988 }; 989 for (int i = 0; i < patterns.length; i += 2) { 990 assertEquals("[" + (i/2) + "] \"" + patterns[i] + "\"", patterns[i+1], MessageFormat.autoQuoteApostrophe(patterns[i])); 991 } 992 } 993 994 // This tests passing named arguments instead of numbers to format(). 995 @Test 996 public void testFormatNamedArguments() { 997 Map arguments = new HashMap(); 998 arguments.put("startDate", new Date(871068000000L)); 999 1000 StringBuffer result = new StringBuffer(); 1001 1002 String formatStr = "On {startDate,date}, it began."; 1003 String compareStr = "On Aug 8, 1997, it began."; 1004 1005 MessageFormat msg = new MessageFormat(formatStr); 1006 FieldPosition fp = new FieldPosition(0); 1007 1008 try { 1009 msg.format(arguments.get("startDate"), result, fp); 1010 errln("*** MSG format without expected error code."); 1011 } catch (Exception e1) { 1012 } 1013 1014 result.setLength(0); 1015 result = msg.format( 1016 arguments, 1017 result, 1018 fp); 1019 assertEquals("format", compareStr, result.toString()); 1020 } 1021 1022 // This tests parsing formatted messages with named arguments instead of 1023 // numbers. 1024 @Test 1025 public void testParseNamedArguments() { 1026 String msgFormatString = "{foo} =sep= {bar}"; 1027 MessageFormat msg = new MessageFormat(msgFormatString); 1028 String source = "abc =sep= def"; 1029 1030 try { 1031 Map fmt_map = msg.parseToMap(source); 1032 if (fmt_map.keySet().size() != 2) { 1033 errln("*** MSG parse (ustring, count, err) count err."); 1034 } else { 1035 assertEquals("parse()[0]", "abc", fmt_map.get("foo")); 1036 assertEquals("parse()[1]", "def", fmt_map.get("bar")); 1037 } 1038 } catch (ParseException e1) { 1039 errln("*** MSG parse (ustring, count, err) error."); 1040 } 1041 1042 ParsePosition pp = new ParsePosition(0); 1043 Map fmt_map = msg.parseToMap(source, pp); 1044 if (pp.getIndex()==0 || fmt_map==null) { 1045 errln("*** MSG parse (ustring, parsepos., count) error."); 1046 } else { 1047 if (fmt_map.keySet().size() != 2) { 1048 errln("*** MSG parse (ustring, parsepos., count) count err."); 1049 } else { 1050 assertEquals("parse()[0]", "abc", fmt_map.get("foo")); 1051 assertEquals("parse()[1]", "def", fmt_map.get("bar")); 1052 } 1053 } 1054 1055 pp.setIndex(0); 1056 1057 Map fmta = (Map) msg.parseObject( source, pp ); 1058 if (pp.getIndex() == 0) { 1059 errln("*** MSG parse (ustring, Object, parsepos ) error."); 1060 } else { 1061 if (fmta.keySet().size() != 2) { 1062 errln("*** MSG parse (ustring, count, err) count err."); 1063 } else { 1064 assertEquals("parse()[0]", "abc", fmta.get("foo")); 1065 assertEquals("parse()[1]", "def", fmta.get("bar")); 1066 } 1067 } 1068 } 1069 1070 // Ensure that methods designed for numeric arguments only, will throw 1071 // an exception when called on MessageFormat objects created with 1072 // named arguments. 1073 @Test 1074 public void testNumericOnlyMethods() { 1075 MessageFormat msg = new MessageFormat("Number of files: {numfiles}"); 1076 boolean gotException = false; 1077 try { 1078 Format fmts[] = {new DecimalFormat()}; 1079 msg.setFormatsByArgumentIndex(fmts); 1080 } catch (IllegalArgumentException e) { 1081 gotException = true; 1082 } 1083 if (!gotException) { 1084 errln("MessageFormat.setFormatsByArgumentIndex() should throw an " + 1085 "IllegalArgumentException when called on formats with " + 1086 "named arguments but did not!"); 1087 } 1088 1089 gotException = false; 1090 try { 1091 msg.setFormatByArgumentIndex(0, new DecimalFormat()); 1092 } catch (IllegalArgumentException e) { 1093 gotException = true; 1094 } 1095 if (!gotException) { 1096 errln("MessageFormat.setFormatByArgumentIndex() should throw an " + 1097 "IllegalArgumentException when called on formats with " + 1098 "named arguments but did not!"); 1099 } 1100 1101 gotException = false; 1102 try { 1103 msg.getFormatsByArgumentIndex(); 1104 } catch (IllegalArgumentException e) { 1105 gotException = true; 1106 } 1107 if (!gotException) { 1108 errln("MessageFormat.getFormatsByArgumentIndex() should throw an " + 1109 "IllegalArgumentException when called on formats with " + 1110 "named arguments but did not!"); 1111 } 1112 1113 gotException = false; 1114 try { 1115 Object args[] = {new Long(42)}; 1116 msg.format(args, new StringBuffer(), new FieldPosition(0)); 1117 } catch (IllegalArgumentException e) { 1118 gotException = true; 1119 } 1120 if (!gotException) { 1121 errln("MessageFormat.format(Object[], StringBuffer, FieldPosition) " + 1122 "should throw an IllegalArgumentException when called on " + 1123 "formats with named arguments but did not!"); 1124 } 1125 1126 gotException = false; 1127 try { 1128 Object args[] = {new Long(42)}; 1129 msg.format((Object) args, new StringBuffer(), new FieldPosition(0)); 1130 } catch (IllegalArgumentException e) { 1131 gotException = true; 1132 } 1133 if (!gotException) { 1134 errln("MessageFormat.format(Object, StringBuffer, FieldPosition) " + 1135 "should throw an IllegalArgumentException when called with " + 1136 "non-Map object as argument on formats with named " + 1137 "arguments but did not!"); 1138 } 1139 1140 gotException = false; 1141 try { 1142 msg.parse("Number of files: 5", new ParsePosition(0)); 1143 } catch (IllegalArgumentException e) { 1144 gotException = true; 1145 } 1146 if (!gotException) { 1147 errln("MessageFormat.parse(String, ParsePosition) " + 1148 "should throw an IllegalArgumentException when called with " + 1149 "non-Map object as argument on formats with named " + 1150 "arguments but did not!"); 1151 } 1152 1153 gotException = false; 1154 try { 1155 msg.parse("Number of files: 5"); 1156 } catch (IllegalArgumentException e) { 1157 gotException = true; 1158 } catch (ParseException e) { 1159 errln("Wrong exception thrown."); 1160 } 1161 if (!gotException) { 1162 errln("MessageFormat.parse(String) " + 1163 "should throw an IllegalArgumentException when called with " + 1164 "non-Map object as argument on formats with named " + 1165 "arguments but did not!"); 1166 } 1167 } 1168 1169 @Test 1170 public void testNamedArguments() { 1171 // ICU 4.8 allows mixing named and numbered arguments. 1172 assertTrue( 1173 "has some named arguments", 1174 new MessageFormat("Number of files in folder {0}: {numfiles}").usesNamedArguments()); 1175 assertTrue( 1176 "has some named arguments", 1177 new MessageFormat("Number of files in folder {folder}: {1}").usesNamedArguments()); 1178 1179 // Test named arguments. 1180 MessageFormat mf = new MessageFormat("Number of files in folder {folder}: {numfiles}"); 1181 if (!mf.usesNamedArguments()) { 1182 errln("message format 1 should have used named arguments"); 1183 } 1184 mf = new MessageFormat("Wavelength: {\u028EValue\uFF14}"); 1185 if (!mf.usesNamedArguments()) { 1186 errln("message format 2 should have used named arguments"); 1187 } 1188 1189 // Test argument names with invalid start characters. 1190 // Modified: ICU 4.8 allows all characters except for Pattern_White_Space and Pattern_Syntax. 1191 try { 1192 new MessageFormat("Wavelength: {^\u028EValue\uFF14}"); 1193 errln("Creating a MessageFormat with invalid argument names " + 1194 "should throw an IllegalArgumentException but did not!"); 1195 } catch (IllegalArgumentException e) {} 1196 1197 try { 1198 new MessageFormat("Wavelength: {\uFE45\u028EValue}"); 1199 errln("Creating a MessageFormat with invalid argument names " + 1200 "should throw an IllegalArgumentException but did not!"); 1201 } catch (IllegalArgumentException e) {} 1202 1203 // Test argument names with invalid continue characters. 1204 // Modified: ICU 4.8 allows all characters except for Pattern_White_Space and Pattern_Syntax. 1205 try { 1206 new MessageFormat("Wavelength: {Value@\uFF14}"); 1207 errln("Creating a MessageFormat with invalid argument names " + 1208 "should throw an IllegalArgumentException but did not!"); 1209 } catch (IllegalArgumentException e) {} 1210 1211 try { 1212 new MessageFormat("Wavelength: {Value(\uFF14)}"); 1213 errln("Creating a MessageFormat with invalid argument names " + 1214 "should throw an IllegalArgumentException but did not!"); 1215 } catch (IllegalArgumentException e) {} 1216 } 1217 1218 @Test 1219 public void testNumericFormatWithMap() { 1220 MessageFormat mf = new MessageFormat("X:{2} Y:{1}"); 1221 if (mf.usesNamedArguments()) { 1222 errln("should not use named arguments"); 1223 } 1224 1225 Map map12 = new HashMap(); 1226 map12.put("1", "one"); 1227 map12.put("2", "two"); 1228 1229 String target = "X:two Y:one"; 1230 String result = mf.format(map12); 1231 if (!target.equals(result)) { 1232 errln("expected '" + target + "' but got '" + result + "'"); 1233 } 1234 1235 try { 1236 Map mapResult = mf.parseToMap(target); 1237 if (!map12.equals(mapResult)) { 1238 errln("expected " + map12 + " but got " + mapResult); 1239 } 1240 } catch (ParseException e) { 1241 errln("unexpected exception: " + e.getMessage()); 1242 } 1243 1244 Map map10 = new HashMap(); 1245 map10.put("1", "one"); 1246 map10.put("0", "zero"); 1247 target = "X:{2} Y:one"; 1248 result = mf.format(map10); 1249 if (!target.equals(result)) { 1250 errln("expected '" + target + "' but got '" + result + "'"); 1251 } 1252 1253 DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.MEDIUM); 1254 DateFormat timeFormat = DateFormat.getTimeInstance(DateFormat.MEDIUM); 1255 Map fmtMap = new HashMap(); 1256 fmtMap.put("1", dateFormat); 1257 fmtMap.put("2", timeFormat); 1258 mf.setFormatsByArgumentName(fmtMap); 1259 Date date = new Date(661439820000L); 1260 1261 try { 1262 result = mf.format(map12); // should fail, wrong argument type 1263 fail("expected exception but got '" + result + "'"); 1264 } catch (IllegalArgumentException e) { 1265 // expect this 1266 } 1267 1268 Map argMap = new HashMap(); 1269 argMap.put("1", date); 1270 argMap.put("2", date); 1271 target = "X:5:17:00 AM Y:Dec 17, 1990"; 1272 result = mf.format(argMap); 1273 if (!target.equals(result)) { 1274 errln("expected '" + target + "' but got '" + result + "'"); 1275 } 1276 } 1277 1278 // This tests nested Formats inside PluralFormat. 1279 @Test 1280 public void testNestedFormatsInPluralFormat() { 1281 try { 1282 MessageFormat msgFmt = new MessageFormat( 1283 "{0, plural, one {{0, number,C''est #,##0.0# fichier}} " + 1284 "other {Ce sont # fichiers}} dans la liste.", 1285 new ULocale("fr")); 1286 Object objArray[] = {new Long(0)}; 1287 HashMap objMap = new HashMap(); 1288 objMap.put("argument", objArray[0]); 1289 String result = msgFmt.format(objArray); 1290 if (!result.equals("C'est 0,0 fichier dans la liste.")) { 1291 errln("PluralFormat produced wrong message string."); 1292 } 1293 } catch (Exception e) { 1294 e.printStackTrace(); 1295 throw new RuntimeException(e.getMessage()); 1296 } 1297 } 1298 1299 // This tests PluralFormats used inside MessageFormats. 1300 @Test 1301 public void testPluralFormat() { 1302 { 1303 MessageFormat mfNum = new MessageFormat( 1304 "{0, plural, one{C''est # fichier} other " + 1305 "{Ce sont # fichiers}} dans la liste.", 1306 new ULocale("fr")); 1307 MessageFormat mfAlpha = new MessageFormat( 1308 "{argument, plural, one{C''est # fichier} other {Ce " + 1309 "sont # fichiers}} dans la liste.", 1310 new ULocale("fr")); 1311 Object objArray[] = {new Long(0)}; 1312 HashMap objMap = new HashMap(); 1313 objMap.put("argument", objArray[0]); 1314 String result = mfNum.format(objArray); 1315 if (!result.equals(mfAlpha.format(objMap))) { 1316 errln("PluralFormat's output differs when using named " + 1317 "arguments instead of numbers!"); 1318 } 1319 if (!result.equals("C'est 0 fichier dans la liste.")) { 1320 errln("PluralFormat produced wrong message string."); 1321 } 1322 } 1323 { 1324 MessageFormat mfNum = new MessageFormat ( 1325 "There {0, plural, one{is # zavod}few{are {0, " + 1326 "number,###.0} zavoda} other{are # zavodov}} in the " + 1327 "directory.", 1328 new ULocale("uk")); 1329 MessageFormat mfAlpha = new MessageFormat ( 1330 "There {argument, plural, one{is # zavod}few{" + 1331 "are {argument, number,###.0} zavoda} other{are # " + 1332 "zavodov}} in the directory.", 1333 new ULocale("uk")); 1334 Object objArray[] = {new Long(4)}; 1335 HashMap objMap = new HashMap(); 1336 objMap.put("argument", objArray[0]); 1337 String result = mfNum.format(objArray); 1338 if (!result.equals(mfAlpha.format(objMap))) { 1339 errln("PluralFormat's output differs when using named " + 1340 "arguments instead of numbers!"); 1341 } 1342 if (!result.equals("There are 4,0 zavoda in the directory.")) { 1343 errln("PluralFormat produced wrong message string."); 1344 } 1345 } 1346 } 1347 1348 @Test 1349 public void testApostropheInPluralAndSelect() { 1350 MessageFormat fmt = new MessageFormat( 1351 "abc_{0,plural,other{#'#'#'{'#''}}_def_{1,select,other{sel'}'ect''}}_xyz", 1352 Locale.ENGLISH); 1353 String expected = "abc_3#3{3'_def_sel}ect'_xyz"; 1354 String result = fmt.format(new Object[] { 3, "x" }); 1355 if (!result.equals(expected)) { 1356 errln("MessageFormat with apostrophes in plural/select arguments failed:\n" + 1357 "Expected "+expected+"\n" + 1358 "Got "+result); 1359 } 1360 } 1361 1362 // Test toPattern when there is a PluralFormat 1363 @Test 1364 public void testPluralFormatToPattern() { 1365 String[] patterns = { 1366 "Beware of vicious {0, plural, one {hamster} other {hamsters}}.", 1367 "{0, plural, one {{0, number,C''''est #,##0.0# fichier}} other {Ce sont # fichiers}} dans la liste.", 1368 "{0, plural, one {C''est # fichier} other {Ce sont # fichiers}} dans la liste.", 1369 }; 1370 1371 for (int i = 0; i < patterns.length; ++i) { 1372 String pattern = patterns[i]; 1373 MessageFormat mf = new MessageFormat(pattern); 1374 MessageFormat mf2 = new MessageFormat(mf.toPattern()); 1375 if (!mf.equals(mf2)) { 1376 errln("message formats not equal for pattern:\n*** '" + pattern + "'\n*** '" + 1377 mf.toPattern() + "'"); 1378 } 1379 } 1380 } 1381 1382 /** 1383 * This tests SelectFormats used inside MessageFormats. 1384 */ 1385 @Test 1386 public void testSelectFormat() { 1387 String pattern = null; 1388 MessageFormat msgFmt = null ; 1389 1390 //Create the MessageFormat with simple French pattern 1391 pattern = "{0} est {1, select, female {all\\u00E9e} other {all\\u00E9}} \\u00E0 Paris."; 1392 msgFmt = new MessageFormat(pattern); 1393 assertNotNull( "ERROR:Failure in constructing with simple French pattern", msgFmt); 1394 1395 //Format 1396 Object testArgs[][] ={ 1397 {"Kirti","female"} , 1398 {"Victor","other"} , 1399 {"Ash","unknown"} , 1400 }; 1401 String exp[] = { 1402 "Kirti est all\\u00E9e \\u00E0 Paris." , 1403 "Victor est all\\u00E9 \\u00E0 Paris.", 1404 "Ash est all\\u00E9 \\u00E0 Paris." 1405 }; 1406 for ( int i=0; i< 3; i++){ 1407 assertEquals("ERROR:Failure in format with simple French Pattern" , 1408 exp[i] , msgFmt.format(testArgs[i]) ); 1409 } 1410 1411 //Create the MessageFormat with Quoted French Pattern 1412 pattern = "{0} est {1, select, female {all\\u00E9e c''est} other {all\\u00E9 c''est}} \\u00E0 Paris."; 1413 msgFmt = new MessageFormat(pattern); 1414 assertNotNull( "ERROR:Failure in constructing with quoted French pattern", msgFmt); 1415 1416 //Format 1417 Object testArgs1[][] ={ 1418 {"Kirti","female"} , 1419 {"Victor","other"} , 1420 {"Ash","male"} , 1421 }; 1422 String exp1[] = { 1423 "Kirti est all\\u00E9e c'est \\u00E0 Paris." , 1424 "Victor est all\\u00E9 c'est \\u00E0 Paris.", 1425 "Ash est all\\u00E9 c'est \\u00E0 Paris." 1426 }; 1427 for ( int i=0; i< 3; i++){ 1428 assertEquals("ERROR:Failure in format with quoted French Pattern" , 1429 exp1[i] , msgFmt.format(testArgs1[i]) ); 1430 } 1431 1432 //Nested patterns with plural, number ,choice ,select format etc. 1433 //Select Format with embedded number format 1434 pattern = "{0} est {1, select, female {{2,number,integer} all\\u00E9e} other {all\\u00E9}} \\u00E0 Paris."; 1435 msgFmt = new MessageFormat(pattern); 1436 assertNotNull( "ERROR:Failure in constructing with nested pattern 1", msgFmt); 1437 1438 //Format 1439 Object testArgs3[][] ={ 1440 {"Kirti", "female", 6} , 1441 {"Kirti", "female", 100.100} , 1442 {"Kirti", "other", 6} , 1443 }; 1444 String exp3[] = { 1445 "Kirti est 6 all\\u00E9e \\u00E0 Paris." , 1446 "Kirti est 100 all\\u00E9e \\u00E0 Paris.", 1447 "Kirti est all\\u00E9 \\u00E0 Paris." 1448 }; 1449 1450 for ( int i=0; i< 3; i++){ 1451 assertEquals("ERROR:Failure in format with nested Pattern 1" , 1452 exp3[i] , msgFmt.format(testArgs3[i]) ); 1453 } 1454 1455 //Plural format with embedded select format 1456 pattern = "{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."; 1457 msgFmt = new MessageFormat(pattern); 1458 assertNotNull( "ERROR:Failure in constructing with nested pattern 2", msgFmt); 1459 1460 //Format 1461 Object testArgs4[][] ={ 1462 {"Kirti",6,"female"}, 1463 {"Kirti",1,"female"}, 1464 {"Ash",1,"other"}, 1465 {"Ash",5,"other"}, 1466 }; 1467 String exp4[] = { 1468 "Kirti sont all\\u00E9es \\u00E0 Paris." , 1469 "Kirti est all\\u00E9e \\u00E0 Paris.", 1470 "Ash est all\\u00E9 \\u00E0 Paris.", 1471 "Ash sont all\\u00E9s \\u00E0 Paris." 1472 }; 1473 for ( int i=0; i< 4; i++){ 1474 assertEquals("ERROR:Failure in format with nested Pattern 2" , 1475 exp4[i] , msgFmt.format(testArgs4[i]) ); 1476 } 1477 1478 //Select, plural, and number formats heavily nested 1479 pattern = "{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."; 1480 msgFmt = new MessageFormat(pattern); 1481 assertNotNull( "ERROR:Failure in constructing with nested pattern 3", msgFmt); 1482 1483 //Format 1484 Object testArgs5[][] ={ 1485 {"Kirti","other",1,"other"}, 1486 {"Kirti","other",6,"other"}, 1487 {"Kirti","other",1,"female"}, 1488 {"Kirti","other",3,"female"}, 1489 {"Kirti","female",1,"female"}, 1490 {"Kirti","female",5,"female"}, 1491 {"Kirti","female",1,"other"}, 1492 {"Kirti","female",5,"other"}, 1493 {"Kirti","mixed",1,"mixed"}, 1494 {"Kirti","mixed",1,"other"}, 1495 {"Kirti","female",1,"mixed"}, 1496 {"Kirti","mixed",5,"mixed"}, 1497 {"Kirti","mixed",5,"other"}, 1498 {"Kirti","female",5,"mixed"}, 1499 }; 1500 String exp5[] = { 1501 "Kirti und sein Freund gingen nach Paris." , 1502 "Kirti und seine 6 Freunde gingen nach Paris." , 1503 "Kirti und seine Freundin gingen nach Paris.", 1504 "Kirti und seine 3 Freundinnen gingen nach Paris.", 1505 "Kirti und ihre Freundin gingen nach Paris.", 1506 "Kirti und ihre 5 Freundinnen gingen nach Paris.", 1507 "Kirti und ihr Freund gingen nach Paris.", 1508 "Kirti und ihre 5 Freunde gingen nach Paris.", 1509 "Kirti und sein Freund gingen nach Paris.", 1510 "Kirti und sein Freund gingen nach Paris.", 1511 "Kirti und ihr Freund gingen nach Paris.", 1512 "Kirti und seine 5 Freunde gingen nach Paris." , 1513 "Kirti und seine 5 Freunde gingen nach Paris." , 1514 "Kirti und ihre 5 Freunde gingen nach Paris." 1515 }; 1516 //Format 1517 for ( int i=0; i< 14; i++){ 1518 assertEquals("ERROR:Failure in format with nested Pattern 3" , 1519 exp5[i] , msgFmt.format(testArgs5[i]) ); 1520 } 1521 } 1522 1523 /** 1524 * Test toPattern when there is a SelectFormat 1525 */ 1526 @Test 1527 public void testSelectFormatToPattern() { 1528 String[] patterns = { 1529 //Pattern with some text at start and at end 1530 "{0} est {1,select, female {all\\u00E9e} other {all\\u00E9}} \\u00E0 Paris.", 1531 //Pattern with some text at start 1532 "{0} est {1,select, female {all\\u00E9e} other {all\\u00E9}}", 1533 //Pattern with some text at end 1534 "{1, select,female {all\\u00E9e} other {all\\u00E9}} \\u00E0 Paris.", 1535 //Pattern with no text at any end 1536 "{1, select,female {all\\u00E9e} other {all\\u00E9}}.", 1537 //Quoted French pattern 1538 "{0} est {1,select, female {all\\u00E9e c''est} other {all\\u00E9 c''est}} \\u00E0 Paris.", 1539 }; 1540 1541 for (int i = 0; i < patterns.length; ++i) { 1542 String pattern = patterns[i]; 1543 MessageFormat mf = new MessageFormat(pattern); 1544 MessageFormat mf2 = new MessageFormat(mf.toPattern()); 1545 if (!mf.equals(mf2)) { 1546 errln("message formats not equal for pattern:\n*** '" 1547 + pattern + "'\n*** '" + mf.toPattern() + "'"); 1548 } 1549 } 1550 } 1551 1552 // Test case for null arguments. 1553 // Ticket#6361 1554 @Test 1555 public void TestNullArgs() { 1556 MessageFormat msgfmt = new MessageFormat("{0} - {1}"); 1557 Object[][] TEST_CASES = { 1558 {null, "{0} - {1}"}, 1559 {new Object[] {null}, "null - {1}"}, 1560 {new Object[] {null, null}, "null - null"}, 1561 {new Object[] {"one"}, "one - {1}"}, 1562 {new Object[] {"one", null}, "one - null"}, 1563 {new Object[] {null, "two"}, "null - two"}, 1564 }; 1565 1566 for (int i = 0; i < TEST_CASES.length; i++) { 1567 String text = msgfmt.format(TEST_CASES[i][0]); 1568 if (!text.equals(TEST_CASES[i][1])) { 1569 errln("FAIL: Returned[" + text + "] Expected[" + TEST_CASES[i][1] + "]"); 1570 } 1571 } 1572 } 1573 1574 @Test 1575 public void TestSetFormat() { 1576 MessageFormat ms = new MessageFormat("{number} {date}", ULocale.ENGLISH); 1577 final DecimalFormat decimalFormat = new DecimalFormat("000.000", DecimalFormatSymbols.getInstance(ULocale.ENGLISH)); 1578 ms.setFormatByArgumentName("number", decimalFormat); 1579 final SimpleDateFormat dateFormat = new SimpleDateFormat("'year:'yy 'month:'MM 'day:'dd"); 1580 dateFormat.setTimeZone(TimeZone.getTimeZone("Etc/GMT")); 1581 ms.setFormatByArgumentName("date", dateFormat); 1582 Map map = new HashMap(); 1583 map.put("number", new Integer(1234)); 1584 map.put("date", new Date(0,0,0)); 1585 String result = ms.format(map); 1586 assertEquals("setFormatByArgumentName", "1234.000 year:99 month:12 day:31", result); 1587 Set formatNames = ms.getArgumentNames(); 1588 assertEquals("Format Names match", formatNames, map.keySet()); 1589 assertEquals("Decimal", decimalFormat, ms.getFormatByArgumentName("number")); 1590 assertEquals("Date", dateFormat, ms.getFormatByArgumentName("date")); 1591 } 1592 1593 // Test case for formatToCharacterIterator 1594 @Test 1595 public void TestFormatToCharacterIterator() { 1596 MessageFormat[] msgfmts = { 1597 new MessageFormat( 1598 "The {3,ordinal} folder ''{0}'' contains {2,number} file(s), created at {1,time} on {1,date}."), 1599 new MessageFormat( 1600 "The {arg3,ordinal} folder ''{arg0}'' contains {arg2,number} file(s), created at {arg1,time} on {arg1,date}."), // same 1601 // as 1602 // above, 1603 // but 1604 // named 1605 // args 1606 new MessageFormat("The folder contains {0}.") }; 1607 1608 double filelimits[] = { 0, 1, 2 }; 1609 String filepart[] = { "no files", "one file", "{0,number} files" }; 1610 ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart); 1611 msgfmts[2].setFormat(0, fileform); 1612 1613 Object[] args0 = new Object[] { "tmp", new Date(1184777888000L), new Integer(15), new Integer(2) }; 1614 1615 HashMap args1 = new HashMap(); 1616 args1.put("arg0", "tmp"); 1617 args1.put("arg1", new Date(1184777888000L)); 1618 args1.put("arg2", new Integer(15)); 1619 args1.put("arg3", new Integer(2)); 1620 1621 Object[] args2 = new Object[] { new Integer(34) }; 1622 1623 Object[] args = { args0, args1, args2 }; 1624 1625 String[] expectedStrings = { 1626 "The 2nd folder 'tmp' contains 15 file(s), created at 9:58:08 AM on Jul 18, 2007.", 1627 "The 2nd folder 'tmp' contains 15 file(s), created at 9:58:08 AM on Jul 18, 2007.", 1628 "The folder contains 34 files." }; 1629 1630 AttributedString[] expectedAttributedStrings = { new AttributedString(expectedStrings[0]), 1631 new AttributedString(expectedStrings[1]), new AttributedString(expectedStrings[2]) }; 1632 1633 // Add expected attributes to the expectedAttributedStrings[0] 1634 expectedAttributedStrings[0].addAttribute(MessageFormat.Field.ARGUMENT, new Integer(3), 4, 7); 1635 expectedAttributedStrings[0].addAttribute(MessageFormat.Field.ARGUMENT, new Integer(0), 16, 19); 1636 expectedAttributedStrings[0].addAttribute(MessageFormat.Field.ARGUMENT, new Integer(2), 30, 32); 1637 expectedAttributedStrings[0].addAttribute(NumberFormat.Field.INTEGER, NumberFormat.Field.INTEGER, 30, 32); 1638 expectedAttributedStrings[0].addAttribute(MessageFormat.Field.ARGUMENT, new Integer(1), 53, 63); 1639 expectedAttributedStrings[0].addAttribute(DateFormat.Field.HOUR1, DateFormat.Field.HOUR1, 53, 54); 1640 //expectedAttributedStrings[0].addAttribute(DateFormat.Field.TIME_SEPARATOR, DateFormat.Field.TIME_SEPARATOR, 54, 55); 1641 expectedAttributedStrings[0].addAttribute(DateFormat.Field.MINUTE, DateFormat.Field.MINUTE, 55, 57); 1642 //expectedAttributedStrings[0].addAttribute(DateFormat.Field.TIME_SEPARATOR, DateFormat.Field.TIME_SEPARATOR, 57, 58); 1643 expectedAttributedStrings[0].addAttribute(DateFormat.Field.SECOND, DateFormat.Field.SECOND, 58, 60); 1644 expectedAttributedStrings[0].addAttribute(DateFormat.Field.AM_PM, DateFormat.Field.AM_PM, 61, 63); 1645 expectedAttributedStrings[0].addAttribute(MessageFormat.Field.ARGUMENT, new Integer(1), 67, 79); 1646 expectedAttributedStrings[0].addAttribute(DateFormat.Field.MONTH, DateFormat.Field.MONTH, 67, 70); 1647 expectedAttributedStrings[0].addAttribute(DateFormat.Field.DAY_OF_MONTH, DateFormat.Field.DAY_OF_MONTH, 71, 73); 1648 expectedAttributedStrings[0].addAttribute(DateFormat.Field.YEAR, DateFormat.Field.YEAR, 75, 79); 1649 1650 // Add expected attributes to the expectedAttributedStrings[1] 1651 expectedAttributedStrings[1].addAttribute(MessageFormat.Field.ARGUMENT, "arg3", 4, 7); 1652 expectedAttributedStrings[1].addAttribute(MessageFormat.Field.ARGUMENT, "arg0", 16, 19); 1653 expectedAttributedStrings[1].addAttribute(MessageFormat.Field.ARGUMENT, "arg2", 30, 32); 1654 expectedAttributedStrings[1].addAttribute(NumberFormat.Field.INTEGER, NumberFormat.Field.INTEGER, 30, 32); 1655 expectedAttributedStrings[1].addAttribute(MessageFormat.Field.ARGUMENT, "arg1", 53, 63); 1656 expectedAttributedStrings[1].addAttribute(DateFormat.Field.HOUR1, DateFormat.Field.HOUR1, 53, 54); 1657 //expectedAttributedStrings[1].addAttribute(DateFormat.Field.TIME_SEPARATOR, DateFormat.Field.TIME_SEPARATOR, 54, 55); 1658 expectedAttributedStrings[1].addAttribute(DateFormat.Field.MINUTE, DateFormat.Field.MINUTE, 55, 57); 1659 //expectedAttributedStrings[1].addAttribute(DateFormat.Field.TIME_SEPARATOR, DateFormat.Field.TIME_SEPARATOR, 57, 58); 1660 expectedAttributedStrings[1].addAttribute(DateFormat.Field.SECOND, DateFormat.Field.SECOND, 58, 60); 1661 expectedAttributedStrings[1].addAttribute(DateFormat.Field.AM_PM, DateFormat.Field.AM_PM, 61, 63); 1662 expectedAttributedStrings[1].addAttribute(MessageFormat.Field.ARGUMENT, "arg1", 67, 79); 1663 expectedAttributedStrings[1].addAttribute(DateFormat.Field.MONTH, DateFormat.Field.MONTH, 67, 70); 1664 expectedAttributedStrings[1].addAttribute(DateFormat.Field.DAY_OF_MONTH, DateFormat.Field.DAY_OF_MONTH, 71, 73); 1665 expectedAttributedStrings[1].addAttribute(DateFormat.Field.YEAR, DateFormat.Field.YEAR, 75, 79); 1666 1667 // Add expected attributes to the expectedAttributedStrings[2] 1668 expectedAttributedStrings[2].addAttribute(MessageFormat.Field.ARGUMENT, new Integer(0), 20, 28); 1669 expectedAttributedStrings[2].addAttribute(NumberFormat.Field.INTEGER, NumberFormat.Field.INTEGER, 20, 22); 1670 1671 for (int i = 0; i < msgfmts.length; i++) { 1672 AttributedCharacterIterator acit = msgfmts[i].formatToCharacterIterator(args[i]); 1673 AttributedCharacterIterator expectedAcit = expectedAttributedStrings[i].getIterator(); 1674 1675 // Check available attributes 1676 Set attrSet = acit.getAllAttributeKeys(); 1677 Set expectedAttrSet = expectedAcit.getAllAttributeKeys(); 1678 if (attrSet.size() != expectedAttrSet.size()) { 1679 errln("FAIL: Number of attribute keys is " + attrSet.size() + " expected: " + expectedAttrSet.size()); 1680 } 1681 Iterator attrIterator = attrSet.iterator(); 1682 while (attrIterator.hasNext()) { 1683 AttributedCharacterIterator.Attribute attr = (AttributedCharacterIterator.Attribute) attrIterator 1684 .next(); 1685 if (!expectedAttrSet.contains(attr)) { 1686 errln("FAIL: The attribute " + attr + " is not expected."); 1687 } 1688 } 1689 1690 StringBuffer buf = new StringBuffer(); 1691 int index = acit.getBeginIndex(); 1692 int end = acit.getEndIndex(); 1693 int indexExp = expectedAcit.getBeginIndex(); 1694 int expectedLen = expectedAcit.getEndIndex() - indexExp; 1695 if (end - index != expectedLen) { 1696 errln("FAIL: Length of the result attributed string is " + (end - index) + " expected: " + expectedLen); 1697 } else { 1698 // Check attributes associated with each character 1699 while (index < end) { 1700 char c = acit.setIndex(index); 1701 buf.append(c); 1702 expectedAcit.setIndex(indexExp); 1703 1704 Map attrs = acit.getAttributes(); 1705 Map attrsExp = expectedAcit.getAttributes(); 1706 if (attrs.size() != attrsExp.size()) { 1707 errln("FAIL: Number of attributes associated with index " + index + " is " + attrs.size() 1708 + " expected: " + attrsExp.size()); 1709 } else { 1710 // Check all attributes at the index 1711 Iterator entryIterator = attrsExp.entrySet().iterator(); 1712 while (entryIterator.hasNext()) { 1713 Map.Entry entry = (Map.Entry) entryIterator.next(); 1714 if (attrs.containsKey(entry.getKey())) { 1715 Object value = attrs.get(entry.getKey()); 1716 assertEquals("Attribute value at index " + index, entry.getValue(), value); 1717 } else { 1718 errln("FAIL: Attribute " + entry.getKey() + " is missing at index " + index); 1719 } 1720 } 1721 } 1722 index++; 1723 indexExp++; 1724 } 1725 assertEquals("AttributedString contents", expectedStrings[i], buf.toString()); 1726 } 1727 } 1728 1729 // Tests when "if (arguments == null)" is true 1730 try { 1731 MessageFormat mf = new MessageFormat(""); 1732 mf.formatToCharacterIterator(null); 1733 errln("MessageFormat.formatToCharacterIterator(Object) was suppose " 1734 + "to return an exception when null is passed."); 1735 } catch (Exception e) { 1736 } 1737 } 1738 1739 /* 1740 * Tests the method public Format getFormatByArgumentName(String argumentName) 1741 */ 1742 @Test 1743 public void TestGetFormatByArgumentName() { 1744 MessageFormat mf = new MessageFormat(""); 1745 if (mf.getFormatByArgumentName("") != null) { 1746 errln("MessageFormat.getFormatByArgumentName(String) was suppose " 1747 + "to return an null if argumentName was not found."); 1748 } 1749 } 1750 1751 public String getPatternAndSkipSyntax(MessagePattern pattern) { 1752 StringBuilder sb = new StringBuilder(pattern.getPatternString()); 1753 int count = pattern.countParts(); 1754 for (int i = count; i > 0;) { 1755 MessagePattern.Part part = pattern.getPart(--i); 1756 if (part.getType() == MessagePattern.Part.Type.SKIP_SYNTAX) { 1757 sb.delete(part.getIndex(), part.getLimit()); 1758 } 1759 } 1760 return sb.toString(); 1761 } 1762 1763 @Test 1764 public void TestApostropheMode() { 1765 MessagePattern ado_mp = new MessagePattern(MessagePattern.ApostropheMode.DOUBLE_OPTIONAL); 1766 MessagePattern adr_mp = new MessagePattern(MessagePattern.ApostropheMode.DOUBLE_REQUIRED); 1767 assertEquals("wrong value", 1768 MessagePattern.ApostropheMode.DOUBLE_OPTIONAL, 1769 ado_mp.getApostropheMode()); 1770 assertEquals("wrong value", 1771 MessagePattern.ApostropheMode.DOUBLE_REQUIRED, 1772 adr_mp.getApostropheMode()); 1773 assertNotEquals("MessagePatterns with different ApostropheMode (no pattern)", ado_mp, adr_mp); 1774 assertNotEquals("MessagePatterns with different ApostropheMode (a)", 1775 ado_mp.parse("a"), adr_mp.parse("a")); 1776 1777 String[] tuples = new String[] { 1778 // Desired output 1779 // DOUBLE_OPTIONAL pattern 1780 // DOUBLE_REQUIRED pattern (null=same as DOUBLE_OPTIONAL) 1781 "I see {many}", "I see '{many}'", null, 1782 "I said {'Wow!'}", "I said '{''Wow!''}'", null, 1783 "I dont know", "I dont know", "I don't know", 1784 "I don't know", "I don't know", "I don''t know", 1785 "I don't know", "I don''t know", "I don''t know", 1786 }; 1787 for (int i = 0; i < tuples.length; i += 3) { 1788 String desired = tuples[i]; 1789 String ado_pattern = tuples[i + 1]; 1790 assertEquals("DOUBLE_OPTIONAL failure", desired, 1791 getPatternAndSkipSyntax(ado_mp.parse(ado_pattern))); 1792 String adr_pattern = tuples[i + 2]; 1793 if (adr_pattern == null) { 1794 adr_pattern = ado_pattern; 1795 } 1796 assertEquals("DOUBLE_REQUIRED failure", desired, 1797 getPatternAndSkipSyntax(adr_mp.parse(adr_pattern))); 1798 } 1799 } 1800 1801 // Compare behavior of JDK and ICU's DOUBLE_REQUIRED compatibility mode. 1802 @Test 1803 public void TestCompatibleApostrophe() { 1804 // Message with choice argument which does not contain another argument. 1805 // The JDK performs only one apostrophe-quoting pass on this pattern. 1806 String pattern = "ab{0,choice,0#1'2''3'''4''''.}yz"; 1807 java.text.MessageFormat jdkMsg = 1808 new java.text.MessageFormat(pattern, Locale.ENGLISH); 1809 1810 MessageFormat compMsg = new MessageFormat("", Locale.ENGLISH); 1811 compMsg.applyPattern(pattern, MessagePattern.ApostropheMode.DOUBLE_REQUIRED); 1812 assertEquals("wrong value", 1813 MessagePattern.ApostropheMode.DOUBLE_REQUIRED, 1814 compMsg.getApostropheMode()); 1815 1816 MessageFormat icuMsg = new MessageFormat("", Locale.ENGLISH); 1817 icuMsg.applyPattern(pattern, MessagePattern.ApostropheMode.DOUBLE_OPTIONAL); 1818 assertEquals("wrong value", 1819 MessagePattern.ApostropheMode.DOUBLE_OPTIONAL, 1820 icuMsg.getApostropheMode()); 1821 1822 Object[] zero0 = new Object[] { 0 }; 1823 assertEquals("unexpected JDK MessageFormat apostrophe behavior", 1824 "ab12'3'4''.yz", 1825 jdkMsg.format(zero0)); 1826 assertEquals("incompatible ICU MessageFormat compatibility-apostrophe behavior", 1827 "ab12'3'4''.yz", 1828 compMsg.format(zero0)); 1829 assertEquals("unexpected ICU MessageFormat double-apostrophe-optional behavior", 1830 "ab1'2'3''4''.yz", 1831 icuMsg.format(zero0)); 1832 1833 // Message with choice argument which contains a nested simple argument. 1834 // The JDK performs two apostrophe-quoting passes. 1835 pattern = "ab{0,choice,0#1'2''3'''4''''.{0,number,'#x'}}yz"; 1836 jdkMsg.applyPattern(pattern); 1837 compMsg.applyPattern(pattern); 1838 icuMsg.applyPattern(pattern); 1839 assertEquals("unexpected JDK MessageFormat apostrophe behavior", 1840 "ab1234'.0xyz", 1841 jdkMsg.format(zero0)); 1842 assertEquals("incompatible ICU MessageFormat compatibility-apostrophe behavior", 1843 "ab1234'.0xyz", 1844 compMsg.format(zero0)); 1845 assertEquals("unexpected ICU MessageFormat double-apostrophe-optional behavior", 1846 "ab1'2'3''4''.#x0yz", 1847 icuMsg.format(zero0)); 1848 1849 // Message with choice argument which contains a nested choice argument. 1850 // The JDK fails to parse this pattern. 1851 // jdkMsg.applyPattern("cd{0,choice,0#ef{0,choice,0#1'2''3'''4''''.}uv}wx"); 1852 // For lack of comparison, we do not test ICU with this pattern. 1853 1854 // The JDK ChoiceFormat itself always performs one apostrophe-quoting pass. 1855 ChoiceFormat choice = new ChoiceFormat("0#1'2''3'''4''''."); 1856 assertEquals("unexpected JDK ChoiceFormat apostrophe behavior", 1857 "12'3'4''.", 1858 choice.format(0)); 1859 choice.applyPattern("0#1'2''3'''4''''.{0,number,'#x'}"); 1860 assertEquals("unexpected JDK ChoiceFormat apostrophe behavior", 1861 "12'3'4''.{0,number,#x}", 1862 choice.format(0)); 1863 } 1864 1865 @Test 1866 public void TestTrimArgumentName() { 1867 // ICU 4.8 allows and ignores white space around argument names and numbers. 1868 MessageFormat m = new MessageFormat("a { 0 , number , '#,#'#.0 } z", Locale.ENGLISH); 1869 assertEquals("trim-numbered-arg format() failed", "a #,#2.0 z", m.format(new Object[] { 2 })); 1870 1871 m.applyPattern("x { _oOo_ , number , integer } y"); 1872 Map<String, Object> map = new HashMap<String, Object>(); 1873 map.put("_oOo_", new Integer(3)); 1874 StringBuffer result = new StringBuffer(); 1875 assertEquals("trim-named-arg format() failed", "x 3 y", 1876 m.format(map, result, new FieldPosition(0)).toString()); 1877 } 1878 1879 @Test 1880 public void TestSelectOrdinal() { 1881 // Test plural & ordinal together, 1882 // to make sure that we get the correct cached PluralSelector for each. 1883 MessageFormat m = new MessageFormat( 1884 "{0,plural,one{1 file}other{# files}}, " + 1885 "{0,selectordinal,one{#st file}two{#nd file}few{#rd file}other{#th file}}", 1886 ULocale.ENGLISH); 1887 Object[] args = new Object[] { 21 }; 1888 FieldPosition ignore = null; 1889 StringBuffer result = new StringBuffer(); 1890 assertEquals("plural-and-ordinal format(21)", "21 files, 21st file", 1891 m.format(args, result, ignore).toString()); 1892 1893 args[0] = 2; 1894 result.delete(0, result.length()); 1895 assertEquals("plural-and-ordinal format(2) failed", "2 files, 2nd file", 1896 m.format(args, result, ignore).toString()); 1897 1898 args[0] = 1; 1899 result.delete(0, result.length()); 1900 assertEquals("plural-and-ordinal format(1) failed", "1 file, 1st file", 1901 m.format(args, result, ignore).toString()); 1902 1903 args[0] = 3; 1904 result.delete(0, result.length()); 1905 assertEquals("plural-and-ordinal format(3) failed", "3 files, 3rd file", 1906 m.format(args, result, ignore).toString()); 1907 } 1908 1909 @Test 1910 public void TestDecimals() { 1911 // Simple number replacement. 1912 MessageFormat m = new MessageFormat( 1913 "{0,plural,one{one meter}other{# meters}}", 1914 ULocale.ENGLISH); 1915 Object[] args = new Object[] { 1 }; 1916 FieldPosition ignore = null; 1917 StringBuffer result = new StringBuffer(); 1918 assertEquals("simple format(1)", "one meter", 1919 m.format(args, result, ignore).toString()); 1920 1921 args[0] = 1.5; 1922 result.delete(0, result.length()); 1923 assertEquals("simple format(1.5)", "1.5 meters", 1924 m.format(args, result, ignore).toString()); 1925 1926 // Simple but explicit. 1927 MessageFormat m0 = new MessageFormat( 1928 "{0,plural,one{one meter}other{{0} meters}}", 1929 ULocale.ENGLISH); 1930 args[0] = 1; 1931 result.delete(0, result.length()); 1932 assertEquals("explicit format(1)", "one meter", 1933 m0.format(args, result, ignore).toString()); 1934 1935 args[0] = 1.5; 1936 result.delete(0, result.length()); 1937 assertEquals("explicit format(1.5)", "1.5 meters", 1938 m0.format(args, result, ignore).toString()); 1939 1940 // With offset and specific simple format with optional decimals. 1941 MessageFormat m1 = new MessageFormat( 1942 "{0,plural,offset:1 one{another meter}other{{0,number,00.#} meters}}", 1943 ULocale.ENGLISH); 1944 args[0] = 1; 1945 result.delete(0, result.length()); 1946 assertEquals("offset format(1)", "01 meters", 1947 m1.format(args, result, ignore).toString()); 1948 1949 args[0] = 2; 1950 result.delete(0, result.length()); 1951 assertEquals("offset format(1)", "another meter", 1952 m1.format(args, result, ignore).toString()); 1953 1954 args[0] = 2.5; 1955 result.delete(0, result.length()); 1956 assertEquals("offset format(1)", "02.5 meters", 1957 m1.format(args, result, ignore).toString()); 1958 1959 // With offset and specific simple format with forced decimals. 1960 MessageFormat m2 = new MessageFormat( 1961 "{0,plural,offset:1 one{another meter}other{{0,number,0.0} meters}}", 1962 ULocale.ENGLISH); 1963 args[0] = 1; 1964 result.delete(0, result.length()); 1965 assertEquals("offset-decimals format(1)", "1.0 meters", 1966 m2.format(args, result, ignore).toString()); 1967 1968 args[0] = 2; 1969 result.delete(0, result.length()); 1970 assertEquals("offset-decimals format(1)", "2.0 meters", 1971 m2.format(args, result, ignore).toString()); 1972 1973 args[0] = 2.5; 1974 result.delete(0, result.length()); 1975 assertEquals("offset-decimals format(1)", "2.5 meters", 1976 m2.format(args, result, ignore).toString()); 1977 } 1978 1979 @Test 1980 public void TestArgIsPrefixOfAnother() { 1981 // Ticket #11952 1982 MessageFormat mf1 = new MessageFormat( 1983 "{0,select,a{A}ab{AB}abc{ABC}other{?}}", ULocale.ENGLISH); 1984 assertEquals("a", "A", mf1.format(new Object[] { "a" })); 1985 assertEquals("ab", "AB", mf1.format(new Object[] { "ab" })); 1986 assertEquals("abc", "ABC", mf1.format(new Object[] { "abc" })); 1987 1988 // Ticket #12172 1989 MessageFormat mf2 = new MessageFormat("{a} {aa} {aaa}", ULocale.ENGLISH); 1990 Map<String, Object> args = new TreeMap<String, Object>(); 1991 args.put("a", "A"); 1992 args.put("aa", "AB"); 1993 args.put("aaa", "ABC"); 1994 assertEquals("a aa aaa", "A AB ABC", mf2.format(args, new StringBuffer(), null).toString()); 1995 1996 // Ticket #12172 1997 MessageFormat mf3 = new MessageFormat("{aa} {aaa}", ULocale.ENGLISH); 1998 assertEquals("aa aaa", "AB ABC", mf3.format(args, new StringBuffer(), null).toString()); 1999 } 2000 2001 public void TestMessagePatternAutoQuoteApostropheDeep() { 2002 // Example input & output taken from API docs. 2003 MessagePattern pattern = new MessagePattern( 2004 "I don't '{know}' {gender,select,female{h''er}other{h'im}}."); 2005 assertEquals("autoQuoteApostropheDeep()", 2006 "I don''t '{know}' {gender,select,female{h''er}other{h''im}}.", 2007 pattern.autoQuoteApostropheDeep()); 2008 } 2009 2010 public void TestMessagePatternFreezable() { 2011 MessagePattern pattern = new MessagePattern(); 2012 assertFalse("just constructed, not yet frozen", pattern.isFrozen()); 2013 pattern.parse("fee"); 2014 assertTrue("parsed, not empty", pattern.countParts() > 0); 2015 pattern.freeze(); 2016 assertTrue("just frozen", pattern.isFrozen()); 2017 try { 2018 pattern.parse("fi"); 2019 fail("MessagePattern.freeze().parse() did not fail"); 2020 } catch (Exception expected) { 2021 } 2022 assertEquals("frozen+parse: no change", "fee", pattern.autoQuoteApostropheDeep()); 2023 MessagePattern thawed = pattern.cloneAsThawed(); 2024 assertFalse("thawed", thawed.isFrozen()); 2025 assertTrue("still frozen", pattern.isFrozen()); 2026 assertTrue("frozen!=thawed", pattern != thawed); 2027 thawed.parse("fo"); 2028 assertEquals("thawed+parse", "fo", thawed.autoQuoteApostropheDeep()); 2029 } 2030 2031 public void TestMessagePatternNamedAndNumberedArguments() { 2032 MessagePattern pattern = new MessagePattern(); 2033 pattern.parse("fee"); 2034 assertFalse("fee no named args", pattern.hasNamedArguments()); 2035 assertFalse("fee no numbered args", pattern.hasNumberedArguments()); 2036 pattern.parse("fi {0}"); 2037 assertFalse("fi {0} no named args", pattern.hasNamedArguments()); 2038 assertTrue("fi {0} has numbered args", pattern.hasNumberedArguments()); 2039 pattern.parse("fo {name}"); 2040 assertTrue("fo {name} has named args", pattern.hasNamedArguments()); 2041 assertFalse("fo {name} no numbered args", pattern.hasNumberedArguments()); 2042 pattern.parse("fum {0} {name}"); 2043 assertTrue("fum {0} {name} has named args", pattern.hasNamedArguments()); 2044 assertTrue("fum {0} {name} no numbered args", pattern.hasNumberedArguments()); 2045 } 2046 2047 public void TestMessagePatternPartCoverage() { 2048 MessagePattern pattern = new MessagePattern("ab{17}c"); 2049 assertEquals("msg start { arg number } msg limit", 5, pattern.countParts()); 2050 MessagePattern.Part arg = pattern.getPart(2); 2051 assertEquals("arg number", MessagePattern.Part.Type.ARG_NUMBER, arg.getType()); 2052 assertEquals("arg number start", 3, arg.getIndex()); 2053 assertEquals("arg number length", 2, arg.getLength()); 2054 assertEquals("arg number limit", 5, arg.getLimit()); 2055 assertEquals("arg number 17", 17, arg.getValue()); 2056 } 2057 2058 public void TestMessagePatternParseChoiceStyle() { 2059 // This would be tested by ChoiceFormat if ICU4J had its own version of that, 2060 // like ICU4C does. 2061 // Instead, there is only java.text.ChoiceFormat. 2062 // Most of the implementation gets covered by testing with a MessageFormat 2063 // that contains a nested ChoiceFormat pattern, 2064 // but that does not call this public API method. 2065 MessagePattern pattern = new MessagePattern(); 2066 // Example string from java.text.ChoiceFormat class docs. 2067 pattern.parseChoiceStyle( 2068 "-1#is negative| 0#is zero or fraction | 1#is one |" + 2069 "1.0<is 1+ |2#is two |2<is more than 2."); 2070 // Only simple API coverage. The parser implementation is tested via MessageFormat. 2071 assertTrue("many parts", pattern.countParts() > 10); 2072 } 2073 2074 public void TestDateFormatHashCode() { 2075 DateFormat testDF = DateFormat.getDateInstance(DateFormat.DEFAULT, ULocale.GERMAN); 2076 NumberFormat testNF = testDF.getNumberFormat(); 2077 2078 int expectedResult = 2079 testNF.getMaximumIntegerDigits() * 37 + testNF.getMaximumFractionDigits(); 2080 int actualHashResult = testDF.hashCode(); 2081 assertEquals("DateFormat hashCode", expectedResult, actualHashResult); 2082 } 2083 } 2084