diff --git a/CHANGELOG.md b/CHANGELOG.md
index f8d65551e..3b7f8ad3a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
# Prowide Core - CHANGELOG
+#### 10.3.20 - SNAPSHOT
+ * Feat: new `IsoUtils#getCountryName(code)` with the ISO 3166-1 English short name of a country, looked up by its alpha-2, alpha-3 or numeric code
+ * Feat: `IsoUtils#isUserAssignedCountryCode(code)` is now public, for the ISO 3166-1 user assigned range XA to XZ; it no longer accepts an upper case letter of another alphabet after the X, so `isValidISOCountry` rejects codes such as "XЖ"
+
#### 10.3.19 - August 2026
* (PW-3433) Fix: `OptionJPartyField.getValueByCodeword` no longer shifts the codeword/value pairs that follow a codeword with a blank value (for example "/CITY/" followed by "/USFW/021000018" returned "USFW" for CITY and null for USFW); a codeword present with a blank value now returns an empty string
* (GH-341) Fix: `SwiftMessageUtils.money` revised for category 7: amount added for MT744, MT760, MT765 and MT786; changed to field 32B for MT750 and MT752, and to 34B for MT769; removed for MT707
diff --git a/src/main/java/com/prowidesoftware/swift/utils/IsoUtils.java b/src/main/java/com/prowidesoftware/swift/utils/IsoUtils.java
index 387b28d42..caf79d597 100644
--- a/src/main/java/com/prowidesoftware/swift/utils/IsoUtils.java
+++ b/src/main/java/com/prowidesoftware/swift/utils/IsoUtils.java
@@ -15,7 +15,9 @@
*/
package com.prowidesoftware.swift.utils;
+import java.io.IOException;
import java.util.*;
+import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
@@ -27,6 +29,9 @@
* change or add new values. This can be particularly helpful when the application is not running on
* the latest Java version and a currency change or addition has not yet been updated in the used JRE.
*
+ *
The ISO 3166-1 country names are also available, by alpha-2, alpha-3 or numeric code, with
+ * {@link #getCountryName(String)}.
+ *
* @since 7.9.2
*/
public final class IsoUtils {
@@ -96,8 +101,109 @@ public boolean isValidISOCountry(String countryCode) {
return false;
}
- private boolean isUserAssignedCountryCode(String code) {
- return code.charAt(0) == 'X' && Character.isUpperCase(code.charAt(1));
+ /**
+ * Checks if the country code belongs to the ISO 3166-1 user assigned range XA to XZ, for example XK or XX.
+ *
+ *
These codes are accepted by {@link #isValidISOCountry(String)} regardless of the country codes list. The other
+ * ISO 3166-1 user assigned codes (AA, QM to QZ and ZZ) are not part of this range.
+ *
+ * @param countryCode a two letters capitalized country code, example: XK
+ * @return true if the parameter is an X followed by a letter in the A-Z range, false otherwise, including null
+ * @since 10.3.20
+ */
+ public boolean isUserAssignedCountryCode(String countryCode) {
+ return StringUtils.length(countryCode) == 2
+ && countryCode.charAt(0) == 'X'
+ && countryCode.charAt(1) >= 'A'
+ && countryCode.charAt(1) <= 'Z';
+ }
+
+ /**
+ * Gets the English short name of a country from its ISO 3166-1 code.
+ *
+ *
The parameter can be the alpha-2 code (US), the alpha-3 code (USA) or the numeric code (840). The lookup is
+ * case-insensitive, ignores surrounding whitespace, accepts a numeric code with fewer or more leading zeros than
+ * the three digits of the ISO code (28 or 0028 for Antigua and Barbuda, whose ISO numeric code is 028), and does
+ * not depend on the default locale.
+ *
+ *
The names are the English short names of the officially assigned codes, in the comma-inverted form of the
+ * ISO 3166-1 lists (for example "Bolivia, Plurinational State of"). This catalog is independent of the country
+ * codes list: a code added with {@link #addCountry(String)} has no name, and the user assigned codes (the XA to
+ * XZ range) have no name either.
+ *
+ * @param code an alpha-2, alpha-3 or numeric ISO 3166-1 country code
+ * @return the English short name of the country, or null if the parameter is null, blank or not an officially
+ * assigned code
+ * @since 10.3.20
+ */
+ public String getCountryName(String code) {
+ if (code == null) {
+ return null;
+ }
+ String key = code.trim().toUpperCase(Locale.ROOT);
+ if (isAsciiDigits(key)) {
+ String digits = stripLeadingZeros(key);
+ if (digits.length() > 3) {
+ return null;
+ }
+ key = "000".substring(digits.length()) + digits;
+ }
+ return CountryNames.BY_CODE.get(key);
+ }
+
+ private static boolean isAsciiDigits(String s) {
+ if (s.isEmpty()) {
+ return false;
+ }
+ for (int i = 0; i < s.length(); i++) {
+ char c = s.charAt(i);
+ if (c < '0' || c > '9') {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static String stripLeadingZeros(String digits) {
+ int i = 0;
+ while (i < digits.length() && digits.charAt(i) == '0') {
+ i++;
+ }
+ return digits.substring(i);
+ }
+
+ /**
+ * Lazily loaded ISO 3166-1 names, keyed by the alpha-2, alpha-3 and numeric codes.
+ *
+ *
The data comes from the IsoCountries.txt resource, one country per line as alpha-2;alpha-3;numeric;name,
+ * with lines starting with # ignored.
+ */
+ private static final class CountryNames {
+ private static final Map BY_CODE = load();
+
+ private static Map load() {
+ Map map = new HashMap<>();
+ try {
+ String content = Lib.readResource("IsoCountries.txt", "UTF-8", IsoUtils.class);
+ for (String line : content.split("\\R")) {
+ if (line.isEmpty() || line.charAt(0) == '#') {
+ continue;
+ }
+ String[] fields = line.split(";", 4);
+ if (fields.length == 4) {
+ map.put(fields[0], fields[3]);
+ map.put(fields[1], fields[3]);
+ map.put(fields[2], fields[3]);
+ }
+ }
+ } catch (IOException e) {
+ log.log(Level.SEVERE, "Could not load the ISO 3166-1 country names", e);
+ }
+ if (map.isEmpty()) {
+ log.severe("The ISO 3166-1 country names resource IsoCountries.txt is missing or empty");
+ }
+ return map;
+ }
}
/**
diff --git a/src/main/resources/IsoCountries.txt b/src/main/resources/IsoCountries.txt
new file mode 100644
index 000000000..6bd49ecb0
--- /dev/null
+++ b/src/main/resources/IsoCountries.txt
@@ -0,0 +1,250 @@
+# ISO 3166-1 officially assigned countries: alpha-2;alpha-3;numeric;English short name
+AD;AND;020;Andorra
+AE;ARE;784;United Arab Emirates
+AF;AFG;004;Afghanistan
+AG;ATG;028;Antigua and Barbuda
+AI;AIA;660;Anguilla
+AL;ALB;008;Albania
+AM;ARM;051;Armenia
+AO;AGO;024;Angola
+AQ;ATA;010;Antarctica
+AR;ARG;032;Argentina
+AS;ASM;016;American Samoa
+AT;AUT;040;Austria
+AU;AUS;036;Australia
+AW;ABW;533;Aruba
+AX;ALA;248;Åland Islands
+AZ;AZE;031;Azerbaijan
+BA;BIH;070;Bosnia and Herzegovina
+BB;BRB;052;Barbados
+BD;BGD;050;Bangladesh
+BE;BEL;056;Belgium
+BF;BFA;854;Burkina Faso
+BG;BGR;100;Bulgaria
+BH;BHR;048;Bahrain
+BI;BDI;108;Burundi
+BJ;BEN;204;Benin
+BL;BLM;652;Saint Barthélemy
+BM;BMU;060;Bermuda
+BN;BRN;096;Brunei Darussalam
+BO;BOL;068;Bolivia, Plurinational State of
+BQ;BES;535;Bonaire, Sint Eustatius and Saba
+BR;BRA;076;Brazil
+BS;BHS;044;Bahamas
+BT;BTN;064;Bhutan
+BV;BVT;074;Bouvet Island
+BW;BWA;072;Botswana
+BY;BLR;112;Belarus
+BZ;BLZ;084;Belize
+CA;CAN;124;Canada
+CC;CCK;166;Cocos (Keeling) Islands
+CD;COD;180;Congo, Democratic Republic of the
+CF;CAF;140;Central African Republic
+CG;COG;178;Congo
+CH;CHE;756;Switzerland
+CI;CIV;384;Côte d'Ivoire
+CK;COK;184;Cook Islands
+CL;CHL;152;Chile
+CM;CMR;120;Cameroon
+CN;CHN;156;China
+CO;COL;170;Colombia
+CR;CRI;188;Costa Rica
+CU;CUB;192;Cuba
+CV;CPV;132;Cabo Verde
+CW;CUW;531;Curaçao
+CX;CXR;162;Christmas Island
+CY;CYP;196;Cyprus
+CZ;CZE;203;Czechia
+DE;DEU;276;Germany
+DJ;DJI;262;Djibouti
+DK;DNK;208;Denmark
+DM;DMA;212;Dominica
+DO;DOM;214;Dominican Republic
+DZ;DZA;012;Algeria
+EC;ECU;218;Ecuador
+EE;EST;233;Estonia
+EG;EGY;818;Egypt
+EH;ESH;732;Western Sahara
+ER;ERI;232;Eritrea
+ES;ESP;724;Spain
+ET;ETH;231;Ethiopia
+FI;FIN;246;Finland
+FJ;FJI;242;Fiji
+FK;FLK;238;Falkland Islands (Malvinas)
+FM;FSM;583;Micronesia, Federated States of
+FO;FRO;234;Faroe Islands
+FR;FRA;250;France
+GA;GAB;266;Gabon
+GB;GBR;826;United Kingdom of Great Britain and Northern Ireland
+GD;GRD;308;Grenada
+GE;GEO;268;Georgia
+GF;GUF;254;French Guiana
+GG;GGY;831;Guernsey
+GH;GHA;288;Ghana
+GI;GIB;292;Gibraltar
+GL;GRL;304;Greenland
+GM;GMB;270;Gambia
+GN;GIN;324;Guinea
+GP;GLP;312;Guadeloupe
+GQ;GNQ;226;Equatorial Guinea
+GR;GRC;300;Greece
+GS;SGS;239;South Georgia and the South Sandwich Islands
+GT;GTM;320;Guatemala
+GU;GUM;316;Guam
+GW;GNB;624;Guinea-Bissau
+GY;GUY;328;Guyana
+HK;HKG;344;Hong Kong
+HM;HMD;334;Heard Island and McDonald Islands
+HN;HND;340;Honduras
+HR;HRV;191;Croatia
+HT;HTI;332;Haiti
+HU;HUN;348;Hungary
+ID;IDN;360;Indonesia
+IE;IRL;372;Ireland
+IL;ISR;376;Israel
+IM;IMN;833;Isle of Man
+IN;IND;356;India
+IO;IOT;086;British Indian Ocean Territory
+IQ;IRQ;368;Iraq
+IR;IRN;364;Iran, Islamic Republic of
+IS;ISL;352;Iceland
+IT;ITA;380;Italy
+JE;JEY;832;Jersey
+JM;JAM;388;Jamaica
+JO;JOR;400;Jordan
+JP;JPN;392;Japan
+KE;KEN;404;Kenya
+KG;KGZ;417;Kyrgyzstan
+KH;KHM;116;Cambodia
+KI;KIR;296;Kiribati
+KM;COM;174;Comoros
+KN;KNA;659;Saint Kitts and Nevis
+KP;PRK;408;Korea, Democratic People's Republic of
+KR;KOR;410;Korea, Republic of
+KW;KWT;414;Kuwait
+KY;CYM;136;Cayman Islands
+KZ;KAZ;398;Kazakhstan
+LA;LAO;418;Lao People's Democratic Republic
+LB;LBN;422;Lebanon
+LC;LCA;662;Saint Lucia
+LI;LIE;438;Liechtenstein
+LK;LKA;144;Sri Lanka
+LR;LBR;430;Liberia
+LS;LSO;426;Lesotho
+LT;LTU;440;Lithuania
+LU;LUX;442;Luxembourg
+LV;LVA;428;Latvia
+LY;LBY;434;Libya
+MA;MAR;504;Morocco
+MC;MCO;492;Monaco
+MD;MDA;498;Moldova, Republic of
+ME;MNE;499;Montenegro
+MF;MAF;663;Saint Martin (French part)
+MG;MDG;450;Madagascar
+MH;MHL;584;Marshall Islands
+MK;MKD;807;North Macedonia
+ML;MLI;466;Mali
+MM;MMR;104;Myanmar
+MN;MNG;496;Mongolia
+MO;MAC;446;Macao
+MP;MNP;580;Northern Mariana Islands
+MQ;MTQ;474;Martinique
+MR;MRT;478;Mauritania
+MS;MSR;500;Montserrat
+MT;MLT;470;Malta
+MU;MUS;480;Mauritius
+MV;MDV;462;Maldives
+MW;MWI;454;Malawi
+MX;MEX;484;Mexico
+MY;MYS;458;Malaysia
+MZ;MOZ;508;Mozambique
+NA;NAM;516;Namibia
+NC;NCL;540;New Caledonia
+NE;NER;562;Niger
+NF;NFK;574;Norfolk Island
+NG;NGA;566;Nigeria
+NI;NIC;558;Nicaragua
+NL;NLD;528;Netherlands, Kingdom of the
+NO;NOR;578;Norway
+NP;NPL;524;Nepal
+NR;NRU;520;Nauru
+NU;NIU;570;Niue
+NZ;NZL;554;New Zealand
+OM;OMN;512;Oman
+PA;PAN;591;Panama
+PE;PER;604;Peru
+PF;PYF;258;French Polynesia
+PG;PNG;598;Papua New Guinea
+PH;PHL;608;Philippines
+PK;PAK;586;Pakistan
+PL;POL;616;Poland
+PM;SPM;666;Saint Pierre and Miquelon
+PN;PCN;612;Pitcairn
+PR;PRI;630;Puerto Rico
+PS;PSE;275;Palestine, State of
+PT;PRT;620;Portugal
+PW;PLW;585;Palau
+PY;PRY;600;Paraguay
+QA;QAT;634;Qatar
+RE;REU;638;Réunion
+RO;ROU;642;Romania
+RS;SRB;688;Serbia
+RU;RUS;643;Russian Federation
+RW;RWA;646;Rwanda
+SA;SAU;682;Saudi Arabia
+SB;SLB;090;Solomon Islands
+SC;SYC;690;Seychelles
+SD;SDN;729;Sudan
+SE;SWE;752;Sweden
+SG;SGP;702;Singapore
+SH;SHN;654;Saint Helena, Ascension and Tristan da Cunha
+SI;SVN;705;Slovenia
+SJ;SJM;744;Svalbard and Jan Mayen
+SK;SVK;703;Slovakia
+SL;SLE;694;Sierra Leone
+SM;SMR;674;San Marino
+SN;SEN;686;Senegal
+SO;SOM;706;Somalia
+SR;SUR;740;Suriname
+SS;SSD;728;South Sudan
+ST;STP;678;Sao Tome and Principe
+SV;SLV;222;El Salvador
+SX;SXM;534;Sint Maarten (Dutch part)
+SY;SYR;760;Syrian Arab Republic
+SZ;SWZ;748;Eswatini
+TC;TCA;796;Turks and Caicos Islands
+TD;TCD;148;Chad
+TF;ATF;260;French Southern Territories
+TG;TGO;768;Togo
+TH;THA;764;Thailand
+TJ;TJK;762;Tajikistan
+TK;TKL;772;Tokelau
+TL;TLS;626;Timor-Leste
+TM;TKM;795;Turkmenistan
+TN;TUN;788;Tunisia
+TO;TON;776;Tonga
+TR;TUR;792;Türkiye
+TT;TTO;780;Trinidad and Tobago
+TV;TUV;798;Tuvalu
+TW;TWN;158;Taiwan, Province of China
+TZ;TZA;834;Tanzania, United Republic of
+UA;UKR;804;Ukraine
+UG;UGA;800;Uganda
+UM;UMI;581;United States Minor Outlying Islands
+US;USA;840;United States of America
+UY;URY;858;Uruguay
+UZ;UZB;860;Uzbekistan
+VA;VAT;336;Holy See
+VC;VCT;670;Saint Vincent and the Grenadines
+VE;VEN;862;Venezuela, Bolivarian Republic of
+VG;VGB;092;Virgin Islands (British)
+VI;VIR;850;Virgin Islands (U.S.)
+VN;VNM;704;Viet Nam
+VU;VUT;548;Vanuatu
+WF;WLF;876;Wallis and Futuna
+WS;WSM;882;Samoa
+YE;YEM;887;Yemen
+YT;MYT;175;Mayotte
+ZA;ZAF;710;South Africa
+ZM;ZMB;894;Zambia
+ZW;ZWE;716;Zimbabwe
diff --git a/src/test/java/com/prowidesoftware/swift/utils/IsoUtilsTest.java b/src/test/java/com/prowidesoftware/swift/utils/IsoUtilsTest.java
index e7cfea1a6..8c886549e 100644
--- a/src/test/java/com/prowidesoftware/swift/utils/IsoUtilsTest.java
+++ b/src/test/java/com/prowidesoftware/swift/utils/IsoUtilsTest.java
@@ -15,9 +15,9 @@
*/
package com.prowidesoftware.swift.utils;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.*;
+import java.util.Locale;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@@ -99,6 +99,32 @@ public void testCountriesUserAssigned() {
assertTrue(IsoUtils.getInstance().isValidISOCountry("XZ"));
}
+ @Test
+ public void testIsUserAssignedCountryCode() {
+ for (char c = 'A'; c <= 'Z'; c++) {
+ assertTrue(IsoUtils.getInstance().isUserAssignedCountryCode("X" + c), "X" + c);
+ }
+ assertFalse(IsoUtils.getInstance().isUserAssignedCountryCode(null));
+ assertFalse(IsoUtils.getInstance().isUserAssignedCountryCode(""));
+ assertFalse(IsoUtils.getInstance().isUserAssignedCountryCode("X"));
+ assertFalse(IsoUtils.getInstance().isUserAssignedCountryCode("XXX"));
+ assertFalse(IsoUtils.getInstance().isUserAssignedCountryCode("xx"));
+ assertFalse(IsoUtils.getInstance().isUserAssignedCountryCode("Xx"));
+ assertFalse(IsoUtils.getInstance().isUserAssignedCountryCode("X1"));
+ assertFalse(IsoUtils.getInstance().isUserAssignedCountryCode("FR"));
+ assertFalse(IsoUtils.getInstance().isUserAssignedCountryCode("AA"));
+ assertFalse(IsoUtils.getInstance().isUserAssignedCountryCode("QM"));
+ assertFalse(IsoUtils.getInstance().isUserAssignedCountryCode("ZZ"));
+ }
+
+ /** Only the A-Z range follows the X, an upper case letter of another alphabet is not a user assigned code */
+ @Test
+ public void testUserAssignedCountryCodeIsAsciiOnly() {
+ assertFalse(IsoUtils.getInstance().isUserAssignedCountryCode("XЖ"));
+ assertFalse(IsoUtils.getInstance().isValidISOCountry("XЖ"));
+ assertFalse(IsoUtils.getInstance().isValidISOCountry("XÉ"));
+ }
+
@Test
public void testAddCountry_1() {
Assertions.assertThrows(
@@ -162,4 +188,111 @@ public void testAddCurrency_5() {
IsoUtils.getInstance().removeCurrency("DSZ");
assertFalse(IsoUtils.getInstance().isValidISOCurrency("DSZ"));
}
+
+ @Test
+ public void testCountryNameByAlpha2() {
+ assertEquals("United States of America", IsoUtils.getInstance().getCountryName("US"));
+ assertEquals("Spain", IsoUtils.getInstance().getCountryName("ES"));
+ assertEquals("Antigua and Barbuda", IsoUtils.getInstance().getCountryName("AG"));
+ }
+
+ @Test
+ public void testCountryNameByAlpha3() {
+ assertEquals("Spain", IsoUtils.getInstance().getCountryName("ESP"));
+ assertEquals("Antigua and Barbuda", IsoUtils.getInstance().getCountryName("ATG"));
+ assertEquals("Sudan", IsoUtils.getInstance().getCountryName("SDN"));
+ }
+
+ @Test
+ public void testCountryNameByNumeric() {
+ assertEquals("Antigua and Barbuda", IsoUtils.getInstance().getCountryName("028"));
+ assertEquals("Solomon Islands", IsoUtils.getInstance().getCountryName("090"));
+ assertEquals("Uruguay", IsoUtils.getInstance().getCountryName("858"));
+ assertEquals("United States of America", IsoUtils.getInstance().getCountryName("840"));
+ }
+
+ /** A numeric code with fewer or more leading zeros than the three ISO digits still identifies the country */
+ @Test
+ public void testCountryNameByNumericWithOtherLeadingZeros() {
+ assertEquals("Antigua and Barbuda", IsoUtils.getInstance().getCountryName("28"));
+ assertEquals("Afghanistan", IsoUtils.getInstance().getCountryName("4"));
+ assertEquals("Antigua and Barbuda", IsoUtils.getInstance().getCountryName("0028"));
+ assertEquals("United States of America", IsoUtils.getInstance().getCountryName("000840"));
+ assertNull(IsoUtils.getInstance().getCountryName("0000"));
+ assertNull(IsoUtils.getInstance().getCountryName("1234"));
+ }
+
+ @Test
+ public void testCountryNameIsLenientWithCaseAndSurroundingSpace() {
+ assertEquals("Uruguay", IsoUtils.getInstance().getCountryName("uy"));
+ assertEquals("Sudan", IsoUtils.getInstance().getCountryName("Sdn"));
+ assertEquals("Spain", IsoUtils.getInstance().getCountryName(" ES "));
+ }
+
+ /** The numeric lookup must not depend on the digits of the default locale */
+ @Test
+ public void testCountryNameByNumericIsIndependentOfTheDefaultLocale() {
+ Locale previous = Locale.getDefault();
+ Locale.setDefault(new Locale.Builder().setLanguage("ar").setRegion("EG").build());
+ try {
+ assertEquals("Antigua and Barbuda", IsoUtils.getInstance().getCountryName("28"));
+ assertEquals("Afghanistan", IsoUtils.getInstance().getCountryName("004"));
+ } finally {
+ Locale.setDefault(previous);
+ }
+ }
+
+ @Test
+ public void testCountryNameUnknownIsNull() {
+ assertNull(IsoUtils.getInstance().getCountryName(null));
+ assertNull(IsoUtils.getInstance().getCountryName(""));
+ assertNull(IsoUtils.getInstance().getCountryName(" "));
+ assertNull(IsoUtils.getInstance().getCountryName("UK"));
+ assertNull(IsoUtils.getInstance().getCountryName("foo"));
+ assertNull(IsoUtils.getInstance().getCountryName("999"));
+ assertNull(IsoUtils.getInstance().getCountryName("99999999999999999999999"));
+ assertNull(IsoUtils.getInstance().getCountryName("USAX"));
+ }
+
+ /** The user assigned codes have no name, even when added to the country codes */
+ @Test
+ public void testCountryNameOfUserAssignedCodes() {
+ for (String code : new String[] {"XA", "XK", "XX", "XZ", "QM", "QZ", "AA", "ZZ"}) {
+ assertNull(IsoUtils.getInstance().getCountryName(code), code);
+ }
+ IsoUtils.getInstance().addCountry("XK");
+ try {
+ assertNull(IsoUtils.getInstance().getCountryName("XK"));
+ } finally {
+ IsoUtils.getInstance().removeCountry("XK");
+ }
+ }
+
+ /** The ISO short names, free of footnote marks, with the non-ASCII names read as UTF-8 */
+ @Test
+ public void testCountryNamesAreTheIsoShortNames() {
+ assertEquals("Afghanistan", IsoUtils.getInstance().getCountryName("AF"));
+ assertEquals("China", IsoUtils.getInstance().getCountryName("CN"));
+ assertEquals("Taiwan, Province of China", IsoUtils.getInstance().getCountryName("TW"));
+ assertEquals("Bonaire, Sint Eustatius and Saba", IsoUtils.getInstance().getCountryName("BQ"));
+ assertEquals("Svalbard and Jan Mayen", IsoUtils.getInstance().getCountryName("SJ"));
+ assertEquals("Bolivia, Plurinational State of", IsoUtils.getInstance().getCountryName("BO"));
+ assertEquals("Korea, Republic of", IsoUtils.getInstance().getCountryName("KR"));
+ assertEquals("Türkiye", IsoUtils.getInstance().getCountryName("TR"));
+ assertEquals("Côte d'Ivoire", IsoUtils.getInstance().getCountryName("CI"));
+ assertEquals("Åland Islands", IsoUtils.getInstance().getCountryName("AX"));
+ }
+
+ /** Every officially assigned country known to the JDK has a name, by any of its three codes */
+ @Test
+ public void testEveryJdkCountryHasAName() {
+ for (String alpha2 : Locale.getISOCountries()) {
+ String name = IsoUtils.getInstance().getCountryName(alpha2);
+ assertNotNull(name, alpha2);
+ assertFalse(name.isEmpty(), alpha2);
+ assertFalse(name.contains("["), alpha2 + " carries a footnote: " + name);
+ String alpha3 = new Locale.Builder().setRegion(alpha2).build().getISO3Country();
+ assertEquals(name, IsoUtils.getInstance().getCountryName(alpha3), alpha2 + " by alpha-3 " + alpha3);
+ }
+ }
}