This is an automated email from the ASF dual-hosted git repository.

claude pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/creadur-rat.git


The following commit(s) were added to refs/heads/master by this push:
     new 25f95abc RAT-538: Update CasedString for efficency (#626)
25f95abc is described below

commit 25f95abc0f9a574441db16160525ed7e154cf08b
Author: Claude Warren <[email protected]>
AuthorDate: Wed Mar 25 21:50:33 2026 +0100

    RAT-538: Update CasedString for efficency (#626)
    
    * Switched to cased string preserving the parts from the parsing
    * fixed pascal/camel confusion in tests
    * fixed Pascal/Camel case useage confusion
    * fixed Camel/Pascal case confusion in Maven and Ant UI
    ---------
    
    Co-authored-by: P. Ottlinger <[email protected]>
---
 .../org/apache/rat/report/xml/XmlElements.java     |   2 +-
 .../java/org/apache/rat/utils/CasedString.java     | 295 ++++++++++++--------
 .../org/apache/rat/utils/CasedStringTests.java     | 296 +++++++++++++++++++++
 .../rat/documentation/options/AntOption.java       |   2 +-
 apache-rat-tools/src/main/resources/Ant.tpl        |   2 +-
 apache-rat-tools/src/main/resources/Maven.tpl      |   2 +-
 6 files changed, 481 insertions(+), 118 deletions(-)

diff --git 
a/apache-rat-core/src/main/java/org/apache/rat/report/xml/XmlElements.java 
b/apache-rat-core/src/main/java/org/apache/rat/report/xml/XmlElements.java
index e8301aa8..35d14b10 100644
--- a/apache-rat-core/src/main/java/org/apache/rat/report/xml/XmlElements.java
+++ b/apache-rat-core/src/main/java/org/apache/rat/report/xml/XmlElements.java
@@ -43,7 +43,7 @@ public class XmlElements {
      */
     private static String normalizeName(final String name) {
         CasedString casedName = new CasedString(CasedString.StringCase.SNAKE, 
name.toLowerCase(Locale.ROOT));
-       return casedName.toCase(CasedString.StringCase.CAMEL);
+       return casedName.toCase(CasedString.StringCase.PASCAL);
     }
 
     /**
diff --git 
a/apache-rat-core/src/main/java/org/apache/rat/utils/CasedString.java 
b/apache-rat-core/src/main/java/org/apache/rat/utils/CasedString.java
index 79b29d10..6751ad17 100644
--- a/apache-rat-core/src/main/java/org/apache/rat/utils/CasedString.java
+++ b/apache-rat-core/src/main/java/org/apache/rat/utils/CasedString.java
@@ -19,177 +19,244 @@
 package org.apache.rat.utils;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Locale;
+import java.util.Objects;
 import java.util.function.Function;
 import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
 
+import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.text.WordUtils;
 
 /**
  * Handles converting from one string case to another (e.g. camel case to 
snake case).
  * @since 0.17
  */
-public class CasedString {
-    /** the string of the cased format. */
-    private final String string;
-    /** the case of the string. */
+public final class CasedString {
+    /** The segments of the cased string */
+    private final String[] segments;
+    /** The case of the string as parsed */
     private final StringCase stringCase;
+    /** A joiner used for the pascal and camel cases. */
+    private static final Function<String[], String> CAMEL_JOINER = strings -> {
+        StringBuilder sb = new StringBuilder();
+        Arrays.stream(strings).map(s -> s == null ? "" : s).forEach(token -> 
sb.append(WordUtils.capitalize(token.toLowerCase(Locale.ROOT))));
+        return sb.toString();
+    };
 
     /**
-     * A method to join camel string fragments together.
+     * Creates a cased string by parsing the string argument for the specific 
case.
+     * @param stringCase the case of the string being parsed.
+     * @param string the string to parse.
      */
-    private static final Function<String[], String> CAMEL_JOINER = a -> {
-        StringBuilder sb = new StringBuilder(a[0].toLowerCase(Locale.ROOT));
+    public CasedString(final StringCase stringCase, final String string) {
+        this.segments = string == null ? CasedString.StringCase.NULL_SEGMENT : 
stringCase.getSegments(string.trim());
+        this.stringCase = stringCase;
+    }
 
-        for (int i = 1; i < a.length; i++) {
-            sb.append(WordUtils.capitalize(a[i].toLowerCase(Locale.ROOT)));
+    /**
+     * Creates a cased string of the specified case and segments.
+     * @param stringCase the case of the string.
+     * @param segments the segments of the string.
+     */
+    public CasedString(final StringCase stringCase, final String[] segments) {
+        this.segments = segments;
+        this.stringCase = stringCase;
+    }
+
+    /**
+     * Converts this cased string into another format.
+     * @param stringCase the desired format.
+     * @return the new CasedString.
+     */
+    public CasedString as(final StringCase stringCase) {
+        return stringCase.name.equals(this.stringCase.name) ? this : new 
CasedString(stringCase, (String[]) Arrays.copyOf(this.segments, 
this.segments.length));
+    }
+
+    /**
+     * Gets the segments of this cased string.
+     * @return the segments of this cased string.
+     */
+    public String[] getSegments() {
+        return this.segments;
+    }
+
+    /**
+     * Generates a string from this cased string but with the desired case.
+     * @param stringCase the desired case.
+     * @return this cased string in the desired case.
+     */
+    public String toCase(final StringCase stringCase) {
+        return this.segments == CasedString.StringCase.NULL_SEGMENT ? null : 
stringCase.assemble(this.getSegments());
+    }
+
+    @Override
+    public String toString() {
+        return this.toCase(this.stringCase);
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (o == null || getClass() != o.getClass()) {
+            return false;
         }
-        return sb.toString();
-    };
+        CasedString that = (CasedString) o;
+        return Objects.deepEquals(getSegments(), that.getSegments()) && 
Objects.equals(stringCase, that.stringCase);
+    }
+
+    @Override
+    public int hashCode() {
+        return Arrays.hashCode(getSegments());
+    }
 
     /**
-     * An enumeration of supported string cases.  These cases tag strings as 
having a specific format.
+     * The definition of a string case.
      */
-    public enum StringCase {
-        /**
-         * Camel case tags strings like 'CamelCase' or 'camelCase'. This 
conversion forces the first character to
-         * lower case. If specific capitalization rules are required use 
{@link WordUtils#capitalize(String)} to set the first
-         * character of the string.
+    public static final class StringCase {
+        /** The camel case. Example: "HelloWorld"*/
+        public static final StringCase CAMEL;
+        /** The pascal case. Example: "helloWorld" */
+        public static final StringCase PASCAL;
+        /** The Snake case. Example: "hello_world" */
+        public static final StringCase SNAKE;
+        /** The Kebab case. Example: "hello-world" */
+        public static final StringCase KEBAB;
+        /** The phrase case. Example: "hello world" */
+        public static final StringCase PHRASE;
+        /** The dot case. Example: "hello.world" */
+        public static final StringCase DOT;
+        /** The slash case. Example: "hello/world" */
+        public static final StringCase SLASH;
+        /** A marker for the parsing of a NULL string. */
+        static final String[] NULL_SEGMENT;
+        /** An empty segment marker. */
+        static final String[] EMPTY_SEGMENT;
+        /** The name of this case */
+        private final String name;
+        /** The predicate that determines if a character is a splitter 
character. A splitter character
+         * is the character that signals the start of a new segment.
          */
-        CAMEL(Character::isUpperCase, true, CAMEL_JOINER),
-        /**
-         * Snake case tags strings like 'Snake_Case'.  This conversion does 
not change the capitalization of any characters
-         * in the string.  If specific capitalization is required use {@link 
String#toUpperCase()}, {@link String#toLowerCase()},
-         * or the commons-text methods {@link WordUtils#capitalize(String)}, 
or {@link WordUtils#uncapitalize(String)} as required.
-         */
-        SNAKE(c -> c == '_', false, a -> String.join("_", a)),
+        private final Predicate<Character> splitter;
         /**
-         * Kebab case tags strings like 'kebab-case'.  This conversion does 
not change the capitalization of any characters
-         * in the string.  If specific capitalization is required use {@link 
String#toUpperCase()}, {@link String#toLowerCase()},
-         *          * or the commons-text methods {@link 
WordUtils#capitalize(String)}, or {@link WordUtils#uncapitalize(String)} as 
required.
+         * If {@code true}, the splitter character is preserved as part of the 
subsequent section otherwise,
+         * the splitter character is discarded.
          */
-        KEBAB(c -> c == '-', false, a -> String.join("-", a)),
+        private final boolean preserveSplit;
+        /** The function that converts segments into the String representation 
*/
+        private final Function<String[], String> joiner;
+        /** A function to provide post-processing on the joined string */
+        private final UnaryOperator<String> postProcess;
 
         /**
-         * Phrase case tags phrases of words like 'phrase case'. This 
conversion does not change the capitalization of any characters
-         * in the string.  If specific capitalization is required use {@link 
String#toUpperCase()}, {@link String#toLowerCase()},
-         *          * or the commons-text methods {@link 
WordUtils#capitalize(String)}, or {@link WordUtils#uncapitalize(String)} as 
required.
+         * Constructs a StringCase
+         * @param name the name of the case.
+         * @param splitter the splitter to determine when to split a string.
+         * @param preserveSplit the preserveSplit flag.
+         * @param joiner the joiner to assemble the String from the segments.
          */
-        PHRASE(Character::isWhitespace, false, a -> String.join(" ", a)),
+        public StringCase(final String name, final Predicate<Character> 
splitter, final boolean preserveSplit, final Function<String[], String> joiner) 
{
+            this(name, splitter, preserveSplit, joiner, 
UnaryOperator.identity());
+        }
 
         /**
-         * Dot case tags phrases of words like 'phrase.case'. This conversion 
does not change the capitalization of any characters
-         * in the string.  If specific capitalization is required use {@link 
String#toUpperCase()}, {@link String#toLowerCase()},
-         *          * or the commons-text methods {@link 
WordUtils#capitalize(String)}, or {@link WordUtils#uncapitalize(String)} as 
required.
+         * Constructs a String case for the common cases where the delimiter 
is not preserved in the segments.
+         * @param name the name of the case.
+         * @param delimiter the delimter between segments.
          */
-        DOT(c -> c == '.', false, a -> String.join(".", a));
-
-        /** The segment value for a null string */
-        private static final String[] NULL_SEGMENT = new String[0];
-        /** The segment value for an empty string */
-        private static final String[] EMPTY_SEGMENT = {""};
-
-        /** test for split position character. */
-        private final Predicate<Character> splitter;
-        /** if {@code true} split position character will be preserved in 
following segment. */
-        private final boolean preserveSplit;
-        /** a function to joining the segments into this case type. */
-        private final Function<String[], String> joiner;
+        public StringCase(final String name, final char delimiter) {
+            this(name, c -> c == delimiter, false, simpleJoiner(delimiter));
+        }
 
         /**
-         * Defines a String Case.
-         * @param splitter The predicate that determines when a new word in 
the cased string begins.
-         * @param preserveSplit if {@code true} the character that the 
splitter detected is preserved as the first character of the new word.
-         * @param joiner The function to merge a list of strings into the 
cased String.
+         * Constructs a StingCase.
+         * @param name the name of the string case.
+         * @param splitter the splitter to detect segments.
+         * @param preserveSplit the flag to preserve the splitter character.
+         * @param joiner the joiner to assemble a String from segments.
+         * @param postProcess the post-process applied to the segments after 
the splitter has created them.
          */
-        StringCase(final Predicate<Character> splitter, final boolean 
preserveSplit, final Function<String[], String> joiner) {
+        public StringCase(final String name, final Predicate<Character> 
splitter, final boolean preserveSplit, final Function<String[], String> joiner,
+                          final UnaryOperator<String> postProcess) {
+            this.name = name;
             this.splitter = splitter;
             this.preserveSplit = preserveSplit;
             this.joiner = joiner;
+            this.postProcess = postProcess;
         }
 
         /**
-         * Creates a cased string from a collection of segments.
-         * @param segments the segments to create the CasedString from.
-         * @return a CasedString
+         * A simple joiner that assembles a String from a collection of 
segments.
+         * Correctly handles the case where there are zero length segments.
+         * @param delimiter the delimiter to use between the segments.
+         * @return the assembled string.
+         */
+        public static Function<String[], String> simpleJoiner(final char 
delimiter) {
+            return s -> String.join(String.valueOf(delimiter), 
(CharSequence[]) 
Arrays.stream(s).filter(Objects::nonNull).toArray(String[]::new));
+        }
+
+        @Override
+        public String toString() {
+            return this.name;
+        }
+
+        /**
+         * Assembles segments into a String.
+         * @param segments the segments to assemble.
+         * @return the complete String.
          */
         public String assemble(final String[] segments) {
-            return segments.length == 0 ? null : this.joiner.apply(segments);
+            return this.joiner.apply(segments);
         }
 
         /**
-         * Returns an array of each of the segments in this CasedString.  
Segments are defined as the strings between
-         * the separators in the CasedString. For the CAMEL case the segments 
are determined by the presence of a capital letter.
-         * @return the array of Strings that are segments of the cased string.
+         * Parses a String into segments.
+         * @param string the string to parse
+         * @return the segments from the string.
          */
         public String[] getSegments(final String string) {
             if (string == null) {
                 return NULL_SEGMENT;
-            }
-            if (string.isEmpty()) {
+            } else if (string.isEmpty()) {
                 return EMPTY_SEGMENT;
-            }
-            List<String> lst = new ArrayList<>();
-            StringBuilder sb = new StringBuilder();
-            for (char c : string.toCharArray()) {
-                if (splitter.test(c)) {
-                    if (!sb.isEmpty()) {
+            } else {
+                List<String> lst = new ArrayList<>();
+                StringBuilder sb = new StringBuilder();
+
+                for (char c : string.toCharArray()) {
+                    if (this.splitter.test(c)) {
                         lst.add(sb.toString());
                         sb.setLength(0);
-                    }
-                    if (preserveSplit) {
+                        if (this.preserveSplit) {
+                            sb.append(c);
+                        }
+                    } else {
                         sb.append(c);
                     }
-                } else {
-                    sb.append(c);
                 }
+
+                if (!sb.isEmpty()) {
+                    lst.add(sb.toString());
+                }
+
+                return 
lst.stream().map(this.postProcess).filter(Objects::nonNull).toArray(String[]::new);
             }
-            if (!sb.isEmpty()) {
-                lst.add(sb.toString());
-            }
-            return lst.toArray(new String[0]);
         }
-    }
-
-    /**
-     * A representation of a cased string and the identified case of that 
string.
-     * @param stringCase The {@code StringCase} that the {@code string} 
argument is in.
-     * @param string The string.
-     */
-    public CasedString(final StringCase stringCase, final String string) {
-        this.string = string == null ? null : 
stringCase.assemble(stringCase.getSegments(string.trim()));
-        this.stringCase = stringCase;
-    }
 
-    /**
-     * Returns an array of each of the segments in this CasedString.  Segments 
are defined as the strings between
-     * the separators in the CasedString.  For the CAMEL case the segments are 
determined by the presence of a capital letter.
-     * @return the array of Strings that are segments of the cased string.
-     */
-    public String[] getSegments() {
-        return stringCase.getSegments(string);
-    }
 
-    /**
-     * Converts this cased string into a {@code String} of another format.
-     * The upper/lower case of the characters within the string are not 
modified.
-     * @param stringCase The format to convert to.
-     * @return the String current string represented in the new format.
-     */
-    public String toCase(final StringCase stringCase) {
-        if (stringCase == this.stringCase) {
-            return string;
+        static {
+            CAMEL = new StringCase("CAMEL", Character::isUpperCase, true, 
CasedString.CAMEL_JOINER,
+                    x -> (String) StringUtils.defaultIfEmpty(x, (CharSequence) 
null));
+            PASCAL = new StringCase("PASCAL", Character::isUpperCase, true, 
CasedString.CAMEL_JOINER.andThen(WordUtils::uncapitalize),
+                    x -> (String) StringUtils.defaultIfEmpty(x, (CharSequence) 
null));
+            SNAKE = new StringCase("SNAKE", '_');
+            KEBAB = new StringCase("KEBAB", '-');
+            PHRASE = new StringCase("PHRASE", Character::isWhitespace, false, 
simpleJoiner(' '));
+            DOT = new StringCase("DOT", '.');
+            SLASH = new StringCase("SLASH", '/');
+            NULL_SEGMENT = new String[0];
+            EMPTY_SEGMENT = new String[]{""};
         }
-        return string == null ? null : stringCase.joiner.apply(getSegments());
-    }
-
-    /**
-     * Returns the string representation provided in the constructor.
-     * @return the string representation.
-     */
-    @Override
-    public String toString() {
-        return string;
     }
 }
diff --git 
a/apache-rat-core/src/test/java/org/apache/rat/utils/CasedStringTests.java 
b/apache-rat-core/src/test/java/org/apache/rat/utils/CasedStringTests.java
new file mode 100644
index 00000000..f69c1160
--- /dev/null
+++ b/apache-rat-core/src/test/java/org/apache/rat/utils/CasedStringTests.java
@@ -0,0 +1,296 @@
+/*
+ * 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.rat.utils;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class CasedStringTests {
+
+    @MethodSource("testSegmentationData")
+    @ParameterizedTest
+    void testSegmentation(String pattern, CasedString.StringCase stringCase, 
String[] expected) {
+        CasedString casedString = new CasedString(stringCase, pattern);
+        assertThat(casedString.getSegments()).isEqualTo(expected);
+    }
+
+    static Stream<Arguments> testSegmentationData() {
+        List<Arguments> lst = new ArrayList<>();
+        lst.add(Arguments.of("CamelCase", CasedString.StringCase.CAMEL, new 
String[]{"Camel", "Case"}));
+        lst.add(Arguments.of("CamelPMDCase", CasedString.StringCase.CAMEL,
+                new String[]{"Camel", "P", "M", "D", "Case"}));
+        lst.add(Arguments.of("camelCase", CasedString.StringCase.CAMEL, new 
String[]{"camel", "Case"}));
+        lst.add(Arguments.of("camelPMDCase", CasedString.StringCase.CAMEL,
+                new String[]{"camel", "P", "M", "D", "Case"}));
+        lst.add(Arguments.of("PascalCase", CasedString.StringCase.PASCAL, new 
String[]{"Pascal", "Case"}));
+        lst.add(Arguments.of("PascalPMDCase", CasedString.StringCase.PASCAL,
+                new String[]{"Pascal", "P", "M", "D", "Case"}));
+        lst.add(Arguments.of("pascalCase", CasedString.StringCase.PASCAL, new 
String[]{"pascal", "Case"}));
+        lst.add(Arguments.of("pascalPMDCase", CasedString.StringCase.PASCAL,
+                new String[]{"pascal", "P", "M", "D", "Case"}));
+        lst.add(Arguments.of("snake_case", CasedString.StringCase.SNAKE, new 
String[]{"snake", "case"}));
+        lst.add(Arguments.of("snake_Case", CasedString.StringCase.SNAKE, new 
String[]{"snake", "Case"}));
+        lst.add(Arguments.of("snake__Case", CasedString.StringCase.SNAKE, new 
String[]{"snake", "", "Case"}));
+        lst.add(Arguments.of("kebab-case", CasedString.StringCase.KEBAB, new 
String[]{"kebab", "case"}));
+        lst.add(Arguments.of("kebab-Case", CasedString.StringCase.KEBAB, new 
String[]{"kebab", "Case"}));
+        lst.add(Arguments.of("kebab--case", CasedString.StringCase.KEBAB, new 
String[]{"kebab", "", "case"}));
+        lst.add(Arguments.of("phrase case", CasedString.StringCase.PHRASE, new 
String[]{"phrase", "case"}));
+        lst.add(Arguments.of("phrase Case", CasedString.StringCase.PHRASE, new 
String[]{"phrase", "Case"}));
+        lst.add(Arguments.of("phrase  case", CasedString.StringCase.PHRASE, 
new String[]{"phrase", "", "case"}));
+        lst.add(Arguments.of("dot.case", CasedString.StringCase.DOT, new 
String[]{"dot", "case"}));
+        lst.add(Arguments.of("dot..case", CasedString.StringCase.DOT, new 
String[]{"dot", "", "case"}));
+        lst.add(Arguments.of("dot.Case", CasedString.StringCase.DOT, new 
String[]{"dot", "Case"}));
+        return lst.stream();
+    }
+
+    @MethodSource("testToCaseData")
+    @ParameterizedTest(name = "{index} {0} {1}")
+    void testToCase(CasedString casedString, CasedString.StringCase 
stringCase, String expected) {
+        assertThat(casedString.toCase(stringCase)).isEqualTo(expected);
+    }
+
+    static Stream<Arguments> testToCaseData() {
+        List<Arguments> lst = new ArrayList<>();
+
+        CasedString underTest = new CasedString(CasedString.StringCase.PASCAL, 
"camelCase");
+        lst.add(Arguments.of(underTest, CasedString.StringCase.PASCAL, 
"camelCase"));
+        lst.add(Arguments.of(underTest, CasedString.StringCase.SNAKE, 
"camel_Case"));
+        lst.add(Arguments.of(underTest, CasedString.StringCase.KEBAB, 
"camel-Case"));
+        lst.add(Arguments.of(underTest, CasedString.StringCase.PHRASE, "camel 
Case"));
+        lst.add(Arguments.of(underTest, CasedString.StringCase.DOT, 
"camel.Case"));
+        lst.add(Arguments.of(underTest, CasedString.StringCase.CAMEL, 
"CamelCase"));
+
+        underTest = new CasedString(CasedString.StringCase.SNAKE, 
"snake_case");
+        lst.add(Arguments.of(underTest, CasedString.StringCase.PASCAL, 
"snakeCase"));
+        lst.add(Arguments.of(underTest, CasedString.StringCase.SNAKE, 
"snake_case"));
+        lst.add(Arguments.of(underTest, CasedString.StringCase.KEBAB, 
"snake-case"));
+        lst.add(Arguments.of(underTest, CasedString.StringCase.PHRASE, "snake 
case"));
+        lst.add(Arguments.of(underTest, CasedString.StringCase.DOT, 
"snake.case"));
+        lst.add(Arguments.of(underTest, CasedString.StringCase.CAMEL, 
"SnakeCase"));
+
+        underTest = new CasedString(CasedString.StringCase.KEBAB, 
"kebab-case");
+        lst.add(Arguments.of(underTest, CasedString.StringCase.PASCAL, 
"kebabCase"));
+        lst.add(Arguments.of(underTest, CasedString.StringCase.SNAKE, 
"kebab_case"));
+        lst.add(Arguments.of(underTest, CasedString.StringCase.KEBAB, 
"kebab-case"));
+        lst.add(Arguments.of(underTest, CasedString.StringCase.PHRASE, "kebab 
case"));
+        lst.add(Arguments.of(underTest, CasedString.StringCase.DOT, 
"kebab.case"));
+        lst.add(Arguments.of(underTest, CasedString.StringCase.CAMEL, 
"KebabCase"));
+
+        underTest = new CasedString(CasedString.StringCase.PHRASE, "phrase 
case");
+        lst.add(Arguments.of(underTest, CasedString.StringCase.PASCAL, 
"phraseCase"));
+        lst.add(Arguments.of(underTest, CasedString.StringCase.SNAKE, 
"phrase_case"));
+        lst.add(Arguments.of(underTest, CasedString.StringCase.KEBAB, 
"phrase-case"));
+        lst.add(Arguments.of(underTest, CasedString.StringCase.PHRASE, "phrase 
case"));
+        lst.add(Arguments.of(underTest, CasedString.StringCase.DOT, 
"phrase.case"));
+        lst.add(Arguments.of(underTest, CasedString.StringCase.CAMEL, 
"PhraseCase"));
+
+        underTest = new CasedString(CasedString.StringCase.DOT, "dot.case");
+        lst.add(Arguments.of(underTest, CasedString.StringCase.PASCAL, 
"dotCase"));
+        lst.add(Arguments.of(underTest, CasedString.StringCase.SNAKE, 
"dot_case"));
+        lst.add(Arguments.of(underTest, CasedString.StringCase.KEBAB, 
"dot-case"));
+        lst.add(Arguments.of(underTest, CasedString.StringCase.PHRASE, "dot 
case"));
+        lst.add(Arguments.of(underTest, CasedString.StringCase.DOT, 
"dot.case"));
+        lst.add(Arguments.of(underTest, CasedString.StringCase.CAMEL, 
"DotCase"));
+
+        underTest = new CasedString(CasedString.StringCase.PASCAL, 
"pascalCase");
+        lst.add(Arguments.of(underTest, CasedString.StringCase.PASCAL, 
"pascalCase"));
+        lst.add(Arguments.of(underTest, CasedString.StringCase.SNAKE, 
"pascal_Case"));
+        lst.add(Arguments.of(underTest, CasedString.StringCase.KEBAB, 
"pascal-Case"));
+        lst.add(Arguments.of(underTest, CasedString.StringCase.PHRASE, "pascal 
Case"));
+        lst.add(Arguments.of(underTest, CasedString.StringCase.DOT, 
"pascal.Case"));
+        lst.add(Arguments.of(underTest, CasedString.StringCase.CAMEL, 
"PascalCase"));
+
+        underTest = new CasedString(CasedString.StringCase.DOT, "one..two");
+        lst.add(Arguments.of(underTest, CasedString.StringCase.PASCAL, 
"oneTwo"));
+        lst.add(Arguments.of(underTest, CasedString.StringCase.SNAKE, 
"one__two"));
+        lst.add(Arguments.of(underTest, CasedString.StringCase.KEBAB, 
"one--two"));
+        lst.add(Arguments.of(underTest, CasedString.StringCase.PHRASE, "one  
two"));
+        lst.add(Arguments.of(underTest, CasedString.StringCase.DOT, 
"one..two"));
+        lst.add(Arguments.of(underTest, CasedString.StringCase.CAMEL, 
"OneTwo"));
+
+        return lst.stream();
+    }
+
+    @MethodSource("testAssembleData")
+    @ParameterizedTest(name = "{index} {0} {1}")
+    void testAssemble(CasedString.StringCase underTest, String[] data, String 
expected) {
+        assertThat(underTest.assemble(data)).isEqualTo(expected);
+    }
+
+    static Stream<Arguments> testAssembleData() {
+        List<Arguments> lst = new ArrayList<>();
+        String[] emptyFirst = {"", "one", "two"};
+        String[] emptyMiddle = {"one", "", "two"};
+        String[] emptyEnd = {"one", "two", ""};
+        String[] nullFirst = {null, "one", "two"};
+        String[] nullMiddle = {"one", null, "two"};
+        String[] nullEnd = {"one", "two", null};
+        String[] doubleEmpty = {"one", "", "", "two"};
+        String[] doubleNull = {"one", null, null, "two"};
+
+        CasedString.StringCase underTest = CasedString.StringCase.PASCAL;
+        lst.add(Arguments.of(underTest, emptyFirst, "oneTwo"));
+        lst.add(Arguments.of(underTest, emptyMiddle, "oneTwo"));
+        lst.add(Arguments.of(underTest, emptyEnd, "oneTwo"));
+        lst.add(Arguments.of(underTest, nullFirst, "oneTwo"));
+        lst.add(Arguments.of(underTest, nullMiddle, "oneTwo"));
+        lst.add(Arguments.of(underTest, nullEnd, "oneTwo"));
+        lst.add(Arguments.of(underTest, doubleEmpty, "oneTwo"));
+        lst.add(Arguments.of(underTest, doubleNull, "oneTwo"));
+
+        underTest = CasedString.StringCase.CAMEL;
+        lst.add(Arguments.of(underTest, emptyFirst, "OneTwo"));
+        lst.add(Arguments.of(underTest, emptyMiddle, "OneTwo"));
+        lst.add(Arguments.of(underTest, emptyEnd, "OneTwo"));
+        lst.add(Arguments.of(underTest, nullFirst, "OneTwo"));
+        lst.add(Arguments.of(underTest, nullMiddle, "OneTwo"));
+        lst.add(Arguments.of(underTest, nullEnd, "OneTwo"));
+        lst.add(Arguments.of(underTest, doubleEmpty, "OneTwo"));
+        lst.add(Arguments.of(underTest, doubleNull, "OneTwo"));
+
+        underTest = CasedString.StringCase.SNAKE;
+        lst.add(Arguments.of(underTest, emptyFirst, "_one_two"));
+        lst.add(Arguments.of(underTest, emptyMiddle, "one__two"));
+        lst.add(Arguments.of(underTest, emptyEnd, "one_two_"));
+        lst.add(Arguments.of(underTest, nullFirst, "one_two"));
+        lst.add(Arguments.of(underTest, nullMiddle, "one_two"));
+        lst.add(Arguments.of(underTest, nullEnd, "one_two"));
+        lst.add(Arguments.of(underTest, doubleEmpty, "one___two"));
+        lst.add(Arguments.of(underTest, doubleNull, "one_two"));
+
+        underTest = CasedString.StringCase.KEBAB;
+        lst.add(Arguments.of(underTest, emptyFirst, "-one-two"));
+        lst.add(Arguments.of(underTest, emptyMiddle, "one--two"));
+        lst.add(Arguments.of(underTest, emptyEnd, "one-two-"));
+        lst.add(Arguments.of(underTest, nullFirst, "one-two"));
+        lst.add(Arguments.of(underTest, nullMiddle, "one-two"));
+        lst.add(Arguments.of(underTest, nullEnd, "one-two"));
+        lst.add(Arguments.of(underTest, doubleEmpty, "one---two"));
+        lst.add(Arguments.of(underTest, doubleNull, "one-two"));
+
+        underTest = CasedString.StringCase.PHRASE;
+        lst.add(Arguments.of(underTest, emptyFirst, " one two"));
+        lst.add(Arguments.of(underTest, emptyMiddle, "one  two"));
+        lst.add(Arguments.of(underTest, emptyEnd, "one two "));
+        lst.add(Arguments.of(underTest, nullFirst, "one two"));
+        lst.add(Arguments.of(underTest, nullMiddle, "one two"));
+        lst.add(Arguments.of(underTest, nullEnd, "one two"));
+        lst.add(Arguments.of(underTest, doubleEmpty, "one   two"));
+        lst.add(Arguments.of(underTest, doubleNull, "one two"));
+
+        underTest = CasedString.StringCase.DOT;
+        lst.add(Arguments.of(underTest, emptyFirst, ".one.two"));
+        lst.add(Arguments.of(underTest, emptyMiddle, "one..two"));
+        lst.add(Arguments.of(underTest, emptyEnd, "one.two."));
+        lst.add(Arguments.of(underTest, nullFirst, "one.two"));
+        lst.add(Arguments.of(underTest, nullMiddle, "one.two"));
+        lst.add(Arguments.of(underTest, nullEnd, "one.two"));
+        lst.add(Arguments.of(underTest, doubleEmpty, "one...two"));
+        lst.add(Arguments.of(underTest, doubleNull, "one.two"));
+
+        underTest = CasedString.StringCase.SLASH;
+        lst.add(Arguments.of(underTest, emptyFirst, "/one/two"));
+        lst.add(Arguments.of(underTest, emptyMiddle, "one//two"));
+        lst.add(Arguments.of(underTest, emptyEnd, "one/two/"));
+        lst.add(Arguments.of(underTest, nullFirst, "one/two"));
+        lst.add(Arguments.of(underTest, nullMiddle, "one/two"));
+        lst.add(Arguments.of(underTest, nullEnd, "one/two"));
+        lst.add(Arguments.of(underTest, doubleEmpty, "one///two"));
+        lst.add(Arguments.of(underTest, doubleNull, "one/two"));
+
+        return lst.stream();
+    }
+
+    @Test
+    void asTest() {
+        CasedString underTest = new CasedString(CasedString.StringCase.CAMEL, 
"camelCase");
+        
assertThat(underTest.as(CasedString.StringCase.CAMEL)).isEqualTo(underTest);
+        CasedString expected = new CasedString(CasedString.StringCase.KEBAB, 
"camel-Case");
+        
assertThat(underTest.as(CasedString.StringCase.KEBAB)).isEqualTo(expected);
+        underTest.getSegments()[0] = "Cow";
+        assertThat(expected.getSegments()[0]).as("verify segments not 
shared").isEqualTo("camel");
+    }
+
+    @Test
+    void testHashCode() {
+        CasedString s1 = new CasedString(CasedString.StringCase.KEBAB, 
"the-test-string");
+        CasedString s2 = new CasedString(CasedString.StringCase.DOT, 
"the.test.string");
+        CasedString s3 = new CasedString(CasedString.StringCase.SLASH, 
"the/test/String");
+        assertThat(s1).hasSameHashCodeAs(s2);
+        assertThat(s1.hashCode()).isNotEqualTo(s3.hashCode());
+    }
+
+    @Test
+    void testSegmentConstructor() {
+        CasedString s1 = new CasedString(CasedString.StringCase.KEBAB, new 
String[]{"the", "test", "string"});
+        CasedString s2 = new CasedString(CasedString.StringCase.KEBAB, 
"the-test-string");
+        assertThat(s1).isEqualTo(s2);
+        CasedString s3 = new CasedString(CasedString.StringCase.DOT, new 
String[]{"the", "test", "string"});
+        assertThat(s1).isNotEqualTo(s3);
+    }
+
+    @Test
+    void testNullValue() {
+        CasedString nullValue = new CasedString(CasedString.StringCase.CAMEL, 
(String) null);
+        
assertThat(nullValue.getSegments()).isEqualTo(CasedString.StringCase.NULL_SEGMENT);
+        assertThat(nullValue.toString()).isNull();
+        
assertThat(nullValue.as(CasedString.StringCase.DOT).getSegments()).isEqualTo(CasedString.StringCase.NULL_SEGMENT);
+        assertThat(nullValue.toCase(CasedString.StringCase.DOT)).isNull();
+        assertThat(nullValue).isEqualTo(new 
CasedString(CasedString.StringCase.CAMEL, (String) null))
+                        .isNotEqualTo(new 
CasedString(CasedString.StringCase.CAMEL, ""));
+    }
+
+    @Test
+    void testEmptyString() {
+        CasedString emptyValue = new CasedString(CasedString.StringCase.CAMEL, 
"");
+        
assertThat(emptyValue.getSegments()).isEqualTo(CasedString.StringCase.EMPTY_SEGMENT);
+        assertThat(emptyValue.toString()).isEmpty();
+        
assertThat(emptyValue.as(CasedString.StringCase.DOT).getSegments()).isEqualTo(CasedString.StringCase.EMPTY_SEGMENT);
+        assertThat(emptyValue.toCase(CasedString.StringCase.DOT)).isEmpty();
+        assertThat(emptyValue).isEqualTo(new 
CasedString(CasedString.StringCase.CAMEL, ""))
+                .isNotEqualTo(new CasedString(CasedString.StringCase.CAMEL, 
(String)null));
+    }
+
+    @Test
+    void testCamel() {
+        CasedString underTest = new CasedString(CasedString.StringCase.CAMEL, 
"camelCase");
+        assertThat(underTest).hasToString("CamelCase");
+        assertThat(underTest.getSegments()).isEqualTo(new String[]{"camel", 
"Case"});
+        underTest = new CasedString(CasedString.StringCase.CAMEL, new 
String[]{"camel", "case"});
+        assertThat(underTest).hasToString("CamelCase");
+
+    }
+
+    @Test
+    void testPascal() {
+        CasedString underTest = new CasedString(CasedString.StringCase.PASCAL, 
"PascalCase");
+        assertThat(underTest).hasToString("pascalCase");
+        assertThat(underTest.getSegments()).isEqualTo(new String[]{"Pascal", 
"Case"});
+        underTest = new CasedString(CasedString.StringCase.PASCAL, new 
String[]{"pascal", "case"});
+        assertThat(underTest).hasToString("pascalCase");
+    }
+}
diff --git 
a/apache-rat-tools/src/main/java/org/apache/rat/documentation/options/AntOption.java
 
b/apache-rat-tools/src/main/java/org/apache/rat/documentation/options/AntOption.java
index 7cbfa16c..38e88ba2 100644
--- 
a/apache-rat-tools/src/main/java/org/apache/rat/documentation/options/AntOption.java
+++ 
b/apache-rat-tools/src/main/java/org/apache/rat/documentation/options/AntOption.java
@@ -210,7 +210,7 @@ public class AntOption extends AbstractOption {
     public static String createName(final Option option) {
         String name = option.getLongOpt();
         name = StringUtils.defaultIfEmpty(RENAME_MAP.get(name), 
name).toLowerCase(Locale.ROOT);
-        return new CasedString(CasedString.StringCase.KEBAB, 
name).toCase(CasedString.StringCase.CAMEL);
+        return new CasedString(CasedString.StringCase.KEBAB, 
name).toCase(CasedString.StringCase.PASCAL);
     }
 
     /**
diff --git a/apache-rat-tools/src/main/resources/Ant.tpl 
b/apache-rat-tools/src/main/resources/Ant.tpl
index 952f4551..cc43adfb 100644
--- a/apache-rat-tools/src/main/resources/Ant.tpl
+++ b/apache-rat-tools/src/main/resources/Ant.tpl
@@ -58,7 +58,7 @@ ${static}
 
     public static String createName(String longOpt) {
         String name = StringUtils.defaultIfEmpty(xlateName.get(longOpt), 
longOpt).toLowerCase(Locale.ROOT);
-        return new CasedString(CasedString.StringCase.KEBAB, 
name).toCase(CasedString.StringCase.CAMEL);
+        return new CasedString(CasedString.StringCase.KEBAB, 
name).toCase(CasedString.StringCase.PASCAL);
     }
 
     public static List<String> unsupportedArgs() {
diff --git a/apache-rat-tools/src/main/resources/Maven.tpl 
b/apache-rat-tools/src/main/resources/Maven.tpl
index c1bc2c19..0c6cc9a7 100644
--- a/apache-rat-tools/src/main/resources/Maven.tpl
+++ b/apache-rat-tools/src/main/resources/Maven.tpl
@@ -62,7 +62,7 @@ ${static}
      */
     public static String createName(String longOpt) {
         String name = xlateName.get(longOpt);
-        return name != null ? name : new 
CasedString(CasedString.StringCase.KEBAB, 
longOpt).toCase(CasedString.StringCase.CAMEL);
+        return name != null ? name : new 
CasedString(CasedString.StringCase.KEBAB, 
longOpt).toCase(CasedString.StringCase.PASCAL);
     }
 
     /**


Reply via email to