diff --git a/src/main/java/org/apache/commons/text/CaseUtils.java b/src/main/java/org/apache/commons/text/CaseUtils.java index d079fb8b84..075903a948 100644 --- a/src/main/java/org/apache/commons/text/CaseUtils.java +++ b/src/main/java/org/apache/commons/text/CaseUtils.java @@ -17,6 +17,7 @@ package org.apache.commons.text; import java.util.HashSet; +import java.util.Locale; import java.util.Set; import org.apache.commons.lang3.ArrayUtils; @@ -70,7 +71,7 @@ public static String toCamelCase(String str, final boolean capitalizeFirstLetter if (StringUtils.isEmpty(str)) { return str; } - str = str.toLowerCase(); + str = str.toLowerCase(Locale.ROOT); final int strLen = str.length(); final int[] newCodePoints = new int[strLen]; int outOffset = 0; diff --git a/src/main/java/org/apache/commons/text/WordUtils.java b/src/main/java/org/apache/commons/text/WordUtils.java index 720ca5f98c..f76f028859 100644 --- a/src/main/java/org/apache/commons/text/WordUtils.java +++ b/src/main/java/org/apache/commons/text/WordUtils.java @@ -17,6 +17,7 @@ package org.apache.commons.text; import java.util.HashSet; +import java.util.Locale; import java.util.Set; import java.util.function.Predicate; import java.util.regex.Matcher; @@ -250,7 +251,7 @@ public static String capitalizeFully(String str, final char... delimiters) { if (StringUtils.isEmpty(str)) { return str; } - str = str.toLowerCase(); + str = str.toLowerCase(Locale.ROOT); return capitalize(str, delimiters); } diff --git a/src/main/java/org/apache/commons/text/lookup/StringLookupFactory.java b/src/main/java/org/apache/commons/text/lookup/StringLookupFactory.java index 699b7deab7..a9c7b0ba10 100644 --- a/src/main/java/org/apache/commons/text/lookup/StringLookupFactory.java +++ b/src/main/java/org/apache/commons/text/lookup/StringLookupFactory.java @@ -328,7 +328,7 @@ private static Map parseStringLookups(final String str) { try { for (final String lookupName : str.split("[\\s,]+")) { if (!lookupName.isEmpty()) { - addLookup(DefaultStringLookup.valueOf(lookupName.toUpperCase()), lookupMap); + addLookup(DefaultStringLookup.valueOf(lookupName.toUpperCase(Locale.ROOT)), lookupMap); } } } catch (final IllegalArgumentException exc) { diff --git a/src/test/java/org/apache/commons/text/CaseUtilsTest.java b/src/test/java/org/apache/commons/text/CaseUtilsTest.java index 899e5e8d22..f9d7237d5b 100644 --- a/src/test/java/org/apache/commons/text/CaseUtilsTest.java +++ b/src/test/java/org/apache/commons/text/CaseUtilsTest.java @@ -26,6 +26,7 @@ import java.lang.reflect.Modifier; import org.junit.jupiter.api.Test; +import org.junitpioneer.jupiter.DefaultLocale; /** * Tests {@link CaseUtils} class. @@ -77,4 +78,12 @@ void testToCamelCase() { assertEquals("\uD800\uDF00\uD800\uDF01\uD800\uDF02\uD800\uDF03", CaseUtils.toCamelCase("\uD800\uDF00\uD800\uDF01\uD800\uDF14\uD800\uDF02\uD800\uDF03", true, '\uD800', '\uDF14')); } + + @Test + @DefaultLocale(language = "tr", country = "TR") + void testToCamelCaseLocaleIndependent() { + // Turkish lower-cases 'I' (U+0049) to dotless 'i' (U+0131), which would otherwise leak into the result. + assertEquals("TipTop", CaseUtils.toCamelCase("TIP.TOP", true, '.')); + assertEquals("toCamelCase", CaseUtils.toCamelCase("TO CAMEL CASE", false, null)); + } } diff --git a/src/test/java/org/apache/commons/text/WordUtilsTest.java b/src/test/java/org/apache/commons/text/WordUtilsTest.java index 429a8934ff..85b8d1d462 100644 --- a/src/test/java/org/apache/commons/text/WordUtilsTest.java +++ b/src/test/java/org/apache/commons/text/WordUtilsTest.java @@ -32,6 +32,7 @@ import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.junit.jupiter.api.Test; +import org.junitpioneer.jupiter.DefaultLocale; /** * Tests {@link WordUtils}. @@ -124,6 +125,14 @@ void testCapitalizeFully_String() { } + @Test + @DefaultLocale(language = "tr", country = "TR") + void testCapitalizeFully_LocaleIndependent() { + // Turkish lower-cases 'I' (U+0049) to dotless 'i' (U+0131), which would otherwise leak into the result. + assertEquals("Heli World", WordUtils.capitalizeFully("HELI WORLD")); + assertEquals("I Am Here 123", WordUtils.capitalizeFully("I AM HERE 123")); + } + @Test void testCapitalizeFully_Text88() { assertEquals("I am fine now", WordUtils.capitalizeFully("i am fine now", new char[] {})); diff --git a/src/test/java/org/apache/commons/text/lookup/StringLookupFactoryTest.java b/src/test/java/org/apache/commons/text/lookup/StringLookupFactoryTest.java index caeccd8289..e0fdf8abe7 100644 --- a/src/test/java/org/apache/commons/text/lookup/StringLookupFactoryTest.java +++ b/src/test/java/org/apache/commons/text/lookup/StringLookupFactoryTest.java @@ -32,6 +32,7 @@ import javax.xml.XMLConstants; import org.junit.jupiter.api.Test; +import org.junitpioneer.jupiter.DefaultLocale; import org.junitpioneer.jupiter.SetSystemProperty; /** @@ -173,6 +174,16 @@ void testDefaultStringLookupsHolder_givenSingleLookup() { checkDefaultStringLookupsHolder(props, "base64", StringLookupFactory.KEY_BASE64_ENCODER); } + @Test + @DefaultLocale(language = "tr", country = "TR") + void testDefaultStringLookupsHolder_givenSingleLookup_localeIndependent() { + // Turkish upper-cases 'i' (U+0069) to dotted 'İ' (U+0130), so "file" would fold to "FİLE" + // and fail to resolve against the DefaultStringLookup enum without Locale.ROOT. + final Properties props = new Properties(); + props.setProperty(StringLookupFactory.DEFAULT_STRING_LOOKUPS_PROPERTY, "file"); + checkDefaultStringLookupsHolder(props, StringLookupFactory.KEY_FILE); + } + @Test void testDefaultStringLookupsHolder_givenSingleLookup_weirdString() { final Properties props = new Properties();