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