Path: blob/master/test/jdk/java/util/Currency/ValidateISO4217.java
66644 views
/*1* Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/22/*23* @test24* @bug 4691089 4819436 4942982 5104960 6544471 6627549 7066203 719575925* 8039317 8074350 8074351 8145952 8187946 8193552 8202026 820426926* 8208746 8209775 8264792 8274658 828327727* @summary Validate ISO 4217 data for Currency class.28* @modules java.base/java.util:open29* jdk.localedata30*/3132/*33* ############################################################################34*35* ValidateISO4217 is a tool to detect differences between the latest ISO 421736* data and and Java's currency data which is based on ISO 4217.37* If there is a difference, the following file which includes currency data38* may need to be updated.39* src/share/classes/java/util/CurrencyData.properties40*41* ############################################################################42*43* 1) Make a golden-data file.44* From BSi's ISO4217 data (TABLE A1.doc), extract four (or eight, if currency is changing)45* fields and save as ./tablea1.txt.46* <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>]47* The Cutover Date is given in SimpleDateFormat's 'yyyy-MM-dd-HH-mm-ss' format in the GMT time zone.48*49* 2) Compile ValidateISO4217.java50*51* 3) Execute ValidateISO4217 as follows:52* java ValidateISO421753*/5455import java.io.*;56import java.text.*;57import java.util.*;5859public class ValidateISO4217 {6061static final int ALPHA_NUM = 26;6263static final byte UNDEFINED = 0;64static final byte DEFINED = 1;65static final byte SKIPPED = 2;6667/* input files */68static final String datafile = "tablea1.txt";6970/* alpha2-code table */71static byte[] codes = new byte[ALPHA_NUM * ALPHA_NUM];7273static final String[][] additionalCodes = {74/* Defined in ISO 4217 list, but don't have code and minor unit info. */75{"AQ", "", "", "0"}, // Antarctica7677/*78* Defined in ISO 4217 list, but don't have code and minor unit info in79* it. On the other hand, both code and minor unit are defined in80* .properties file. I don't know why, though.81*/82{"GS", "GBP", "826", "2"}, // South Georgia And The South Sandwich Islands8384/* Not defined in ISO 4217 list, but defined in .properties file. */85{"AX", "EUR", "978", "2"}, // \u00c5LAND ISLANDS86{"PS", "ILS", "376", "2"}, // Palestinian Territory, Occupied8788/* Not defined in ISO 4217 list, but added in ISO 3166 country code list */89{"JE", "GBP", "826", "2"}, // Jersey90{"GG", "GBP", "826", "2"}, // Guernsey91{"IM", "GBP", "826", "2"}, // Isle of Man92{"BL", "EUR", "978", "2"}, // Saint Barthelemy93{"MF", "EUR", "978", "2"}, // Saint Martin9495/* Defined neither in ISO 4217 nor ISO 3166 list */96{"XK", "EUR", "978", "2"}, // Kosovo97};9899/* Codes that are obsolete, do not have related country, extra currency */100static final String otherCodes =101"ADP-AFA-ATS-AYM-AZM-BEF-BGL-BOV-BYB-BYR-CHE-CHW-CLF-COU-CUC-CYP-"102+ "DEM-EEK-ESP-FIM-FRF-GHC-GRD-GWP-IEP-ITL-LTL-LUF-LVL-MGF-MRO-MTL-MXV-MZM-NLG-"103+ "PTE-ROL-RUR-SDD-SIT-SLL-SKK-SRG-STD-TMM-TPE-TRL-VEF-UYI-USN-USS-VEB-VED-"104+ "XAG-XAU-XBA-XBB-XBC-XBD-XDR-XFO-XFU-XPD-XPT-XSU-XTS-XUA-XXX-"105+ "YUM-ZMK-ZWD-ZWN-ZWR";106107static boolean err = false;108109static Set<Currency> testCurrencies = new HashSet<Currency>();110111public static void main(String[] args) throws Exception {112CheckDataVersion.check();113test1();114test2();115getAvailableCurrenciesTest();116117if (err) {118throw new RuntimeException("Failed: Validation ISO 4217 data");119}120}121122static void test1() throws Exception {123124try (FileReader fr = new FileReader(new File(System.getProperty("test.src", "."), datafile));125BufferedReader in = new BufferedReader(fr))126{127String line;128SimpleDateFormat format = null;129130while ((line = in.readLine()) != null) {131if (line.length() == 0 || line.charAt(0) == '#') {132continue;133}134135StringTokenizer tokens = new StringTokenizer(line, "\t");136String country = tokens.nextToken();137if (country.length() != 2) {138continue;139}140141String currency;142String numeric;143String minorUnit;144int tokensCount = tokens.countTokens();145if (tokensCount < 3) {146currency = "";147numeric = "0";148minorUnit = "0";149} else {150currency = tokens.nextToken();151numeric = tokens.nextToken();152minorUnit = tokens.nextToken();153testCurrencies.add(Currency.getInstance(currency));154155// check for the cutover156if (tokensCount > 3) {157if (format == null) {158format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.US);159format.setTimeZone(TimeZone.getTimeZone("GMT"));160format.setLenient(false);161}162if (format.parse(tokens.nextToken()).getTime() <163System.currentTimeMillis()) {164currency = tokens.nextToken();165numeric = tokens.nextToken();166minorUnit = tokens.nextToken();167testCurrencies.add(Currency.getInstance(currency));168}169}170}171int index = toIndex(country);172testCountryCurrency(country, currency, Integer.parseInt(numeric),173Integer.parseInt(minorUnit), index);174}175}176177for (int i = 0; i < additionalCodes.length; i++) {178int index = toIndex(additionalCodes[i][0]);179if (additionalCodes[i][1].length() != 0) {180testCountryCurrency(additionalCodes[i][0], additionalCodes[i][1],181Integer.parseInt(additionalCodes[i][2]),182Integer.parseInt(additionalCodes[i][3]), index);183testCurrencies.add(Currency.getInstance(additionalCodes[i][1]));184} else {185codes[index] = SKIPPED;186}187}188}189190static int toIndex(String s) {191return ((s.charAt(0) - 'A') * ALPHA_NUM + s.charAt(1) - 'A');192}193194static void testCountryCurrency(String country, String currencyCode,195int numericCode, int digits, int index) {196if (currencyCode.length() == 0) {197return;198}199testCurrencyDefined(currencyCode, numericCode, digits);200201Locale loc = new Locale("", country);202try {203Currency currency = Currency.getInstance(loc);204if (!currency.getCurrencyCode().equals(currencyCode)) {205System.err.println("Error: [" + country + ":" +206loc.getDisplayCountry() + "] expected: " + currencyCode +207", got: " + currency.getCurrencyCode());208err = true;209}210211if (codes[index] != UNDEFINED) {212System.out.println("Warning: [" + country + ":" +213loc.getDisplayCountry() +214"] multiple definitions. currency code=" + currencyCode);215}216codes[index] = DEFINED;217}218catch (Exception e) {219System.err.println("Error: " + e + ": Country=" + country);220err = true;221}222}223224static void testCurrencyDefined(String currencyCode, int numericCode, int digits) {225try {226Currency currency = currency = Currency.getInstance(currencyCode);227228if (currency.getNumericCode() != numericCode) {229System.err.println("Error: [" + currencyCode + "] expected: " +230numericCode + "; got: " + currency.getNumericCode());231err = true;232}233234if (currency.getDefaultFractionDigits() != digits) {235System.err.println("Error: [" + currencyCode + "] expected: " +236digits + "; got: " + currency.getDefaultFractionDigits());237err = true;238}239}240catch (Exception e) {241System.err.println("Error: " + e + ": Currency code=" +242currencyCode);243err = true;244}245}246247static void test2() {248for (int i = 0; i < ALPHA_NUM; i++) {249for (int j = 0; j < ALPHA_NUM; j++) {250char[] code = new char[2];251code[0] = (char)('A'+ i);252code[1] = (char)('A'+ j);253String country = new String(code);254boolean ex;255256if (codes[toIndex(country)] == UNDEFINED) {257ex = false;258try {259Currency.getInstance(new Locale("", country));260}261catch (IllegalArgumentException e) {262ex = true;263}264if (!ex) {265System.err.println("Error: This should be an undefined code and throw IllegalArgumentException: " +266country);267err = true;268}269} else if (codes[toIndex(country)] == SKIPPED) {270Currency cur = null;271try {272cur = Currency.getInstance(new Locale("", country));273}274catch (Exception e) {275System.err.println("Error: " + e + ": Country=" +276country);277err = true;278}279if (cur != null) {280System.err.println("Error: Currency.getInstance() for an this locale should return null: " +281country);282err = true;283}284}285}286}287}288289/**290* This test depends on test1(), where 'testCurrencies' set is constructed291*/292static void getAvailableCurrenciesTest() {293Set<Currency> jreCurrencies = Currency.getAvailableCurrencies();294295// add otherCodes296StringTokenizer st = new StringTokenizer(otherCodes, "-");297while (st.hasMoreTokens()) {298testCurrencies.add(Currency.getInstance(st.nextToken()));299}300301if (!testCurrencies.containsAll(jreCurrencies)) {302System.err.print("Error: getAvailableCurrencies() returned extra currencies than expected: ");303jreCurrencies.removeAll(testCurrencies);304for (Currency c : jreCurrencies) {305System.err.print(" "+c);306}307System.err.println();308err = true;309}310}311}312313314