1 /*
   2  * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @bug 4052440 7003643 8062588 8210406
  27  * @summary NumberFormatProvider tests
  28  * @library providersrc/foobarutils
  29  *          providersrc/fooprovider
  30  * @modules java.base/sun.util.locale.provider
  31  * @build com.foobar.Utils
  32  *        com.foo.*
  33  * @run main/othervm -Djava.locale.providers=JRE,SPI NumberFormatProviderTest
  34  */
  35 
  36 import java.text.DecimalFormat;
  37 import java.text.DecimalFormatSymbols;
  38 import java.text.MessageFormat;
  39 import java.text.NumberFormat;
  40 import java.util.Arrays;
  41 import java.util.Currency;
  42 import java.util.HashSet;
  43 import java.util.List;
  44 import java.util.Locale;
  45 import java.util.Set;
  46 
  47 import com.foo.FooNumberFormat;
  48 import com.foo.NumberFormatProviderImpl;
  49 
  50 import sun.util.locale.provider.LocaleProviderAdapter;
  51 
  52 public class NumberFormatProviderTest extends ProviderTest {
  53 
  54     NumberFormatProviderImpl nfp = new NumberFormatProviderImpl();
  55     List<Locale> availloc = Arrays.asList(NumberFormat.getAvailableLocales());
  56     List<Locale> providerloc = Arrays.asList(nfp.getAvailableLocales());
  57     List<Locale> jreloc = Arrays.asList(LocaleProviderAdapter.forJRE().getAvailableLocales());
  58     List<Locale> jreimplloc = Arrays.asList(LocaleProviderAdapter.forJRE().getNumberFormatProvider().getAvailableLocales());
  59 
  60     public static void main(String[] s) {
  61         new NumberFormatProviderTest();
  62     }
  63 
  64     NumberFormatProviderTest() {
  65         availableLocalesTest();
  66         objectValidityTest();
  67         messageFormatTest();
  68     }
  69 
  70     void availableLocalesTest() {
  71         Set<Locale> localesFromAPI = new HashSet<>(availloc);
  72         Set<Locale> localesExpected = new HashSet<>(jreloc);
  73         localesExpected.addAll(providerloc);
  74         if (localesFromAPI.equals(localesExpected)) {
  75             System.out.println("availableLocalesTest passed.");
  76         } else {
  77             throw new RuntimeException("availableLocalesTest failed");
  78         }
  79     }
  80 
  81     void objectValidityTest() {
  82 
  83         for (Locale target: availloc) {
  84             boolean jreSupportsLocale = jreimplloc.contains(target);
  85 
  86             // JRE string arrays
  87             String[] jreNumberPatterns = null;
  88             if (jreSupportsLocale) {
  89                 jreNumberPatterns = LocaleProviderAdapter.forJRE().getLocaleResources(target).getNumberPatterns();
  90             }
  91 
  92             // result object
  93             String resultCur = getPattern(NumberFormat.getCurrencyInstance(target));
  94             String resultInt = getPattern(NumberFormat.getIntegerInstance(target));
  95             String resultNum = getPattern(NumberFormat.getNumberInstance(target));
  96             String resultPer = getPattern(NumberFormat.getPercentInstance(target));
  97 
  98             // provider's object (if any)
  99             String providersCur = null;
 100             String providersInt = null;
 101             String providersNum = null;
 102             String providersPer = null;
 103             if (providerloc.contains(target)) {
 104                 NumberFormat dfCur = nfp.getCurrencyInstance(target);
 105                 if (dfCur != null) {
 106                     providersCur = getPattern(dfCur);
 107                 }
 108                 NumberFormat dfInt = nfp.getIntegerInstance(target);
 109                 if (dfInt != null) {
 110                     providersInt = getPattern(dfInt);
 111                 }
 112                 NumberFormat dfNum = nfp.getNumberInstance(target);
 113                 if (dfNum != null) {
 114                     providersNum = getPattern(dfNum);
 115                 }
 116                 NumberFormat dfPer = nfp.getPercentInstance(target);
 117                 if (dfPer != null) {
 118                     providersPer = getPattern(dfPer);
 119                 }
 120             }
 121 
 122             // JRE's object (if any)
 123             // note that this totally depends on the current implementation
 124             String jresCur = null;
 125             String jresInt = null;
 126             String jresNum = null;
 127             String jresPer = null;
 128             if (jreSupportsLocale) {
 129                 DecimalFormat dfCur = new DecimalFormat(jreNumberPatterns[1],
 130                     DecimalFormatSymbols.getInstance(target));
 131                 if (dfCur != null) {
 132                     adjustForCurrencyDefaultFractionDigits(dfCur);
 133                     jresCur = dfCur.toPattern();
 134                 }
 135                 DecimalFormat dfInt = new DecimalFormat(jreNumberPatterns[0],
 136                     DecimalFormatSymbols.getInstance(target));
 137                 if (dfInt != null) {
 138                     dfInt.setMaximumFractionDigits(0);
 139                     dfInt.setDecimalSeparatorAlwaysShown(false);
 140                     dfInt.setParseIntegerOnly(true);
 141                     jresInt = dfInt.toPattern();
 142                 }
 143                 DecimalFormat dfNum = new DecimalFormat(jreNumberPatterns[0],
 144                     DecimalFormatSymbols.getInstance(target));
 145                 if (dfNum != null) {
 146                     jresNum = dfNum.toPattern();
 147                 }
 148                 DecimalFormat dfPer = new DecimalFormat(jreNumberPatterns[2],
 149                     DecimalFormatSymbols.getInstance(target));
 150                 if (dfPer != null) {
 151                     jresPer = dfPer.toPattern();
 152                 }
 153             }
 154 
 155             checkValidity(target, jresCur, providersCur, resultCur, jreSupportsLocale);
 156             checkValidity(target, jresInt, providersInt, resultInt, jreSupportsLocale);
 157             checkValidity(target, jresNum, providersNum, resultNum, jreSupportsLocale);
 158             checkValidity(target, jresPer, providersPer, resultPer, jreSupportsLocale);
 159         }
 160     }
 161 
 162     /**
 163      * Adjusts the minimum and maximum fraction digits to values that
 164      * are reasonable for the currency's default fraction digits.
 165      */
 166     void adjustForCurrencyDefaultFractionDigits(DecimalFormat df) {
 167         DecimalFormatSymbols dfs = df.getDecimalFormatSymbols();
 168         Currency currency = dfs.getCurrency();
 169         if (currency == null) {
 170             try {
 171                 currency = Currency.getInstance(dfs.getInternationalCurrencySymbol());
 172             } catch (IllegalArgumentException e) {
 173             }
 174         }
 175         if (currency != null) {
 176             int digits = currency.getDefaultFractionDigits();
 177             if (digits != -1) {
 178                 int oldMinDigits = df.getMinimumFractionDigits();
 179                 // Common patterns are "#.##", "#.00", "#".
 180                 // Try to adjust all of them in a reasonable way.
 181                 if (oldMinDigits == df.getMaximumFractionDigits()) {
 182                     df.setMinimumFractionDigits(digits);
 183                     df.setMaximumFractionDigits(digits);
 184                 } else {
 185                     df.setMinimumFractionDigits(Math.min(digits, oldMinDigits));
 186                     df.setMaximumFractionDigits(digits);
 187                 }
 188             }
 189         }
 190     }
 191 
 192     private static String getPattern(NumberFormat nf) {
 193         if (nf instanceof DecimalFormat) {
 194             return ((DecimalFormat)nf).toPattern();
 195         }
 196         if (nf instanceof FooNumberFormat) {
 197             return ((FooNumberFormat)nf).toPattern();
 198         }
 199         return null;
 200     }
 201 
 202     private static final String[] NUMBER_PATTERNS = {
 203         "num={0,number}",
 204         "num={0,number,currency}",
 205         "num={0,number,percent}",
 206         "num={0,number,integer}"
 207     };
 208 
 209     void messageFormatTest() {
 210         for (Locale target : providerloc) {
 211             for (String pattern : NUMBER_PATTERNS) {
 212                 MessageFormat mf = new MessageFormat(pattern, target);
 213                 String toPattern = mf.toPattern();
 214                 if (!pattern.equals(toPattern)) {
 215                     throw new RuntimeException("MessageFormat.toPattern: got '"
 216                                                + toPattern
 217                                                + "', expected '" + pattern + "'");
 218                 }
 219             }
 220         }
 221     }
 222 }