d6b4693c05
Reviewed-by: iris, joehw
315 lines
12 KiB
Java
315 lines
12 KiB
Java
/*
|
|
* Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
/*
|
|
* @test
|
|
* @bug 4290801 4692419 4693631 5101540 5104960 6296410 6336600 6371531
|
|
* 6488442 7036905 8008577 8039317 8074350 8074351 8150324 8167143
|
|
* 8264792
|
|
* @summary Basic tests for Currency class.
|
|
* @modules java.base/java.util:open
|
|
* jdk.localedata
|
|
*/
|
|
|
|
import java.io.ByteArrayInputStream;
|
|
import java.io.ByteArrayOutputStream;
|
|
import java.io.ObjectInputStream;
|
|
import java.io.ObjectOutputStream;
|
|
import java.time.LocalDate;
|
|
import java.time.LocalTime;
|
|
import java.time.ZoneId;
|
|
import java.time.ZonedDateTime;
|
|
import java.util.Currency;
|
|
import java.util.Locale;
|
|
|
|
|
|
public class CurrencyTest {
|
|
|
|
public static void main(String[] args) throws Exception {
|
|
CheckDataVersion.check();
|
|
testCurrencyCodeValidation();
|
|
testLocaleMapping();
|
|
testSymbols();
|
|
testFractionDigits();
|
|
testSerialization();
|
|
testDisplayNames();
|
|
testFundsCodes();
|
|
}
|
|
|
|
static void testCurrencyCodeValidation() {
|
|
// test creation of some valid currencies
|
|
testValidCurrency("USD");
|
|
testValidCurrency("EUR");
|
|
testValidCurrency("GBP");
|
|
testValidCurrency("JPY");
|
|
testValidCurrency("CNY");
|
|
testValidCurrency("CHF");
|
|
|
|
// test creation of some fictitious currencies
|
|
testInvalidCurrency("AQD");
|
|
testInvalidCurrency("US$");
|
|
testInvalidCurrency("\u20AC");
|
|
}
|
|
|
|
static void testValidCurrency(String currencyCode) {
|
|
Currency currency1 = Currency.getInstance(currencyCode);
|
|
Currency currency2 = Currency.getInstance(currencyCode);
|
|
if (currency1 != currency2) {
|
|
throw new RuntimeException("Didn't get same instance for same currency code");
|
|
}
|
|
if (!currency1.getCurrencyCode().equals(currencyCode)) {
|
|
throw new RuntimeException("Currency code changed");
|
|
}
|
|
}
|
|
|
|
static void testInvalidCurrency(String currencyCode) {
|
|
boolean gotException = false;
|
|
try {
|
|
Currency currency = Currency.getInstance(currencyCode);
|
|
} catch (IllegalArgumentException e) {
|
|
gotException = true;
|
|
}
|
|
if (!gotException) {
|
|
throw new RuntimeException("didn't get specified exception");
|
|
}
|
|
}
|
|
|
|
static void testLocaleMapping() {
|
|
// very basic test: most countries have their own currency, and then
|
|
// their currency code is an extension of their country code.
|
|
Locale[] locales = Locale.getAvailableLocales();
|
|
int goodCountries = 0;
|
|
int ownCurrencies = 0;
|
|
for (int i = 0; i < locales.length; i++) {
|
|
Locale locale = locales[i];
|
|
String ctryCode = locale.getCountry();
|
|
int ctryLength = ctryCode.length();
|
|
if (ctryLength == 0 ||
|
|
ctryLength == 3 || // UN M.49 code
|
|
ctryCode.matches("AA|Q[M-Z]|X[A-JL-Z]|ZZ" + // user defined codes, excluding "XK" (Kosovo)
|
|
"AC|CP|DG|EA|EU|FX|IC|SU|TA|UK")) { // exceptional reservation codes
|
|
boolean gotException = false;
|
|
try {
|
|
Currency.getInstance(locale);
|
|
} catch (IllegalArgumentException e) {
|
|
gotException = true;
|
|
}
|
|
if (!gotException) {
|
|
throw new RuntimeException("didn't get specified exception");
|
|
}
|
|
} else {
|
|
goodCountries++;
|
|
Currency currency = Currency.getInstance(locale);
|
|
if (currency.getCurrencyCode().indexOf(locale.getCountry()) == 0) {
|
|
ownCurrencies++;
|
|
}
|
|
}
|
|
}
|
|
System.out.println("Countries tested: " + goodCountries +
|
|
", own currencies: " + ownCurrencies);
|
|
if (ownCurrencies < (goodCountries / 2 + 1)) {
|
|
throw new RuntimeException("suspicious: not enough countries have their own currency.");
|
|
}
|
|
|
|
// check a few countries that don't change their currencies too often
|
|
String[] country1 = {"US", "CA", "JP", "CN", "SG", "CH"};
|
|
String[] currency1 = {"USD", "CAD", "JPY", "CNY", "SGD", "CHF"};
|
|
for (int i = 0; i < country1.length; i++) {
|
|
checkCountryCurrency(country1[i], currency1[i]);
|
|
}
|
|
|
|
/*
|
|
* check currency changes
|
|
* In current implementation, there is no data of old currency and transition date at jdk/src/java.base/share/data/currency/CurrencyData.properties.
|
|
* 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
|
|
* arrays here can be updated so that the program can check the currency switch.
|
|
*/
|
|
String[] switchOverCtry = {};
|
|
String[] switchOverOld = {};
|
|
String[] switchOverNew = {};
|
|
String[] switchOverTZ = {};
|
|
int[] switchOverYear = {};
|
|
int[] switchOverMonth = {}; // java.time APIs accept month starting from 1 i.e. 01 for January
|
|
int[] switchOverDay = {};
|
|
|
|
for (int i = 0; i < switchOverCtry.length; i++) {
|
|
ZoneId zoneId = ZoneId.of(switchOverTZ[i]);
|
|
ZonedDateTime zonedDateAndTime = ZonedDateTime.of(LocalDate.of(switchOverYear[i], switchOverMonth[i], switchOverDay[i]),
|
|
LocalTime.MIDNIGHT, zoneId);
|
|
ZonedDateTime currentZonedDateAndTime = ZonedDateTime.now(zoneId);
|
|
checkCountryCurrency(switchOverCtry[i], (currentZonedDateAndTime.isAfter(zonedDateAndTime) ||
|
|
currentZonedDateAndTime.isEqual(zonedDateAndTime)) ? switchOverNew[i] : switchOverOld[i]);
|
|
}
|
|
|
|
// check a country code which doesn't have a currency
|
|
checkCountryCurrency("AQ", null);
|
|
|
|
// check an invalid country code
|
|
boolean gotException = false;
|
|
try {
|
|
Currency.getInstance(Locale.of("", "EU"));
|
|
} catch (IllegalArgumentException e) {
|
|
gotException = true;
|
|
}
|
|
if (!gotException) {
|
|
throw new RuntimeException("didn't get specified exception.");
|
|
}
|
|
}
|
|
|
|
static void checkCountryCurrency(String countryCode, String expected) {
|
|
Locale locale = Locale.of("", countryCode);
|
|
Currency currency = Currency.getInstance(locale);
|
|
String code = (currency != null) ? currency.getCurrencyCode() : null;
|
|
if (!(expected == null ? code == null : expected.equals(code))) {
|
|
throw new RuntimeException("Wrong currency for " +
|
|
locale.getDisplayCountry() +
|
|
": expected " + expected + ", got " + code);
|
|
}
|
|
}
|
|
|
|
static void testSymbols() {
|
|
testSymbol("USD", Locale.US, "$");
|
|
testSymbol("EUR", Locale.GERMANY, "\u20AC");
|
|
testSymbol("USD", Locale.PRC, "US$");
|
|
}
|
|
|
|
static void testSymbol(String currencyCode, Locale locale, String expectedSymbol) {
|
|
String symbol = Currency.getInstance(currencyCode).getSymbol(locale);
|
|
if (!symbol.equals(expectedSymbol)) {
|
|
throw new RuntimeException("Wrong symbol for currency " +
|
|
currencyCode +": expected " + expectedSymbol +
|
|
", got " + symbol);
|
|
}
|
|
}
|
|
|
|
static void testFractionDigits() {
|
|
testFractionDigits("USD", 2);
|
|
testFractionDigits("EUR", 2);
|
|
testFractionDigits("JPY", 0);
|
|
testFractionDigits("XDR", -1);
|
|
|
|
testFractionDigits("BHD", 3);
|
|
testFractionDigits("IQD", 3);
|
|
testFractionDigits("JOD", 3);
|
|
testFractionDigits("KWD", 3);
|
|
testFractionDigits("LYD", 3);
|
|
testFractionDigits("OMR", 3);
|
|
testFractionDigits("TND", 3);
|
|
|
|
// Turkish Lira
|
|
testFractionDigits("TRL", 0);
|
|
testFractionDigits("TRY", 2);
|
|
}
|
|
|
|
static void testFractionDigits(String currencyCode, int expectedFractionDigits) {
|
|
int digits = Currency.getInstance(currencyCode).getDefaultFractionDigits();
|
|
if (digits != expectedFractionDigits) {
|
|
throw new RuntimeException("Wrong number of fraction digits for currency " +
|
|
currencyCode +": expected " + expectedFractionDigits +
|
|
", got " + digits);
|
|
}
|
|
}
|
|
|
|
static void testSerialization() throws Exception {
|
|
Currency currency1 = Currency.getInstance("DEM");
|
|
|
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
ObjectOutputStream oStream = new ObjectOutputStream(baos);
|
|
oStream.writeObject(currency1);
|
|
oStream.flush();
|
|
byte[] bytes = baos.toByteArray();
|
|
|
|
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
|
|
ObjectInputStream iStream = new ObjectInputStream(bais);
|
|
Currency currency2 = (Currency) iStream.readObject();
|
|
|
|
if (currency1 != currency2) {
|
|
throw new RuntimeException("serialization breaks class invariant");
|
|
}
|
|
}
|
|
|
|
static void testDisplayNames() {
|
|
// null argument test
|
|
try {
|
|
testDisplayName("USD", null, "");
|
|
throw new RuntimeException("getDisplayName(NULL) did not throw an NPE.");
|
|
} catch (NullPointerException npe) {}
|
|
|
|
testDisplayName("USD", Locale.ENGLISH, "US Dollar");
|
|
testDisplayName("FRF", Locale.FRENCH, "franc fran\u00e7ais");
|
|
testDisplayName("DEM", Locale.GERMAN, "Deutsche Mark");
|
|
testDisplayName("ESP", Locale.of("es"), "peseta espa\u00f1ola");
|
|
testDisplayName("ITL", Locale.ITALIAN, "lira italiana");
|
|
testDisplayName("JPY", Locale.JAPANESE, "\u65e5\u672c\u5186");
|
|
testDisplayName("KRW", Locale.KOREAN, "\ub300\ud55c\ubbfc\uad6d \uc6d0");
|
|
testDisplayName("SEK", Locale.of("sv"), "svensk krona");
|
|
testDisplayName("CNY", Locale.SIMPLIFIED_CHINESE, "\u4eba\u6c11\u5e01");
|
|
testDisplayName("TWD", Locale.TRADITIONAL_CHINESE, "\u65b0\u53f0\u5e63");
|
|
}
|
|
|
|
static void testDisplayName(String currencyCode, Locale locale, String expectedName) {
|
|
String name = Currency.getInstance(currencyCode).getDisplayName(locale);
|
|
if (!name.equals(expectedName)) {
|
|
throw new RuntimeException("Wrong display name for currency " +
|
|
currencyCode +": expected '" + expectedName +
|
|
"', got '" + name + "'");
|
|
}
|
|
}
|
|
static void testFundsCodes() {
|
|
testValidCurrency("BOV");
|
|
testValidCurrency("CHE");
|
|
testValidCurrency("CHW");
|
|
testValidCurrency("CLF");
|
|
testValidCurrency("COU");
|
|
testValidCurrency("MXV");
|
|
testValidCurrency("USN");
|
|
testValidCurrency("UYI");
|
|
|
|
testFractionDigits("BOV", 2);
|
|
testFractionDigits("CHE", 2);
|
|
testFractionDigits("CHW", 2);
|
|
testFractionDigits("CLF", 4);
|
|
testFractionDigits("COU", 2);
|
|
testFractionDigits("MXV", 2);
|
|
testFractionDigits("USN", 2);
|
|
testFractionDigits("UYI", 0);
|
|
|
|
testNumericCode("BOV", 984);
|
|
testNumericCode("CHE", 947);
|
|
testNumericCode("CHW", 948);
|
|
testNumericCode("CLF", 990);
|
|
testNumericCode("COU", 970);
|
|
testNumericCode("MXV", 979);
|
|
testNumericCode("USN", 997);
|
|
testNumericCode("UYI", 940);
|
|
}
|
|
|
|
static void testNumericCode(String currencyCode, int expectedNumeric) {
|
|
int numeric = Currency.getInstance(currencyCode).getNumericCode();
|
|
if (numeric != expectedNumeric) {
|
|
throw new RuntimeException("Wrong numeric code for currency " +
|
|
currencyCode +": expected " + expectedNumeric +
|
|
", got " + numeric);
|
|
}
|
|
}
|
|
}
|