Refactor: extract TextUtils from StringUtils

The TextUtils class has been extracted from StringUtils to handle
methods specific to text management, enhancing class segregation.
Additionally, the inline code delimiter ("`") and the code delimiter
sequence ("```") have been centralized within TextUtils to enhance code
maintainability.

Jira-Id: IT-103
Change-Id: I54b39220376a91d86e41a02ea232c019e5de075b
Signed-off-by: Patrizio <patrizio.gelosi@amarulasolutions.com>
diff --git a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/client/DebugComment.java b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/client/DebugComment.java
index 428f9af..b32bea8 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/client/DebugComment.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/client/DebugComment.java
@@ -6,23 +6,21 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import static com.googlesource.gerrit.plugins.chatgpt.utils.StringUtils.joinWithNewLine;
-import static com.googlesource.gerrit.plugins.chatgpt.utils.StringUtils.prettyStringifyObject;
+import static com.googlesource.gerrit.plugins.chatgpt.utils.TextUtils.*;
 
 public class DebugComment {
     private static final String OPENING_TITLE = "DEBUGGING DETAILS";
-    private static final String COMMENT_OPENING = "\n\n```\n" + OPENING_TITLE + "\n";
+    private static final String COMMENT_OPENING = CODE_DELIMITER_BEGIN + OPENING_TITLE + "\n";
     private static final String HIDDEN_REPLY = "hidden: %s";
-    private static final String COMMENT_CLOSING = "```";
-    private static final Pattern DEBUG_MESSAGE_PATTERN = Pattern.compile("\\s+```\\s*" + OPENING_TITLE + ".*```\\s*",
-            Pattern.DOTALL);
+    private static final Pattern DEBUG_MESSAGE_PATTERN = Pattern.compile("\\s+" + CODE_DELIMITER +"\\s*" +
+                    OPENING_TITLE + ".*" + CODE_DELIMITER + "\\s*", Pattern.DOTALL);
 
     public static String getDebugMessage(ChatGptReplyItem replyItem, boolean isHidden) {
         return joinWithNewLine(new ArrayList<>() {{
             add(COMMENT_OPENING);
             add(String.format(HIDDEN_REPLY, isHidden));
             add(prettyStringifyObject(replyItem));
-            add(COMMENT_CLOSING);
+            add(CODE_DELIMITER);
         }});
     }
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/client/patch/code/InlineCode.java b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/client/patch/code/InlineCode.java
index 6d669b3..25f556b 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/client/patch/code/InlineCode.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/client/patch/code/InlineCode.java
@@ -10,7 +10,7 @@
 import java.util.List;
 import java.util.Optional;
 
-import static com.googlesource.gerrit.plugins.chatgpt.utils.StringUtils.joinWithNewLine;
+import static com.googlesource.gerrit.plugins.chatgpt.utils.TextUtils.joinWithNewLine;
 
 @Slf4j
 public class InlineCode {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/client/patch/diff/FileDiffProcessed.java b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/client/patch/diff/FileDiffProcessed.java
index 9bfeb8a..70f725b 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/client/patch/diff/FileDiffProcessed.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/client/patch/diff/FileDiffProcessed.java
@@ -14,7 +14,7 @@
 import java.util.List;
 import java.util.TreeMap;
 
-import static com.googlesource.gerrit.plugins.chatgpt.utils.StringUtils.joinWithNewLine;
+import static com.googlesource.gerrit.plugins.chatgpt.utils.TextUtils.joinWithNewLine;
 
 @Slf4j
 public class FileDiffProcessed {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/client/prompt/ChatGptPrompt.java b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/client/prompt/ChatGptPrompt.java
index 1ae8600..f72923a 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/client/prompt/ChatGptPrompt.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/client/prompt/ChatGptPrompt.java
@@ -15,13 +15,12 @@
 import java.util.*;
 import java.util.stream.Collectors;
 
-import static com.googlesource.gerrit.plugins.chatgpt.utils.StringUtils.*;
+import static com.googlesource.gerrit.plugins.chatgpt.utils.TextUtils.*;
 
 @Slf4j
 public class ChatGptPrompt {
     public static final String SPACE = " ";
     public static final String DOT = ". ";
-    public static final String BACKTICK = "`";
 
     // Reply attributes
     public static final String ATTRIBUTE_ID = "id";
@@ -143,7 +142,7 @@
         Map<String, String> attributes = DEFAULT_GPT_REPLIES_ATTRIBUTES.entrySet().stream()
                 .filter(entry -> orderedFilterFields.contains(entry.getKey()))
                 .collect(Collectors.toMap(
-                        entry -> BACKTICK + entry.getKey() + BACKTICK,
+                        entry -> INLINE_CODE_DELIMITER + entry.getKey() + INLINE_CODE_DELIMITER,
                         Map.Entry::getValue,
                         (oldValue, newValue) -> oldValue,
                         LinkedHashMap::new
diff --git a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/client/prompt/MessageSanitizer.java b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/client/prompt/MessageSanitizer.java
index fb16356..fe20cef 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/client/prompt/MessageSanitizer.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/client/prompt/MessageSanitizer.java
@@ -3,8 +3,7 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import static com.googlesource.gerrit.plugins.chatgpt.utils.StringUtils.parseOutOfDelimiters;
-import static com.googlesource.gerrit.plugins.chatgpt.utils.StringUtils.backslashEachChar;
+import static com.googlesource.gerrit.plugins.chatgpt.utils.TextUtils.*;
 
 public class MessageSanitizer {
     private static final Pattern SANITIZE_BOLD_REGEX = Pattern.compile("(\\*{1,2}|(?<!\\w)_{1,2})(.+?)\\1",
@@ -12,15 +11,15 @@
     private static final Pattern SANITIZE_NUM_REGEX = Pattern.compile("^(\\s*)(#+)(?=\\s)", Pattern.MULTILINE);
 
     public static String sanitizeChatGptMessage(String message) {
-        // Sanitize code blocks (delimited by "```") by stripping out the language for syntax highlighting and ensuring
-        // that is preceded by two "\n" chars. Additionally, sanitize the content outside these blocks.
-        return parseOutOfDelimiters(message, "\\s*```\\w*\\s*", MessageSanitizer::sanitizeOutsideInlineCodeBlocks,
-                "\n\n```\n", "\n```\n");
+        // Sanitize code blocks (delimited by CODE_DELIMITER) by stripping out the language for syntax highlighting and
+        // ensuring that is preceded by two "\n" chars. Additionally, sanitize the content outside these blocks.
+        return parseOutOfDelimiters(message, "\\s*" + CODE_DELIMITER + "\\w*\\s*",
+                MessageSanitizer::sanitizeOutsideInlineCodeBlocks, CODE_DELIMITER_BEGIN, CODE_DELIMITER_END);
     }
 
     private static String sanitizeOutsideInlineCodeBlocks(String message) {
-        // Sanitize the content outside the inline code blocks (delimited by a single "`").
-        return parseOutOfDelimiters(message, "`", MessageSanitizer::sanitizeGerritComment);
+        // Sanitize the content outside the inline code blocks (delimited by INLINE_CODE_DELIMITER).
+        return parseOutOfDelimiters(message, INLINE_CODE_DELIMITER, MessageSanitizer::sanitizeGerritComment);
     }
 
     private static String sanitizeGerritComment(String message) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/utils/StringUtils.java b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/utils/StringUtils.java
index 06f1274..19f9e91 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/utils/StringUtils.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/utils/StringUtils.java
@@ -2,41 +2,10 @@
 
 import lombok.extern.slf4j.Slf4j;
 
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
-import java.util.Set;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-import java.util.stream.IntStream;
 
 @Slf4j
 public class StringUtils {
-    private static final String COMMA = ", ";
-    private static final String SEMICOLON = "; ";
-
-    public static String parseOutOfDelimiters(String body, String splitDelim, Function<String, String> processMessage,
-                                              String leftDelimReplacement, String rightDelimReplacement) {
-        String[] chunks = body.split(splitDelim, -1);
-        List<String> resultChunks = new ArrayList<>();
-        int lastChunk = chunks.length -1;
-        for (int i = 0; i <= lastChunk; i++) {
-            String chunk = chunks[i];
-            if (i % 2 == 0 || i == lastChunk) {
-                resultChunks.add(processMessage.apply(chunk));
-            }
-            else {
-                resultChunks.addAll(Arrays.asList(leftDelimReplacement, chunk, rightDelimReplacement));
-            }
-        }
-        return concatenate(resultChunks);
-    }
-
-    public static String parseOutOfDelimiters(String body, String splitDelim, Function<String, String> processMessage) {
-        return parseOutOfDelimiters(body, splitDelim, processMessage, splitDelim, splitDelim);
-    }
-
     public static String backslashEachChar(String body) {
         StringBuilder slashedBody = new StringBuilder();
 
@@ -50,39 +19,4 @@
         return String.join("", components);
     }
 
-    public static String joinWithNewLine(List<String> components) {
-        return String.join("\n", components);
-    }
-
-    public static String joinWithComma(Set<String> components) {
-        return String.join(COMMA, components);
-    }
-
-    public static String joinWithSemicolon(List<String> components) {
-        return String.join(SEMICOLON, components);
-    }
-
-    public static List<String> getNumberedList(List<String> components) {
-        return IntStream.range(0, components.size())
-                .mapToObj(i -> (i + 1) + ". " + components.get(i))
-                .collect(Collectors.toList());
-    }
-
-    public static String getNumberedListString(List<String> components) {
-        return joinWithSemicolon(getNumberedList(components));
-    }
-
-    public static String prettyStringifyObject(Object object) {
-        List<String> lines = new ArrayList<>();
-        for (Field field : object.getClass().getDeclaredFields()) {
-            field.setAccessible(true);
-            try {
-                lines.add(field.getName() + ": " + field.get(object));
-            } catch (IllegalAccessException e) {
-                log.debug("Error while accessing field {} in {}", field.getName(), object, e);
-            }
-        }
-        return joinWithNewLine(lines);
-    }
-
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/utils/TextUtils.java b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/utils/TextUtils.java
new file mode 100644
index 0000000..7a3bc74
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/utils/TextUtils.java
@@ -0,0 +1,80 @@
+package com.googlesource.gerrit.plugins.chatgpt.utils;
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+@Slf4j
+public class TextUtils extends StringUtils {
+    public static final String INLINE_CODE_DELIMITER = "`";
+    public static final String CODE_DELIMITER = "```";
+    public static final String CODE_DELIMITER_BEGIN ="\n\n" + CODE_DELIMITER + "\n";
+    public static final String CODE_DELIMITER_END ="\n" + CODE_DELIMITER + "\n";
+
+    private static final String COMMA = ", ";
+    private static final String SEMICOLON = "; ";
+
+    public static String parseOutOfDelimiters(String body, String splitDelim, Function<String, String> processMessage,
+                                              String leftDelimReplacement, String rightDelimReplacement) {
+        String[] chunks = body.split(splitDelim, -1);
+        List<String> resultChunks = new ArrayList<>();
+        int lastChunk = chunks.length -1;
+        for (int i = 0; i <= lastChunk; i++) {
+            String chunk = chunks[i];
+            if (i % 2 == 0 || i == lastChunk) {
+                resultChunks.add(processMessage.apply(chunk));
+            }
+            else {
+                resultChunks.addAll(Arrays.asList(leftDelimReplacement, chunk, rightDelimReplacement));
+            }
+        }
+        return concatenate(resultChunks);
+    }
+
+    public static String parseOutOfDelimiters(String body, String splitDelim, Function<String, String> processMessage) {
+        return parseOutOfDelimiters(body, splitDelim, processMessage, splitDelim, splitDelim);
+    }
+
+    public static String joinWithNewLine(List<String> components) {
+        return String.join("\n", components);
+    }
+
+    public static String joinWithComma(Set<String> components) {
+        return String.join(COMMA, components);
+    }
+
+    public static String joinWithSemicolon(List<String> components) {
+        return String.join(SEMICOLON, components);
+    }
+
+    public static List<String> getNumberedList(List<String> components) {
+        return IntStream.range(0, components.size())
+                .mapToObj(i -> (i + 1) + ". " + components.get(i))
+                .collect(Collectors.toList());
+    }
+
+    public static String getNumberedListString(List<String> components) {
+        return joinWithSemicolon(getNumberedList(components));
+    }
+
+    public static String prettyStringifyObject(Object object) {
+        List<String> lines = new ArrayList<>();
+        for (Field field : object.getClass().getDeclaredFields()) {
+            field.setAccessible(true);
+            try {
+                lines.add(field.getName() + ": " + field.get(object));
+            } catch (IllegalAccessException e) {
+                log.debug("Error while accessing field {} in {}", field.getName(), object, e);
+            }
+        }
+        return joinWithNewLine(lines);
+    }
+
+}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/chatgpt/ChatGptReviewTest.java b/src/test/java/com/googlesource/gerrit/plugins/chatgpt/ChatGptReviewTest.java
index fdc94b8..d844741 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/chatgpt/ChatGptReviewTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/chatgpt/ChatGptReviewTest.java
@@ -50,7 +50,7 @@
 
 import static com.google.gerrit.extensions.client.ChangeKind.REWORK;
 import static com.googlesource.gerrit.plugins.chatgpt.client.UriResourceLocator.*;
-import static com.googlesource.gerrit.plugins.chatgpt.utils.StringUtils.joinWithNewLine;
+import static com.googlesource.gerrit.plugins.chatgpt.utils.TextUtils.joinWithNewLine;
 import static java.net.HttpURLConnection.HTTP_OK;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;