1 /* 2 ******************************************************************************* 3 * Copyright (C) 1996-2015, International Business Machines Corporation and * 4 * others. All Rights Reserved. * 5 ******************************************************************************* 6 */ 7 package com.ibm.icu.dev.test.format; 8 9 import java.math.BigInteger; 10 import java.text.ParseException; 11 import java.util.Locale; 12 import java.util.Random; 13 14 import com.ibm.icu.dev.test.TestFmwk; 15 import com.ibm.icu.text.DecimalFormat; 16 import com.ibm.icu.text.DecimalFormatSymbols; 17 import com.ibm.icu.text.DisplayContext; 18 import com.ibm.icu.text.NumberFormat; 19 import com.ibm.icu.text.RuleBasedNumberFormat; 20 import com.ibm.icu.util.ULocale; 21 22 /** 23 * This does not test lenient parse mode, since testing the default implementation 24 * introduces a dependency on collation. See RbnfLenientScannerTest. 25 */ 26 public class RbnfTest extends TestFmwk { 27 public static void main(String[] args) { 28 RbnfTest test = new RbnfTest(); 29 30 try { 31 test.run(args); 32 } 33 catch (Throwable e) { 34 System.out.println("Entire test failed because of exception: " 35 + e.toString()); 36 e.printStackTrace(); 37 } 38 } 39 40 static String fracRules = 41 "%main:\n" + 42 // this rule formats the number if it's 1 or more. It formats 43 // the integral part using a DecimalFormat ("#,##0" puts 44 // thousands separators in the right places) and the fractional 45 // part using %%frac. If there is no fractional part, it 46 // just shows the integral part. 47 " x.0: <#,##0<[ >%%frac>];\n" + 48 // this rule formats the number if it's between 0 and 1. It 49 // shows only the fractional part (0.5 shows up as "1/2," not 50 // "0 1/2") 51 " 0.x: >%%frac>;\n" + 52 // the fraction rule set. This works the same way as the one in the 53 // preceding example: We multiply the fractional part of the number 54 // being formatted by each rule's base value and use the rule that 55 // produces the result closest to 0 (or the first rule that produces 0). 56 // Since we only provide rules for the numbers from 2 to 10, we know 57 // we'll get a fraction with a denominator between 2 and 10. 58 // "<0<" causes the numerator of the fraction to be formatted 59 // using numerals 60 "%%frac:\n" + 61 " 2: 1/2;\n" + 62 " 3: <0</3;\n" + 63 " 4: <0</4;\n" + 64 " 5: <0</5;\n" + 65 " 6: <0</6;\n" + 66 " 7: <0</7;\n" + 67 " 8: <0</8;\n" + 68 " 9: <0</9;\n" + 69 " 10: <0</10;\n"; 70 71 public void TestCoverage() { 72 String durationInSecondsRules = 73 // main rule set for formatting with words 74 "%with-words:\n" 75 // take care of singular and plural forms of "second" 76 + " 0 seconds; 1 second; =0= seconds;\n" 77 // use %%min to format values greater than 60 seconds 78 + " 60/60: <%%min<[, >>];\n" 79 // use %%hr to format values greater than 3,600 seconds 80 // (the ">>>" below causes us to see the number of minutes 81 // when when there are zero minutes) 82 + " 3600/60: <%%hr<[, >>>];\n" 83 // this rule set takes care of the singular and plural forms 84 // of "minute" 85 + "%%min:\n" 86 + " 0 minutes; 1 minute; =0= minutes;\n" 87 // this rule set takes care of the singular and plural forms 88 // of "hour" 89 + "%%hr:\n" 90 + " 0 hours; 1 hour; =0= hours;\n" 91 92 // main rule set for formatting in numerals 93 + "%in-numerals:\n" 94 // values below 60 seconds are shown with "sec." 95 + " =0= sec.;\n" 96 // higher values are shown with colons: %%min-sec is used for 97 // values below 3,600 seconds... 98 + " 60: =%%min-sec=;\n" 99 // ...and %%hr-min-sec is used for values of 3,600 seconds 100 // and above 101 + " 3600: =%%hr-min-sec=;\n" 102 // this rule causes values of less than 10 minutes to show without 103 // a leading zero 104 + "%%min-sec:\n" 105 + " 0: :=00=;\n" 106 + " 60/60: <0<>>;\n" 107 // this rule set is used for values of 3,600 or more. Minutes are always 108 // shown, and always shown with two digits 109 + "%%hr-min-sec:\n" 110 + " 0: :=00=;\n" 111 + " 60/60: <00<>>;\n" 112 + " 3600/60: <#,##0<:>>>;\n" 113 // the lenient-parse rules allow several different characters to be used 114 // as delimiters between hours, minutes, and seconds 115 + "%%lenient-parse:\n" 116 + " & : = . = ' ' = -;\n"; 117 118 // extra calls to boost coverage numbers 119 RuleBasedNumberFormat fmt0 = new RuleBasedNumberFormat(RuleBasedNumberFormat.SPELLOUT); 120 RuleBasedNumberFormat fmt1 = (RuleBasedNumberFormat)fmt0.clone(); 121 RuleBasedNumberFormat fmt2 = new RuleBasedNumberFormat(RuleBasedNumberFormat.SPELLOUT); 122 if (!fmt0.equals(fmt0)) { 123 errln("self equality fails"); 124 } 125 if (!fmt0.equals(fmt1)) { 126 errln("clone equality fails"); 127 } 128 if (!fmt0.equals(fmt2)) { 129 errln("duplicate equality fails"); 130 } 131 String str = fmt0.toString(); 132 logln(str); 133 134 RuleBasedNumberFormat fmt3 = new RuleBasedNumberFormat(durationInSecondsRules); 135 136 if (fmt0.equals(fmt3)) { 137 errln("nonequal fails"); 138 } 139 if (!fmt3.equals(fmt3)) { 140 errln("self equal 2 fails"); 141 } 142 str = fmt3.toString(); 143 logln(str); 144 145 String[] names = fmt3.getRuleSetNames(); 146 147 try { 148 fmt3.setDefaultRuleSet(null); 149 fmt3.setDefaultRuleSet("%%foo"); 150 errln("sdrf %%foo didn't fail"); 151 } 152 catch (Exception e) { 153 logln("Got the expected exception"); 154 } 155 156 try { 157 fmt3.setDefaultRuleSet("%bogus"); 158 errln("sdrf %bogus didn't fail"); 159 } 160 catch (Exception e) { 161 logln("Got the expected exception"); 162 } 163 164 try { 165 str = fmt3.format(2.3, names[0]); 166 logln(str); 167 str = fmt3.format(2.3, "%%foo"); 168 errln("format double %%foo didn't fail"); 169 } 170 catch (Exception e) { 171 logln("Got the expected exception"); 172 } 173 174 try { 175 str = fmt3.format(123L, names[0]); 176 logln(str); 177 str = fmt3.format(123L, "%%foo"); 178 errln("format double %%foo didn't fail"); 179 } 180 catch (Exception e) { 181 logln("Got the expected exception"); 182 } 183 184 RuleBasedNumberFormat fmt4 = new RuleBasedNumberFormat(fracRules, Locale.ENGLISH); 185 RuleBasedNumberFormat fmt5 = new RuleBasedNumberFormat(fracRules, Locale.ENGLISH); 186 str = fmt4.toString(); 187 logln(str); 188 if (!fmt4.equals(fmt5)) { 189 errln("duplicate 2 equality failed"); 190 } 191 str = fmt4.format(123L); 192 logln(str); 193 try { 194 Number num = fmt4.parse(str); 195 logln(num.toString()); 196 } 197 catch (Exception e) { 198 errln("parse caught exception"); 199 } 200 201 str = fmt4.format(.000123); 202 logln(str); 203 try { 204 Number num = fmt4.parse(str); 205 logln(num.toString()); 206 } 207 catch (Exception e) { 208 errln("parse caught exception"); 209 } 210 211 str = fmt4.format(456.000123); 212 logln(str); 213 try { 214 Number num = fmt4.parse(str); 215 logln(num.toString()); 216 } 217 catch (Exception e) { 218 errln("parse caught exception"); 219 } 220 } 221 222 public void TestUndefinedSpellout() { 223 Locale greek = new Locale("el", "", ""); 224 RuleBasedNumberFormat[] formatters = { 225 new RuleBasedNumberFormat(greek, RuleBasedNumberFormat.SPELLOUT), 226 new RuleBasedNumberFormat(greek, RuleBasedNumberFormat.ORDINAL), 227 new RuleBasedNumberFormat(greek, RuleBasedNumberFormat.DURATION), 228 }; 229 230 String[] data = { 231 "0", 232 "1", 233 "15", 234 "20", 235 "23", 236 "73", 237 "88", 238 "100", 239 "106", 240 "127", 241 "200", 242 "579", 243 "1,000", 244 "2,000", 245 "3,004", 246 "4,567", 247 "15,943", 248 "105,000", 249 "2,345,678", 250 "-36", 251 "-36.91215", 252 "234.56789" 253 }; 254 255 NumberFormat decFormat = NumberFormat.getInstance(Locale.US); 256 for (int j = 0; j < formatters.length; ++j) { 257 com.ibm.icu.text.NumberFormat formatter = formatters[j]; 258 logln("formatter[" + j + "]"); 259 for (int i = 0; i < data.length; ++i) { 260 try { 261 String result = formatter.format(decFormat.parse(data[i])); 262 logln("[" + i + "] " + data[i] + " ==> " + result); 263 } 264 catch (Exception e) { 265 errln("formatter[" + j + "], data[" + i + "] " + data[i] + " threw exception " + e.getMessage()); 266 } 267 } 268 } 269 } 270 271 /** 272 * Perform a simple spot check on the English spellout rules 273 */ 274 public void TestEnglishSpellout() { 275 RuleBasedNumberFormat formatter = new RuleBasedNumberFormat(Locale.US, 276 RuleBasedNumberFormat.SPELLOUT); 277 String[][] testData = { 278 { "1", "one" }, 279 { "15", "fifteen" }, 280 { "20", "twenty" }, 281 { "23", "twenty-three" }, 282 { "73", "seventy-three" }, 283 { "88", "eighty-eight" }, 284 { "100", "one hundred" }, 285 { "106", "one hundred six" }, 286 { "127", "one hundred twenty-seven" }, 287 { "200", "two hundred" }, 288 { "579", "five hundred seventy-nine" }, 289 { "1,000", "one thousand" }, 290 { "2,000", "two thousand" }, 291 { "3,004", "three thousand four" }, 292 { "4,567", "four thousand five hundred sixty-seven" }, 293 { "15,943", "fifteen thousand nine hundred forty-three" }, 294 { "2,345,678", "two million three hundred forty-five " 295 + "thousand six hundred seventy-eight" }, 296 { "-36", "minus thirty-six" }, 297 { "234.567", "two hundred thirty-four point five six seven" } 298 }; 299 300 doTest(formatter, testData, true); 301 } 302 303 /** 304 * Perform a simple spot check on the English ordinal-abbreviation rules 305 */ 306 public void TestOrdinalAbbreviations() { 307 RuleBasedNumberFormat formatter= new RuleBasedNumberFormat(Locale.US, 308 RuleBasedNumberFormat.ORDINAL); 309 String[][] testData = { 310 { "1", "1st" }, 311 { "2", "2nd" }, 312 { "3", "3rd" }, 313 { "4", "4th" }, 314 { "7", "7th" }, 315 { "10", "10th" }, 316 { "11", "11th" }, 317 { "13", "13th" }, 318 { "20", "20th" }, 319 { "21", "21st" }, 320 { "22", "22nd" }, 321 { "23", "23rd" }, 322 { "24", "24th" }, 323 { "33", "33rd" }, 324 { "102", "102nd" }, 325 { "312", "312th" }, 326 { "12,345", "12,345th" } 327 }; 328 329 doTest(formatter, testData, false); 330 } 331 332 /** 333 * Perform a simple spot check on the duration-formatting rules 334 */ 335 public void TestDurations() { 336 RuleBasedNumberFormat formatter = new RuleBasedNumberFormat(Locale.US, 337 RuleBasedNumberFormat.DURATION); 338 String[][] testData = { 339 { "3,600", "1:00:00" }, //move me and I fail 340 { "0", "0 sec." }, 341 { "1", "1 sec." }, 342 { "24", "24 sec." }, 343 { "60", "1:00" }, 344 { "73", "1:13" }, 345 { "145", "2:25" }, 346 { "666", "11:06" }, 347 // { "3,600", "1:00:00" }, 348 { "3,740", "1:02:20" }, 349 { "10,293", "2:51:33" } 350 }; 351 352 doTest(formatter, testData, true); 353 } 354 355 /** 356 * Perform a simple spot check on the Spanish spellout rules 357 */ 358 public void TestSpanishSpellout() { 359 RuleBasedNumberFormat formatter = new RuleBasedNumberFormat(new Locale("es", "es", 360 ""), RuleBasedNumberFormat.SPELLOUT); 361 String[][] testData = { 362 { "1", "uno" }, 363 { "6", "seis" }, 364 { "16", "diecis\u00e9is" }, 365 { "20", "veinte" }, 366 { "24", "veinticuatro" }, 367 { "26", "veintis\u00e9is" }, 368 { "73", "setenta y tres" }, 369 { "88", "ochenta y ocho" }, 370 { "100", "cien" }, 371 { "106", "ciento seis" }, 372 { "127", "ciento veintisiete" }, 373 { "200", "doscientos" }, 374 { "579", "quinientos setenta y nueve" }, 375 { "1,000", "mil" }, 376 { "2,000", "dos mil" }, 377 { "3,004", "tres mil cuatro" }, 378 { "4,567", "cuatro mil quinientos sesenta y siete" }, 379 { "15,943", "quince mil novecientos cuarenta y tres" }, 380 { "2,345,678", "dos millones trescientos cuarenta y cinco mil " 381 + "seiscientos setenta y ocho"}, 382 { "-36", "menos treinta y seis" }, 383 { "234.567", "doscientos treinta y cuatro coma cinco seis siete" } 384 }; 385 386 doTest(formatter, testData, true); 387 } 388 389 /** 390 * Perform a simple spot check on the French spellout rules 391 */ 392 public void TestFrenchSpellout() { 393 RuleBasedNumberFormat formatter = new RuleBasedNumberFormat(Locale.FRANCE, 394 RuleBasedNumberFormat.SPELLOUT); 395 String[][] testData = { 396 { "1", "un" }, 397 { "15", "quinze" }, 398 { "20", "vingt" }, 399 { "21", "vingt-et-un" }, 400 { "23", "vingt-trois" }, 401 { "62", "soixante-deux" }, 402 { "70", "soixante-dix" }, 403 { "71", "soixante-et-onze" }, 404 { "73", "soixante-treize" }, 405 { "80", "quatre-vingts" }, 406 { "88", "quatre-vingt-huit" }, 407 { "100", "cent" }, 408 { "106", "cent six" }, 409 { "127", "cent vingt-sept" }, 410 { "200", "deux cents" }, 411 { "579", "cinq cent soixante-dix-neuf" }, 412 { "1,000", "mille" }, 413 { "1,123", "mille cent vingt-trois" }, 414 { "1,594", "mille cinq cent quatre-vingt-quatorze" }, 415 { "2,000", "deux mille" }, 416 { "3,004", "trois mille quatre" }, 417 { "4,567", "quatre mille cinq cent soixante-sept" }, 418 { "15,943", "quinze mille neuf cent quarante-trois" }, 419 { "2,345,678", "deux millions trois cent quarante-cinq mille " 420 + "six cent soixante-dix-huit" }, 421 { "-36", "moins trente-six" }, 422 { "234.567", "deux cent trente-quatre virgule cinq six sept" } 423 }; 424 425 doTest(formatter, testData, true); 426 } 427 428 /** 429 * Perform a simple spot check on the Swiss French spellout rules 430 */ 431 public void TestSwissFrenchSpellout() { 432 RuleBasedNumberFormat formatter = new RuleBasedNumberFormat(new Locale("fr", "CH"), 433 RuleBasedNumberFormat.SPELLOUT); 434 String[][] testData = { 435 { "1", "un" }, 436 { "15", "quinze" }, 437 { "20", "vingt" }, 438 { "21", "vingt-et-un" }, 439 { "23", "vingt-trois" }, 440 { "62", "soixante-deux" }, 441 { "70", "septante" }, 442 { "71", "septante-et-un" }, 443 { "73", "septante-trois" }, 444 { "80", "huitante" }, 445 { "88", "huitante-huit" }, 446 { "100", "cent" }, 447 { "106", "cent six" }, 448 { "127", "cent vingt-sept" }, 449 { "200", "deux cents" }, 450 { "579", "cinq cent septante-neuf" }, 451 { "1,000", "mille" }, 452 { "1,123", "mille cent vingt-trois" }, 453 { "1,594", "mille cinq cent nonante-quatre" }, 454 { "2,000", "deux mille" }, 455 { "3,004", "trois mille quatre" }, 456 { "4,567", "quatre mille cinq cent soixante-sept" }, 457 { "15,943", "quinze mille neuf cent quarante-trois" }, 458 { "2,345,678", "deux millions trois cent quarante-cinq mille " 459 + "six cent septante-huit" }, 460 { "-36", "moins trente-six" }, 461 { "234.567", "deux cent trente-quatre virgule cinq six sept" } 462 }; 463 464 doTest(formatter, testData, true); 465 } 466 467 /** 468 * Perform a simple spot check on the Italian spellout rules 469 */ 470 public void TestItalianSpellout() { 471 RuleBasedNumberFormat formatter = new RuleBasedNumberFormat(Locale.ITALIAN, 472 RuleBasedNumberFormat.SPELLOUT); 473 String[][] testData = { 474 { "1", "uno" }, 475 { "15", "quindici" }, 476 { "20", "venti" }, 477 { "23", "venti\u00ADtr\u00E9" }, 478 { "73", "settanta\u00ADtr\u00E9" }, 479 { "88", "ottant\u00ADotto" }, 480 { "100", "cento" }, 481 { "106", "cento\u00ADsei" }, 482 { "108", "cent\u00ADotto" }, 483 { "127", "cento\u00ADventi\u00ADsette" }, 484 { "181", "cent\u00ADottant\u00ADuno" }, 485 { "200", "due\u00ADcento" }, 486 { "579", "cinque\u00ADcento\u00ADsettanta\u00ADnove" }, 487 { "1,000", "mille" }, 488 { "2,000", "due\u00ADmila" }, 489 { "3,004", "tre\u00ADmila\u00ADquattro" }, 490 { "4,567", "quattro\u00ADmila\u00ADcinque\u00ADcento\u00ADsessanta\u00ADsette" }, 491 { "15,943", "quindici\u00ADmila\u00ADnove\u00ADcento\u00ADquaranta\u00ADtr\u00E9" }, 492 { "-36", "meno trenta\u00ADsei" }, 493 { "234.567", "due\u00ADcento\u00ADtrenta\u00ADquattro virgola cinque sei sette" } 494 }; 495 496 doTest(formatter, testData, true); 497 } 498 499 /** 500 * Perform a simple spot check on the German spellout rules 501 */ 502 public void TestGermanSpellout() { 503 RuleBasedNumberFormat formatter = new RuleBasedNumberFormat(Locale.GERMANY, 504 RuleBasedNumberFormat.SPELLOUT); 505 String[][] testData = { 506 { "1", "eins" }, 507 { "15", "f\u00fcnfzehn" }, 508 { "20", "zwanzig" }, 509 { "23", "drei\u00ADund\u00ADzwanzig" }, 510 { "73", "drei\u00ADund\u00ADsiebzig" }, 511 { "88", "acht\u00ADund\u00ADachtzig" }, 512 { "100", "ein\u00ADhundert" }, 513 { "106", "ein\u00ADhundert\u00ADsechs" }, 514 { "127", "ein\u00ADhundert\u00ADsieben\u00ADund\u00ADzwanzig" }, 515 { "200", "zwei\u00ADhundert" }, 516 { "579", "f\u00fcnf\u00ADhundert\u00ADneun\u00ADund\u00ADsiebzig" }, 517 { "1,000", "ein\u00ADtausend" }, 518 { "2,000", "zwei\u00ADtausend" }, 519 { "3,004", "drei\u00ADtausend\u00ADvier" }, 520 { "4,567", "vier\u00ADtausend\u00ADf\u00fcnf\u00ADhundert\u00ADsieben\u00ADund\u00ADsechzig" }, 521 { "15,943", "f\u00fcnfzehn\u00ADtausend\u00ADneun\u00ADhundert\u00ADdrei\u00ADund\u00ADvierzig" }, 522 { "2,345,678", "zwei Millionen drei\u00ADhundert\u00ADf\u00fcnf\u00ADund\u00ADvierzig\u00ADtausend\u00AD" 523 + "sechs\u00ADhundert\u00ADacht\u00ADund\u00ADsiebzig" } 524 }; 525 526 doTest(formatter, testData, true); 527 } 528 529 /** 530 * Perform a simple spot check on the Thai spellout rules 531 */ 532 public void TestThaiSpellout() { 533 RuleBasedNumberFormat formatter = new RuleBasedNumberFormat(new Locale("th", "TH"), 534 RuleBasedNumberFormat.SPELLOUT); 535 String[][] testData = { 536 { "0", "\u0e28\u0e39\u0e19\u0e22\u0e4c" }, 537 { "1", "\u0e2b\u0e19\u0e36\u0e48\u0e07" }, 538 { "10", "\u0e2a\u0e34\u0e1a" }, 539 { "11", "\u0e2a\u0e34\u0e1a\u200b\u0e40\u0e2d\u0e47\u0e14" }, 540 { "21", "\u0e22\u0e35\u0e48\u200b\u0e2a\u0e34\u0e1a\u200b\u0e40\u0e2d\u0e47\u0e14" }, 541 { "101", "\u0e2b\u0e19\u0e36\u0e48\u0e07\u200b\u0e23\u0e49\u0e2d\u0e22\u200b\u0e2b\u0e19\u0e36\u0e48\u0e07" }, 542 { "1.234", "\u0e2b\u0e19\u0e36\u0e48\u0e07\u200b\u0e08\u0e38\u0e14\u200b\u0e2a\u0e2d\u0e07\u0e2a\u0e32\u0e21\u0e2a\u0e35\u0e48" }, 543 { "21.45", "\u0e22\u0e35\u0e48\u200b\u0e2a\u0e34\u0e1a\u200b\u0e40\u0e2d\u0e47\u0e14\u200b\u0e08\u0e38\u0e14\u200b\u0e2a\u0e35\u0e48\u0e2b\u0e49\u0e32" }, 544 { "22.45", "\u0e22\u0e35\u0e48\u200b\u0e2a\u0e34\u0e1a\u200b\u0e2a\u0e2d\u0e07\u200b\u0e08\u0e38\u0e14\u200b\u0e2a\u0e35\u0e48\u0e2b\u0e49\u0e32" }, 545 { "23.45", "\u0e22\u0e35\u0e48\u200b\u0e2a\u0e34\u0e1a\u200b\u0e2a\u0e32\u0e21\u200b\u0e08\u0e38\u0e14\u200b\u0e2a\u0e35\u0e48\u0e2b\u0e49\u0e32" }, 546 { "123.45", "\u0e2b\u0e19\u0e36\u0e48\u0e07\u200b\u0e23\u0e49\u0e2d\u0e22\u200b\u0e22\u0e35\u0e48\u200b\u0e2a\u0e34\u0e1a\u200b\u0e2a\u0e32\u0e21\u200b\u0e08\u0e38\u0e14\u200b\u0e2a\u0e35\u0e48\u0e2b\u0e49\u0e32" }, 547 { "12,345.678", "\u0E2B\u0E19\u0E36\u0E48\u0E07\u200b\u0E2B\u0E21\u0E37\u0E48\u0E19\u200b\u0E2A\u0E2D\u0E07\u200b\u0E1E\u0E31\u0E19\u200b\u0E2A\u0E32\u0E21\u200b\u0E23\u0E49\u0E2D\u0E22\u200b\u0E2A\u0E35\u0E48\u200b\u0E2A\u0E34\u0E1A\u200b\u0E2B\u0E49\u0E32\u200b\u0E08\u0E38\u0E14\u200b\u0E2B\u0E01\u0E40\u0E08\u0E47\u0E14\u0E41\u0E1B\u0E14" }, 548 }; 549 550 doTest(formatter, testData, true); 551 } 552 553 /** 554 * Perform a simple spot check on the ordinal spellout rules 555 */ 556 public void TestPluralRules() { 557 String enRules = "%digits-ordinal:" 558 + "-x: >>;" 559 + "0: =#,##0=$(ordinal,one{st}two{nd}few{rd}other{th})$;"; 560 RuleBasedNumberFormat enFormatter = new RuleBasedNumberFormat(enRules, ULocale.ENGLISH); 561 String[][] enTestData = { 562 { "1", "1st" }, 563 { "2", "2nd" }, 564 { "3", "3rd" }, 565 { "4", "4th" }, 566 { "11", "11th" }, 567 { "12", "12th" }, 568 { "13", "13th" }, 569 { "14", "14th" }, 570 { "21", "21st" }, 571 { "22", "22nd" }, 572 { "23", "23rd" }, 573 { "24", "24th" }, 574 }; 575 576 doTest(enFormatter, enTestData, true); 577 578 // This is trying to model the feminine form, but don't worry about the details too much. 579 // We're trying to test the plural rules. 580 String ruRules = "%spellout-numbering:" 581 + "-x: >>;" 582 + "x.x: << >>;" 583 + "0: ;" 584 + "1: ;" 585 + "2: ;" 586 + "3: ;" 587 + "4: ;" 588 + "5: ;" 589 + "6: ;" 590 + "7: ;" 591 + "8: ;" 592 + "9: ;" 593 + "10: ;" 594 + "11: ;" 595 + "12: ;" 596 + "13: ;" 597 + "14: ;" 598 + "15: ;" 599 + "16: ;" 600 + "17: ;" 601 + "18: ;" 602 + "19: ;" 603 + "20: [ >>];" 604 + "30: [ >>];" 605 + "40: [ >>];" 606 + "50: [ >>];" 607 + "60: [ >>];" 608 + "70: [ >>];" 609 + "80: [ >>];" 610 + "90: [ >>];" 611 + "100: [ >>];" 612 + "200: <<[ >>];" 613 + "300: <<[ >>];" 614 + "500: <<[ >>];" 615 + "1000: << $(cardinal,one{}few{}other{})$[ >>];" 616 + "1000000: << $(cardinal,one{}few{}other{})$[ >>];"; 617 RuleBasedNumberFormat ruFormatter = new RuleBasedNumberFormat(ruRules, new ULocale("ru")); 618 String[][] ruTestData = { 619 { "1", "" }, 620 { "100", "" }, 621 { "125", " " }, 622 { "399", " " }, 623 { "1,000", " " }, 624 { "1,001", " " }, 625 { "2,000", " " }, 626 { "2,001", " " }, 627 { "2,002", " " }, 628 { "3,333", " " }, 629 { "5,000", " " }, 630 { "11,000", " " }, 631 { "21,000", " " }, 632 { "22,000", " " }, 633 { "25,001", " " }, 634 }; 635 636 doTest(ruFormatter, ruTestData, true); 637 638 // Make sure there are no divide by 0 errors. 639 String result = new RuleBasedNumberFormat(ruRules, new ULocale("ru")).format(21000); 640 if (!" ".equals(result)) { 641 errln("Got " + result + " for 21000"); 642 } 643 } 644 645 /** 646 * Perform a simple spot check on the parsing going into an infinite loop for alternate rules. 647 */ 648 public void TestMultiplePluralRules() { 649 // This is trying to model the feminine form, but don't worry about the details too much. 650 // We're trying to test the plural rules where there are different prefixes. 651 String ruRules = "%spellout-cardinal-feminine-genitive:" 652 + "-x: >>;" 653 + "x.x: << >>;" 654 + "0: ;" 655 + "1: ;" 656 + "2: ;" 657 + "3: ;" 658 + "4: ;" 659 + "5: ;" 660 + "6: ;" 661 + "7: ;" 662 + "8: ;" 663 + "9: ;" 664 + "10: ;" 665 + "11: ;" 666 + "12: ;" 667 + "13: ;" 668 + "14: ;" 669 + "15: ;" 670 + "16: ;" 671 + "17: ;" 672 + "18: ;" 673 + "19: ;" 674 + "20: [ >>];" 675 + "30: [ >>];" 676 + "40: [ >>];" 677 + "50: [ >>];" 678 + "60: [ >>];" 679 + "70: [ >>];" 680 + "80: [ >>];" 681 + "90: [ >>];" 682 + "100: [ >>];" 683 + "200: <<[ >>];" 684 + "1000: << $(cardinal,one{}few{}other{})$[ >>];" 685 + "1000000: =#,##0=;" 686 + "%spellout-cardinal-feminine:" 687 + "-x: >>;" 688 + "x.x: << >>;" 689 + "0: ;" 690 + "1: ;" 691 + "2: ;" 692 + "3: ;" 693 + "4: ;" 694 + "5: ;" 695 + "6: ;" 696 + "7: ;" 697 + "8: ;" 698 + "9: ;" 699 + "10: ;" 700 + "11: ;" 701 + "12: ;" 702 + "13: ;" 703 + "14: ;" 704 + "15: ;" 705 + "16: ;" 706 + "17: ;" 707 + "18: ;" 708 + "19: ;" 709 + "20: [ >>];" 710 + "30: [ >>];" 711 + "40: [ >>];" 712 + "50: [ >>];" 713 + "60: [ >>];" 714 + "70: [ >>];" 715 + "80: [ >>];" 716 + "90: [ >>];" 717 + "100: [ >>];" 718 + "200: <<[ >>];" 719 + "300: <<[ >>];" 720 + "500: <<[ >>];" 721 + "1000: << $(cardinal,one{}few{}other{})$[ >>];" 722 + "1000000: =#,##0=;"; 723 RuleBasedNumberFormat ruFormatter = new RuleBasedNumberFormat(ruRules, new ULocale("ru")); 724 try { 725 Number result; 726 if (1000 != (result = ruFormatter.parse(ruFormatter.format(1000))).doubleValue()) { 727 errln("RuleBasedNumberFormat did not return the correct value. Got: " + result); 728 } 729 if (1000 != (result = ruFormatter.parse(ruFormatter.format(1000, "%spellout-cardinal-feminine-genitive"))).doubleValue()) { 730 errln("RuleBasedNumberFormat did not return the correct value. Got: " + result); 731 } 732 if (1000 != (result = ruFormatter.parse(ruFormatter.format(1000, "%spellout-cardinal-feminine"))).doubleValue()) { 733 errln("RuleBasedNumberFormat did not return the correct value. Got: " + result); 734 } 735 } 736 catch (ParseException e) { 737 errln(e.toString()); 738 } 739 } 740 741 public void TestFractionalRuleSet() { 742 RuleBasedNumberFormat formatter = new RuleBasedNumberFormat(fracRules, 743 Locale.ENGLISH); 744 745 String[][] testData = { 746 { "0", "0" }, 747 { "1", "1" }, 748 { "10", "10" }, 749 { ".1", "1/10" }, 750 { ".11", "1/9" }, 751 { ".125", "1/8" }, 752 { ".1428", "1/7" }, 753 { ".1667", "1/6" }, 754 { ".2", "1/5" }, 755 { ".25", "1/4" }, 756 { ".333", "1/3" }, 757 { ".5", "1/2" }, 758 { "1.1", "1 1/10" }, 759 { "2.11", "2 1/9" }, 760 { "3.125", "3 1/8" }, 761 { "4.1428", "4 1/7" }, 762 { "5.1667", "5 1/6" }, 763 { "6.2", "6 1/5" }, 764 { "7.25", "7 1/4" }, 765 { "8.333", "8 1/3" }, 766 { "9.5", "9 1/2" }, 767 { ".2222", "2/9" }, 768 { ".4444", "4/9" }, 769 { ".5555", "5/9" }, 770 { "1.2856", "1 2/7" } 771 }; 772 doTest(formatter, testData, false); // exact values aren't parsable from fractions 773 } 774 775 public void TestSwedishSpellout() 776 { 777 Locale locale = new Locale("sv", "", ""); 778 RuleBasedNumberFormat formatter = new RuleBasedNumberFormat(locale, 779 RuleBasedNumberFormat.SPELLOUT); 780 781 String[][] testDataDefault = { 782 { "101", "ett\u00ADhundra\u00ADett" }, 783 { "123", "ett\u00ADhundra\u00ADtjugo\u00ADtre" }, 784 { "1,001", "et\u00ADtusen ett" }, 785 { "1,100", "et\u00ADtusen ett\u00ADhundra" }, 786 { "1,101", "et\u00ADtusen ett\u00ADhundra\u00ADett" }, 787 { "1,234", "et\u00ADtusen tv\u00e5\u00ADhundra\u00ADtrettio\u00ADfyra" }, 788 { "10,001", "tio\u00ADtusen ett" }, 789 { "11,000", "elva\u00ADtusen" }, 790 { "12,000", "tolv\u00ADtusen" }, 791 { "20,000", "tjugo\u00ADtusen" }, 792 { "21,000", "tjugo\u00ADet\u00ADtusen" }, 793 { "21,001", "tjugo\u00ADet\u00ADtusen ett" }, 794 { "200,000", "tv\u00e5\u00ADhundra\u00ADtusen" }, 795 { "201,000", "tv\u00e5\u00ADhundra\u00ADet\u00ADtusen" }, 796 { "200,200", "tv\u00e5\u00ADhundra\u00ADtusen tv\u00e5\u00ADhundra" }, 797 { "2,002,000", "tv\u00e5 miljoner tv\u00e5\u00ADtusen" }, 798 { "12,345,678", "tolv miljoner tre\u00ADhundra\u00ADfyrtio\u00ADfem\u00ADtusen sex\u00ADhundra\u00ADsjuttio\u00AD\u00e5tta" }, 799 { "123,456.789", "ett\u00ADhundra\u00ADtjugo\u00ADtre\u00ADtusen fyra\u00ADhundra\u00ADfemtio\u00ADsex komma sju \u00e5tta nio" }, 800 { "-12,345.678", "minus tolv\u00ADtusen tre\u00ADhundra\u00ADfyrtio\u00ADfem komma sex sju \u00e5tta" }, 801 }; 802 803 logln("testing default rules"); 804 doTest(formatter, testDataDefault, true); 805 806 String[][] testDataNeutrum = { 807 { "101", "ett\u00adhundra\u00adett" }, 808 { "1,001", "et\u00adtusen ett" }, 809 { "1,101", "et\u00adtusen ett\u00adhundra\u00adett" }, 810 { "10,001", "tio\u00adtusen ett" }, 811 { "21,001", "tjugo\u00adet\u00adtusen ett" } 812 }; 813 814 formatter.setDefaultRuleSet("%spellout-cardinal-neuter"); 815 logln("testing neutrum rules"); 816 doTest(formatter, testDataNeutrum, true); 817 818 String[][] testDataYear = { 819 { "101", "ett\u00adhundra\u00adett" }, 820 { "900", "nio\u00adhundra" }, 821 { "1,001", "et\u00adtusen ett" }, 822 { "1,100", "elva\u00adhundra" }, 823 { "1,101", "elva\u00adhundra\u00adett" }, 824 { "1,234", "tolv\u00adhundra\u00adtrettio\u00adfyra" }, 825 { "2,001", "tjugo\u00adhundra\u00adett" }, 826 { "10,001", "tio\u00adtusen ett" } 827 }; 828 829 formatter.setDefaultRuleSet("%spellout-numbering-year"); 830 logln("testing year rules"); 831 doTest(formatter, testDataYear, true); 832 } 833 834 public void TestBigNumbers() { 835 BigInteger bigI = new BigInteger("1234567890", 10); 836 StringBuffer buf = new StringBuffer(); 837 RuleBasedNumberFormat fmt = new RuleBasedNumberFormat(RuleBasedNumberFormat.SPELLOUT); 838 fmt.format(bigI, buf, null); 839 logln("big int: " + buf.toString()); 840 841 buf.setLength(0); 842 java.math.BigDecimal bigD = new java.math.BigDecimal(bigI); 843 fmt.format(bigD, buf, null); 844 logln("big dec: " + buf.toString()); 845 } 846 847 public void TestTrailingSemicolon() { 848 String thaiRules = 849 "%default:\n" + 850 " -x: \u0e25\u0e1a>>;\n" + 851 " x.x: <<\u0e08\u0e38\u0e14>>>;\n" + 852 " \u0e28\u0e39\u0e19\u0e22\u0e4c; \u0e2b\u0e19\u0e36\u0e48\u0e07; \u0e2a\u0e2d\u0e07; \u0e2a\u0e32\u0e21;\n" + 853 " \u0e2a\u0e35\u0e48; \u0e2b\u0e49\u0e32; \u0e2b\u0e01; \u0e40\u0e08\u0e47\u0e14; \u0e41\u0e1b\u0e14;\n" + 854 " \u0e40\u0e01\u0e49\u0e32; \u0e2a\u0e34\u0e1a; \u0e2a\u0e34\u0e1a\u0e40\u0e2d\u0e47\u0e14;\n" + 855 " \u0e2a\u0e34\u0e1a\u0e2a\u0e2d\u0e07; \u0e2a\u0e34\u0e1a\u0e2a\u0e32\u0e21;\n" + 856 " \u0e2a\u0e34\u0e1a\u0e2a\u0e35\u0e48; \u0e2a\u0e34\u0e1a\u0e2b\u0e49\u0e32;\n" + 857 " \u0e2a\u0e34\u0e1a\u0e2b\u0e01; \u0e2a\u0e34\u0e1a\u0e40\u0e08\u0e47\u0e14;\n" + 858 " \u0e2a\u0e34\u0e1a\u0e41\u0e1b\u0e14; \u0e2a\u0e34\u0e1a\u0e40\u0e01\u0e49\u0e32;\n" + 859 " 20: \u0e22\u0e35\u0e48\u0e2a\u0e34\u0e1a[>%%alt-ones>];\n" + 860 " 30: \u0e2a\u0e32\u0e21\u0e2a\u0e34\u0e1a[>%%alt-ones>];\n" + 861 " 40: \u0e2a\u0e35\u0e48\u0e2a\u0e34\u0e1a[>%%alt-ones>];\n" + 862 " 50: \u0e2b\u0e49\u0e32\u0e2a\u0e34\u0e1a[>%%alt-ones>];\n" + 863 " 60: \u0e2b\u0e01\u0e2a\u0e34\u0e1a[>%%alt-ones>];\n" + 864 " 70: \u0e40\u0e08\u0e47\u0e14\u0e2a\u0e34\u0e1a[>%%alt-ones>];\n" + 865 " 80: \u0e41\u0e1b\u0e14\u0e2a\u0e34\u0e1a[>%%alt-ones>];\n" + 866 " 90: \u0e40\u0e01\u0e49\u0e32\u0e2a\u0e34\u0e1a[>%%alt-ones>];\n" + 867 " 100: <<\u0e23\u0e49\u0e2d\u0e22[>>];\n" + 868 " 1000: <<\u0e1e\u0e31\u0e19[>>];\n" + 869 " 10000: <<\u0e2b\u0e21\u0e37\u0e48\u0e19[>>];\n" + 870 " 100000: <<\u0e41\u0e2a\u0e19[>>];\n" + 871 " 1,000,000: <<\u0e25\u0e49\u0e32\u0e19[>>];\n" + 872 " 1,000,000,000: <<\u0e1e\u0e31\u0e19\u0e25\u0e49\u0e32\u0e19[>>];\n" + 873 " 1,000,000,000,000: <<\u0e25\u0e49\u0e32\u0e19\u0e25\u0e49\u0e32\u0e19[>>];\n" + 874 " 1,000,000,000,000,000: =#,##0=;\n" + 875 "%%alt-ones:\n" + 876 " \u0e28\u0e39\u0e19\u0e22\u0e4c;\n" + 877 " \u0e40\u0e2d\u0e47\u0e14;\n" + 878 " =%default=;\n ; ;; "; 879 880 RuleBasedNumberFormat formatter = new RuleBasedNumberFormat(thaiRules, new Locale("th", "TH", "")); 881 882 String[][] testData = { 883 { "0", "\u0e28\u0e39\u0e19\u0e22\u0e4c" }, 884 { "1", "\u0e2b\u0e19\u0e36\u0e48\u0e07" }, 885 { "123.45", "\u0e2b\u0e19\u0e36\u0e48\u0e07\u0e23\u0e49\u0e2d\u0e22\u0e22\u0e35\u0e48\u0e2a\u0e34\u0e1a\u0e2a\u0e32\u0e21\u0e08\u0e38\u0e14\u0e2a\u0e35\u0e48\u0e2b\u0e49\u0e32" } 886 }; 887 888 doTest(formatter, testData, true); 889 } 890 891 public void TestSmallValues() { 892 String[][] testData = { 893 { "0.001", "zero point zero zero one" }, 894 { "0.0001", "zero point zero zero zero one" }, 895 { "0.00001", "zero point zero zero zero zero one" }, 896 { "0.000001", "zero point zero zero zero zero zero one" }, 897 { "0.0000001", "zero point zero zero zero zero zero zero one" }, 898 { "0.00000001", "zero point zero zero zero zero zero zero zero one" }, 899 { "0.000000001", "zero point zero zero zero zero zero zero zero zero one" }, 900 { "0.0000000001", "zero point zero zero zero zero zero zero zero zero zero one" }, 901 { "0.00000000001", "zero point zero zero zero zero zero zero zero zero zero zero one" }, 902 { "0.000000000001", "zero point zero zero zero zero zero zero zero zero zero zero zero one" }, 903 { "0.0000000000001", "zero point zero zero zero zero zero zero zero zero zero zero zero zero one" }, 904 { "0.00000000000001", "zero point zero zero zero zero zero zero zero zero zero zero zero zero zero one" }, 905 { "0.000000000000001", "zero point zero zero zero zero zero zero zero zero zero zero zero zero zero zero one" }, 906 { "10,000,000.001", "ten million point zero zero one" }, 907 { "10,000,000.0001", "ten million point zero zero zero one" }, 908 { "10,000,000.00001", "ten million point zero zero zero zero one" }, 909 { "10,000,000.000001", "ten million point zero zero zero zero zero one" }, 910 { "10,000,000.0000001", "ten million point zero zero zero zero zero zero one" }, 911 { "10,000,000.00000001", "ten million point zero zero zero zero zero zero zero one" }, 912 { "10,000,000.000000002", "ten million point zero zero zero zero zero zero zero zero two" }, 913 { "10,000,000", "ten million" }, 914 { "1,234,567,890.0987654", "one billion two hundred thirty-four million five hundred sixty-seven thousand eight hundred ninety point zero nine eight seven six five four" }, 915 { "123,456,789.9876543", "one hundred twenty-three million four hundred fifty-six thousand seven hundred eighty-nine point nine eight seven six five four three" }, 916 { "12,345,678.87654321", "twelve million three hundred forty-five thousand six hundred seventy-eight point eight seven six five four three two one" }, 917 { "1,234,567.7654321", "one million two hundred thirty-four thousand five hundred sixty-seven point seven six five four three two one" }, 918 { "123,456.654321", "one hundred twenty-three thousand four hundred fifty-six point six five four three two one" }, 919 { "12,345.54321", "twelve thousand three hundred forty-five point five four three two one" }, 920 { "1,234.4321", "one thousand two hundred thirty-four point four three two one" }, 921 { "123.321", "one hundred twenty-three point three two one" }, 922 { "0.0000000011754944", "zero point zero zero zero zero zero zero zero zero one one seven five four nine four four" }, 923 { "0.000001175494351", "zero point zero zero zero zero zero one one seven five four nine four three five one" }, 924 }; 925 926 RuleBasedNumberFormat formatter = new RuleBasedNumberFormat(Locale.US, RuleBasedNumberFormat.SPELLOUT); 927 doTest(formatter, testData, true); 928 } 929 930 public void TestRuleSetDisplayName() { 931 /** 932 * Spellout rules for U.K. English. 933 * I borrow the rule sets for TestRuleSetDisplayName() 934 */ 935 final String ukEnglish = 936 "%simplified:\n" 937 + " -x: minus >>;\n" 938 + " x.x: << point >>;\n" 939 + " zero; one; two; three; four; five; six; seven; eight; nine;\n" 940 + " ten; eleven; twelve; thirteen; fourteen; fifteen; sixteen;\n" 941 + " seventeen; eighteen; nineteen;\n" 942 + " 20: twenty[->>];\n" 943 + " 30: thirty[->>];\n" 944 + " 40: forty[->>];\n" 945 + " 50: fifty[->>];\n" 946 + " 60: sixty[->>];\n" 947 + " 70: seventy[->>];\n" 948 + " 80: eighty[->>];\n" 949 + " 90: ninety[->>];\n" 950 + " 100: << hundred[ >>];\n" 951 + " 1000: << thousand[ >>];\n" 952 + " 1,000,000: << million[ >>];\n" 953 + " 1,000,000,000,000: << billion[ >>];\n" 954 + " 1,000,000,000,000,000: =#,##0=;\n" 955 + "%alt-teens:\n" 956 + " =%simplified=;\n" 957 + " 1000>: <%%alt-hundreds<[ >>];\n" 958 + " 10,000: =%simplified=;\n" 959 + " 1,000,000: << million[ >%simplified>];\n" 960 + " 1,000,000,000,000: << billion[ >%simplified>];\n" 961 + " 1,000,000,000,000,000: =#,##0=;\n" 962 + "%%alt-hundreds:\n" 963 + " 0: SHOULD NEVER GET HERE!;\n" 964 + " 10: <%simplified< thousand;\n" 965 + " 11: =%simplified= hundred>%%empty>;\n" 966 + "%%empty:\n" 967 + " 0:;" 968 + "%ordinal:\n" 969 + " zeroth; first; second; third; fourth; fifth; sixth; seventh;\n" 970 + " eighth; ninth;\n" 971 + " tenth; eleventh; twelfth; thirteenth; fourteenth;\n" 972 + " fifteenth; sixteenth; seventeenth; eighteenth;\n" 973 + " nineteenth;\n" 974 + " twentieth; twenty->>;\n" 975 + " 30: thirtieth; thirty->>;\n" 976 + " 40: fortieth; forty->>;\n" 977 + " 50: fiftieth; fifty->>;\n" 978 + " 60: sixtieth; sixty->>;\n" 979 + " 70: seventieth; seventy->>;\n" 980 + " 80: eightieth; eighty->>;\n" 981 + " 90: ninetieth; ninety->>;\n" 982 + " 100: <%simplified< hundredth; <%simplified< hundred >>;\n" 983 + " 1000: <%simplified< thousandth; <%simplified< thousand >>;\n" 984 + " 1,000,000: <%simplified< millionth; <%simplified< million >>;\n" 985 + " 1,000,000,000,000: <%simplified< billionth;\n" 986 + " <%simplified< billion >>;\n" 987 + " 1,000,000,000,000,000: =#,##0=;" 988 + "%default:\n" 989 + " -x: minus >>;\n" 990 + " x.x: << point >>;\n" 991 + " =%simplified=;\n" 992 + " 100: << hundred[ >%%and>];\n" 993 + " 1000: << thousand[ >%%and>];\n" 994 + " 100,000>>: << thousand[>%%commas>];\n" 995 + " 1,000,000: << million[>%%commas>];\n" 996 + " 1,000,000,000,000: << billion[>%%commas>];\n" 997 + " 1,000,000,000,000,000: =#,##0=;\n" 998 + "%%and:\n" 999 + " and =%default=;\n" 1000 + " 100: =%default=;\n" 1001 + "%%commas:\n" 1002 + " ' and =%default=;\n" 1003 + " 100: , =%default=;\n" 1004 + " 1000: , <%default< thousand, >%default>;\n" 1005 + " 1,000,000: , =%default=;" 1006 + "%%lenient-parse:\n" 1007 + " & ' ' , ',' ;\n"; 1008 ULocale.setDefault(ULocale.US); 1009 String[][] localizations = new String[][] { 1010 /* public rule sets*/ 1011 {"%simplified", "%default", "%ordinal"}, 1012 /* display names in "en_US" locale*/ 1013 {"en_US", "Simplified", "Default", "Ordinal"}, 1014 /* display names in "zh_Hans" locale*/ 1015 {"zh_Hans", "\u7B80\u5316", "\u7F3A\u7701", "\u5E8F\u5217"}, 1016 /* display names in a fake locale*/ 1017 {"foo_Bar_BAZ", "Simplified", "Default", "Ordinal"} 1018 }; 1019 1020 //Construct RuleBasedNumberFormat by rule sets and localizations list 1021 RuleBasedNumberFormat formatter 1022 = new RuleBasedNumberFormat(ukEnglish, localizations, ULocale.US); 1023 RuleBasedNumberFormat f2= new RuleBasedNumberFormat(ukEnglish, localizations); 1024 assertTrue("Check the two formatters' equality", formatter.equals(f2)); 1025 1026 //get displayName by name 1027 String[] ruleSetNames = formatter.getRuleSetNames(); 1028 for (int i=0; i<ruleSetNames.length; i++) { 1029 logln("Rule set name: " + ruleSetNames[i]); 1030 String RSName_defLoc = formatter.getRuleSetDisplayName(ruleSetNames[i]); 1031 assertEquals("Display name in default locale", localizations[1][i+1], RSName_defLoc); 1032 String RSName_loc = formatter.getRuleSetDisplayName(ruleSetNames[i], ULocale.CHINA); 1033 assertEquals("Display name in Chinese", localizations[2][i+1], RSName_loc); 1034 } 1035 1036 // getDefaultRuleSetName 1037 String defaultRS = formatter.getDefaultRuleSetName(); 1038 //you know that the default rule set is %simplified according to rule sets string ukEnglish 1039 assertEquals("getDefaultRuleSetName", "%simplified", defaultRS); 1040 1041 //get locales of localizations 1042 ULocale[] locales = formatter.getRuleSetDisplayNameLocales(); 1043 for (int i=0; i<locales.length; i++) { 1044 logln(locales[i].getName()); 1045 } 1046 1047 //get displayNames 1048 String[] RSNames_defLoc = formatter.getRuleSetDisplayNames(); 1049 for (int i=0; i<RSNames_defLoc.length; i++) { 1050 assertEquals("getRuleSetDisplayNames in default locale", localizations[1][i+1], RSNames_defLoc[i]); 1051 } 1052 1053 String[] RSNames_loc = formatter.getRuleSetDisplayNames(ULocale.UK); 1054 for (int i=0; i<RSNames_loc.length; i++) { 1055 assertEquals("getRuleSetDisplayNames in English", localizations[1][i+1], RSNames_loc[i]); 1056 } 1057 1058 RSNames_loc = formatter.getRuleSetDisplayNames(ULocale.CHINA); 1059 for (int i=0; i<RSNames_loc.length; i++) { 1060 assertEquals("getRuleSetDisplayNames in Chinese", localizations[2][i+1], RSNames_loc[i]); 1061 } 1062 1063 RSNames_loc = formatter.getRuleSetDisplayNames(new ULocale("foo_Bar_BAZ")); 1064 for (int i=0; i<RSNames_loc.length; i++) { 1065 assertEquals("getRuleSetDisplayNames in fake locale", localizations[3][i+1], RSNames_loc[i]); 1066 } 1067 } 1068 1069 public void TestAllLocales() { 1070 StringBuilder errors = new StringBuilder(); 1071 String[] names = { 1072 " (spellout) ", 1073 " (ordinal) " 1074 //" (duration) " // English only 1075 }; 1076 double[] numbers = {45.678, 1, 2, 10, 11, 100, 110, 200, 1000, 1111, -1111}; 1077 int count = numbers.length; 1078 Random r = (count <= numbers.length ? null : createRandom()); 1079 1080 for (ULocale loc : NumberFormat.getAvailableULocales()) { 1081 for (int j = 0; j < names.length; ++j) { 1082 RuleBasedNumberFormat fmt = new RuleBasedNumberFormat(loc, j+1); 1083 if (!loc.equals(fmt.getLocale(ULocale.ACTUAL_LOCALE))) { 1084 // Skip the redundancy 1085 break; 1086 } 1087 1088 for (int c = 0; c < count; c++) { 1089 double n; 1090 if (c < numbers.length) { 1091 n = numbers[c]; 1092 } else { 1093 n = (r.nextInt(10000) - 3000) / 16d; 1094 } 1095 1096 String s = fmt.format(n); 1097 if (isVerbose()) { 1098 logln(loc.getName() + names[j] + "success format: " + n + " -> " + s); 1099 } 1100 1101 try { 1102 // RBNF parse is extremely slow when lenient option is enabled. 1103 // non-lenient parse 1104 fmt.setLenientParseMode(false); 1105 Number num = fmt.parse(s); 1106 if (isVerbose()) { 1107 logln(loc.getName() + names[j] + "success parse: " + s + " -> " + num); 1108 } 1109 if (j != 0) { 1110 // TODO: Fix the ordinal rules. 1111 continue; 1112 } 1113 if (n != num.doubleValue()) { 1114 errors.append("\n" + loc + names[j] + "got " + num + " expected " + n); 1115 } 1116 } catch (ParseException pe) { 1117 String msg = loc.getName() + names[j] + "ERROR:" + pe.getMessage(); 1118 logln(msg); 1119 errors.append("\n" + msg); 1120 } 1121 } 1122 } 1123 } 1124 if (errors.length() > 0) { 1125 errln(errors.toString()); 1126 } 1127 } 1128 1129 void doTest(RuleBasedNumberFormat formatter, String[][] testData, 1130 boolean testParsing) { 1131 // NumberFormat decFmt = NumberFormat.getInstance(Locale.US); 1132 NumberFormat decFmt = new DecimalFormat("#,###.################"); 1133 try { 1134 for (int i = 0; i < testData.length; i++) { 1135 String number = testData[i][0]; 1136 String expectedWords = testData[i][1]; 1137 if (isVerbose()) { 1138 logln("test[" + i + "] number: " + number + " target: " + expectedWords); 1139 } 1140 Number num = decFmt.parse(number); 1141 String actualWords = formatter.format(num); 1142 1143 if (!actualWords.equals(expectedWords)) { 1144 errln("Spot check format failed: for " + number + ", expected\n " 1145 + expectedWords + ", but got\n " + 1146 actualWords); 1147 } 1148 else if (testParsing) { 1149 String actualNumber = decFmt.format(formatter 1150 .parse(actualWords)); 1151 1152 if (!actualNumber.equals(number)) { 1153 errln("Spot check parse failed: for " + actualWords + 1154 ", expected " + number + ", but got " + 1155 actualNumber); 1156 } 1157 } 1158 } 1159 } 1160 catch (Throwable e) { 1161 e.printStackTrace(); 1162 errln("Test failed with exception: " + e.toString()); 1163 } 1164 } 1165 1166 /* Tests the method 1167 * public boolean equals(Object that) 1168 */ 1169 public void TestEquals(){ 1170 // Tests when "if (!(that instanceof RuleBasedNumberFormat))" is true 1171 RuleBasedNumberFormat rbnf = new RuleBasedNumberFormat("dummy"); 1172 if (rbnf.equals("dummy") || 1173 rbnf.equals(new Character('a')) || 1174 rbnf.equals(new Object()) || 1175 rbnf.equals(-1) || 1176 rbnf.equals(0) || 1177 rbnf.equals(1) || 1178 rbnf.equals(-1.0) || 1179 rbnf.equals(0.0) || 1180 rbnf.equals(1.0)) 1181 { 1182 errln("RuleBasedNumberFormat.equals(Object that) was suppose to " + 1183 "be false for an invalid object."); 1184 } 1185 1186 // Tests when 1187 // "if (!locale.equals(that2.locale) || lenientParse != that2.lenientParse)" 1188 // is true 1189 RuleBasedNumberFormat rbnf1 = new RuleBasedNumberFormat("dummy", new Locale("en")); 1190 RuleBasedNumberFormat rbnf2 = new RuleBasedNumberFormat("dummy", new Locale("jp")); 1191 RuleBasedNumberFormat rbnf3 = new RuleBasedNumberFormat("dummy", new Locale("sp")); 1192 RuleBasedNumberFormat rbnf4 = new RuleBasedNumberFormat("dummy", new Locale("fr")); 1193 1194 if(rbnf1.equals(rbnf2) || rbnf1.equals(rbnf3) || 1195 rbnf1.equals(rbnf4) || rbnf2.equals(rbnf3) || 1196 rbnf2.equals(rbnf4) || rbnf3.equals(rbnf4)){ 1197 errln("RuleBasedNumberFormat.equals(Object that) was suppose to " + 1198 "be false for an invalid object."); 1199 } 1200 1201 if(!rbnf1.equals(rbnf1)){ 1202 errln("RuleBasedNumberFormat.equals(Object that) was not suppose to " + 1203 "be false for an invalid object."); 1204 } 1205 1206 if(!rbnf2.equals(rbnf2)){ 1207 errln("RuleBasedNumberFormat.equals(Object that) was not suppose to " + 1208 "be false for an invalid object."); 1209 } 1210 1211 if(!rbnf3.equals(rbnf3)){ 1212 errln("RuleBasedNumberFormat.equals(Object that) was not suppose to " + 1213 "be false for an invalid object."); 1214 } 1215 1216 if(!rbnf4.equals(rbnf4)){ 1217 errln("RuleBasedNumberFormat.equals(Object that) was not suppose to " + 1218 "be false for an invalid object."); 1219 } 1220 1221 RuleBasedNumberFormat rbnf5 = new RuleBasedNumberFormat("dummy", new Locale("en")); 1222 RuleBasedNumberFormat rbnf6 = new RuleBasedNumberFormat("dummy", new Locale("en")); 1223 1224 if(!rbnf5.equals(rbnf6)){ 1225 errln("RuleBasedNumberFormat.equals(Object that) was not suppose to " + 1226 "be false for an invalid object."); 1227 } 1228 rbnf6.setLenientParseMode(true); 1229 1230 if(rbnf5.equals(rbnf6)){ 1231 errln("RuleBasedNumberFormat.equals(Object that) was suppose to " + 1232 "be false for an invalid object."); 1233 } 1234 1235 // Tests when "if (!ruleSets[i].equals(that2.ruleSets[i]))" is true 1236 RuleBasedNumberFormat rbnf7 = new RuleBasedNumberFormat("not_dummy", new Locale("en")); 1237 if(rbnf5.equals(rbnf7)){ 1238 errln("RuleBasedNumberFormat.equals(Object that) was suppose to " + 1239 "be false for an invalid object."); 1240 } 1241 } 1242 1243 /* Tests the method 1244 * public ULocale[] getRuleSetDisplayNameLocales() 1245 */ 1246 public void TestGetRuleDisplayNameLocales(){ 1247 // Tests when "if (ruleSetDisplayNames != null" is false 1248 RuleBasedNumberFormat rbnf = new RuleBasedNumberFormat("dummy"); 1249 rbnf.getRuleSetDisplayNameLocales(); 1250 if(rbnf.getRuleSetDisplayNameLocales() != null){ 1251 errln("RuleBasedNumberFormat.getRuleDisplayNameLocales() was suppose to " + 1252 "return null."); 1253 } 1254 } 1255 1256 /* Tests the method 1257 * private String[] getNameListForLocale(ULocale loc) 1258 * public String[] getRuleSetDisplayNames(ULocale loc) 1259 */ 1260 public void TestGetNameListForLocale(){ 1261 // Tests when "if (names != null)" is false and 1262 // "if (loc != null && ruleSetDisplayNames != null)" is false 1263 RuleBasedNumberFormat rbnf = new RuleBasedNumberFormat("dummy"); 1264 rbnf.getRuleSetDisplayNames(null); 1265 try{ 1266 rbnf.getRuleSetDisplayNames(null); 1267 } catch(Exception e){ 1268 errln("RuleBasedNumberFormat.getRuleSetDisplayNames(ULocale loc) " + 1269 "was not suppose to have an exception."); 1270 } 1271 } 1272 1273 /* Tests the method 1274 * public String getRuleSetDisplayName(String ruleSetName, ULocale loc) 1275 */ 1276 public void TestGetRulesSetDisplayName(){ 1277 RuleBasedNumberFormat rbnf = new RuleBasedNumberFormat("dummy"); 1278 //rbnf.getRuleSetDisplayName("dummy", new ULocale("en_US")); 1279 1280 // Tests when "if (names != null) " is true 1281 1282 // Tests when the method throws an exception 1283 try{ 1284 rbnf.getRuleSetDisplayName("", new ULocale("en_US")); 1285 errln("RuleBasedNumberFormat.getRuleSetDisplayName(String ruleSetName, ULocale loc) " + 1286 "was suppose to have an exception."); 1287 } catch(Exception e){} 1288 1289 try{ 1290 rbnf.getRuleSetDisplayName("dummy", new ULocale("en_US")); 1291 errln("RuleBasedNumberFormat.getRuleSetDisplayName(String ruleSetName, ULocale loc) " + 1292 "was suppose to have an exception."); 1293 } catch(Exception e){} 1294 } 1295 1296 /* Test the method 1297 * public void process(StringBuffer buf, NFRuleSet ruleSet) 1298 */ 1299 public void TestChineseProcess(){ 1300 String ruleWithChinese = 1301 "%simplified:\n" 1302 + " -x: minus >>;\n" 1303 + " x.x: << point >>;\n" 1304 + " zero; one; two; three; four; five; six; seven; eight; nine;\n" 1305 + " ten; eleven; twelve; thirteen; fourteen; fifteen; sixteen;\n" 1306 + " seventeen; eighteen; nineteen;\n" 1307 + " 20: twenty[->>];\n" 1308 + " 30: thirty[->>];\n" 1309 + " 40: forty[->>];\n" 1310 + " 50: fifty[->>];\n" 1311 + " 60: sixty[->>];\n" 1312 + " 70: seventy[->>];\n" 1313 + " 80: eighty[->>];\n" 1314 + " 90: ninety[->>];\n" 1315 + " 100: << hundred[ >>];\n" 1316 + " 1000: << thousand[ >>];\n" 1317 + " 1,000,000: << million[ >>];\n" 1318 + " 1,000,000,000,000: << billion[ >>];\n" 1319 + " 1,000,000,000,000,000: =#,##0=;\n" 1320 + "%alt-teens:\n" 1321 + " =%simplified=;\n" 1322 + " 1000>: <%%alt-hundreds<[ >>];\n" 1323 + " 10,000: =%simplified=;\n" 1324 + " 1,000,000: << million[ >%simplified>];\n" 1325 + " 1,000,000,000,000: << billion[ >%simplified>];\n" 1326 + " 1,000,000,000,000,000: =#,##0=;\n" 1327 + "%%alt-hundreds:\n" 1328 + " 0: SHOULD NEVER GET HERE!;\n" 1329 + " 10: <%simplified< thousand;\n" 1330 + " 11: =%simplified= hundred>%%empty>;\n" 1331 + "%%empty:\n" 1332 + " 0:;" 1333 + "%accounting:\n" 1334 + " \u842c; \u842c; \u842c; \u842c; \u842c; \u842c; \u842c; \u842c;\n" 1335 + " \u842c; \u842c;\n" 1336 + " \u842c; \u842c; \u842c; \u842c; \u842c;\n" 1337 + " \u842c; \u842c; \u842c; \u842c;\n" 1338 + " \u842c;\n" 1339 + " twentieth; \u96f6|>>;\n" 1340 + " 30: \u96f6; \u96f6|>>;\n" 1341 + " 40: \u96f6; \u96f6|>>;\n" 1342 + " 50: \u96f6; \u96f6|>>;\n" 1343 + " 60: \u96f6; \u96f6|>>;\n" 1344 + " 70: \u96f6; \u96f6|>>;\n" 1345 + " 80: \u96f6; \u96f6|>>;\n" 1346 + " 90: \u96f6; \u96f6|>>;\n" 1347 + " 100: <%simplified< \u96f6; <%simplified< \u96f6 >>;\n" 1348 + " 1000: <%simplified< \u96f6; <%simplified< \u96f6 >>;\n" 1349 + " 1,000,000: <%simplified< \u96f6; <%simplified< \u96f6 >>;\n" 1350 + " 1,000,000,000,000: <%simplified< \u96f6;\n" 1351 + " <%simplified< \u96f6 >>;\n" 1352 + " 1,000,000,000,000,000: =#,##0=;" 1353 + "%default:\n" 1354 + " -x: minus >>;\n" 1355 + " x.x: << point >>;\n" 1356 + " =%simplified=;\n" 1357 + " 100: << hundred[ >%%and>];\n" 1358 + " 1000: << thousand[ >%%and>];\n" 1359 + " 100,000>>: << thousand[>%%commas>];\n" 1360 + " 1,000,000: << million[>%%commas>];\n" 1361 + " 1,000,000,000,000: << billion[>%%commas>];\n" 1362 + " 1,000,000,000,000,000: =#,##0=;\n" 1363 + "%%and:\n" 1364 + " and =%default=;\n" 1365 + " 100: =%default=;\n" 1366 + "%%commas:\n" 1367 + " ' and =%default=;\n" 1368 + " 100: , =%default=;\n" 1369 + " 1000: , <%default< thousand, >%default>;\n" 1370 + " 1,000,000: , =%default=;" 1371 + "%traditional:\n" 1372 + " -x: \u3007| >>;\n" 1373 + " x.x: << \u9ede >>;\n" 1374 + " \u842c; \u842c; \u842c; \u842c; \u842c; \u842c; \u842c; \u842c; \u842c; \u842c;\n" 1375 + " \u842c; \u842c; \u842c; \u842c; \u842c; \u842c; \u842c;\n" 1376 + " \u842c; \u842c; \u842c;\n" 1377 + " 20: \u842c[->>];\n" 1378 + " 30: \u842c[->>];\n" 1379 + " 40: \u842c[->>];\n" 1380 + " 50: \u842c[->>];\n" 1381 + " 60: \u842c[->>];\n" 1382 + " 70: \u842c[->>];\n" 1383 + " 80: \u842c[->>];\n" 1384 + " 90: \u842c[->>];\n" 1385 + " 100: << \u842c[ >>];\n" 1386 + " 1000: << \u842c[ >>];\n" 1387 + " 1,000,000: << \u842c[ >>];\n" 1388 + " 1,000,000,000,000: << \u842c[ >>];\n" 1389 + " 1,000,000,000,000,000: =#,##0=;\n" 1390 + "%time:\n" 1391 + " =0= sec.;\n" 1392 + " 60: =%%min-sec=;\n" 1393 + " 3600: =%%hr-min-sec=;\n" 1394 + "%%min-sec:\n" 1395 + " 0: *=00=;\n" 1396 + " 60/60: <0<>>;\n" 1397 + "%%hr-min-sec:\n" 1398 + " 0: *=00=;\n" 1399 + " 60/60: <00<>>;\n" 1400 + " 3600/60: <#,##0<:>>>;\n" 1401 + "%%post-process:com.ibm.icu.text.RBNFChinesePostProcessor\n"; 1402 1403 RuleBasedNumberFormat rbnf = new RuleBasedNumberFormat(ruleWithChinese, ULocale.CHINESE); 1404 String[] ruleNames = rbnf.getRuleSetNames(); 1405 try{ 1406 // Test with "null" rules 1407 rbnf.format(0.0,null); 1408 errln("This was suppose to return an exception for a null format"); 1409 } catch(Exception e){} 1410 for(int i=0; i<ruleNames.length; i++){ 1411 try{ 1412 rbnf.format(-123450.6789,ruleNames[i]); 1413 } catch(Exception e){ 1414 errln("RBNFChinesePostProcessor was not suppose to return an exception " + 1415 "when being formatted with parameters 0.0 and " + ruleNames[i]); 1416 } 1417 } 1418 } 1419 1420 public void TestSetDecimalFormatSymbols() { 1421 RuleBasedNumberFormat rbnf = new RuleBasedNumberFormat(Locale.ENGLISH, RuleBasedNumberFormat.ORDINAL); 1422 1423 DecimalFormatSymbols dfs = new DecimalFormatSymbols(Locale.ENGLISH); 1424 1425 double number = 1001; 1426 1427 String[] expected = { "1,001st", "1&001st" }; 1428 1429 String result = rbnf.format(number); 1430 if (!result.equals(expected[0])) { 1431 errln("Format Error - Got: " + result + " Expected: " + expected[0]); 1432 } 1433 1434 /* Set new symbol for testing */ 1435 dfs.setGroupingSeparator('&'); 1436 rbnf.setDecimalFormatSymbols(dfs); 1437 1438 result = rbnf.format(number); 1439 if (!result.equals(expected[1])) { 1440 errln("Format Error - Got: " + result + " Expected: " + expected[1]); 1441 } 1442 } 1443 1444 public void TestContext() { 1445 class TextContextItem { 1446 public String locale; 1447 public int format; 1448 public DisplayContext context; 1449 public double value; 1450 public String expectedResult; 1451 // Simple constructor 1452 public TextContextItem(String loc, int fmt, DisplayContext ctxt, double val, String expRes) { 1453 locale = loc; 1454 format = fmt; 1455 context = ctxt; 1456 value = val; 1457 expectedResult = expRes; 1458 } 1459 } 1460 final TextContextItem[] items = { 1461 new TextContextItem( "sv", RuleBasedNumberFormat.SPELLOUT, DisplayContext.CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, 123.45, "ett\u00ADhundra\u00ADtjugo\u00ADtre komma fyra fem" ), 1462 new TextContextItem( "sv", RuleBasedNumberFormat.SPELLOUT, DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, 123.45, "Ett\u00ADhundra\u00ADtjugo\u00ADtre komma fyra fem" ), 1463 new TextContextItem( "sv", RuleBasedNumberFormat.SPELLOUT, DisplayContext.CAPITALIZATION_FOR_UI_LIST_OR_MENU, 123.45, "ett\u00ADhundra\u00ADtjugo\u00ADtre komma fyra fem" ), 1464 new TextContextItem( "sv", RuleBasedNumberFormat.SPELLOUT, DisplayContext.CAPITALIZATION_FOR_STANDALONE, 123.45, "ett\u00ADhundra\u00ADtjugo\u00ADtre komma fyra fem" ), 1465 new TextContextItem( "en", RuleBasedNumberFormat.SPELLOUT, DisplayContext.CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, 123.45, "one hundred twenty-three point four five" ), 1466 new TextContextItem( "en", RuleBasedNumberFormat.SPELLOUT, DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, 123.45, "One hundred twenty-three point four five" ), 1467 new TextContextItem( "en", RuleBasedNumberFormat.SPELLOUT, DisplayContext.CAPITALIZATION_FOR_UI_LIST_OR_MENU, 123.45, "One hundred twenty-three point four five" ), 1468 new TextContextItem( "en", RuleBasedNumberFormat.SPELLOUT, DisplayContext.CAPITALIZATION_FOR_STANDALONE, 123.45, "One hundred twenty-three point four five" ), 1469 }; 1470 for (TextContextItem item: items) { 1471 ULocale locale = new ULocale(item.locale); 1472 RuleBasedNumberFormat rbnf = new RuleBasedNumberFormat(locale, item.format); 1473 rbnf.setContext(item.context); 1474 String result = rbnf.format(item.value, rbnf.getDefaultRuleSetName()); 1475 if (!result.equals(item.expectedResult)) { 1476 errln("Error for locale " + item.locale + ", context " + item.context + ", expected " + item.expectedResult + ", got " + result); 1477 } 1478 RuleBasedNumberFormat rbnfClone = (RuleBasedNumberFormat)rbnf.clone(); 1479 if (!rbnfClone.equals(rbnf)) { 1480 errln("Error for locale " + item.locale + ", context " + item.context + ", rbnf.clone() != rbnf"); 1481 } else { 1482 result = rbnfClone.format(item.value, rbnfClone.getDefaultRuleSetName()); 1483 if (!result.equals(item.expectedResult)) { 1484 errln("Error with clone for locale " + item.locale + ", context " + item.context + ", expected " + item.expectedResult + ", got " + result); 1485 } 1486 } 1487 } 1488 } 1489 1490 } 1491