0N/A/*
3909N/A * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
0N/A * published by the Free Software Foundation.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A/*
0N/A * @test
4358N/A * @bug 4691089 4819436 4942982 5104960 6544471 6627549 7066203
0N/A * @summary Validate ISO 4217 data for Currency class.
0N/A */
0N/A
0N/A/*
0N/A * ############################################################################
0N/A *
0N/A * ValidateISO4217 is a tool to detect differences between the latest ISO 4217
0N/A * data and and Java's currency data which is based on ISO 4217.
0N/A * If there is a difference, the following file which includes currency data
0N/A * may need to be updated.
0N/A * src/share/classes/java/util/CurrencyData.properties
0N/A *
0N/A * ############################################################################
0N/A *
0N/A * 1) Make a golden-data file.
0N/A * From BSi's ISO4217 data (TABLE A1.doc), extract four (or eight, if currency is changing)
0N/A * fields and save as ./tablea1.txt.
0N/A * <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>]
0N/A * The Cutover Date is given in SimpleDateFormat's 'yyyy-MM-dd-HH-mm-ss' format in the GMT time zone.
0N/A *
0N/A * 2) Compile ValidateISO4217.java
0N/A *
0N/A * 3) Execute ValidateISO4217 as follows:
0N/A * java ValidateISO4217
0N/A */
0N/A
0N/Aimport java.io.*;
0N/Aimport java.text.*;
0N/Aimport java.util.*;
0N/A
0N/Apublic class ValidateISO4217 {
0N/A
0N/A static final int ALPHA_NUM = 26;
0N/A
0N/A static final byte UNDEFINED = 0;
0N/A static final byte DEFINED = 1;
0N/A static final byte SKIPPED = 2;
0N/A
0N/A /* input files */
0N/A static final String datafile = "tablea1.txt";
0N/A
0N/A /* alpha2-code table */
0N/A static byte[] codes = new byte[ALPHA_NUM * ALPHA_NUM];
0N/A
0N/A static final String[][] additionalCodes = {
0N/A /* Defined in ISO 4217 list, but don't have code and minor unit info. */
0N/A {"AQ", "", "", "0"}, // Antarctica
0N/A
0N/A /*
0N/A * Defined in ISO 4217 list, but don't have code and minor unit info in
0N/A * it. On the othe hand, both code and minor unit are defined in
0N/A * .properties file. I don't know why, though.
0N/A */
0N/A {"GS", "GBP", "826", "2"}, // South Georgia And The South Sandwich Islands
0N/A
0N/A /* Not defined in ISO 4217 list, but defined in .properties file. */
0N/A {"AX", "EUR", "978", "2"}, // \u00c5LAND ISLANDS
0N/A {"PS", "ILS", "376", "2"}, // Palestinian Territory, Occupied
0N/A
0N/A /* Not defined in ISO 4217 list, but added in ISO 3166 country code list */
0N/A {"JE", "GBP", "826", "2"}, // Jersey
0N/A {"GG", "GBP", "826", "2"}, // Guernsey
0N/A {"IM", "GBP", "826", "2"}, // Isle of Man
831N/A {"BL", "EUR", "978", "2"}, // Saint Barthelemy
831N/A {"MF", "EUR", "978", "2"}, // Saint Martin
0N/A };
0N/A
0N/A /* Codes that are obsolete, do not have related country */
0N/A static final String otherCodes =
4358N/A "ADP-AFA-ATS-AYM-BEF-BGL-BOV-BYB-CLF-CUC-CYP-DEM-EEK-ESP-FIM-FRF-GRD-GWP-IEP-ITL-LUF-MGF-MTL-MXV-NLG-PTE-RUR-SDD-SIT-SKK-SRG-TMM-TPE-TRL-VEF-USN-USS-XAG-XAU-XBA-XBB-XBC-XBD-XDR-XFO-XFU-XPD-XPT-XSU-XTS-XUA-XXX-YUM-ZWD-ZWN-ZWR";
0N/A
0N/A static boolean err = false;
0N/A
0N/A static Set<Currency> testCurrencies = new HashSet<Currency>();
0N/A
0N/A public static void main(String[] args) throws Exception {
0N/A CheckDataVersion.check();
0N/A test1();
0N/A test2();
0N/A getAvailableCurrenciesTest();
0N/A
0N/A if (err) {
0N/A throw new RuntimeException("Failed: Validation ISO 4217 data");
0N/A }
0N/A }
0N/A
0N/A static void test1() throws Exception {
0N/A
3646N/A try (FileReader fr = new FileReader(new File(System.getProperty("test.src", "."), datafile));
3646N/A BufferedReader in = new BufferedReader(fr))
3646N/A {
3646N/A String line;
3646N/A SimpleDateFormat format = null;
0N/A
3646N/A while ((line = in.readLine()) != null) {
3646N/A if (line.length() == 0 || line.charAt(0) == '#') {
3646N/A continue;
3646N/A }
0N/A
3646N/A StringTokenizer tokens = new StringTokenizer(line, "\t");
3646N/A String country = tokens.nextToken();
3646N/A if (country.length() != 2) {
3646N/A continue;
3646N/A }
0N/A
3646N/A String currency;
3646N/A String numeric;
3646N/A String minorUnit;
3646N/A int tokensCount = tokens.countTokens();
3646N/A if (tokensCount < 3) {
3646N/A currency = "";
3646N/A numeric = "0";
3646N/A minorUnit = "0";
3646N/A } else {
3646N/A currency = tokens.nextToken();
3646N/A numeric = tokens.nextToken();
3646N/A minorUnit = tokens.nextToken();
3646N/A testCurrencies.add(Currency.getInstance(currency));
0N/A
3646N/A // check for the cutover
3646N/A if (tokensCount > 3) {
3646N/A if (format == null) {
3646N/A format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.US);
3646N/A format.setTimeZone(TimeZone.getTimeZone("GMT"));
3646N/A format.setLenient(false);
3646N/A }
3646N/A if (format.parse(tokens.nextToken()).getTime() <
3646N/A System.currentTimeMillis()) {
3646N/A currency = tokens.nextToken();
3646N/A numeric = tokens.nextToken();
3646N/A minorUnit = tokens.nextToken();
3646N/A testCurrencies.add(Currency.getInstance(currency));
3646N/A }
0N/A }
0N/A }
3646N/A int index = toIndex(country);
3646N/A testCountryCurrency(country, currency, Integer.parseInt(numeric),
3646N/A Integer.parseInt(minorUnit), index);
0N/A }
0N/A }
0N/A
0N/A for (int i = 0; i < additionalCodes.length; i++) {
0N/A int index = toIndex(additionalCodes[i][0]);
0N/A if (additionalCodes[i][1].length() != 0) {
0N/A testCountryCurrency(additionalCodes[i][0], additionalCodes[i][1],
0N/A Integer.parseInt(additionalCodes[i][2]),
0N/A Integer.parseInt(additionalCodes[i][3]), index);
0N/A testCurrencies.add(Currency.getInstance(additionalCodes[i][1]));
0N/A } else {
0N/A codes[index] = SKIPPED;
0N/A }
0N/A }
0N/A }
0N/A
0N/A static int toIndex(String s) {
0N/A return ((s.charAt(0) - 'A') * ALPHA_NUM + s.charAt(1) - 'A');
0N/A }
0N/A
0N/A static void testCountryCurrency(String country, String currencyCode,
0N/A int numericCode, int digits, int index) {
0N/A if (currencyCode.length() == 0) {
0N/A return;
0N/A }
0N/A testCurrencyDefined(currencyCode, numericCode, digits);
0N/A
0N/A Locale loc = new Locale("", country);
0N/A try {
0N/A Currency currency = Currency.getInstance(loc);
0N/A if (!currency.getCurrencyCode().equals(currencyCode)) {
0N/A System.err.println("Error: [" + country + ":" +
0N/A loc.getDisplayCountry() + "] expected: " + currencyCode +
0N/A ", got: " + currency.getCurrencyCode());
0N/A err = true;
0N/A }
0N/A
0N/A if (codes[index] != UNDEFINED) {
0N/A System.out.println("Warning: [" + country + ":" +
0N/A loc.getDisplayCountry() +
0N/A "] multiple definitions. currency code=" + currencyCode);
0N/A }
0N/A codes[index] = DEFINED;
0N/A }
0N/A catch (Exception e) {
0N/A System.err.println("Error: " + e + ": Country=" + country);
0N/A err = true;
0N/A }
0N/A }
0N/A
0N/A static void testCurrencyDefined(String currencyCode, int numericCode, int digits) {
0N/A try {
0N/A Currency currency = currency = Currency.getInstance(currencyCode);
0N/A
0N/A if (currency.getNumericCode() != numericCode) {
0N/A System.err.println("Error: [" + currencyCode + "] expected: " +
0N/A numericCode + "; got: " + currency.getNumericCode());
0N/A err = true;
0N/A }
0N/A
0N/A if (currency.getDefaultFractionDigits() != digits) {
0N/A System.err.println("Error: [" + currencyCode + "] expected: " +
0N/A digits + "; got: " + currency.getDefaultFractionDigits());
0N/A err = true;
0N/A }
0N/A }
0N/A catch (Exception e) {
0N/A System.err.println("Error: " + e + ": Currency code=" +
0N/A currencyCode);
0N/A err = true;
0N/A }
0N/A }
0N/A
0N/A static void test2() {
0N/A for (int i = 0; i < ALPHA_NUM; i++) {
0N/A for (int j = 0; j < ALPHA_NUM; j++) {
0N/A char[] code = new char[2];
0N/A code[0] = (char)('A'+ i);
0N/A code[1] = (char)('A'+ j);
0N/A String country = new String(code);
0N/A boolean ex;
0N/A
0N/A if (codes[toIndex(country)] == UNDEFINED) {
0N/A ex = false;
0N/A try {
0N/A Currency.getInstance(new Locale("", country));
0N/A }
0N/A catch (IllegalArgumentException e) {
0N/A ex = true;
0N/A }
0N/A if (!ex) {
0N/A System.err.println("Error: This should be an undefined code and throw IllegalArgumentException: " +
0N/A country);
0N/A err = true;
0N/A }
0N/A } else if (codes[toIndex(country)] == SKIPPED) {
0N/A Currency cur = null;
0N/A try {
0N/A cur = Currency.getInstance(new Locale("", country));
0N/A }
0N/A catch (Exception e) {
0N/A System.err.println("Error: " + e + ": Country=" +
0N/A country);
0N/A err = true;
0N/A }
0N/A if (cur != null) {
0N/A System.err.println("Error: Currency.getInstance() for an this locale should return null: " +
0N/A country);
0N/A err = true;
0N/A }
0N/A }
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * This test depends on test1(), where 'testCurrencies' set is constructed
0N/A */
0N/A static void getAvailableCurrenciesTest() {
0N/A Set<Currency> jreCurrencies = Currency.getAvailableCurrencies();
0N/A
0N/A // add otherCodes
0N/A StringTokenizer st = new StringTokenizer(otherCodes, "-");
0N/A while (st.hasMoreTokens()) {
0N/A testCurrencies.add(Currency.getInstance(st.nextToken()));
0N/A }
0N/A
0N/A if (!testCurrencies.containsAll(jreCurrencies)) {
0N/A System.err.print("Error: getAvailableCurrencies() returned extra currencies than expected: ");
0N/A jreCurrencies.removeAll(testCurrencies);
0N/A for (Currency c : jreCurrencies) {
0N/A System.err.print(" "+c);
0N/A }
0N/A System.err.println();
0N/A err = true;
0N/A }
0N/A }
0N/A}