1 /*
   2  * Copyright (c) 2007, 2015, 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  * @test
  25  * @bug 4290801 4692419 4693631 5101540 5104960 6296410 6336600 6371531
  26  *    6488442 7036905 8039317 8074350 8074351
  27  * @summary Basic tests for Currency class.
  28  */
  29 
  30 import java.io.ByteArrayInputStream;
  31 import java.io.ByteArrayOutputStream;
  32 import java.io.ObjectInputStream;
  33 import java.io.ObjectOutputStream;
  34 import java.util.Calendar;
  35 import java.util.Date;
  36 import java.util.Currency;
  37 import java.util.GregorianCalendar;
  38 import java.util.Locale;
  39 import java.util.TimeZone;
  40 
  41 
  42 public class CurrencyTest {
  43 
  44     public static void main(String[] args) throws Exception {
  45         CheckDataVersion.check();
  46         testCurrencyCodeValidation();
  47         testLocaleMapping();
  48         testSymbols();
  49         testFractionDigits();
  50         testSerialization();
  51         testDisplayNames();
  52         testFundsCodes();
  53     }
  54 
  55     static void testCurrencyCodeValidation() {
  56         // test creation of some valid currencies
  57         testValidCurrency("USD");
  58         testValidCurrency("EUR");
  59         testValidCurrency("GBP");
  60         testValidCurrency("JPY");
  61         testValidCurrency("CNY");
  62         testValidCurrency("CHF");
  63 
  64         // test creation of some fictitious currencies
  65         testInvalidCurrency("AQD");
  66         testInvalidCurrency("US$");
  67         testInvalidCurrency("\u20AC");
  68     }
  69 
  70     static void testValidCurrency(String currencyCode) {
  71         Currency currency1 = Currency.getInstance(currencyCode);
  72         Currency currency2 = Currency.getInstance(currencyCode);
  73         if (currency1 != currency2) {
  74             throw new RuntimeException("Didn't get same instance for same currency code");
  75         }
  76         if (!currency1.getCurrencyCode().equals(currencyCode)) {
  77             throw new RuntimeException("Currency code changed");
  78         }
  79     }
  80 
  81     static void testInvalidCurrency(String currencyCode) {
  82         boolean gotException = false;
  83         try {
  84             Currency currency = Currency.getInstance(currencyCode);
  85         } catch (IllegalArgumentException e) {
  86             gotException = true;
  87         }
  88         if (!gotException) {
  89             throw new RuntimeException("didn't get specified exception");
  90         }
  91     }
  92 
  93     static void testLocaleMapping() {
  94         // very basic test: most countries have their own currency, and then
  95         // their currency code is an extension of their country code.
  96         Locale[] locales = Locale.getAvailableLocales();
  97         int goodCountries = 0;
  98         int ownCurrencies = 0;
  99         for (int i = 0; i < locales.length; i++) {
 100             Locale locale = locales[i];
 101             if (locale.getCountry().length() == 0) {
 102                 boolean gotException = false;
 103                 try {
 104                     Currency.getInstance(locale);
 105                 } catch (IllegalArgumentException e) {
 106                     gotException = true;
 107                 }
 108                 if (!gotException) {
 109                     throw new RuntimeException("didn't get specified exception");
 110                 }
 111             } else {
 112                 goodCountries++;
 113                 Currency currency = Currency.getInstance(locale);
 114                 if (currency.getCurrencyCode().indexOf(locale.getCountry()) == 0) {
 115                     ownCurrencies++;
 116                 }
 117             }
 118         }
 119         System.out.println("Countries tested: " + goodCountries +
 120                 ", own currencies: " + ownCurrencies);
 121         if (ownCurrencies < (goodCountries / 2 + 1)) {
 122             throw new RuntimeException("suspicious: not enough countries have their own currency.");
 123         }
 124 
 125         // check a few countries that don't change their currencies too often
 126         String[] country1 = {"US", "CA", "JP", "CN", "SG", "CH"};
 127         String[] currency1 = {"USD", "CAD", "JPY", "CNY", "SGD", "CHF"};
 128         for (int i = 0; i < country1.length; i++) {
 129             checkCountryCurrency(country1[i], currency1[i]);
 130         }
 131 
 132         /*
 133         * check currency changes
 134         * In current implementation, there is no data of old currency and transition date at jdk/src/share/classes/java/util/CurrencyData.properties.
 135         * So, all the switch data arrays are empty. In the future, if data of old currency and transition date are necessary for any country, the
 136         * arrays here can be updated so that the program can check the currency switch.
 137         */
 138         String[] switchOverCtry = {};
 139         String[] switchOverOld = {};
 140         String[] switchOverNew = {};
 141         String[] switchOverTZ = {};
 142         int[] switchOverYear = {};
 143         int[] switchOverMonth = {};
 144         int[] switchOverDay = {};
 145 
 146         for (int i = 0; i < switchOverCtry.length; i++) {
 147             TimeZone.setDefault(TimeZone.getTimeZone(switchOverTZ[i]));
 148             Calendar date = new GregorianCalendar(switchOverYear[i], switchOverMonth[i], switchOverDay[i]);
 149             long switchOver = date.getTime().getTime();
 150             boolean switchedOver = System.currentTimeMillis() >= switchOver;
 151             checkCountryCurrency(switchOverCtry[i], switchedOver ? switchOverNew[i] : switchOverOld[i]);
 152         }
 153 
 154         // check a country code which doesn't have a currency
 155         checkCountryCurrency("AQ", null);
 156 
 157         // check an invalid country code
 158         boolean gotException = false;
 159         try {
 160             Currency.getInstance(new Locale("", "EU"));
 161         } catch (IllegalArgumentException e) {
 162             gotException = true;
 163         }
 164         if (!gotException) {
 165             throw new RuntimeException("didn't get specified exception.");
 166         }
 167     }
 168 
 169     static void checkCountryCurrency(String countryCode, String expected) {
 170         Locale locale = new Locale("", countryCode);
 171         Currency currency = Currency.getInstance(locale);
 172         String code = (currency != null) ? currency.getCurrencyCode() : null;
 173         if (!(expected == null ? code == null : expected.equals(code))) {
 174             throw new RuntimeException("Wrong currency for " +
 175                     locale.getDisplayCountry() +
 176                     ": expected " + expected + ", got " + code);
 177         }
 178     }
 179 
 180     static void testSymbols() {
 181         testSymbol("USD", Locale.US, "$");
 182         testSymbol("EUR", Locale.GERMANY, "\u20AC");
 183         testSymbol("USD", Locale.PRC, "USD");
 184     }
 185 
 186     static void testSymbol(String currencyCode, Locale locale, String expectedSymbol) {
 187         String symbol = Currency.getInstance(currencyCode).getSymbol(locale);
 188         if (!symbol.equals(expectedSymbol)) {
 189             throw new RuntimeException("Wrong symbol for currency " +
 190                     currencyCode +": expected " + expectedSymbol +
 191                     ", got " + symbol);
 192         }
 193     }
 194 
 195     static void testFractionDigits() {
 196         testFractionDigits("USD", 2);
 197         testFractionDigits("EUR", 2);
 198         testFractionDigits("JPY", 0);
 199         testFractionDigits("XDR", -1);
 200 
 201         testFractionDigits("BHD", 3);
 202         testFractionDigits("IQD", 3);
 203         testFractionDigits("JOD", 3);
 204         testFractionDigits("KWD", 3);
 205         testFractionDigits("LYD", 3);
 206         testFractionDigits("OMR", 3);
 207         testFractionDigits("TND", 3);
 208 
 209         // Turkish Lira
 210         testFractionDigits("TRL", 0);
 211         testFractionDigits("TRY", 2);
 212     }
 213 
 214     static void testFractionDigits(String currencyCode, int expectedFractionDigits) {
 215         int digits = Currency.getInstance(currencyCode).getDefaultFractionDigits();
 216         if (digits != expectedFractionDigits) {
 217             throw new RuntimeException("Wrong number of fraction digits for currency " +
 218                     currencyCode +": expected " + expectedFractionDigits +
 219                     ", got " + digits);
 220         }
 221     }
 222 
 223     static void testSerialization() throws Exception {
 224         Currency currency1 = Currency.getInstance("DEM");
 225 
 226         ByteArrayOutputStream baos = new ByteArrayOutputStream();
 227         ObjectOutputStream oStream = new ObjectOutputStream(baos);
 228         oStream.writeObject(currency1);
 229         oStream.flush();
 230         byte[] bytes = baos.toByteArray();
 231 
 232         ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
 233         ObjectInputStream iStream = new ObjectInputStream(bais);
 234         Currency currency2 = (Currency) iStream.readObject();
 235 
 236         if (currency1 != currency2) {
 237             throw new RuntimeException("serialization breaks class invariant");
 238         }
 239     }
 240 
 241     static void testDisplayNames() {
 242         // null argument test
 243         try {
 244             testDisplayName("USD", null, "");
 245             throw new RuntimeException("getDisplayName(NULL) did not throw an NPE.");
 246         } catch (NullPointerException npe) {}
 247 
 248         testDisplayName("USD", Locale.ENGLISH, "US Dollar");
 249         testDisplayName("FRF", Locale.FRENCH, "franc fran\u00e7ais");
 250         testDisplayName("DEM", Locale.GERMAN, "Deutsche Mark");
 251         testDisplayName("ESP", new Locale("es"), "peseta espa\u00f1ola");
 252         testDisplayName("ITL", new Locale("it"), "Lira Italiana");
 253         testDisplayName("JPY", Locale.JAPANESE, "\u65e5\u672c\u5186");
 254         testDisplayName("KRW", Locale.KOREAN, "\ub300\ud55c\ubbfc\uad6d \uc6d0");
 255         testDisplayName("SEK", new Locale("sv"), "svensk krona");
 256         testDisplayName("CNY", Locale.SIMPLIFIED_CHINESE, "\u4eba\u6c11\u5e01");
 257         testDisplayName("TWD", Locale.TRADITIONAL_CHINESE, "\u65b0\u81fa\u5e63");
 258     }
 259 
 260     static void testDisplayName(String currencyCode, Locale locale, String expectedName) {
 261         String name = Currency.getInstance(currencyCode).getDisplayName(locale);
 262         if (!name.equals(expectedName)) {
 263             throw new RuntimeException("Wrong display name for currency " +
 264                     currencyCode +": expected '" + expectedName +
 265                     "', got '" + name + "'");
 266         }
 267     }
 268 
 269     static void testFundsCodes() {
 270         testValidCurrency("BOV");
 271         testValidCurrency("CHE");
 272         testValidCurrency("CHW");
 273         testValidCurrency("CLF");
 274         testValidCurrency("COU");
 275         testValidCurrency("MXV");
 276         testValidCurrency("USN");
 277         testValidCurrency("UYI");
 278 
 279         testFractionDigits("BOV", 2);
 280         testFractionDigits("CHE", 2);
 281         testFractionDigits("CHW", 2);
 282         testFractionDigits("CLF", 4);
 283         testFractionDigits("COU", 2);
 284         testFractionDigits("MXV", 2);
 285         testFractionDigits("USN", 2);
 286         testFractionDigits("UYI", 0);
 287 
 288         testNumericCode("BOV", 984);
 289         testNumericCode("CHE", 947);
 290         testNumericCode("CHW", 948);
 291         testNumericCode("CLF", 990);
 292         testNumericCode("COU", 970);
 293         testNumericCode("MXV", 979);
 294         testNumericCode("USN", 997);
 295         testNumericCode("UYI", 940);
 296     }
 297 
 298     static void testNumericCode(String currencyCode, int expectedNumeric) {
 299         int numeric = Currency.getInstance(currencyCode).getNumericCode();
 300         if (numeric != expectedNumeric) {
 301             throw new RuntimeException("Wrong numeric code for currency " +
 302                     currencyCode +": expected " + expectedNumeric +
 303                     ", got " + numeric);
 304         }
 305     }
 306 }