8310923: Refactor Currency tests to use JUnit

Reviewed-by: mbaesken
Backport-of: e848d9471f5de86e5ac157b710cd7371f12f0024
This commit is contained in:
Andrew Lu 2024-02-01 08:51:03 +00:00
parent 83649747f7
commit 44ed380eae
9 changed files with 736 additions and 672 deletions

View File

@ -1,68 +0,0 @@
/*
* Copyright (c) 2007, 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 4512215 4818420 4819436
* @summary Updated currency data.
*/
import java.util.Currency;
import java.util.Locale;
public class Bug4512215 {
public static void main(String[] args) throws Exception {
testCurrencyDefined("XBD", -1);
testCountryCurrency("TJ", "TJS", 2);
testCountryCurrency("FO", "DKK", 2);
testCountryCurrency("FK", "FKP", 2);
testCountryCurrency("AF", "AFN", 2); // changed from "AFA"
// Newsletter V-5 on ISO 3166-1 (2002-05-20)
testCountryCurrency("TL", "USD", 2); // successor to TP/TPE
// Newsletter V-8 on ISO 3166-1 (2003-07-23)
testCountryCurrency("CS", "CSD", 2); // successor to YU/YUM
}
private static void testCountryCurrency(String country, String currencyCode,
int digits) {
testCurrencyDefined(currencyCode, digits);
Currency currency = Currency.getInstance(new Locale("", country));
if (!currency.getCurrencyCode().equals(currencyCode)) {
throw new RuntimeException("[" + country
+ "] expected: " + currencyCode
+ "; got: " + currency.getCurrencyCode());
}
}
private static void testCurrencyDefined(String currencyCode, int digits) {
Currency currency = Currency.getInstance(currencyCode);
if (currency.getDefaultFractionDigits() != digits) {
throw new RuntimeException("[" + currencyCode
+ "] expected: " + digits
+ "; got: " + currency.getDefaultFractionDigits());
}
}
}

View File

@ -1,84 +0,0 @@
/*
* Copyright (c) 2010, 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 6807534
* @summary check whether the default implementation of
* CurrencNameProvider.getDisplayName(String, Locale) throws appropriate
* exceptions when necessary.
*/
import java.util.Locale;
import java.util.spi.CurrencyNameProvider;
public class Bug6807534 {
static final CurrencyNameProvider cnp = new CurrencyNameProviderImpl();
public static void main(String[] args) throws Exception {
// test for NullPointerException (currencyCode)
try {
cnp.getDisplayName(null, Locale.US);
throwException("NPE was not thrown with null currencyCode");
} catch (NullPointerException npe) {}
// test for NullPointerException (locale)
try {
cnp.getDisplayName("USD", null);
throwException("NPE was not thrown with null locale");
} catch (NullPointerException npe) {}
// test for IllegalArgumentException (illegal currencyCode)
try {
cnp.getDisplayName("INVALID", Locale.US);
throwException("IllegalArgumentException was not thrown with invalid currency code");
} catch (IllegalArgumentException iae) {}
try {
cnp.getDisplayName("inv", Locale.US);
throwException("IllegalArgumentException was not thrown with invalid currency code");
} catch (IllegalArgumentException iae) {}
// test for IllegalArgumentException (non-supported locale)
try {
cnp.getDisplayName("USD", Locale.JAPAN);
throwException("IllegalArgumentException was not thrown with non-supported locale");
} catch (IllegalArgumentException iae) {}
}
static void throwException(String msg) {
throw new RuntimeException("test failed. "+msg);
}
static class CurrencyNameProviderImpl extends CurrencyNameProvider {
// dummy implementation
public String getSymbol(String currencyCode, Locale locale) {
return "";
}
public Locale[] getAvailableLocales() {
Locale[] avail = new Locale[1];
avail[0] = Locale.US;
return avail;
}
}
}

View File

@ -1,55 +0,0 @@
/*
* Copyright (c) 2016, 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 8154295
* @summary Check getNumericCodeAsString() method which returns numeric code as a 3 digit String.
*/
import java.util.Currency;
public class Bug8154295 {
public static void main(String[] args) {
String numericCode = Currency.getInstance("AFA").getNumericCodeAsString();
if (!numericCode.equals("004")) { //should return "004" (a 3 digit string)
throw new RuntimeException("[Expected 004, "
+ "found "+numericCode+" for AFA]");
}
numericCode = Currency.getInstance("AUD").getNumericCodeAsString();
if (!numericCode.equals("036")) { //should return "036" (a 3 digit string)
throw new RuntimeException("[Expected 036, "
+ "found "+numericCode+" for AUD]");
}
numericCode = Currency.getInstance("USD").getNumericCodeAsString();
if (!numericCode.equals("840")) {// should return "840" (a 3 digit string)
throw new RuntimeException("[Expected 840, "
+ "found "+numericCode+" for USD]");
}
}
}

View File

@ -0,0 +1,101 @@
/*
* Copyright (c) 2010, 2023, 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 6807534
* @summary check whether the default implementation of
* CurrencyNameProvider.getDisplayName(String, Locale) throws appropriate
* exceptions when necessary.
* @run junit CNPGetDisplayName
*/
import java.util.Locale;
import java.util.spi.CurrencyNameProvider;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class CNPGetDisplayName {
static final CurrencyNameProvider cnp = new CurrencyNameProviderImpl();
/**
* Tests that the currency name provider throws a NullPointerException
* under the expected circumstances.
*/
@ParameterizedTest
@MethodSource("nullArgProvider")
public void NPETest(String currencyCode, Locale locale, String err) {
assertThrows(NullPointerException.class,
() -> cnp.getDisplayName(currencyCode, locale), err);
}
/**
* Tests that the currency name provider throws a IllegalArgumentException
* under the expected circumstances.
*/
@ParameterizedTest
@MethodSource("illegalArgProvider")
public void IAETest(String currencyCode, Locale locale, String err) {
assertThrows(IllegalArgumentException.class,
() -> cnp.getDisplayName(currencyCode, locale), err);
}
private static Stream<Arguments> nullArgProvider() {
return Stream.of(
Arguments.of(null, Locale.US,
"NPE was not thrown with null currencyCode"),
Arguments.of("USD", null,
"NPE was not thrown with null locale")
);
}
private static Stream<Arguments> illegalArgProvider() {
return Stream.of(
Arguments.of("INVALID", Locale.US,
"IAE was not thrown with invalid currency code"),
Arguments.of("inv", Locale.US,
"IAE was not thrown with invalid currency code"),
Arguments.of("USD", Locale.JAPAN,
"IllegalArgumentException was not thrown with non-supported locale")
);
}
static class CurrencyNameProviderImpl extends CurrencyNameProvider {
// dummy implementation
public String getSymbol(String currencyCode, Locale locale) {
return "";
}
public Locale[] getAvailableLocales() {
Locale[] avail = new Locale[1];
avail[0] = Locale.US;
return avail;
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 2023, 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
@ -20,15 +20,21 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
*
*
* Check the consistency between the regression tests and the currency data in the JRE
/*
Check the consistency between the regression tests and the currency
data in the JRE. This class is used by other test classes.
*/
import java.io.*;
import java.lang.reflect.*;
import java.security.*;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Currency;
class CheckDataVersion {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 2023, 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
@ -20,6 +20,7 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4290801 4692419 4693631 5101540 5104960 6296410 6336600 6371531
@ -28,6 +29,7 @@
* @summary Basic tests for Currency class.
* @modules java.base/java.util:open
* jdk.localedata
* @run junit CurrencyTest
*/
import java.io.ByteArrayInputStream;
@ -38,198 +40,232 @@ import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Currency;
import java.util.List;
import java.util.Locale;
import java.util.stream.Stream;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class CurrencyTest {
public static void main(String[] args) throws Exception {
// 'tablea1.txt' should be up-to-date before testing
@Test
public void dataVersionTest() {
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");
@Nested
class CodeValidationTests {
// Calling getInstance() on equal currency codes should return equal currencies
@ParameterizedTest
@MethodSource("validCurrencies")
public void validCurrencyTest(String currencyCode) {
compareCurrencies(currencyCode);
}
if (!currency1.getCurrencyCode().equals(currencyCode)) {
throw new RuntimeException("Currency code changed");
private static Stream<String> validCurrencies() {
return Stream.of("USD", "EUR", "GBP", "JPY", "CNY", "CHF");
}
// Calling getInstance() with an invalid currency code should throw an IAE
@ParameterizedTest
@MethodSource("invalidCurrencies")
public void invalidCurrencyTest(String currencyCode) {
assertThrows(IllegalArgumentException.class, () ->
Currency.getInstance(currencyCode), "getInstance() did not throw IAE");
}
private static Stream<String> invalidCurrencies() {
return Stream.of("AQD", "US$", "\u20AC");
}
}
static void testInvalidCurrency(String currencyCode) {
boolean gotException = false;
try {
Currency currency = Currency.getInstance(currencyCode);
} catch (IllegalArgumentException e) {
gotException = true;
@Nested
class FundsCodesTests {
// Calling getInstance() on equal currency codes should return equal currencies
@ParameterizedTest
@MethodSource("fundsCodes")
public void validCurrencyTest(String currencyCode) {
compareCurrencies(currencyCode);
}
if (!gotException) {
throw new RuntimeException("didn't get specified exception");
// Verify a currency has the expected fractional digits
@ParameterizedTest
@MethodSource("fundsCodes")
public void fractionDigitTest(String currencyCode, int expectedFractionDigits) {
compareFractionDigits(currencyCode, expectedFractionDigits);
}
// Verify a currency has the expected numeric code
@ParameterizedTest
@MethodSource("fundsCodes")
public void numericCodeTest(String currencyCode, int ignored, int expectedNumeric) {
int numeric = Currency.getInstance(currencyCode).getNumericCode();
assertEquals(numeric, expectedNumeric, String.format(
"Wrong numeric code for currency %s, expected %s, got %s",
currencyCode, expectedNumeric, numeric));
}
private static Stream<Arguments> fundsCodes() {
return Stream.of(
Arguments.of("BOV", 2, 984), Arguments.of("CHE", 2, 947),
Arguments.of("CHW", 2, 948), Arguments.of("CLF", 4, 990),
Arguments.of("COU", 2, 970), Arguments.of("MXV", 2, 979),
Arguments.of("USN", 2, 997), Arguments.of("UYI", 0, 940)
);
}
}
static void testLocaleMapping() {
@Nested
class LocaleMappingTests {
// 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++;
@Test
public void localeMappingTest() {
Locale[] locales = Locale.getAvailableLocales();
int goodCountries = 0;
int ownCurrencies = 0;
for (Locale locale : locales) {
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
assertThrows(IllegalArgumentException.class, () -> Currency.getInstance(locale), "Did not throw IAE");
} 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.");
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 an invalid country code
@Test
public void invalidCountryTest() {
assertThrows(IllegalArgumentException.class, ()->
Currency.getInstance(new Locale("", "EU")), "Did not throw IAE");
}
// Ensure a selection of countries have the expected currency
@ParameterizedTest
@MethodSource({"countryProvider", "switchedOverCountries"})
public void countryCurrencyTest(String countryCode, String expected) {
Locale locale = new Locale("", countryCode);
Currency currency = Currency.getInstance(locale);
String code = (currency != null) ? currency.getCurrencyCode() : null;
assertEquals(expected, code, generateErrMsg(
"currency for", locale.getDisplayCountry(), expected, code));
}
private static Stream<Arguments> countryProvider() {
return Stream.of(
// Check country that does not have a currency
Arguments.of("AQ", null),
// Check some countries that don't change their currencies often
Arguments.of("US", "USD"),
Arguments.of("CA", "CAD"),
Arguments.of("JP", "JPY"),
Arguments.of("CN", "CNY"),
Arguments.of("SG", "SGD"),
Arguments.of("CH", "CHF")
);
}
/*
* check currency changes
* In current implementation, there is no data of old currency and transition date at jdk/make/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 = {};
* Check Currency Changes
* In the 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.
*/
private static List<Arguments> switchedOverCountries() {
List<Arguments> switched = new ArrayList<Arguments>();
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(new Locale("", "EU"));
} catch (IllegalArgumentException e) {
gotException = true;
}
if (!gotException) {
throw new RuntimeException("didn't get specified exception.");
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);
switched.add(Arguments.of(switchOverCtry[i], (currentZonedDateAndTime.isAfter(zonedDateAndTime)
|| currentZonedDateAndTime.isEqual(zonedDateAndTime)) ? switchOverNew[i] : switchOverOld[i]));
}
return switched;
}
}
static void checkCountryCurrency(String countryCode, String expected) {
Locale locale = new Locale("", 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);
}
// NON-NESTED TESTS
// Ensure selection of currencies have the correct fractional digits
@ParameterizedTest
@MethodSource("expectedFractionsProvider")
public void fractionDigitsTest(String currencyCode, int expectedFractionDigits) {
compareFractionDigits(currencyCode, expectedFractionDigits);
}
static void testSymbols() {
testSymbol("USD", Locale.US, "$");
testSymbol("EUR", Locale.GERMANY, "\u20AC");
testSymbol("USD", Locale.PRC, "US$");
private static Stream<Arguments> expectedFractionsProvider() {
return Stream.of(
Arguments.of("USD", 2), Arguments.of("EUR", 2),
Arguments.of("JPY", 0), Arguments.of("XDR", -1),
Arguments.of("BHD", 3), Arguments.of("IQD", 3),
Arguments.of("JOD", 3), Arguments.of("KWD", 3),
Arguments.of("LYD", 3), Arguments.of("OMR", 3),
Arguments.of("TND", 3),
// Old and New Turkish Lira
Arguments.of("TRL", 0), Arguments.of("TRY", 2)
);
}
static void testSymbol(String currencyCode, Locale locale, String expectedSymbol) {
// Ensure selection of currencies have the expected symbol
@ParameterizedTest
@MethodSource("symbolProvider")
public void symbolTest(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);
}
assertEquals(symbol, expectedSymbol, generateErrMsg(
"symbol for", currencyCode, expectedSymbol, 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);
private static Stream<Arguments> symbolProvider() {
return Stream.of(
Arguments.of("USD", Locale.US, "$"),
Arguments.of("EUR", Locale.GERMANY, "\u20AC"),
Arguments.of("USD", Locale.PRC, "US$")
);
}
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 {
// Ensure serialization does not break class invariant.
// Currency should be able to round-trip and remain the same value.
@Test
public void serializationTest() throws Exception {
Currency currency1 = Currency.getInstance("DEM");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
@ -241,74 +277,66 @@ public class CurrencyTest {
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");
}
assertEquals(currency1, currency2, "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", new Locale("es"), "peseta espa\u00f1ola");
testDisplayName("ITL", new Locale("it"), "lira italiana");
testDisplayName("JPY", Locale.JAPANESE, "\u65e5\u672c\u5186");
testDisplayName("KRW", Locale.KOREAN, "\ub300\ud55c\ubbfc\uad6d \uc6d0");
testDisplayName("SEK", new Locale("sv"), "svensk krona");
testDisplayName("CNY", Locale.SIMPLIFIED_CHINESE, "\u4eba\u6c11\u5e01");
testDisplayName("TWD", Locale.TRADITIONAL_CHINESE, "\u65b0\u53f0\u5e63");
// Ensure getInstance() throws null when passed a null locale
@Test
public void nullDisplayNameTest() {
assertThrows(NullPointerException.class, ()->
Currency.getInstance("USD").getDisplayName(null));
}
static void testDisplayName(String currencyCode, Locale locale, String expectedName) {
// Ensure a selection of currencies/locale combos have the correct display name
@ParameterizedTest
@MethodSource("displayNameProvider")
public void displayNameTest(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);
assertEquals(name, expectedName, generateErrMsg(
"display name for", currencyCode, expectedName, name));
}
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);
}
private static Stream<Arguments> displayNameProvider() {
return Stream.of(
Arguments.of("USD", Locale.ENGLISH, "US Dollar"),
Arguments.of("FRF", Locale.FRENCH, "franc fran\u00e7ais"),
Arguments.of("DEM", Locale.GERMAN, "Deutsche Mark"),
Arguments.of("ESP", new Locale("es"), "peseta espa\u00f1ola"),
Arguments.of("ITL", Locale.ITALIAN, "lira italiana"),
Arguments.of("JPY", Locale.JAPANESE, "\u65e5\u672c\u5186"),
Arguments.of("KRW", Locale.KOREAN, "\ub300\ud55c\ubbfc\uad6d \uc6d0"),
Arguments.of("SEK", new Locale("sv"), "svensk krona"),
Arguments.of("CNY", Locale.SIMPLIFIED_CHINESE, "\u4eba\u6c11\u5e01"),
Arguments.of("TWD", Locale.TRADITIONAL_CHINESE, "\u65b0\u53f0\u5e63")
);
}
// HELPER FUNCTIONS
// A Currency instance returned from getInstance() should always be
// equal if supplied the same currencyCode. getCurrencyCode() should
// always be equal to the currencyCode used to create the Currency.
private static void compareCurrencies(String currencyCode) {
Currency currency1 = Currency.getInstance(currencyCode);
Currency currency2 = Currency.getInstance(currencyCode);
assertEquals(currency1, currency2, "Didn't get same instance for same currency code");
assertEquals(currency1.getCurrencyCode(), currencyCode, "getCurrencyCode()" +
" did not return the expected value");
}
// Ensures the getDefaultFractionDigits() method returns the expected amount
private static void compareFractionDigits(String currencyCode,
int expectedFractionDigits) {
int digits = Currency.getInstance(currencyCode).getDefaultFractionDigits();
assertEquals(digits, expectedFractionDigits, generateErrMsg(
"number of fraction digits for currency",
currencyCode, Integer.toString(expectedFractionDigits), Integer.toString(digits)));
}
// Used for logging on failing tests
private static String generateErrMsg(String subject, String currency,
String expected, String got) {
return String.format("Wrong %s %s: expected '%s', got '%s'",
subject, currency, expected, got);
}
}

View File

@ -0,0 +1,66 @@
/*
* Copyright (c) 2007, 2023, 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 4512215 4818420 4819436 8310923
* @summary Test currencies without minor units.
* @run junit NoMinorUnitCurrenciesTest
*/
import java.util.Currency;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class NoMinorUnitCurrenciesTest {
/**
* Spot check some minor undefined currencies and ensure their default fraction
* digits are not 2.
*/
@ParameterizedTest
@MethodSource("minorUndefined")
public void checkFractionDigits(String currencyCode, int digits) {
Currency currency = Currency.getInstance(currencyCode);
assertEquals(currency.getCurrencyCode(), currencyCode);
assertEquals(currency.getDefaultFractionDigits(), digits, String.format(
"[%s] expected: %s; got: %s", currencyCode, digits, currency.getDefaultFractionDigits()));
}
// Currencies from the minorUndefined key of CurrencyData.properties
// (These are currencies without minor units)
private static Stream<Arguments> minorUndefined() {
return Stream.of(
Arguments.of("XBD", -1),
Arguments.of("XAG", -1),
Arguments.of("XAU", -1),
Arguments.of("XBA", -1),
Arguments.of("XBB", -1)
);
}
}

View File

@ -0,0 +1,61 @@
/*
* Copyright (c) 2016, 2023, 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 8154295
* @summary Check getNumericCodeAsString() method which returns numeric code as a 3 digit String.
* @run junit NumCodeAsStringTest
*/
import java.util.Currency;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class NumCodeAsStringTest {
/**
* Ensure getNumericCodeAsString() returns the correct 3-digit numeric code
* for the associated currency Code.
*/
@ParameterizedTest
@MethodSource("codeProvider")
public void checkNumCodeTest(String currCode, String expectedNumCode) {
String actualNumCode = Currency.getInstance(currCode).getNumericCodeAsString();
assertEquals(expectedNumCode, actualNumCode, String.format(
"Expected: %s, but got: %s, for %s", expectedNumCode, actualNumCode, currCode));
}
private static Stream<Arguments> codeProvider() {
return Stream.of(
Arguments.of("AFA", "004"),
Arguments.of("AUD", "036"),
Arguments.of("USD", "840")
);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 2023, 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
@ -20,6 +20,7 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4691089 4819436 4942982 5104960 6544471 6627549 7066203 7195759
@ -28,285 +29,293 @@
* @summary Validate ISO 4217 data for Currency class.
* @modules java.base/java.util:open
* jdk.localedata
* @run junit ValidateISO4217
*/
/*
* ############################################################################
*
* ValidateISO4217 is a tool to detect differences between the latest ISO 4217
* data and Java's currency data which is based on ISO 4217.
* If there is a difference, the following file which includes currency data
* may need to be updated.
* src/share/classes/java/util/CurrencyData.properties
*
* ############################################################################
*
* 1) Make a golden-data file.
* From BSi's ISO4217 data (TABLE A1.doc), extract four (or eight, if currency is changing)
* fields and save as ./tablea1.txt.
* <Country code>\t<Currency code>\t<Numeric code>\t<Minor unit>[\t<Cutover Date>\t<new Currency code>\t<new Numeric code>\t<new Minor unit>]
* The Cutover Date is given in SimpleDateFormat's 'yyyy-MM-dd-HH-mm-ss' format in the GMT time zone.
*
* 2) Compile ValidateISO4217.java
*
* 3) Execute ValidateISO4217 as follows:
* java ValidateISO4217
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Currency;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TimeZone;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* This class tests the latest ISO 4217 data and Java's currency data which is
* based on ISO 4217. The golden-data file (ISO 4217 data) 'tablea1.txt' has the following
* format: <Country code>\t<Currency code>\t<Numeric code>\t<Minor unit>[\t<Cutover Date>\t<new Currency code>\t<new Numeric code>\t<new Minor unit>]
* The Cutover Date is given in SimpleDateFormat's 'yyyy-MM-dd-HH-mm-ss' format in the GMT time zone.
*/
import java.io.*;
import java.text.*;
import java.util.*;
public class ValidateISO4217 {
static final int ALPHA_NUM = 26;
static final byte UNDEFINED = 0;
static final byte DEFINED = 1;
static final byte SKIPPED = 2;
/* input files */
static final String datafile = "tablea1.txt";
/* alpha2-code table */
static byte[] codes = new byte[ALPHA_NUM * ALPHA_NUM];
static final String[][] additionalCodes = {
/* Defined in ISO 4217 list, but don't have code and minor unit info. */
{"AQ", "", "", "0"}, // Antarctica
/*
* Defined in ISO 4217 list, but don't have code and minor unit info in
* it. On the other hand, both code and minor unit are defined in
* .properties file. I don't know why, though.
*/
{"GS", "GBP", "826", "2"}, // South Georgia And The South Sandwich Islands
/* Not defined in ISO 4217 list, but defined in .properties file. */
{"AX", "EUR", "978", "2"}, // \u00c5LAND ISLANDS
{"PS", "ILS", "376", "2"}, // Palestinian Territory, Occupied
/* Not defined in ISO 4217 list, but added in ISO 3166 country code list */
{"JE", "GBP", "826", "2"}, // Jersey
{"GG", "GBP", "826", "2"}, // Guernsey
{"IM", "GBP", "826", "2"}, // Isle of Man
{"BL", "EUR", "978", "2"}, // Saint Barthelemy
{"MF", "EUR", "978", "2"}, // Saint Martin
/* Defined neither in ISO 4217 nor ISO 3166 list */
{"XK", "EUR", "978", "2"}, // Kosovo
// Input golden-data file
private static final File dataFile = new File(System.getProperty(
"test.src", "."), "tablea1.txt");
// Code statuses
private static final byte UNDEFINED = 0;
private static final byte DEFINED = 1;
private static final byte SKIPPED = 2;
private static final byte TESTED = 4;
private static final int ALPHA_NUM = 26;
// An alpha2 code table which maps the status of a country
private static final byte[] codes = new byte[ALPHA_NUM * ALPHA_NUM];
// Codes derived from ISO4217 golden-data file
private static final List<Arguments> ISO4217Codes = new ArrayList<Arguments>();
// Additional codes not from the ISO4217 golden-data file
private static final List<Arguments> additionalCodes = new ArrayList<Arguments>();
// Currencies to test (derived from ISO4217Codes and additionalCodes)
private static final Set<Currency> testCurrencies = new HashSet<>();
// Codes that are obsolete, do not have related country, extra currency
private static final String otherCodes =
"ADP-AFA-ATS-AYM-AZM-BEF-BGL-BOV-BYB-BYR-CHE-CHW-CLF-COU-CUC-CYP-"
+ "DEM-EEK-ESP-FIM-FRF-GHC-GRD-GWP-IEP-ITL-LTL-LUF-LVL-MGF-MRO-MTL-MXV-MZM-NLG-"
+ "PTE-ROL-RUR-SDD-SIT-SLL-SKK-SRG-STD-TMM-TPE-TRL-VEF-UYI-USN-USS-VEB-VED-"
+ "XAG-XAU-XBA-XBB-XBC-XBD-XDR-XFO-XFU-XPD-XPT-XSU-XTS-XUA-XXX-"
+ "YUM-ZMK-ZWD-ZWN-ZWR";
private static final String[][] extraCodes = {
/* Defined in ISO 4217 list, but don't have code and minor unit info. */
{"AQ", "", "", "0"}, // Antarctica
/*
* Defined in ISO 4217 list, but don't have code and minor unit info in
* it. On the other hand, both code and minor unit are defined in
* .properties file. I don't know why, though.
*/
{"GS", "GBP", "826", "2"}, // South Georgia And The South Sandwich Islands
/* Not defined in ISO 4217 list, but defined in .properties file. */
{"AX", "EUR", "978", "2"}, // \u00c5LAND ISLANDS
{"PS", "ILS", "376", "2"}, // Palestinian Territory, Occupied
/* Not defined in ISO 4217 list, but added in ISO 3166 country code list */
{"JE", "GBP", "826", "2"}, // Jersey
{"GG", "GBP", "826", "2"}, // Guernsey
{"IM", "GBP", "826", "2"}, // Isle of Man
{"BL", "EUR", "978", "2"}, // Saint Barthelemy
{"MF", "EUR", "978", "2"}, // Saint Martin
/* Defined neither in ISO 4217 nor ISO 3166 list */
{"XK", "EUR", "978", "2"}, // Kosovo
};
private static SimpleDateFormat format = null;
/* Codes that are obsolete, do not have related country, extra currency */
static final String otherCodes =
"ADP-AFA-ATS-AYM-AZM-BEF-BGL-BOV-BYB-BYR-CHE-CHW-CLF-COU-CUC-CYP-"
+ "DEM-EEK-ESP-FIM-FRF-GHC-GRD-GWP-IEP-ITL-LTL-LUF-LVL-MGF-MRO-MTL-MXV-MZM-NLG-"
+ "PTE-ROL-RUR-SDD-SIT-SLL-SKK-SRG-STD-TMM-TPE-TRL-VEF-UYI-USN-USS-VEB-VED-"
+ "XAG-XAU-XBA-XBB-XBC-XBD-XDR-XFO-XFU-XPD-XPT-XSU-XTS-XUA-XXX-"
+ "YUM-ZMK-ZWD-ZWN-ZWR";
static boolean err = false;
static Set<Currency> testCurrencies = new HashSet<Currency>();
public static void main(String[] args) throws Exception {
CheckDataVersion.check();
test1();
test2();
getAvailableCurrenciesTest();
if (err) {
throw new RuntimeException("Failed: Validation ISO 4217 data");
}
// Sets up the following test data:
// ISO4217Codes, additionalCodes, testCurrencies, codes
@BeforeAll
static void setUpTestingData() throws Exception {
// These functions laterally setup 'testCurrencies' and 'codes'
// at the same time
setUpISO4217Codes();
setUpAdditionalCodes();
setUpOtherCurrencies();
}
static void test1() throws Exception {
try (FileReader fr = new FileReader(new File(System.getProperty("test.src", "."), datafile));
// Parse the ISO4217 file and populate ISO4217Codes and testCurrencies.
private static void setUpISO4217Codes() throws Exception{
try (FileReader fr = new FileReader(dataFile);
BufferedReader in = new BufferedReader(fr))
{
String line;
SimpleDateFormat format = null;
while ((line = in.readLine()) != null) {
if (line.length() == 0 || line.charAt(0) == '#') {
// Skip comments and empty lines
continue;
}
StringTokenizer tokens = new StringTokenizer(line, "\t");
String country = tokens.nextToken();
if (country.length() != 2) {
// Skip invalid countries
continue;
}
// If the country is valid, process the additional columns
processColumns(tokens, country);
}
}
}
String currency;
String numeric;
String minorUnit;
int tokensCount = tokens.countTokens();
if (tokensCount < 3) {
currency = "";
numeric = "0";
minorUnit = "0";
} else {
private static void processColumns(StringTokenizer tokens, String country) throws ParseException {
String currency;
String numeric;
String minorUnit;
int tokensCount = tokens.countTokens();
if (tokensCount < 3) {
// Ill-defined columns
currency = "";
numeric = "0";
minorUnit = "0";
} else {
// Fully defined columns
currency = tokens.nextToken();
numeric = tokens.nextToken();
minorUnit = tokens.nextToken();
testCurrencies.add(Currency.getInstance(currency));
// Check for the cut-over if a currency is changing
if (tokensCount > 3) {
if (format == null) {
createDateFormat();
}
// If the cut-over already passed, test the changed data too
if (format.parse(tokens.nextToken()).getTime() < System.currentTimeMillis()) {
currency = tokens.nextToken();
numeric = tokens.nextToken();
minorUnit = tokens.nextToken();
testCurrencies.add(Currency.getInstance(currency));
// check for the cutover
if (tokensCount > 3) {
if (format == null) {
format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.US);
format.setTimeZone(TimeZone.getTimeZone("GMT"));
format.setLenient(false);
}
if (format.parse(tokens.nextToken()).getTime() <
System.currentTimeMillis()) {
currency = tokens.nextToken();
numeric = tokens.nextToken();
minorUnit = tokens.nextToken();
testCurrencies.add(Currency.getInstance(currency));
}
}
}
int index = toIndex(country);
testCountryCurrency(country, currency, Integer.parseInt(numeric),
Integer.parseInt(minorUnit), index);
}
}
int index = toIndex(country);
ISO4217Codes.add(Arguments.of(country, currency, Integer.parseInt(numeric),
Integer.parseInt(minorUnit), index));
codes[index] = DEFINED;
}
for (int i = 0; i < additionalCodes.length; i++) {
int index = toIndex(additionalCodes[i][0]);
if (additionalCodes[i][1].length() != 0) {
testCountryCurrency(additionalCodes[i][0], additionalCodes[i][1],
Integer.parseInt(additionalCodes[i][2]),
Integer.parseInt(additionalCodes[i][3]), index);
testCurrencies.add(Currency.getInstance(additionalCodes[i][1]));
// Generates a unique index for an alpha-2 country
private static int toIndex(String country) {
return ((country.charAt(0) - 'A') * ALPHA_NUM + country.charAt(1) - 'A');
}
private static void createDateFormat() {
format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.US);
format.setTimeZone(TimeZone.getTimeZone("GMT"));
format.setLenient(false);
}
// Process 'extraCodes', turning them into JUnit arguments and populate
// both additionalCodes and testCurrencies.
private static void setUpAdditionalCodes() {
for (String[] extraCode : extraCodes) {
int index = toIndex(extraCode[0]);
if (extraCode[1].length() != 0) {
additionalCodes.add(Arguments.of(extraCode[0], extraCode[1],
Integer.parseInt(extraCode[2]), Integer.parseInt(extraCode[3]), index));
testCurrencies.add(Currency.getInstance(extraCode[1]));
} else {
codes[index] = SKIPPED;
codes[index] = SKIPPED; // For example, Antarctica
}
}
}
static int toIndex(String s) {
return ((s.charAt(0) - 'A') * ALPHA_NUM + s.charAt(1) - 'A');
}
static void testCountryCurrency(String country, String currencyCode,
int numericCode, int digits, int index) {
if (currencyCode.length() == 0) {
return;
}
testCurrencyDefined(currencyCode, numericCode, digits);
Locale loc = new Locale("", country);
try {
Currency currency = Currency.getInstance(loc);
if (!currency.getCurrencyCode().equals(currencyCode)) {
System.err.println("Error: [" + country + ":" +
loc.getDisplayCountry() + "] expected: " + currencyCode +
", got: " + currency.getCurrencyCode());
err = true;
}
if (codes[index] != UNDEFINED) {
System.out.println("Warning: [" + country + ":" +
loc.getDisplayCountry() +
"] multiple definitions. currency code=" + currencyCode);
}
codes[index] = DEFINED;
}
catch (Exception e) {
System.err.println("Error: " + e + ": Country=" + country);
err = true;
}
}
static void testCurrencyDefined(String currencyCode, int numericCode, int digits) {
try {
Currency currency = currency = Currency.getInstance(currencyCode);
if (currency.getNumericCode() != numericCode) {
System.err.println("Error: [" + currencyCode + "] expected: " +
numericCode + "; got: " + currency.getNumericCode());
err = true;
}
if (currency.getDefaultFractionDigits() != digits) {
System.err.println("Error: [" + currencyCode + "] expected: " +
digits + "; got: " + currency.getDefaultFractionDigits());
err = true;
}
}
catch (Exception e) {
System.err.println("Error: " + e + ": Currency code=" +
currencyCode);
err = true;
}
}
static void test2() {
for (int i = 0; i < ALPHA_NUM; i++) {
for (int j = 0; j < ALPHA_NUM; j++) {
char[] code = new char[2];
code[0] = (char)('A'+ i);
code[1] = (char)('A'+ j);
String country = new String(code);
boolean ex;
if (codes[toIndex(country)] == UNDEFINED) {
ex = false;
try {
Currency.getInstance(new Locale("", country));
}
catch (IllegalArgumentException e) {
ex = true;
}
if (!ex) {
System.err.println("Error: This should be an undefined code and throw IllegalArgumentException: " +
country);
err = true;
}
} else if (codes[toIndex(country)] == SKIPPED) {
Currency cur = null;
try {
cur = Currency.getInstance(new Locale("", country));
}
catch (Exception e) {
System.err.println("Error: " + e + ": Country=" +
country);
err = true;
}
if (cur != null) {
System.err.println("Error: Currency.getInstance() for an this locale should return null: " +
country);
err = true;
}
}
}
}
}
/**
* This test depends on test1(), where 'testCurrencies' set is constructed
*/
static void getAvailableCurrenciesTest() {
Set<Currency> jreCurrencies = Currency.getAvailableCurrencies();
// add otherCodes
// The previous set-up method populated most of testCurrencies. This
// method finishes populating the list with 'otherCodes'.
private static void setUpOtherCurrencies() {
// Add otherCodes
StringTokenizer st = new StringTokenizer(otherCodes, "-");
while (st.hasMoreTokens()) {
testCurrencies.add(Currency.getInstance(st.nextToken()));
}
}
if (!testCurrencies.containsAll(jreCurrencies)) {
System.err.print("Error: getAvailableCurrencies() returned extra currencies than expected: ");
jreCurrencies.removeAll(testCurrencies);
for (Currency c : jreCurrencies) {
System.err.print(" "+c);
}
System.err.println();
err = true;
// Check that the data file is up-to-date
@Test
public void dataVersionTest() {
CheckDataVersion.check();
}
/**
* Tests the JDK's ISO4217 data and ensures the values for getNumericCode(),
* getDefaultFractionDigits(), and getCurrencyCode() are as expected.
*/
@ParameterizedTest
@MethodSource({"ISO4217CodesProvider", "additionalCodesProvider"})
public void countryCurrencyTest(String country, String currencyCode,
int numericCode, int digits, int index) {
currencyTest(currencyCode, numericCode, digits);
countryTest(country, currencyCode);
assertNotEquals(codes[index], TESTED,
"Error: Re-testing a previously defined code, possible duplication");
codes[index] = TESTED;
}
// Test a Currency built from currencyCode
private static void currencyTest(String currencyCode, int numericCode, int digits) {
Currency currency = Currency.getInstance(currencyCode);
assertEquals(currency.getNumericCode(), numericCode);
assertEquals(currency.getDefaultFractionDigits(), digits);
}
// Test a Currency built from country
private static void countryTest(String country, String currencyCode) {
Locale loc = new Locale("", country);
Currency currency = Currency.getInstance(loc);
assertEquals(currency.getCurrencyCode(), currencyCode);
}
private static List<Arguments> ISO4217CodesProvider() {
return ISO4217Codes;
}
private static List<Arguments> additionalCodesProvider() {
return additionalCodes;
}
/**
* Tests trying to create a Currency from an invalid alpha-2 country either
* throws an IllegalArgumentException or returns null. The test data
* supplied is every possible combination of AA -> ZZ.
*/
@ParameterizedTest
@MethodSource("codeCombos")
public void twoLetterCodesTest(String country) {
if (codes[toIndex(country)] == UNDEFINED) {
// if a code is undefined / 0, creating a Currency from it
// should throw an IllegalArgumentException
assertThrows(IllegalArgumentException.class,
()-> Currency.getInstance(new Locale("", country)),
"Error: This should be an undefined code and throw IllegalArgumentException: " + country);
} else if (codes[toIndex(country)] == SKIPPED) {
// if a code is marked as skipped / 2, creating a Currency from it
// should return null
assertNull(Currency.getInstance(new Locale("", country)),
"Error: Currency.getInstance() for this locale should return null: " + country);
}
}
}
// This method generates code combos from AA to ZZ
private static List<String> codeCombos() {
List<String> codeCombos = new ArrayList<>();
for (int i = 0; i < ALPHA_NUM; i++) {
for (int j = 0; j < ALPHA_NUM; j++) {
char[] code = new char[2];
code[0] = (char) ('A' + i);
code[1] = (char) ('A' + j);
codeCombos.add(new String(code));
}
}
return codeCombos;
}
// This method ensures that getAvailableCurrencies() returns
// the expected amount of currencies.
@Test
public void getAvailableCurrenciesTest() {
Set<Currency> jreCurrencies = Currency.getAvailableCurrencies();
// Ensure that testCurrencies has all the JRE currency codes
assertTrue(testCurrencies.containsAll(jreCurrencies),
getSetDiffs(jreCurrencies, testCurrencies));
}
private static String getSetDiffs(Set<Currency> jreCurrencies, Set<Currency> testCurrencies) {
StringBuilder bldr = new StringBuilder();
bldr.append("Error: getAvailableCurrencies() returned unexpected currencies: ");
jreCurrencies.removeAll(testCurrencies);
for (Currency curr : jreCurrencies) {
bldr.append(" " + curr);
}
bldr.append("\n");
return bldr.toString();
}
}