elharo commented on code in PR #450: URL: https://github.com/apache/commons-text/pull/450#discussion_r1370044779
########## src/test/java/org/apache/commons/text/cases/CasesTest.java: ########## @@ -0,0 +1,264 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.text.cases; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class CasesTest { + + @Test + public void testCharacterDelimitedCase() { + Assertions.assertThrows(IllegalArgumentException.class, () -> KebabCase.INSTANCE.format(Arrays.asList("a", "-"))); + Assertions.assertThrows(IllegalArgumentException.class, () -> SnakeCase.INSTANCE.format(Arrays.asList("a", "_"))); + CharacterDelimitedCase nullDelimiters = new CharacterDelimitedCase(); + assertFormat(nullDelimiters, "abc", Arrays.asList("a", "b", "c")); + assertParse(nullDelimiters, "abc", Arrays.asList("abc")); + } + + @Test + public void testKebabCase() { + assertFormatAndParse(KebabCase.INSTANCE, "", Arrays.asList()); + assertFormatAndParse(KebabCase.INSTANCE, "my-Tokens-123-a1", Arrays.asList("my", "Tokens", "123", "a1")); + assertFormatAndParse(KebabCase.INSTANCE, "blank--token", Arrays.asList("blank", "", "token")); + } + + @Test + public void testUtf32() { + assertFormatAndParse(KebabCase.INSTANCE, "\uD800\uDF00-\uD800\uDF01\uD800\uDF14-\uD800\uDF02\uD800\uDF03", + Arrays.asList("\uD800\uDF00", "\uD800\uDF01\uD800\uDF14", "\uD800\uDF02\uD800\uDF03")); + assertFormatAndParse(SnakeCase.INSTANCE, "\uD800\uDF00_\uD800\uDF01\uD800\uDF14_\uD800\uDF02\uD800\uDF03", + Arrays.asList("\uD800\uDF00", "\uD800\uDF01\uD800\uDF14", "\uD800\uDF02\uD800\uDF03")); + + assertFormatAndParse(PascalCase.INSTANCE, "A\uD800\uDF00B\uD800\uDF01\uD800\uDF14C\uD800\uDF02\uD800\uDF03", + Arrays.asList("A\uD800\uDF00", "B\uD800\uDF01\uD800\uDF14", "C\uD800\uDF02\uD800\uDF03")); + assertFormatAndParse(CamelCase.INSTANCE, "a\uD800\uDF00B\uD800\uDF01\uD800\uDF14C\uD800\uDF02\uD800\uDF03", + Arrays.asList("a\uD800\uDF00", "B\uD800\uDF01\uD800\uDF14", "C\uD800\uDF02\uD800\uDF03")); + + } + + @Test + public void testSnakeCase() { + assertFormatAndParse(SnakeCase.INSTANCE, "", Arrays.asList()); + assertFormatAndParse(SnakeCase.INSTANCE, "my_Tokens_123_a1", Arrays.asList("my", "Tokens", "123", "a1")); + assertFormatAndParse(SnakeCase.INSTANCE, "blank__token", Arrays.asList("blank", "", "token")); + } + + @Test + public void testPascalCase() { + + assertFormatAndParse(PascalCase.INSTANCE, "MyVarName", Arrays.asList("My", "Var", "Name")); + assertFormatAndParse(PascalCase.INSTANCE, "MyTokensA1D", Arrays.asList("My", "Tokens", "A1", "D")); + assertFormatAndParse(PascalCase.INSTANCE, "", Arrays.asList()); + assertParse(PascalCase.INSTANCE, "lowerFirst", Arrays.asList("lower", "First")); + assertFormat(PascalCase.INSTANCE, "LowerFirst", Arrays.asList("lower", "First")); + + Assertions.assertThrows(IllegalArgumentException.class, () -> PascalCase.INSTANCE.format(Arrays.asList("1"))); + Assertions.assertThrows(IllegalArgumentException.class, () -> PascalCase.INSTANCE.format(Arrays.asList("a1", "2c"))); + Assertions.assertThrows(IllegalArgumentException.class, () -> PascalCase.INSTANCE.format(Arrays.asList("1a"))); + Assertions.assertThrows(IllegalArgumentException.class, () -> PascalCase.INSTANCE.format(Arrays.asList(""))); + } + + @Test + public void testNumberLetters() { + + // roman numerals - have an upper/lower case but are numbers + + assertFormatAndParse(PascalCase.INSTANCE, "A\u2170\u2160c", Arrays.asList("A\u2170", "\u2160c")); + + assertFormat(PascalCase.INSTANCE, "A\u2170Bc", Arrays.asList("a\u2160", "bc")); + assertParse(PascalCase.INSTANCE, "A\u2170Bc", Arrays.asList("A\u2170", "Bc")); + assertFormat(PascalCase.INSTANCE, "A\u2170", Arrays.asList("a\u2170")); + assertParse(PascalCase.INSTANCE, "A\u2170Bc", Arrays.asList("A\u2170", "Bc")); + + assertFormat(CamelCase.INSTANCE, "a\u2170Bc", Arrays.asList("a\u2160", "bc")); + assertParse(CamelCase.INSTANCE, "\u2160Bc", Arrays.asList("\u2160", "Bc")); + + } + + @Test + public void testCamelCase() { + + assertFormatAndParse(CamelCase.INSTANCE, "", Arrays.asList()); + assertFormatAndParse(CamelCase.INSTANCE, "myTokensAbc123", Arrays.asList("my", "Tokens", "Abc123")); + assertFormatAndParse(CamelCase.INSTANCE, "specChar-Token+", Arrays.asList("spec", "Char-", "Token+")); + + assertParse(CamelCase.INSTANCE, "MyTokens", Arrays.asList("My", "Tokens")); + assertFormat(CamelCase.INSTANCE, "myTokens", Arrays.asList("My", "Tokens")); + + // empty token not supported + Assertions.assertThrows(IllegalArgumentException.class, () -> CamelCase.INSTANCE.format(Arrays.asList("a", "b", ""))); + // must begin with character that can be uppercased + Assertions.assertThrows(IllegalArgumentException.class, () -> CamelCase.INSTANCE.format(Arrays.asList("a", "1b"))); + Assertions.assertThrows(IllegalArgumentException.class, () -> CamelCase.INSTANCE.format(Arrays.asList("1a"))); + } + + @Test + public void testConversionsDelimited() { + + List<String> tokens = Arrays.asList("My", "var", "NAME", "mIXED", "a1", "12", ""); + + String kebabString = "My-var-NAME-mIXED-a1-12-"; + assertFormatAndParse(KebabCase.INSTANCE, kebabString, tokens); + + String snakeString = "My_var_NAME_mIXED_a1_12_"; + assertFormatAndParse(SnakeCase.INSTANCE, snakeString, tokens); + } + + @Test + public void testConversions() { + + List<String> tokens = Arrays.asList("My", "var", "NAME", "mIXED", "a1", "c|=+"); + + String kebabString = "My-var-NAME-mIXED-a1-c|=+"; + assertFormatAndParse(KebabCase.INSTANCE, kebabString, tokens); + + String snakeString = "My_var_NAME_mIXED_a1_c|=+"; + assertFormatAndParse(SnakeCase.INSTANCE, snakeString, tokens); + + String camelString = "myVarNameMixedA1C|=+"; + assertFormatAndParse(CamelCase.INSTANCE, camelString, tokens, true); + + String pascalString = "MyVarNameMixedA1C|=+"; + assertFormatAndParse(PascalCase.INSTANCE, pascalString, tokens, true); + + } + + @Test + public void testEmptyTokens() { + List<String> tokens = Arrays.asList("HAS", "", "empty", "Tokens", ""); + + String snakeString = "HAS__empty_Tokens_"; + assertFormatAndParse(SnakeCase.INSTANCE, snakeString, tokens); + + String kebabString = "HAS--empty-Tokens-"; + assertFormatAndParse(KebabCase.INSTANCE, kebabString, tokens); + + Assertions.assertThrows(IllegalArgumentException.class, () -> PascalCase.INSTANCE.format(tokens)); + Assertions.assertThrows(IllegalArgumentException.class, () -> CamelCase.INSTANCE.format(tokens)); + } + + + + @Test + public void testUnicodeCases() { + + // LATIN SMALL LETTER SHARP S - lower case, no upper case + Assertions.assertThrows(IllegalArgumentException.class, () -> CamelCase.INSTANCE.format(Arrays.asList("a", "\u00DFabc"))); + Assertions.assertThrows(IllegalArgumentException.class, () -> PascalCase.INSTANCE.format(Arrays.asList("\u00DFabc"))); + + // LATIN CAPITAL LETTER L WITH SMALL LETTER J - title case, has upper and lower + assertFormatAndParse(CamelCase.INSTANCE, "\u01CCbc", Arrays.asList("\u01CBbc"), true); + assertFormatAndParse(CamelCase.INSTANCE, "a\u01CAbc", Arrays.asList("a", "\u01CBbc"), true); + + // GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI - title case , no upper case + assertFormatAndParse(PascalCase.INSTANCE, "A\u1f80", Arrays.asList("a\u1f88"), true); + assertFormatAndParse(CamelCase.INSTANCE, "\u1f80", Arrays.asList("\u1f88"), true); + Assertions.assertThrows(IllegalArgumentException.class, () -> PascalCase.INSTANCE.format(Arrays.asList("\u1f88"))); + + //scan all titlecase characters + for (int i = 0; i < Character.MAX_CODE_POINT; i++) { + if (Character.isTitleCase(i)) { + String codeString = new String(new int[] { i }, 0, 1); + + int upperCode = Character.toUpperCase(i); + int lowerCode = Character.toLowerCase(i); + + //if upper exists, ensure it gets upper cased to it + if (upperCode != i) { + String upperCodeString = new String(new int[] { upperCode }, 0, 1); + Assertions.assertEquals(PascalCase.INSTANCE.format(Arrays.asList(codeString + "bc")), upperCodeString + "bc"); + } else { + // if there is no uppercase value + Assertions.assertThrows(IllegalArgumentException.class, () -> PascalCase.INSTANCE.format(Arrays.asList(codeString))); + } + + //if lower exists, ensure it gets lower cased to it + if (lowerCode != i) { + String lowerCodeString = new String(new int[] { lowerCode }, 0, 1); + Assertions.assertEquals(CamelCase.INSTANCE.format(Arrays.asList(codeString + "bc")), lowerCodeString + "bc"); + } else { + Assertions.assertThrows(IllegalArgumentException.class, () -> CamelCase.INSTANCE.format(Arrays.asList("a" + codeString))); + } + } + } + } + + private void assertFormatAndParse(Case caseInstance, String string, List<String> tokens) { + assertFormatAndParse(caseInstance, string, tokens, false); + } + + /** + * Test Util method for ensuring that a case instance parses and formats the expected string and tokens + * to one another + * + * @param case Instance the case instance to use + * @param string the expected formatted string + * @param tokens the expected tokens + * @param caseInsensitive whether to not to validate tokens case insensitively + */ + private void assertFormatAndParse(Case caseInstance, String string, List<String> tokens, Boolean caseInsensitive) { + assertFormat(caseInstance, string, tokens, caseInsensitive); + assertParse(caseInstance, string, tokens, caseInsensitive); + } + + private void assertFormat(Case caseInstance, String string, List<String> tokens) { + assertFormat(caseInstance, string, tokens, false); + } + + private void assertFormat(Case caseInstance, String string, List<String> tokens, boolean caseInsensitive) { + String formatted = caseInstance.format(tokens); + if (caseInsensitive) { + Assertions.assertEquals(string.toLowerCase(), formatted.toLowerCase()); + } else { + Assertions.assertEquals(string, formatted); + } + } + + private void assertParse(Case caseInstance, String string, List<String> tokens) { + assertParse(caseInstance, string, tokens, false); + } + + /** + * Asserts that string parses into the expected tokens, ignoring case if the caseInsensitive parameter is true + * @param caseInstance Review Comment: delete empty params on private methods ########## src/main/java/org/apache/commons/text/cases/package-info.java: ########## @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * <p>Provides algorithms for parsing and formatting various programming "Cases".</p> + * <p>The provided implementations are for the four most common cases:<br> + * CamelCase - delimited by ascii uppercase alpha characters and always beginning with a lowercase ascii alpha<br> + * PascalCase - Similar to CamelCase but always begins with an uppercase ascii alpha<br> + * DelimitedCase - delimited by a constant character, which is omitted from parsed tokens<br> + * SnakeCase - implementation of DelimitedCase in which the delimiter is an underscore '_'<br> + * KebabCase - implementation of DelimitedCase in which the delimiter is a hyphen '-'<br> + * </p> + * + * @since 1.0 Review Comment: commons-text is post 1.0 ########## src/main/java/org/apache/commons/text/cases/UpperCaseDelimitedCase.java: ########## @@ -0,0 +1,163 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.text.cases; + +import java.util.ArrayList; +import java.util.List; + +/** + * Case implementation which parses and formats strings where tokens are delimited by upper case characters. + */ +public class UpperCaseDelimitedCase implements Case { + + /** Flag to indicate whether the first character of the first token should be upper case. */ + private boolean lowerCaseFirstCharacter = false; + + /** + * Constructs a new UpperCaseDelimitedCase instance. + */ + protected UpperCaseDelimitedCase(boolean lowerCaseFirstCharacter) { + this.lowerCaseFirstCharacter = lowerCaseFirstCharacter; + } + + /** + * Parses a string into tokens. + * <p> + * String characters are iterated over and when an upper case Unicode character is + * encountered, that character starts a new token, with the character + * itself included in the token. This method never returns empty tokens. + * </p> + * @param string the string to parse Review Comment: in general, blank line before first javadoc tag ########## src/main/java/org/apache/commons/text/cases/UpperCaseDelimitedCase.java: ########## @@ -0,0 +1,163 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.text.cases; + +import java.util.ArrayList; +import java.util.List; + +/** + * Case implementation which parses and formats strings where tokens are delimited by upper case characters. + */ +public class UpperCaseDelimitedCase implements Case { + + /** Flag to indicate whether the first character of the first token should be upper case. */ + private boolean lowerCaseFirstCharacter = false; + + /** + * Constructs a new UpperCaseDelimitedCase instance. + */ + protected UpperCaseDelimitedCase(boolean lowerCaseFirstCharacter) { Review Comment: Is this intended to be subclassed by third party clients? If not, this can be package protected -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
