• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 ohos.global.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 ohos.global.icu.dev.test.TestUtil;
13 import ohos.global.icu.impl.number.DecimalFormatProperties;
14 import ohos.global.icu.impl.number.DecimalFormatProperties.ParseMode;
15 import ohos.global.icu.impl.number.Padder.PadPosition;
16 import ohos.global.icu.impl.number.PatternStringParser;
17 import ohos.global.icu.impl.number.PatternStringUtils;
18 import ohos.global.icu.impl.number.parse.NumberParserImpl;
19 import ohos.global.icu.number.LocalizedNumberFormatter;
20 import ohos.global.icu.number.NumberFormatter;
21 import ohos.global.icu.text.DecimalFormat;
22 import ohos.global.icu.text.DecimalFormat.PropertySetter;
23 import ohos.global.icu.text.DecimalFormatSymbols;
24 import ohos.global.icu.util.CurrencyAmount;
25 import ohos.global.icu.util.ULocale;
26 
27 
28 
29 public class NumberFormatDataDrivenTest {
30 
31     private static ULocale EN = new ULocale("en");
32 
toNumber(String s)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      */
compareParseResult(String expected, Number actual, ParsePosition ppos)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      */
compareParseCurrencyResult( String expected, String expectedCurrency, CurrencyAmount actual, ParsePosition ppos)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      * Test of available JDK APIs.
297      */
298     private DataDrivenNumberFormatTestUtility.CodeUnderTest JDK = new DataDrivenNumberFormatTestUtility.CodeUnderTest() {
299         @Override
300         public Character Id() {
301             return 'K';
302         }
303 
304         @Override
305         public String format(DataDrivenNumberFormatTestData tuple) {
306             java.text.DecimalFormat fmt = createDecimalFormat(tuple);
307             String actual = fmt.format(toNumber(tuple.format));
308             String expected = tuple.output;
309             if (!expected.equals(actual)) {
310                 return "Expected " + expected + ", got " + actual;
311             }
312             return null;
313         }
314 
315         @Override
316         public String toPattern(DataDrivenNumberFormatTestData tuple) {
317             java.text.DecimalFormat fmt = createDecimalFormat(tuple);
318             StringBuilder result = new StringBuilder();
319             if (tuple.toPattern != null) {
320                 String expected = tuple.toPattern;
321                 String actual = fmt.toPattern();
322                 if (!expected.equals(actual)) {
323                     result.append("Expected toPattern=" + expected + ", got " + actual);
324                 }
325             }
326             if (tuple.toLocalizedPattern != null) {
327                 String expected = tuple.toLocalizedPattern;
328                 String actual = fmt.toLocalizedPattern();
329                 if (!expected.equals(actual)) {
330                     result.append("Expected toLocalizedPattern=" + expected + ", got " + actual);
331                 }
332             }
333             return result.length() == 0 ? null : result.toString();
334         }
335 
336         @Override
337         public String parse(DataDrivenNumberFormatTestData tuple) {
338             java.text.DecimalFormat fmt = createDecimalFormat(tuple);
339             ParsePosition ppos = new ParsePosition(0);
340             Number actual = fmt.parse(tuple.parse, ppos);
341             return compareParseResult(tuple.output, actual, ppos);
342         }
343 
344         /**
345          * @param tuple
346          * @return
347          */
348         private java.text.DecimalFormat createDecimalFormat(DataDrivenNumberFormatTestData tuple) {
349             java.text.DecimalFormat fmt = new java.text.DecimalFormat(
350                     tuple.pattern == null ? "0" : tuple.pattern,
351                     new java.text.DecimalFormatSymbols(
352                             (tuple.locale == null ? EN : tuple.locale).toLocale()));
353             adjustDecimalFormat(tuple, fmt);
354             return fmt;
355         }
356 
357         /**
358          * @param tuple
359          * @param fmt
360          */
361         private void adjustDecimalFormat(
362                 DataDrivenNumberFormatTestData tuple,
363                 java.text.DecimalFormat fmt) {
364             if (tuple.minIntegerDigits != null) {
365                 fmt.setMinimumIntegerDigits(tuple.minIntegerDigits);
366             }
367             if (tuple.maxIntegerDigits != null) {
368                 fmt.setMaximumIntegerDigits(tuple.maxIntegerDigits);
369             }
370             if (tuple.minFractionDigits != null) {
371                 fmt.setMinimumFractionDigits(tuple.minFractionDigits);
372             }
373             if (tuple.maxFractionDigits != null) {
374                 fmt.setMaximumFractionDigits(tuple.maxFractionDigits);
375             }
376             if (tuple.currency != null) {
377                 fmt.setCurrency(java.util.Currency.getInstance(tuple.currency.toString()));
378             }
379             if (tuple.minGroupingDigits != null) {
380                 // Oops we don't support this.
381             }
382             if (tuple.useSigDigits != null) {
383                 // Oops we don't support this
384             }
385             if (tuple.minSigDigits != null) {
386                 // Oops we don't support this
387             }
388             if (tuple.maxSigDigits != null) {
389                 // Oops we don't support this
390             }
391             if (tuple.useGrouping != null) {
392                 fmt.setGroupingUsed(tuple.useGrouping != 0);
393             }
394             if (tuple.multiplier != null) {
395                 fmt.setMultiplier(tuple.multiplier);
396             }
397             if (tuple.roundingIncrement != null) {
398                 // Not supported
399             }
400             if (tuple.formatWidth != null) {
401                 // Not supported
402             }
403             if (tuple.padCharacter != null && tuple.padCharacter.length() > 0) {
404                 // Not supported
405             }
406             if (tuple.useScientific != null) {
407                 // Not supported
408             }
409             if (tuple.grouping != null) {
410                 fmt.setGroupingSize(tuple.grouping);
411             }
412             if (tuple.grouping2 != null) {
413                 // Not supported
414             }
415             if (tuple.roundingMode != null) {
416                 // Not supported
417             }
418             if (tuple.currencyUsage != null) {
419                 // Not supported
420             }
421             if (tuple.minimumExponentDigits != null) {
422                 // Not supported
423             }
424             if (tuple.exponentSignAlwaysShown != null) {
425                 // Not supported
426             }
427             if (tuple.decimalSeparatorAlwaysShown != null) {
428                 fmt.setDecimalSeparatorAlwaysShown(tuple.decimalSeparatorAlwaysShown != 0);
429             }
430             if (tuple.padPosition != null) {
431                 // Not supported
432             }
433             if (tuple.positivePrefix != null) {
434                 fmt.setPositivePrefix(tuple.positivePrefix);
435             }
436             if (tuple.positiveSuffix != null) {
437                 fmt.setPositiveSuffix(tuple.positiveSuffix);
438             }
439             if (tuple.negativePrefix != null) {
440                 fmt.setNegativePrefix(tuple.negativePrefix);
441             }
442             if (tuple.negativeSuffix != null) {
443                 fmt.setNegativeSuffix(tuple.negativeSuffix);
444             }
445             if (tuple.signAlwaysShown != null) {
446                 // Not supported.
447             }
448             if (tuple.localizedPattern != null) {
449                 fmt.applyLocalizedPattern(tuple.localizedPattern);
450             }
451 
452             // lenient parsing not supported by JDK
453             if (tuple.parseIntegerOnly != null) {
454                 fmt.setParseIntegerOnly(tuple.parseIntegerOnly != 0);
455             }
456             if (tuple.parseCaseSensitive != null) {
457                 // Not supported.
458             }
459             if (tuple.decimalPatternMatchRequired != null) {
460                 // Oops, not supported
461             }
462             if (tuple.parseNoExponent != null) {
463                 // Oops, not supported for now
464             }
465         }
466     };
467 
propertiesFromTuple( DataDrivenNumberFormatTestData tuple, DecimalFormatProperties properties)468     static void propertiesFromTuple(
469             DataDrivenNumberFormatTestData tuple,
470             DecimalFormatProperties properties) {
471         if (tuple.minIntegerDigits != null) {
472             properties.setMinimumIntegerDigits(tuple.minIntegerDigits);
473         }
474         if (tuple.maxIntegerDigits != null) {
475             properties.setMaximumIntegerDigits(tuple.maxIntegerDigits);
476         }
477         if (tuple.minFractionDigits != null) {
478             properties.setMinimumFractionDigits(tuple.minFractionDigits);
479         }
480         if (tuple.maxFractionDigits != null) {
481             properties.setMaximumFractionDigits(tuple.maxFractionDigits);
482         }
483         if (tuple.currency != null) {
484             properties.setCurrency(tuple.currency);
485         }
486         if (tuple.minGroupingDigits != null) {
487             properties.setMinimumGroupingDigits(tuple.minGroupingDigits);
488         }
489         if (tuple.useSigDigits != null) {
490             // TODO
491         }
492         if (tuple.minSigDigits != null) {
493             properties.setMinimumSignificantDigits(tuple.minSigDigits);
494         }
495         if (tuple.maxSigDigits != null) {
496             properties.setMaximumSignificantDigits(tuple.maxSigDigits);
497         }
498         if (tuple.useGrouping != null) {
499             properties.setGroupingUsed(tuple.useGrouping > 0);
500         }
501         if (tuple.multiplier != null) {
502             properties.setMultiplier(new BigDecimal(tuple.multiplier));
503         }
504         if (tuple.roundingIncrement != null) {
505             properties.setRoundingIncrement(new BigDecimal(tuple.roundingIncrement.toString()));
506         }
507         if (tuple.formatWidth != null) {
508             properties.setFormatWidth(tuple.formatWidth);
509         }
510         if (tuple.padCharacter != null && tuple.padCharacter.length() > 0) {
511             properties.setPadString(tuple.padCharacter.toString());
512         }
513         if (tuple.useScientific != null) {
514             properties.setMinimumExponentDigits(tuple.useScientific != 0 ? 1 : -1);
515         }
516         if (tuple.grouping != null) {
517             properties.setGroupingSize(tuple.grouping);
518         }
519         if (tuple.grouping2 != null) {
520             properties.setSecondaryGroupingSize(tuple.grouping2);
521         }
522         if (tuple.roundingMode != null) {
523             properties.setRoundingMode(RoundingMode.valueOf(tuple.roundingMode));
524         }
525         if (tuple.currencyUsage != null) {
526             properties.setCurrencyUsage(tuple.currencyUsage);
527         }
528         if (tuple.minimumExponentDigits != null) {
529             properties.setMinimumExponentDigits(tuple.minimumExponentDigits.byteValue());
530         }
531         if (tuple.exponentSignAlwaysShown != null) {
532             properties.setExponentSignAlwaysShown(tuple.exponentSignAlwaysShown != 0);
533         }
534         if (tuple.decimalSeparatorAlwaysShown != null) {
535             properties.setDecimalSeparatorAlwaysShown(tuple.decimalSeparatorAlwaysShown != 0);
536         }
537         if (tuple.padPosition != null) {
538             properties.setPadPosition(PadPosition.fromOld(tuple.padPosition));
539         }
540         if (tuple.positivePrefix != null) {
541             properties.setPositivePrefix(tuple.positivePrefix);
542         }
543         if (tuple.positiveSuffix != null) {
544             properties.setPositiveSuffix(tuple.positiveSuffix);
545         }
546         if (tuple.negativePrefix != null) {
547             properties.setNegativePrefix(tuple.negativePrefix);
548         }
549         if (tuple.negativeSuffix != null) {
550             properties.setNegativeSuffix(tuple.negativeSuffix);
551         }
552         if (tuple.signAlwaysShown != null) {
553             properties.setSignAlwaysShown(tuple.signAlwaysShown != 0);
554         }
555         if (tuple.localizedPattern != null) {
556             DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(tuple.locale);
557             String converted = PatternStringUtils
558                     .convertLocalized(tuple.localizedPattern, symbols, false);
559             PatternStringParser.parseToExistingProperties(converted, properties);
560         }
561         if (tuple.lenient != null) {
562             properties.setParseMode(tuple.lenient == 0 ? ParseMode.STRICT : ParseMode.LENIENT);
563         }
564         if (tuple.parseIntegerOnly != null) {
565             properties.setParseIntegerOnly(tuple.parseIntegerOnly != 0);
566         }
567         if (tuple.parseCaseSensitive != null) {
568             properties.setParseCaseSensitive(tuple.parseCaseSensitive != 0);
569         }
570         if (tuple.decimalPatternMatchRequired != null) {
571             properties.setDecimalPatternMatchRequired(tuple.decimalPatternMatchRequired != 0);
572         }
573         if (tuple.parseNoExponent != null) {
574             properties.setParseNoExponent(tuple.parseNoExponent != 0);
575         }
576     }
577 
578     /**
579      * Same as ICU4J, but bypasses the DecimalFormat wrapper and goes directly to the
580      * DecimalFormatProperties.
581      */
582     private DataDrivenNumberFormatTestUtility.CodeUnderTest ICU4J_Properties = new DataDrivenNumberFormatTestUtility.CodeUnderTest() {
583 
584         @Override
585         public Character Id() {
586             return 'P';
587         }
588 
589         /**
590          * Runs a single formatting test. On success, returns null. On failure, returns the error. This
591          * implementation just returns null. Subclasses should override.
592          *
593          * @param tuple
594          *            contains the parameters of the format test.
595          */
596         @Override
597         public String format(DataDrivenNumberFormatTestData tuple) {
598             String pattern = (tuple.pattern == null) ? "0" : tuple.pattern;
599             ULocale locale = (tuple.locale == null) ? ULocale.ENGLISH : tuple.locale;
600             DecimalFormatProperties properties = PatternStringParser.parseToProperties(pattern,
601                     tuple.currency != null ? PatternStringParser.IGNORE_ROUNDING_ALWAYS
602                             : PatternStringParser.IGNORE_ROUNDING_NEVER);
603             propertiesFromTuple(tuple, properties);
604             DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(locale);
605             LocalizedNumberFormatter fmt = NumberFormatter.fromDecimalFormat(properties, symbols, null)
606                     .locale(locale);
607             Number number = toNumber(tuple.format);
608             String expected = tuple.output;
609             String actual = fmt.format(number).toString();
610             if (!expected.equals(actual)) {
611                 return "Expected \"" + expected + "\", got \"" + actual + "\"";
612             }
613             return null;
614         }
615 
616         /**
617          * Runs a single toPattern test. On success, returns null. On failure, returns the error. This
618          * implementation just returns null. Subclasses should override.
619          *
620          * @param tuple
621          *            contains the parameters of the format test.
622          */
623         @Override
624         public String toPattern(DataDrivenNumberFormatTestData tuple) {
625             String pattern = (tuple.pattern == null) ? "0" : tuple.pattern;
626             final DecimalFormatProperties properties;
627             DecimalFormat df;
628             try {
629                 properties = PatternStringParser.parseToProperties(pattern,
630                         tuple.currency != null ? PatternStringParser.IGNORE_ROUNDING_ALWAYS
631                                 : PatternStringParser.IGNORE_ROUNDING_NEVER);
632                 propertiesFromTuple(tuple, properties);
633                 // TODO: Use PatternString.propertiesToString() directly. (How to deal with
634                 // CurrencyUsage?)
635                 df = new DecimalFormat();
636                 df.setProperties(new PropertySetter() {
637                     @Override
638                     public void set(DecimalFormatProperties props) {
639                         props.copyFrom(properties);
640                     }
641                 });
642             } catch (IllegalArgumentException e) {
643                 e.printStackTrace();
644                 return e.getLocalizedMessage();
645             }
646 
647             if (tuple.toPattern != null) {
648                 String expected = tuple.toPattern;
649                 String actual = df.toPattern();
650                 if (!expected.equals(actual)) {
651                     return "Expected toPattern='" + expected + "'; got '" + actual + "'";
652                 }
653             }
654             if (tuple.toLocalizedPattern != null) {
655                 String expected = tuple.toLocalizedPattern;
656                 String actual = PatternStringUtils.propertiesToPatternString(properties);
657                 if (!expected.equals(actual)) {
658                     return "Expected toLocalizedPattern='" + expected + "'; got '" + actual + "'";
659                 }
660             }
661             return null;
662         }
663 
664         @Override
665         public String parse(DataDrivenNumberFormatTestData tuple) {
666             String pattern = (tuple.pattern == null) ? "0" : tuple.pattern;
667             DecimalFormatProperties properties;
668             ParsePosition ppos = new ParsePosition(0);
669             Number actual;
670             try {
671                 properties = PatternStringParser.parseToProperties(pattern,
672                         tuple.currency != null ? PatternStringParser.IGNORE_ROUNDING_ALWAYS
673                                 : PatternStringParser.IGNORE_ROUNDING_NEVER);
674                 propertiesFromTuple(tuple, properties);
675                 actual = NumberParserImpl.parseStatic(tuple.parse,
676                         ppos,
677                         properties,
678                         DecimalFormatSymbols.getInstance(tuple.locale));
679             } catch (IllegalArgumentException e) {
680                 return "parse exception: " + e.getMessage();
681             }
682             return compareParseResult(tuple.output, actual, ppos);
683         }
684 
685         @Override
686         public String parseCurrency(DataDrivenNumberFormatTestData tuple) {
687             String pattern = (tuple.pattern == null) ? "0" : tuple.pattern;
688             DecimalFormatProperties properties;
689             ParsePosition ppos = new ParsePosition(0);
690             CurrencyAmount actual;
691             try {
692                 properties = PatternStringParser.parseToProperties(pattern,
693                         tuple.currency != null ? PatternStringParser.IGNORE_ROUNDING_ALWAYS
694                                 : PatternStringParser.IGNORE_ROUNDING_NEVER);
695                 propertiesFromTuple(tuple, properties);
696                 actual = NumberParserImpl.parseStaticCurrency(tuple.parse,
697                         ppos,
698                         properties,
699                         DecimalFormatSymbols.getInstance(tuple.locale));
700             } catch (IllegalArgumentException e) {
701                 e.printStackTrace();
702                 return "parse exception: " + e.getMessage();
703             }
704             return compareParseCurrencyResult(tuple.output, tuple.outputCurrency, actual, ppos);
705         }
706     };
707 
708     @Test
TestNoUnknownIDs()709     public void TestNoUnknownIDs() {
710         DataDrivenNumberFormatTestUtility.checkNoUnknownIDs("numberformattestspecification.txt", "CHJKP");
711     }
712 
713     @Test
TestDataDrivenICU4J()714     public void TestDataDrivenICU4J() {
715         DataDrivenNumberFormatTestUtility
716                 .runFormatSuiteIncludingKnownFailures("numberformattestspecification.txt", ICU4J);
717     }
718 
719     @Test
TestDataDrivenJDK()720     public void TestDataDrivenJDK() {
721         // #13373: Since not all JDK implementations are the same, test only whitelisted JDKs
722         // with known behavior. The JDK version should be occasionally updated.
723         org.junit.Assume.assumeTrue(TestUtil.getJavaRuntimeName() == TestUtil.JavaRuntimeName.OpenJDK
724                 && TestUtil.getJavaVersion() == 8);
725 
726         DataDrivenNumberFormatTestUtility
727                 .runFormatSuiteIncludingKnownFailures("numberformattestspecification.txt", JDK);
728     }
729 
730     @Test
TestDataDrivenICU4JProperties()731     public void TestDataDrivenICU4JProperties() {
732         DataDrivenNumberFormatTestUtility
733                 .runFormatSuiteIncludingKnownFailures("numberformattestspecification.txt", ICU4J_Properties);
734     }
735 }
736