1 /* GENERATED SOURCE. DO NOT MODIFY. */ 2 // 2017 and later: Unicode, Inc. and others. 3 // License & terms of use: http://www.unicode.org/copyright.html#License 4 package android.icu.dev.test.format; 5 6 import java.math.BigDecimal; 7 import java.math.RoundingMode; 8 import java.text.ParsePosition; 9 10 import org.junit.Test; 11 12 import android.icu.dev.test.TestUtil; 13 import android.icu.impl.number.DecimalFormatProperties; 14 import android.icu.impl.number.DecimalFormatProperties.ParseMode; 15 import android.icu.impl.number.Padder.PadPosition; 16 import android.icu.impl.number.PatternStringParser; 17 import android.icu.impl.number.PatternStringUtils; 18 import android.icu.impl.number.parse.NumberParserImpl; 19 import android.icu.number.LocalizedNumberFormatter; 20 import android.icu.number.NumberFormatter; 21 import android.icu.text.DecimalFormat; 22 import android.icu.text.DecimalFormat.PropertySetter; 23 import android.icu.text.DecimalFormatSymbols; 24 import android.icu.util.CurrencyAmount; 25 import android.icu.util.ULocale; 26 import android.icu.testsharding.MainTestShard; 27 28 @MainTestShard 29 public class NumberFormatDataDrivenTest { 30 31 private static ULocale EN = new ULocale("en"); 32 33 private static Number toNumber(String s) { 34 if (s.equals("NaN")) { 35 return Double.NaN; 36 } else if (s.equals("-Inf")) { 37 return Double.NEGATIVE_INFINITY; 38 } else if (s.equals("Inf")) { 39 return Double.POSITIVE_INFINITY; 40 } 41 return new BigDecimal(s); 42 } 43 44 /** 45 * Standard function for comparing expected and actual parse results. Handles NaN, Infinity, and 46 * failure cases. 47 */ 48 private static String compareParseResult(String expected, Number actual, ParsePosition ppos) { 49 if (actual == null && ppos.getIndex() != 0) { 50 throw new AssertionError("Error: value is null but parse position is not zero"); 51 } 52 if (ppos.getIndex() == 0) { 53 return "Parse failed; got " + actual + ", but expected " + expected; 54 } 55 if (expected.equals("NaN")) { 56 if (!Double.isNaN(actual.doubleValue())) { 57 return "Expected NaN, but got: " + actual; 58 } 59 return null; 60 } else if (expected.equals("Inf")) { 61 if (!Double.isInfinite(actual.doubleValue()) 62 || Double.compare(actual.doubleValue(), 0.0) < 0) { 63 return "Expected Inf, but got: " + actual; 64 } 65 return null; 66 } else if (expected.equals("-Inf")) { 67 if (!Double.isInfinite(actual.doubleValue()) 68 || Double.compare(actual.doubleValue(), 0.0) > 0) { 69 return "Expected -Inf, but got: " + actual; 70 } 71 return null; 72 } else if (expected.equals("fail")) { 73 return null; 74 } else if (actual.toString().equals("Infinity")) { 75 return "Expected " + expected + ", but got Infinity"; 76 } else { 77 BigDecimal expectedDecimal = new BigDecimal(expected); 78 BigDecimal actualDecimal; 79 try { 80 actualDecimal = new BigDecimal(actual.toString()); 81 } catch (NumberFormatException e) { 82 throw new AssertionError("Could not convert to BigDecimal: " + actual.toString() + " - " + e.getMessage()); 83 } 84 if (expectedDecimal.compareTo(actualDecimal) != 0) { 85 return "Expected: " + expected + ", got: " + actual; 86 } else { 87 return null; 88 } 89 } 90 } 91 92 /** 93 * Standard function for comparing expected and actual parse-currency results. Handles failure cases. 94 * Does not currently handle NaN or Infinity because there are no parse-currency cases with NaN or 95 * Infinity. 96 */ 97 private static String compareParseCurrencyResult( 98 String expected, 99 String expectedCurrency, 100 CurrencyAmount actual, 101 ParsePosition ppos) { 102 if (ppos.getIndex() == 0 || actual.getCurrency().getCurrencyCode().equals("XXX")) { 103 return "Parse failed; got " + actual + ", but expected " + expected; 104 } 105 if (expected.equals("fail")) { 106 return null; 107 } 108 BigDecimal expectedNumber = new BigDecimal(expected); 109 if (expectedNumber.compareTo(new BigDecimal(actual.getNumber().toString())) != 0) { 110 return "Wrong number: Expected: " + expectedNumber + ", got: " + actual; 111 } 112 if (!expectedCurrency.equals(actual.getCurrency().toString())) { 113 return "Wrong currency: Expected: " + expectedCurrency + ", got: " + actual; 114 } 115 return null; 116 } 117 118 /** 119 * Main ICU4J DecimalFormat data-driven test. 120 */ 121 private DataDrivenNumberFormatTestUtility.CodeUnderTest ICU4J = new DataDrivenNumberFormatTestUtility.CodeUnderTest() { 122 @Override 123 public Character Id() { 124 return 'J'; 125 } 126 127 @Override 128 public String format(DataDrivenNumberFormatTestData tuple) { 129 DecimalFormat fmt = createDecimalFormat(tuple); 130 String actual = fmt.format(toNumber(tuple.format)); 131 String expected = tuple.output; 132 if (!expected.equals(actual)) { 133 return "Expected " + expected + ", got " + actual; 134 } 135 return null; 136 } 137 138 @Override 139 public String toPattern(DataDrivenNumberFormatTestData tuple) { 140 DecimalFormat fmt = createDecimalFormat(tuple); 141 StringBuilder result = new StringBuilder(); 142 if (tuple.toPattern != null) { 143 String expected = tuple.toPattern; 144 String actual = fmt.toPattern(); 145 if (!expected.equals(actual)) { 146 result.append("Expected toPattern=" + expected + ", got " + actual); 147 } 148 } 149 if (tuple.toLocalizedPattern != null) { 150 String expected = tuple.toLocalizedPattern; 151 String actual = fmt.toLocalizedPattern(); 152 if (!expected.equals(actual)) { 153 result.append("Expected toLocalizedPattern=" + expected + ", got " + actual); 154 } 155 } 156 return result.length() == 0 ? null : result.toString(); 157 } 158 159 @Override 160 public String parse(DataDrivenNumberFormatTestData tuple) { 161 DecimalFormat fmt = createDecimalFormat(tuple); 162 ParsePosition ppos = new ParsePosition(0); 163 Number actual = fmt.parse(tuple.parse, ppos); 164 return compareParseResult(tuple.output, actual, ppos); 165 } 166 167 @Override 168 public String parseCurrency(DataDrivenNumberFormatTestData tuple) { 169 DecimalFormat fmt = createDecimalFormat(tuple); 170 ParsePosition ppos = new ParsePosition(0); 171 CurrencyAmount actual = fmt.parseCurrency(tuple.parse, ppos); 172 return compareParseCurrencyResult(tuple.output, tuple.outputCurrency, actual, ppos); 173 } 174 175 /** 176 * @param tuple 177 * @return 178 */ 179 private DecimalFormat createDecimalFormat(DataDrivenNumberFormatTestData tuple) { 180 DecimalFormat fmt = new DecimalFormat(tuple.pattern == null ? "0" : tuple.pattern, 181 new DecimalFormatSymbols(tuple.locale == null ? EN : tuple.locale)); 182 adjustDecimalFormat(tuple, fmt); 183 return fmt; 184 } 185 186 /** 187 * @param tuple 188 * @param fmt 189 */ 190 private void adjustDecimalFormat(DataDrivenNumberFormatTestData tuple, DecimalFormat fmt) { 191 if (tuple.minIntegerDigits != null) { 192 fmt.setMinimumIntegerDigits(tuple.minIntegerDigits); 193 } 194 if (tuple.maxIntegerDigits != null) { 195 fmt.setMaximumIntegerDigits(tuple.maxIntegerDigits); 196 } 197 if (tuple.minFractionDigits != null) { 198 fmt.setMinimumFractionDigits(tuple.minFractionDigits); 199 } 200 if (tuple.maxFractionDigits != null) { 201 fmt.setMaximumFractionDigits(tuple.maxFractionDigits); 202 } 203 if (tuple.currency != null) { 204 fmt.setCurrency(tuple.currency); 205 } 206 if (tuple.minGroupingDigits != null) { 207 fmt.setMinimumGroupingDigits(tuple.minGroupingDigits); 208 } 209 if (tuple.useSigDigits != null) { 210 fmt.setSignificantDigitsUsed(tuple.useSigDigits != 0); 211 } 212 if (tuple.minSigDigits != null) { 213 fmt.setMinimumSignificantDigits(tuple.minSigDigits); 214 } 215 if (tuple.maxSigDigits != null) { 216 fmt.setMaximumSignificantDigits(tuple.maxSigDigits); 217 } 218 if (tuple.useGrouping != null) { 219 fmt.setGroupingUsed(tuple.useGrouping != 0); 220 } 221 if (tuple.multiplier != null) { 222 fmt.setMultiplier(tuple.multiplier); 223 } 224 if (tuple.roundingIncrement != null) { 225 fmt.setRoundingIncrement(tuple.roundingIncrement.doubleValue()); 226 } 227 if (tuple.formatWidth != null) { 228 fmt.setFormatWidth(tuple.formatWidth); 229 } 230 if (tuple.padCharacter != null && tuple.padCharacter.length() > 0) { 231 fmt.setPadCharacter(tuple.padCharacter.charAt(0)); 232 } 233 if (tuple.useScientific != null) { 234 fmt.setScientificNotation(tuple.useScientific != 0); 235 } 236 if (tuple.grouping != null) { 237 fmt.setGroupingSize(tuple.grouping); 238 } 239 if (tuple.grouping2 != null) { 240 fmt.setSecondaryGroupingSize(tuple.grouping2); 241 } 242 if (tuple.roundingMode != null) { 243 fmt.setRoundingMode(tuple.roundingMode); 244 } 245 if (tuple.currencyUsage != null) { 246 fmt.setCurrencyUsage(tuple.currencyUsage); 247 } 248 if (tuple.minimumExponentDigits != null) { 249 fmt.setMinimumExponentDigits(tuple.minimumExponentDigits.byteValue()); 250 } 251 if (tuple.exponentSignAlwaysShown != null) { 252 fmt.setExponentSignAlwaysShown(tuple.exponentSignAlwaysShown != 0); 253 } 254 if (tuple.decimalSeparatorAlwaysShown != null) { 255 fmt.setDecimalSeparatorAlwaysShown(tuple.decimalSeparatorAlwaysShown != 0); 256 } 257 if (tuple.padPosition != null) { 258 fmt.setPadPosition(tuple.padPosition); 259 } 260 if (tuple.positivePrefix != null) { 261 fmt.setPositivePrefix(tuple.positivePrefix); 262 } 263 if (tuple.positiveSuffix != null) { 264 fmt.setPositiveSuffix(tuple.positiveSuffix); 265 } 266 if (tuple.negativePrefix != null) { 267 fmt.setNegativePrefix(tuple.negativePrefix); 268 } 269 if (tuple.negativeSuffix != null) { 270 fmt.setNegativeSuffix(tuple.negativeSuffix); 271 } 272 if (tuple.signAlwaysShown != null) { 273 fmt.setSignAlwaysShown(tuple.signAlwaysShown != 0); 274 } 275 if (tuple.localizedPattern != null) { 276 fmt.applyLocalizedPattern(tuple.localizedPattern); 277 } 278 int lenient = tuple.lenient == null ? 1 : tuple.lenient.intValue(); 279 fmt.setParseStrict(lenient == 0); 280 if (tuple.parseIntegerOnly != null) { 281 fmt.setParseIntegerOnly(tuple.parseIntegerOnly != 0); 282 } 283 if (tuple.parseCaseSensitive != null) { 284 fmt.setParseCaseSensitive(tuple.parseCaseSensitive != 0); 285 } 286 if (tuple.decimalPatternMatchRequired != null) { 287 fmt.setDecimalPatternMatchRequired(tuple.decimalPatternMatchRequired != 0); 288 } 289 if (tuple.parseNoExponent != null) { 290 fmt.setParseNoExponent(tuple.parseNoExponent != 0); 291 } 292 } 293 }; 294 295 /** 296 * Backwards-compatibility test: snapshot of DecimalFormat from ICU 58. 297 */ 298 // Android patch: Android can't access DecimalFormat_ICU58 for testing (b/33448125). 299 // That class lived in a package under test and relied on package access, but 300 // 1.) Android Compatibility Test Suite (CTS) run tests with a different ClassLoader, 301 // preventing package access, and 302 // 2.) By default, the OpenJDK 9 toolchain won't compile non-libcore code that in 303 // libcore packages (see http://b/68224249). 304 /* 305 private DataDrivenNumberFormatTestUtility.CodeUnderTest ICU58 = new DataDrivenNumberFormatTestUtility.CodeUnderTest() { 306 @Override 307 public Character Id() { 308 return 'H'; 309 } 310 311 @Override 312 public String format(DataDrivenNumberFormatTestData tuple) { 313 DecimalFormat_ICU58 fmt = createDecimalFormat(tuple); 314 String actual = fmt.format(toNumber(tuple.format)); 315 String expected = tuple.output; 316 if (!expected.equals(actual)) { 317 return "Expected " + expected + ", got " + actual; 318 } 319 return null; 320 } 321 322 @Override 323 public String toPattern(DataDrivenNumberFormatTestData tuple) { 324 DecimalFormat_ICU58 fmt = createDecimalFormat(tuple); 325 StringBuilder result = new StringBuilder(); 326 if (tuple.toPattern != null) { 327 String expected = tuple.toPattern; 328 String actual = fmt.toPattern(); 329 if (!expected.equals(actual)) { 330 result.append("Expected toPattern=" + expected + ", got " + actual); 331 } 332 } 333 if (tuple.toLocalizedPattern != null) { 334 String expected = tuple.toLocalizedPattern; 335 String actual = fmt.toLocalizedPattern(); 336 if (!expected.equals(actual)) { 337 result.append("Expected toLocalizedPattern=" + expected + ", got " + actual); 338 } 339 } 340 return result.length() == 0 ? null : result.toString(); 341 } 342 343 @Override 344 public String parse(DataDrivenNumberFormatTestData tuple) { 345 DecimalFormat_ICU58 fmt = createDecimalFormat(tuple); 346 ParsePosition ppos = new ParsePosition(0); 347 Number actual = fmt.parse(tuple.parse, ppos); 348 return compareParseResult(tuple.output, actual, ppos); 349 } 350 351 @Override 352 public String parseCurrency(DataDrivenNumberFormatTestData tuple) { 353 DecimalFormat_ICU58 fmt = createDecimalFormat(tuple); 354 ParsePosition ppos = new ParsePosition(0); 355 CurrencyAmount actual = fmt.parseCurrency(tuple.parse, ppos); 356 return compareParseCurrencyResult(tuple.output, tuple.outputCurrency, actual, ppos); 357 } 358 359 /** 360 * @param tuple 361 * @return 362 * 363 private DecimalFormat_ICU58 createDecimalFormat(DataDrivenNumberFormatTestData tuple) { 364 365 DecimalFormat_ICU58 fmt = new DecimalFormat_ICU58( 366 tuple.pattern == null ? "0" : tuple.pattern, 367 new DecimalFormatSymbols(tuple.locale == null ? EN : tuple.locale)); 368 adjustDecimalFormat(tuple, fmt); 369 return fmt; 370 } 371 372 /** 373 * @param tuple 374 * @param fmt 375 * 376 private void adjustDecimalFormat(DataDrivenNumberFormatTestData tuple, DecimalFormat_ICU58 fmt) { 377 if (tuple.minIntegerDigits != null) { 378 fmt.setMinimumIntegerDigits(tuple.minIntegerDigits); 379 } 380 if (tuple.maxIntegerDigits != null) { 381 fmt.setMaximumIntegerDigits(tuple.maxIntegerDigits); 382 } 383 if (tuple.minFractionDigits != null) { 384 fmt.setMinimumFractionDigits(tuple.minFractionDigits); 385 } 386 if (tuple.maxFractionDigits != null) { 387 fmt.setMaximumFractionDigits(tuple.maxFractionDigits); 388 } 389 if (tuple.currency != null) { 390 fmt.setCurrency(tuple.currency); 391 } 392 if (tuple.minGroupingDigits != null) { 393 // Oops we don't support this. 394 } 395 if (tuple.useSigDigits != null) { 396 fmt.setSignificantDigitsUsed(tuple.useSigDigits != 0); 397 } 398 if (tuple.minSigDigits != null) { 399 fmt.setMinimumSignificantDigits(tuple.minSigDigits); 400 } 401 if (tuple.maxSigDigits != null) { 402 fmt.setMaximumSignificantDigits(tuple.maxSigDigits); 403 } 404 if (tuple.useGrouping != null) { 405 fmt.setGroupingUsed(tuple.useGrouping != 0); 406 } 407 if (tuple.multiplier != null) { 408 fmt.setMultiplier(tuple.multiplier); 409 } 410 if (tuple.roundingIncrement != null) { 411 fmt.setRoundingIncrement(tuple.roundingIncrement.doubleValue()); 412 } 413 if (tuple.formatWidth != null) { 414 fmt.setFormatWidth(tuple.formatWidth); 415 } 416 if (tuple.padCharacter != null && tuple.padCharacter.length() > 0) { 417 fmt.setPadCharacter(tuple.padCharacter.charAt(0)); 418 } 419 if (tuple.useScientific != null) { 420 fmt.setScientificNotation(tuple.useScientific != 0); 421 } 422 if (tuple.grouping != null) { 423 fmt.setGroupingSize(tuple.grouping); 424 } 425 if (tuple.grouping2 != null) { 426 fmt.setSecondaryGroupingSize(tuple.grouping2); 427 } 428 if (tuple.roundingMode != null) { 429 fmt.setRoundingMode(tuple.roundingMode); 430 } 431 if (tuple.currencyUsage != null) { 432 fmt.setCurrencyUsage(tuple.currencyUsage); 433 } 434 if (tuple.minimumExponentDigits != null) { 435 fmt.setMinimumExponentDigits(tuple.minimumExponentDigits.byteValue()); 436 } 437 if (tuple.exponentSignAlwaysShown != null) { 438 fmt.setExponentSignAlwaysShown(tuple.exponentSignAlwaysShown != 0); 439 } 440 if (tuple.decimalSeparatorAlwaysShown != null) { 441 fmt.setDecimalSeparatorAlwaysShown(tuple.decimalSeparatorAlwaysShown != 0); 442 } 443 if (tuple.padPosition != null) { 444 fmt.setPadPosition(tuple.padPosition); 445 } 446 if (tuple.positivePrefix != null) { 447 fmt.setPositivePrefix(tuple.positivePrefix); 448 } 449 if (tuple.positiveSuffix != null) { 450 fmt.setPositiveSuffix(tuple.positiveSuffix); 451 } 452 if (tuple.negativePrefix != null) { 453 fmt.setNegativePrefix(tuple.negativePrefix); 454 } 455 if (tuple.negativeSuffix != null) { 456 fmt.setNegativeSuffix(tuple.negativeSuffix); 457 } 458 if (tuple.signAlwaysShown != null) { 459 // Not supported. 460 } 461 if (tuple.localizedPattern != null) { 462 fmt.applyLocalizedPattern(tuple.localizedPattern); 463 } 464 int lenient = tuple.lenient == null ? 1 : tuple.lenient.intValue(); 465 fmt.setParseStrict(lenient == 0); 466 if (tuple.parseIntegerOnly != null) { 467 fmt.setParseIntegerOnly(tuple.parseIntegerOnly != 0); 468 } 469 if (tuple.parseCaseSensitive != null) { 470 // Not supported. 471 } 472 if (tuple.decimalPatternMatchRequired != null) { 473 fmt.setDecimalPatternMatchRequired(tuple.decimalPatternMatchRequired != 0); 474 } 475 if (tuple.parseNoExponent != null) { 476 // Oops, not supported for now 477 } 478 } 479 }; 480 */ 481 // Android patch end. 482 483 /** 484 * Test of available JDK APIs. 485 */ 486 private DataDrivenNumberFormatTestUtility.CodeUnderTest JDK = new DataDrivenNumberFormatTestUtility.CodeUnderTest() { 487 @Override 488 public Character Id() { 489 return 'K'; 490 } 491 492 @Override 493 public String format(DataDrivenNumberFormatTestData tuple) { 494 java.text.DecimalFormat fmt = createDecimalFormat(tuple); 495 String actual = fmt.format(toNumber(tuple.format)); 496 String expected = tuple.output; 497 if (!expected.equals(actual)) { 498 return "Expected " + expected + ", got " + actual; 499 } 500 return null; 501 } 502 503 @Override 504 public String toPattern(DataDrivenNumberFormatTestData tuple) { 505 java.text.DecimalFormat fmt = createDecimalFormat(tuple); 506 StringBuilder result = new StringBuilder(); 507 if (tuple.toPattern != null) { 508 String expected = tuple.toPattern; 509 String actual = fmt.toPattern(); 510 if (!expected.equals(actual)) { 511 result.append("Expected toPattern=" + expected + ", got " + actual); 512 } 513 } 514 if (tuple.toLocalizedPattern != null) { 515 String expected = tuple.toLocalizedPattern; 516 String actual = fmt.toLocalizedPattern(); 517 if (!expected.equals(actual)) { 518 result.append("Expected toLocalizedPattern=" + expected + ", got " + actual); 519 } 520 } 521 return result.length() == 0 ? null : result.toString(); 522 } 523 524 @Override 525 public String parse(DataDrivenNumberFormatTestData tuple) { 526 java.text.DecimalFormat fmt = createDecimalFormat(tuple); 527 ParsePosition ppos = new ParsePosition(0); 528 Number actual = fmt.parse(tuple.parse, ppos); 529 return compareParseResult(tuple.output, actual, ppos); 530 } 531 532 /** 533 * @param tuple 534 * @return 535 */ 536 private java.text.DecimalFormat createDecimalFormat(DataDrivenNumberFormatTestData tuple) { 537 java.text.DecimalFormat fmt = new java.text.DecimalFormat( 538 tuple.pattern == null ? "0" : tuple.pattern, 539 new java.text.DecimalFormatSymbols( 540 (tuple.locale == null ? EN : tuple.locale).toLocale())); 541 adjustDecimalFormat(tuple, fmt); 542 return fmt; 543 } 544 545 /** 546 * @param tuple 547 * @param fmt 548 */ 549 private void adjustDecimalFormat( 550 DataDrivenNumberFormatTestData tuple, 551 java.text.DecimalFormat fmt) { 552 if (tuple.minIntegerDigits != null) { 553 fmt.setMinimumIntegerDigits(tuple.minIntegerDigits); 554 } 555 if (tuple.maxIntegerDigits != null) { 556 fmt.setMaximumIntegerDigits(tuple.maxIntegerDigits); 557 } 558 if (tuple.minFractionDigits != null) { 559 fmt.setMinimumFractionDigits(tuple.minFractionDigits); 560 } 561 if (tuple.maxFractionDigits != null) { 562 fmt.setMaximumFractionDigits(tuple.maxFractionDigits); 563 } 564 if (tuple.currency != null) { 565 fmt.setCurrency(java.util.Currency.getInstance(tuple.currency.toString())); 566 } 567 if (tuple.minGroupingDigits != null) { 568 // Oops we don't support this. 569 } 570 if (tuple.useSigDigits != null) { 571 // Oops we don't support this 572 } 573 if (tuple.minSigDigits != null) { 574 // Oops we don't support this 575 } 576 if (tuple.maxSigDigits != null) { 577 // Oops we don't support this 578 } 579 if (tuple.useGrouping != null) { 580 fmt.setGroupingUsed(tuple.useGrouping != 0); 581 } 582 if (tuple.multiplier != null) { 583 fmt.setMultiplier(tuple.multiplier); 584 } 585 if (tuple.roundingIncrement != null) { 586 // Not supported 587 } 588 if (tuple.formatWidth != null) { 589 // Not supported 590 } 591 if (tuple.padCharacter != null && tuple.padCharacter.length() > 0) { 592 // Not supported 593 } 594 if (tuple.useScientific != null) { 595 // Not supported 596 } 597 if (tuple.grouping != null) { 598 fmt.setGroupingSize(tuple.grouping); 599 } 600 if (tuple.grouping2 != null) { 601 // Not supported 602 } 603 if (tuple.roundingMode != null) { 604 // Not supported 605 } 606 if (tuple.currencyUsage != null) { 607 // Not supported 608 } 609 if (tuple.minimumExponentDigits != null) { 610 // Not supported 611 } 612 if (tuple.exponentSignAlwaysShown != null) { 613 // Not supported 614 } 615 if (tuple.decimalSeparatorAlwaysShown != null) { 616 fmt.setDecimalSeparatorAlwaysShown(tuple.decimalSeparatorAlwaysShown != 0); 617 } 618 if (tuple.padPosition != null) { 619 // Not supported 620 } 621 if (tuple.positivePrefix != null) { 622 fmt.setPositivePrefix(tuple.positivePrefix); 623 } 624 if (tuple.positiveSuffix != null) { 625 fmt.setPositiveSuffix(tuple.positiveSuffix); 626 } 627 if (tuple.negativePrefix != null) { 628 fmt.setNegativePrefix(tuple.negativePrefix); 629 } 630 if (tuple.negativeSuffix != null) { 631 fmt.setNegativeSuffix(tuple.negativeSuffix); 632 } 633 if (tuple.signAlwaysShown != null) { 634 // Not supported. 635 } 636 if (tuple.localizedPattern != null) { 637 fmt.applyLocalizedPattern(tuple.localizedPattern); 638 } 639 640 // lenient parsing not supported by JDK 641 if (tuple.parseIntegerOnly != null) { 642 fmt.setParseIntegerOnly(tuple.parseIntegerOnly != 0); 643 } 644 if (tuple.parseCaseSensitive != null) { 645 // Not supported. 646 } 647 if (tuple.decimalPatternMatchRequired != null) { 648 // Oops, not supported 649 } 650 if (tuple.parseNoExponent != null) { 651 // Oops, not supported for now 652 } 653 } 654 }; 655 656 static void propertiesFromTuple( 657 DataDrivenNumberFormatTestData tuple, 658 DecimalFormatProperties properties) { 659 if (tuple.minIntegerDigits != null) { 660 properties.setMinimumIntegerDigits(tuple.minIntegerDigits); 661 } 662 if (tuple.maxIntegerDigits != null) { 663 properties.setMaximumIntegerDigits(tuple.maxIntegerDigits); 664 } 665 if (tuple.minFractionDigits != null) { 666 properties.setMinimumFractionDigits(tuple.minFractionDigits); 667 } 668 if (tuple.maxFractionDigits != null) { 669 properties.setMaximumFractionDigits(tuple.maxFractionDigits); 670 } 671 if (tuple.currency != null) { 672 properties.setCurrency(tuple.currency); 673 } 674 if (tuple.minGroupingDigits != null) { 675 properties.setMinimumGroupingDigits(tuple.minGroupingDigits); 676 } 677 if (tuple.useSigDigits != null) { 678 // TODO 679 } 680 if (tuple.minSigDigits != null) { 681 properties.setMinimumSignificantDigits(tuple.minSigDigits); 682 } 683 if (tuple.maxSigDigits != null) { 684 properties.setMaximumSignificantDigits(tuple.maxSigDigits); 685 } 686 if (tuple.useGrouping != null) { 687 properties.setGroupingUsed(tuple.useGrouping > 0); 688 } 689 if (tuple.multiplier != null) { 690 properties.setMultiplier(new BigDecimal(tuple.multiplier)); 691 } 692 if (tuple.roundingIncrement != null) { 693 properties.setRoundingIncrement(new BigDecimal(tuple.roundingIncrement.toString())); 694 } 695 if (tuple.formatWidth != null) { 696 properties.setFormatWidth(tuple.formatWidth); 697 } 698 if (tuple.padCharacter != null && tuple.padCharacter.length() > 0) { 699 properties.setPadString(tuple.padCharacter.toString()); 700 } 701 if (tuple.useScientific != null) { 702 properties.setMinimumExponentDigits(tuple.useScientific != 0 ? 1 : -1); 703 } 704 if (tuple.grouping != null) { 705 properties.setGroupingSize(tuple.grouping); 706 } 707 if (tuple.grouping2 != null) { 708 properties.setSecondaryGroupingSize(tuple.grouping2); 709 } 710 if (tuple.roundingMode != null) { 711 properties.setRoundingMode(RoundingMode.valueOf(tuple.roundingMode)); 712 } 713 if (tuple.currencyUsage != null) { 714 properties.setCurrencyUsage(tuple.currencyUsage); 715 } 716 if (tuple.minimumExponentDigits != null) { 717 properties.setMinimumExponentDigits(tuple.minimumExponentDigits.byteValue()); 718 } 719 if (tuple.exponentSignAlwaysShown != null) { 720 properties.setExponentSignAlwaysShown(tuple.exponentSignAlwaysShown != 0); 721 } 722 if (tuple.decimalSeparatorAlwaysShown != null) { 723 properties.setDecimalSeparatorAlwaysShown(tuple.decimalSeparatorAlwaysShown != 0); 724 } 725 if (tuple.padPosition != null) { 726 properties.setPadPosition(PadPosition.fromOld(tuple.padPosition)); 727 } 728 if (tuple.positivePrefix != null) { 729 properties.setPositivePrefix(tuple.positivePrefix); 730 } 731 if (tuple.positiveSuffix != null) { 732 properties.setPositiveSuffix(tuple.positiveSuffix); 733 } 734 if (tuple.negativePrefix != null) { 735 properties.setNegativePrefix(tuple.negativePrefix); 736 } 737 if (tuple.negativeSuffix != null) { 738 properties.setNegativeSuffix(tuple.negativeSuffix); 739 } 740 if (tuple.signAlwaysShown != null) { 741 properties.setSignAlwaysShown(tuple.signAlwaysShown != 0); 742 } 743 if (tuple.localizedPattern != null) { 744 DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(tuple.locale); 745 String converted = PatternStringUtils 746 .convertLocalized(tuple.localizedPattern, symbols, false); 747 PatternStringParser.parseToExistingProperties(converted, properties); 748 } 749 if (tuple.lenient != null) { 750 properties.setParseMode(tuple.lenient == 0 ? ParseMode.STRICT : ParseMode.LENIENT); 751 } 752 if (tuple.parseIntegerOnly != null) { 753 properties.setParseIntegerOnly(tuple.parseIntegerOnly != 0); 754 } 755 if (tuple.parseCaseSensitive != null) { 756 properties.setParseCaseSensitive(tuple.parseCaseSensitive != 0); 757 } 758 if (tuple.decimalPatternMatchRequired != null) { 759 properties.setDecimalPatternMatchRequired(tuple.decimalPatternMatchRequired != 0); 760 } 761 if (tuple.parseNoExponent != null) { 762 properties.setParseNoExponent(tuple.parseNoExponent != 0); 763 } 764 } 765 766 /** 767 * Same as ICU4J, but bypasses the DecimalFormat wrapper and goes directly to the 768 * DecimalFormatProperties. 769 */ 770 private DataDrivenNumberFormatTestUtility.CodeUnderTest ICU4J_Properties = new DataDrivenNumberFormatTestUtility.CodeUnderTest() { 771 772 @Override 773 public Character Id() { 774 return 'P'; 775 } 776 777 /** 778 * Runs a single formatting test. On success, returns null. On failure, returns the error. This 779 * implementation just returns null. Subclasses should override. 780 * 781 * @param tuple 782 * contains the parameters of the format test. 783 */ 784 @Override 785 public String format(DataDrivenNumberFormatTestData tuple) { 786 String pattern = (tuple.pattern == null) ? "0" : tuple.pattern; 787 ULocale locale = (tuple.locale == null) ? ULocale.ENGLISH : tuple.locale; 788 DecimalFormatProperties properties = PatternStringParser.parseToProperties(pattern, 789 tuple.currency != null ? PatternStringParser.IGNORE_ROUNDING_ALWAYS 790 : PatternStringParser.IGNORE_ROUNDING_NEVER); 791 propertiesFromTuple(tuple, properties); 792 DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(locale); 793 LocalizedNumberFormatter fmt = NumberFormatter.fromDecimalFormat(properties, symbols, null) 794 .locale(locale); 795 Number number = toNumber(tuple.format); 796 String expected = tuple.output; 797 String actual = fmt.format(number).toString(); 798 if (!expected.equals(actual)) { 799 return "Expected \"" + expected + "\", got \"" + actual + "\""; 800 } 801 return null; 802 } 803 804 /** 805 * Runs a single toPattern test. On success, returns null. On failure, returns the error. This 806 * implementation just returns null. Subclasses should override. 807 * 808 * @param tuple 809 * contains the parameters of the format test. 810 */ 811 @Override 812 public String toPattern(DataDrivenNumberFormatTestData tuple) { 813 String pattern = (tuple.pattern == null) ? "0" : tuple.pattern; 814 final DecimalFormatProperties properties; 815 DecimalFormat df; 816 try { 817 properties = PatternStringParser.parseToProperties(pattern, 818 tuple.currency != null ? PatternStringParser.IGNORE_ROUNDING_ALWAYS 819 : PatternStringParser.IGNORE_ROUNDING_NEVER); 820 propertiesFromTuple(tuple, properties); 821 // TODO: Use PatternString.propertiesToString() directly. (How to deal with 822 // CurrencyUsage?) 823 df = new DecimalFormat(); 824 df.setProperties(new PropertySetter() { 825 @Override 826 public void set(DecimalFormatProperties props) { 827 props.copyFrom(properties); 828 } 829 }); 830 } catch (IllegalArgumentException e) { 831 e.printStackTrace(); 832 return e.getLocalizedMessage(); 833 } 834 835 if (tuple.toPattern != null) { 836 String expected = tuple.toPattern; 837 String actual = df.toPattern(); 838 if (!expected.equals(actual)) { 839 return "Expected toPattern='" + expected + "'; got '" + actual + "'"; 840 } 841 } 842 if (tuple.toLocalizedPattern != null) { 843 String expected = tuple.toLocalizedPattern; 844 String actual = PatternStringUtils.propertiesToPatternString(properties); 845 if (!expected.equals(actual)) { 846 return "Expected toLocalizedPattern='" + expected + "'; got '" + actual + "'"; 847 } 848 } 849 return null; 850 } 851 852 @Override 853 public String parse(DataDrivenNumberFormatTestData tuple) { 854 String pattern = (tuple.pattern == null) ? "0" : tuple.pattern; 855 DecimalFormatProperties properties; 856 ParsePosition ppos = new ParsePosition(0); 857 Number actual; 858 try { 859 properties = PatternStringParser.parseToProperties(pattern, 860 tuple.currency != null ? PatternStringParser.IGNORE_ROUNDING_ALWAYS 861 : PatternStringParser.IGNORE_ROUNDING_NEVER); 862 propertiesFromTuple(tuple, properties); 863 actual = NumberParserImpl.parseStatic(tuple.parse, 864 ppos, 865 properties, 866 DecimalFormatSymbols.getInstance(tuple.locale)); 867 } catch (IllegalArgumentException e) { 868 return "parse exception: " + e.getMessage(); 869 } 870 return compareParseResult(tuple.output, actual, ppos); 871 } 872 873 @Override 874 public String parseCurrency(DataDrivenNumberFormatTestData tuple) { 875 String pattern = (tuple.pattern == null) ? "0" : tuple.pattern; 876 DecimalFormatProperties properties; 877 ParsePosition ppos = new ParsePosition(0); 878 CurrencyAmount actual; 879 try { 880 properties = PatternStringParser.parseToProperties(pattern, 881 tuple.currency != null ? PatternStringParser.IGNORE_ROUNDING_ALWAYS 882 : PatternStringParser.IGNORE_ROUNDING_NEVER); 883 propertiesFromTuple(tuple, properties); 884 actual = NumberParserImpl.parseStaticCurrency(tuple.parse, 885 ppos, 886 properties, 887 DecimalFormatSymbols.getInstance(tuple.locale)); 888 } catch (IllegalArgumentException e) { 889 e.printStackTrace(); 890 return "parse exception: " + e.getMessage(); 891 } 892 return compareParseCurrencyResult(tuple.output, tuple.outputCurrency, actual, ppos); 893 } 894 }; 895 896 @Test 897 public void TestNoUnknownIDs() { 898 DataDrivenNumberFormatTestUtility.checkNoUnknownIDs("numberformattestspecification.txt", "CHJKP"); 899 } 900 901 @Test 902 public void TestDataDrivenICU4J() { 903 DataDrivenNumberFormatTestUtility 904 .runFormatSuiteIncludingKnownFailures("numberformattestspecification.txt", ICU4J); 905 } 906 907 // Android patch: Android can't access DecimalFormat_ICU58 for testing (b/33448125). 908 /* 909 @Test 910 public void TestDataDrivenICU58() { 911 // Android can't access DecimalFormat_ICU58 for testing (ticket #13283). 912 if (TestUtil.getJavaVendor() == TestUtil.JavaVendor.Android) 913 return; 914 915 DataDrivenNumberFormatTestUtility 916 .runFormatSuiteIncludingKnownFailures("numberformattestspecification.txt", ICU58); 917 } 918 */ 919 // Android patch end. 920 921 @Test 922 public void TestDataDrivenJDK() { 923 // #13373: Since not all JDK implementations are the same, test only whitelisted JDKs 924 // with known behavior. The JDK version should be occasionally updated. 925 org.junit.Assume.assumeTrue(TestUtil.getJavaRuntimeName() == TestUtil.JavaRuntimeName.OpenJDK 926 && TestUtil.getJavaVersion() == 8); 927 928 DataDrivenNumberFormatTestUtility 929 .runFormatSuiteIncludingKnownFailures("numberformattestspecification.txt", JDK); 930 } 931 932 @Test 933 public void TestDataDrivenICU4JProperties() { 934 DataDrivenNumberFormatTestUtility 935 .runFormatSuiteIncludingKnownFailures("numberformattestspecification.txt", ICU4J_Properties); 936 } 937 } 938