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