diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/templating/StaticInterceptor.java b/core/src/main/java/com/predic8/membrane/core/interceptor/templating/StaticInterceptor.java
new file mode 100644
index 000000000..e35102ff3
--- /dev/null
+++ b/core/src/main/java/com/predic8/membrane/core/interceptor/templating/StaticInterceptor.java
@@ -0,0 +1,144 @@
+package com.predic8.membrane.core.interceptor.templating;
+
+import com.predic8.membrane.annot.MCAttribute;
+import com.predic8.membrane.annot.MCElement;
+import com.predic8.membrane.annot.MCTextContent;
+import com.predic8.membrane.core.beautifier.JSONBeautifier;
+import com.predic8.membrane.core.exchange.Exchange;
+import com.predic8.membrane.core.http.Message;
+import com.predic8.membrane.core.interceptor.AbstractInterceptor;
+import com.predic8.membrane.core.interceptor.Outcome;
+import com.predic8.membrane.core.util.TextUtil;
+import org.jetbrains.annotations.NotNull;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.StringReader;
+
+import static com.predic8.membrane.core.http.MimeType.*;
+import static com.predic8.membrane.core.interceptor.Outcome.CONTINUE;
+import static com.predic8.membrane.core.util.TextUtil.unifyIndent;
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.apache.commons.text.StringEscapeUtils.escapeHtml4;
+
+@MCElement(name = "static", mixed = true)
+public class StaticInterceptor extends AbstractInterceptor {
+
+ protected String location;
+
+ protected String textTemplate;
+
+ protected String contentType = TEXT_PLAIN;
+
+ protected Boolean pretty = false;
+
+ protected final JSONBeautifier jsonBeautifier = new JSONBeautifier();
+
+ protected static final Logger log = LoggerFactory.getLogger("StaticInterceptor");
+
+ public StaticInterceptor() {
+ name = "Static";
+ }
+
+ @Override
+ public Outcome handleRequest(Exchange exc) throws Exception {
+ return handleInternal(exc.getRequest());
+ }
+
+ @Override
+ public Outcome handleResponse(Exchange exc) throws Exception {
+ return handleInternal(exc.getResponse());
+ }
+
+ private Outcome handleInternal(Message msg) {
+ msg.setBodyContent(getTemplateBytes());
+ msg.getHeader().setContentType(getContentType());
+ return CONTINUE;
+ }
+
+ private byte @NotNull [] getTemplateBytes() {
+ if (!pretty)
+ return textTemplate.getBytes(UTF_8);
+
+ return switch (contentType) {
+ case APPLICATION_JSON -> prettifyJson(textTemplate).getBytes(UTF_8);
+ case APPLICATION_XML, APPLICATION_SOAP, TEXT_HTML, TEXT_XML, TEXT_HTML_UTF8, TEXT_XML_UTF8 -> prettifyXML(textTemplate).getBytes(UTF_8);
+ default -> unifyIndent(textTemplate).getBytes(UTF_8);
+ };
+ }
+
+ private String prettifyXML(String text) {
+ try {
+ return TextUtil.formatXML(new StringReader(text));
+ } catch (Exception e) {
+ log.warn("Failed to format XML", e);
+ return text;
+ }
+ }
+
+ String prettifyJson(String text) {
+ try {
+ return jsonBeautifier.beautify(text);
+ } catch (IOException e) {
+ log.warn("Failed to format JSON", e);
+ return text;
+ }
+ }
+
+ @Override
+ public void init() throws Exception {
+ if (this.getLocation() != null && (getTextTemplate() != null && !getTextTemplate().isBlank())) {
+ throw new IllegalStateException("On <" + getName() + ">, ./text() and ./@location cannot be set at the same time.");
+ }
+ }
+
+ public String getLocation() {
+ return location;
+ }
+
+ @MCAttribute
+ public void setLocation(String location){
+ this.location = location;
+ }
+
+ public String getTextTemplate() {
+ return textTemplate;
+ }
+
+ @MCTextContent
+ public void setTextTemplate(String textTemplate) {
+ this.textTemplate = textTemplate;
+ }
+
+ protected String getName() {
+ return getClass().getAnnotation(MCElement.class).name();
+ }
+
+ public String getContentType() {
+ return contentType;
+ }
+
+ @MCAttribute
+ public void setContentType(String contentType) {
+ this.contentType = contentType;
+ }
+
+ public Boolean getPretty() {
+ return pretty;
+ }
+
+ @MCAttribute
+ public void setPretty(String pretty) {
+ this.pretty = Boolean.valueOf(pretty);
+ }
+
+ private String formatAsHtml(String plaintext) {
+ return String.join("
", escapeHtml4(plaintext).split("\n"));
+ }
+
+ @Override
+ public String getShortDescription() {
+ return formatAsHtml(textTemplate);
+ }
+}
diff --git a/core/src/main/java/com/predic8/membrane/core/interceptor/templating/TemplateInterceptor.java b/core/src/main/java/com/predic8/membrane/core/interceptor/templating/TemplateInterceptor.java
index cfcd399bd..a2002cbfb 100644
--- a/core/src/main/java/com/predic8/membrane/core/interceptor/templating/TemplateInterceptor.java
+++ b/core/src/main/java/com/predic8/membrane/core/interceptor/templating/TemplateInterceptor.java
@@ -14,27 +14,27 @@
package com.predic8.membrane.core.interceptor.templating;
-import com.predic8.membrane.annot.*;
-import com.predic8.membrane.core.beautifier.*;
-import com.predic8.membrane.core.exceptions.*;
-import com.predic8.membrane.core.exchange.*;
-import com.predic8.membrane.core.http.*;
-import com.predic8.membrane.core.interceptor.*;
-import com.predic8.membrane.core.lang.*;
-import com.predic8.membrane.core.resolver.*;
-import groovy.text.*;
-import org.apache.commons.io.*;
-import org.apache.commons.lang3.*;
-import org.slf4j.*;
-
-import java.io.*;
-import java.util.*;
+import com.predic8.membrane.annot.MCElement;
+import com.predic8.membrane.core.exceptions.ProblemDetails;
+import com.predic8.membrane.core.exchange.Exchange;
+import com.predic8.membrane.core.http.Message;
+import com.predic8.membrane.core.interceptor.Outcome;
+import com.predic8.membrane.core.lang.ScriptingUtils;
+import com.predic8.membrane.core.resolver.ResolverMap;
+import groovy.text.StreamingTemplateEngine;
+import groovy.text.Template;
+import groovy.text.TemplateExecutionException;
+import groovy.text.XmlTemplateEngine;
+import org.apache.commons.io.FilenameUtils;
+
+import java.io.InputStreamReader;
+import java.util.HashMap;
import static com.predic8.membrane.core.http.MimeType.*;
-import static com.predic8.membrane.core.interceptor.Interceptor.Flow.*;
-import static com.predic8.membrane.core.interceptor.Outcome.*;
-import static java.nio.charset.StandardCharsets.*;
-import static org.apache.commons.text.StringEscapeUtils.*;
+import static com.predic8.membrane.core.interceptor.Interceptor.Flow.REQUEST;
+import static com.predic8.membrane.core.interceptor.Interceptor.Flow.RESPONSE;
+import static com.predic8.membrane.core.interceptor.Outcome.CONTINUE;
+import static java.nio.charset.StandardCharsets.UTF_8;
/**
* @description Renders the body content of a message from a template. The template can
@@ -48,25 +48,12 @@
@MCElement(name="template", mixed = true)
-public class TemplateInterceptor extends AbstractInterceptor{
-
- /**
- * @description Path of template file
- */
- private String location;
-
- private String textTemplate;
-
- private Template template;
-
- private String contentType = TEXT_PLAIN;
-
- private Boolean pretty = false;
-
- private final JSONBeautifier jsonBeautifier = new JSONBeautifier();
+public class TemplateInterceptor extends StaticInterceptor {
private boolean scriptAccessesJson;
+ protected Template template;
+
public TemplateInterceptor() {
name = "Template";
}
@@ -97,14 +84,6 @@ private Outcome handleInternal(Message msg, Exchange exc, Flow flow) {
return CONTINUE;
}
- String prettifyJson(String text) {
- try {
- return jsonBeautifier.beautify(text);
- } catch (IOException e) {
- return text;
- }
- }
-
@SuppressWarnings("RedundantThrows") // Declaration of exception is needed. However, Groovy does not declare it.
private String fillTemplate(Exchange exc, Message msg, Flow flow) throws TemplateExecutionException {
@@ -155,32 +134,6 @@ public void init() throws Exception {
throw new IllegalStateException("You have to set either ./@location or ./text()");
}
- public String getLocation() {
- return location;
- }
-
- /**
- * @description path of xml template file.
- * @example template.xml
- */
- @MCAttribute
- public void setLocation(String location){
- this.location = location;
- }
-
- public String getTextTemplate() {
- return textTemplate;
- }
-
- @MCTextContent
- public void setTextTemplate(String textTemplate) throws IOException, ClassNotFoundException {
- this.textTemplate = textTemplate;
-
- if(textTemplate != null && !StringUtils.isBlank(textTemplate)){
- template = new StreamingTemplateEngine().createTemplate(this.getTextTemplate());
- }
- }
-
public Template getTemplate() {
return template;
}
@@ -188,45 +141,4 @@ public Template getTemplate() {
public void setTemplate(Template template) {
this.template = template;
}
-
-
- private String getName() {
- return getClass().getAnnotation(MCElement.class).name();
- }
-
- public String getContentType() {
- return contentType;
- }
-
- /**
- * @description content type for body
- * @example application/json
- */
- @MCAttribute
- public void setContentType(String contentType) {
- this.contentType = contentType;
- }
-
- public Boolean getPretty() {
- return pretty;
- }
-
- /**
- * @description Format JSON documents.
- * @example yes
- * @default no
- */
- @MCAttribute
- public void setPretty(String pretty) {
- this.pretty = Boolean.valueOf(pretty);
- }
-
- private String formatAsHtml(String plaintext) {
- return String.join("
", escapeHtml4(plaintext).split("\n"));
- }
-
- @Override
- public String getShortDescription() {
- return formatAsHtml(textTemplate);
- }
}
\ No newline at end of file
diff --git a/core/src/main/java/com/predic8/membrane/core/transport/ssl/PEMSupport.java b/core/src/main/java/com/predic8/membrane/core/transport/ssl/PEMSupport.java
index e2bf4fa74..21b74f207 100644
--- a/core/src/main/java/com/predic8/membrane/core/transport/ssl/PEMSupport.java
+++ b/core/src/main/java/com/predic8/membrane/core/transport/ssl/PEMSupport.java
@@ -36,6 +36,8 @@
import java.util.List;
import java.util.regex.Pattern;
+import static com.predic8.membrane.core.util.TextUtil.unifyIndent;
+
public abstract class PEMSupport {
private static final Logger log = LoggerFactory.getLogger(PEMSupport.class.getName());
@@ -64,21 +66,8 @@ public PEMSupportImpl() {
Security.addProvider(new BouncyCastleProvider());
}
- private String cleanupPEM(String pemBlock) {
- String lines[] = pemBlock.split("\r?\n");
- StringBuilder block = new StringBuilder();
- for (String line : lines) {
- String l = line.replaceAll("^\\s+", "");
- if (l.length() > 0) {
- block.append(l);
- block.append("\n");
- }
- }
- return block.toString();
- }
-
public X509Certificate parseCertificate(String pemBlock) throws IOException {
- PEMParser p2 = new PEMParser(new StringReader(cleanupPEM(pemBlock)));
+ PEMParser p2 = new PEMParser(new StringReader(unifyIndent(pemBlock)));
Object o2 = p2.readObject();
if (o2 == null)
throw new InvalidParameterException("Could not read certificate. Expected the certificate to begin with '-----BEGIN CERTIFICATE-----'.");
@@ -94,7 +83,7 @@ public X509Certificate parseCertificate(String pemBlock) throws IOException {
}
public List parseCertificates(String pemBlock) throws IOException {
List res = new ArrayList<>();
- PEMParser p2 = new PEMParser(new StringReader(cleanupPEM(pemBlock)));
+ PEMParser p2 = new PEMParser(new StringReader(unifyIndent(pemBlock)));
JcaX509CertificateConverter certconv = new JcaX509CertificateConverter().setProvider("BC");
while(true) {
Object o2 = p2.readObject();
@@ -115,7 +104,7 @@ public List parseCertificates(String pemBlock) throws IOExcepti
}
public Key getPrivateKey(String pemBlock) throws IOException {
- PEMParser p = new PEMParser(new StringReader(cleanupPEM(pemBlock)));
+ PEMParser p = new PEMParser(new StringReader(unifyIndent(pemBlock)));
Object o = p.readObject();
if (o == null)
throw new InvalidParameterException("Could not read certificate. Expected the certificate to begin with '-----BEGIN CERTIFICATE-----'.");
@@ -131,7 +120,7 @@ public Key getPrivateKey(String pemBlock) throws IOException {
}
public Object parseKey(String pemBlock) throws IOException {
- PEMParser p = new PEMParser(new StringReader(cleanupPEM(pemBlock)));
+ PEMParser p = new PEMParser(new StringReader(unifyIndent(pemBlock)));
Object o = p.readObject();
if (o == null) {
log.error("Could not read PEM file. Check the contents of PEM file or configuration. Content is {}", pemBlock);
diff --git a/core/src/main/java/com/predic8/membrane/core/util/TextUtil.java b/core/src/main/java/com/predic8/membrane/core/util/TextUtil.java
index bf981bff9..45f064c12 100644
--- a/core/src/main/java/com/predic8/membrane/core/util/TextUtil.java
+++ b/core/src/main/java/com/predic8/membrane/core/util/TextUtil.java
@@ -181,4 +181,62 @@ public static String getLineFromMultilineString(String s,int lineNumber) {
public static String escapeQuotes(String s) {
return s.replace("\"", "\\\"");
}
+
+ /**
+ * Adjusts the indentation of each line in a multiline string to match the minimum indentation found.
+ *
+ * @param multilineString The input multiline string to process.
+ * @return A string with adjusted indentation.
+ */
+ public static String unifyIndent(String multilineString) {
+ String[] lines = multilineString.split("\r?\n");
+ return trimLines(lines, getMinIndent(lines)).toString().replaceFirst("\\s*$", "");
+ }
+
+ /**
+ * Trims excess indentation from each line in the input array, based on a specified minimum indent level.
+ *
+ * @param lines The array of lines to process.
+ * @param minIndent The minimum indent level to maintain.
+ * @return A StringBuilder containing lines with adjusted indentation.
+ */
+ public static StringBuilder trimLines(String[] lines, int minIndent) {
+ StringBuilder result = new StringBuilder();
+ for (String line : lines) {
+ if (!line.trim().isEmpty()) {
+ result.append(" ".repeat(Math.max(getCurrentIndent(line) - minIndent, 0))).append(line.trim()).append("\n");
+ } else {
+ result.append("\n");
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Calculates the current indentation level (number of leading spaces) of a given line.
+ *
+ * @param line The line to calculate the indentation for.
+ * @return The number of leading spaces in the line.
+ */
+ public static int getCurrentIndent(String line) {
+ return line.length() - line.replaceFirst("^\\s+", "").length();
+ }
+
+ /**
+ * Determines the minimum indentation level (number of leading spaces) across all non-empty lines in an array of lines.
+ *
+ * @param lines The array of lines to analyze.
+ * @return The minimum indent level found among the lines.
+ */
+ public static int getMinIndent(String[] lines) {
+ int minIndent = Integer.MAX_VALUE;
+ for (String line : lines) {
+ if (!line.trim().isEmpty()) {
+ int leadingSpaces = getCurrentIndent(line);
+ minIndent = Math.min(minIndent, leadingSpaces);
+ }
+ }
+ return minIndent;
+ }
+
}
diff --git a/core/src/test/java/com/predic8/membrane/core/interceptor/templating/StaticInterceptorTest.java b/core/src/test/java/com/predic8/membrane/core/interceptor/templating/StaticInterceptorTest.java
new file mode 100644
index 000000000..9edfbf074
--- /dev/null
+++ b/core/src/test/java/com/predic8/membrane/core/interceptor/templating/StaticInterceptorTest.java
@@ -0,0 +1,10 @@
+package com.predic8.membrane.core.interceptor.templating;
+
+import org.junit.jupiter.api.Test;
+
+import static com.predic8.membrane.core.interceptor.templating.StaticInterceptor.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class StaticInterceptorTest {
+
+}
\ No newline at end of file
diff --git a/core/src/test/java/com/predic8/membrane/core/util/TextUtilTest.java b/core/src/test/java/com/predic8/membrane/core/util/TextUtilTest.java
index a5ca5036b..fa192966f 100644
--- a/core/src/test/java/com/predic8/membrane/core/util/TextUtilTest.java
+++ b/core/src/test/java/com/predic8/membrane/core/util/TextUtilTest.java
@@ -14,6 +14,7 @@
package com.predic8.membrane.core.util;
import static com.predic8.membrane.core.util.TextUtil.*;
+import static java.lang.Integer.MAX_VALUE;
import static org.junit.jupiter.api.Assertions.*;
import java.util.regex.Pattern;
@@ -23,58 +24,58 @@
public class TextUtilTest {
- @Test
- public void testGlobToExpStarPrefixHost() {
- Pattern pattern = Pattern.compile(globToRegExp("*.predic8.de"));
- assertTrue(pattern.matcher("hgsjagdjhsa.predic8.de").matches());
- assertTrue(pattern.matcher("jhkj.predic8.de").matches());
- assertFalse(pattern.matcher("jhkj.predic8.com").matches());
- }
-
- @Test
- public void testGlobToExpStarSuffixHost() {
- Pattern pattern = Pattern.compile(globToRegExp("predic8.*"));
- assertTrue(pattern.matcher("predic8.de").matches());
- assertTrue(pattern.matcher("predic8.com").matches());
- assertFalse(pattern.matcher("jhkj.predic8.de").matches());
- }
-
- @Test
- public void testGlobToExpStarInfixHost() {
- Pattern pattern = Pattern.compile(globToRegExp("www.*.de"));
- assertTrue(pattern.matcher("www.predic8.de").matches());
- assertTrue(pattern.matcher("www.oio.de").matches());
- assertFalse(pattern.matcher("www.predic8.com").matches());
- assertFalse(pattern.matcher("www.predic8.co.uk").matches());
- assertFalse(pattern.matcher("services.predic8.de").matches());
- }
-
- @Test
- public void testGlobToExpStarPrefixIp() {
- Pattern pattern = Pattern.compile(globToRegExp("*.68.5.122"));
- assertTrue(pattern.matcher("192.68.5.122").matches());
- assertFalse(pattern.matcher("192.68.5.123").matches());
- }
-
- @Test
- public void testGlobToExpStarSuffixIp() {
- Pattern pattern = Pattern.compile(globToRegExp("192.68.7.*"));
- assertTrue(pattern.matcher("192.68.7.12").matches());
- assertTrue(pattern.matcher("192.68.7.4").matches());
- assertFalse(pattern.matcher("192.68.6.12").matches());
- }
-
- @Test
- public void testGlobToExpStarInfixIp() {
- Pattern pattern = Pattern.compile(globToRegExp("192.68.*.15"));
- assertTrue(pattern.matcher("192.68.5.15").matches());
- assertTrue(pattern.matcher("192.68.24.15").matches());
- assertFalse(pattern.matcher("192.68.24.12").matches());
- }
+ @Test
+ void testGlobToExpStarPrefixHost() {
+ Pattern pattern = Pattern.compile(globToRegExp("*.predic8.de"));
+ assertTrue(pattern.matcher("hgsjagdjhsa.predic8.de").matches());
+ assertTrue(pattern.matcher("jhkj.predic8.de").matches());
+ assertFalse(pattern.matcher("jhkj.predic8.com").matches());
+ }
+
+ @Test
+ void testGlobToExpStarSuffixHost() {
+ Pattern pattern = Pattern.compile(globToRegExp("predic8.*"));
+ assertTrue(pattern.matcher("predic8.de").matches());
+ assertTrue(pattern.matcher("predic8.com").matches());
+ assertFalse(pattern.matcher("jhkj.predic8.de").matches());
+ }
+
+ @Test
+ void testGlobToExpStarInfixHost() {
+ Pattern pattern = Pattern.compile(globToRegExp("www.*.de"));
+ assertTrue(pattern.matcher("www.predic8.de").matches());
+ assertTrue(pattern.matcher("www.oio.de").matches());
+ assertFalse(pattern.matcher("www.predic8.com").matches());
+ assertFalse(pattern.matcher("www.predic8.co.uk").matches());
+ assertFalse(pattern.matcher("services.predic8.de").matches());
+ }
+
+ @Test
+ void testGlobToExpStarPrefixIp() {
+ Pattern pattern = Pattern.compile(globToRegExp("*.68.5.122"));
+ assertTrue(pattern.matcher("192.68.5.122").matches());
+ assertFalse(pattern.matcher("192.68.5.123").matches());
+ }
+
+ @Test
+ void testGlobToExpStarSuffixIp() {
+ Pattern pattern = Pattern.compile(globToRegExp("192.68.7.*"));
+ assertTrue(pattern.matcher("192.68.7.12").matches());
+ assertTrue(pattern.matcher("192.68.7.4").matches());
+ assertFalse(pattern.matcher("192.68.6.12").matches());
+ }
+
+ @Test
+ void testGlobToExpStarInfixIp() {
+ Pattern pattern = Pattern.compile(globToRegExp("192.68.*.15"));
+ assertTrue(pattern.matcher("192.68.5.15").matches());
+ assertTrue(pattern.matcher("192.68.24.15").matches());
+ assertFalse(pattern.matcher("192.68.24.12").matches());
+ }
@Test
void getLineFromMultilineStringTest() {
- assertEquals("ccc ccc",TextUtil.getLineFromMultilineString("""
+ assertEquals("ccc ccc", TextUtil.getLineFromMultilineString("""
aaa aaa
bb bb
ccc ccc
@@ -82,15 +83,138 @@ void getLineFromMultilineStringTest() {
""", 3));
}
- @Test
- void getLineFromMultilineStringOneLine() {
- assertEquals("aaa aaa",TextUtil.getLineFromMultilineString("""
+ @Test
+ void getLineFromMultilineStringOneLine() {
+ assertEquals("aaa aaa", TextUtil.getLineFromMultilineString("""
aaa aaa
""", 1));
- }
+ }
+
+ @Test
+ void escapeQuoteSimple() {
+ assertEquals("Test text with \\\" quotes", escapeQuotes("Test text with \" quotes"));
+ }
+
+
+ @Test
+ void testUnifyIndent() {
+ assertEquals("""
+ line1
+ line2
+ line3""", unifyIndent("""
+ line1
+ line2
+ line3"""));
+
+ assertEquals("""
+ line1
+ line2
+ line3""", unifyIndent("""
+ line1
+ line2
+ line3"""));
+
+ assertEquals("""
+ line1
+ line2
+ line3""", unifyIndent("""
+ line1
+ line2
+ line3"""));
+
+ assertEquals("""
+ line1
+
+ line3""", unifyIndent("""
+ line1
+
+ line3"""));
+
+ assertEquals("""
+
+ line1
+ line2
+ line3""", unifyIndent("""
+
+ line1
+ line2
+ line3
+ """));
+
+ assertEquals("", unifyIndent("""
+
+
+ """));
+
+ assertEquals("""
+ line1
+
+ line2""", unifyIndent("""
+ line1\r
+
+ line2"""));
+
+ assertEquals("""
+ line1
+ line2""", unifyIndent("""
+ \tline1
+ \tline2"""));
+
+ assertEquals("""
+ line1
+
+ line2""", unifyIndent("""
+ line1\r
+
+ line2"""));
+
+ assertEquals("""
+ line1
+
+ line2""", unifyIndent("""
+ line1\r
+ \r
+ line2"""));
+
+ }
- @Test
- public void escapeQuoteSimple() {
- assertEquals("Test text with \\\" quotes", escapeQuotes("Test text with \" quotes"));
- }
+ @Test
+ void testTrimLines() {
+ assertEquals("Line1\nLine2\nLine3\n", trimLines(new String[]{"Line1", "Line2", "Line3"}, 0).toString());
+ assertEquals("Line1\n Line2\nLine3\n", trimLines(new String[]{" Line1", " Line2", " Line3"}, 4).toString());
+ assertEquals(" Line1\nLine2\nLine3\n", trimLines(new String[]{" Line1", "\tLine2", " Line3"}, 2).toString());
+ assertEquals("\n\n\n", trimLines(new String[]{" ", "\t", " "}, 2).toString());
+ assertEquals("\n\n\n", trimLines(new String[]{"", "", ""}, 0).toString());
+ assertEquals("Line1\nLine2\nLine3\n", trimLines(new String[]{" Line1", " Line2", " Line3"}, 6).toString());
+ assertEquals("Line1\nLine2\n", trimLines(new String[]{" Line1\r", "\tLine2\r"}, 2).toString());
+ assertEquals("Line1\nLine2\n", trimLines(new String[]{"\tLine1", "\tLine2"}, 1).toString());
+ assertEquals("Line1\nLine2\nLine3\n", trimLines(new String[]{" Line1\r", " Line2", " Line3"}, 2).toString());
+ assertEquals("Line1\n\nLine3\n", trimLines(new String[]{" Line1", "", " Line3"}, 2).toString());
+ }
+
+ @Test
+ void testGetCurrentIndent() {
+ assertEquals(0, getCurrentIndent("NoIndentation"));
+ assertEquals(4, getCurrentIndent(" FourSpaces"));
+ assertEquals(3, getCurrentIndent("\t\t\tThreeTabs"));
+ assertEquals(5, getCurrentIndent(" \t \tMixedSpacesAndTabs"));
+ assertEquals(0, getCurrentIndent(""));
+ assertEquals(6, getCurrentIndent(" "));
+ assertEquals(3, getCurrentIndent(" \rLineWithCarriageReturn"));
+ assertEquals(1, getCurrentIndent("\tLineWithTab"));
+ assertEquals(1, getCurrentIndent("\rLineStartsWithCarriageReturn"));
+ }
+
+ @Test
+ void testGetMinIndent() {
+ assertEquals(0, getMinIndent(new String[]{"Line1", "Line2", "Line3"}));
+ assertEquals(2, getMinIndent(new String[]{" Line1", " Line2", " Line3"}));
+ assertEquals(1, getMinIndent(new String[]{" Line1", "\tLine2", " Line3"}));
+ assertEquals(MAX_VALUE, getMinIndent(new String[]{" ", "\t", ""}));
+ assertEquals(0, getMinIndent(new String[]{" Line1", "", " Line2", "Line3"}));
+ assertEquals(MAX_VALUE, getMinIndent(new String[]{"", " ", "\t"}));
+ assertEquals(2, getMinIndent(new String[]{" Line1\r", " Line2"}));
+ assertEquals(1, getMinIndent(new String[]{"\tLine1", " Line2"}));
+ assertEquals(0, getMinIndent(new String[]{"Line1\r", "\tLine2", "Line3"}));
+ }
}
\ No newline at end of file