Fix length change omission for StringSubstitutor cyclic detection
StringSubstitutor#substitute would throw StringIndexOutOfBoundsException when removing a variable start marker if StringSubstitutor wasn't using the internal representation of TextStringBuilder#buffer. The local variable, priorVariables, contains unbalanced squirrely parentheses (replacing $${${TEST}} would cause priorVariables to add ${${TEST}}} -- amusingly didn't result in unexpected behavior). I discovered this when swapping all instances of buf.buffer to buf.toCharArray(). This PR ensures that both now have equivalent behavior. I was unable to tease out a test for this, as the length is only decremented to that point (but this change in length goes unused, hence the exception for toCharArray), so no overflows. I did port a test from StrSubstitutorTest.java, but the test passes before and after this change.
I believe this to be a trivial change (hence no JIRA ticket). Let me know if otherwise
Coverage increased (+0.1%) to 98.031% when pulling e291fb56ffa30536a8e9abf1fa471d4da3f4fd30 on nickbabcock:sub-cycle-fix into 8b07e17402a7ca148aa6442c1c1e25a2f700c713 on apache:master.
My apologies!
- Checkout
masterbranch - Apply diff
diff --git a/src/main/java/org/apache/commons/text/StringSubstitutor.java b/src/main/java/org/apache/commons/text/StringSubstitutor.java
index f4b53ee..4680edc 100644
--- a/src/main/java/org/apache/commons/text/StringSubstitutor.java
+++ b/src/main/java/org/apache/commons/text/StringSubstitutor.java
@@ -1330,7 +1330,7 @@ public class StringSubstitutor {
final boolean top = priorVariables == null;
boolean altered = false;
int lengthChange = 0;
- char[] chars = buf.buffer;
+ char[] chars = buf.toCharArray();
int bufEnd = offset + length;
int pos = offset;
while (pos < bufEnd) {
@@ -1346,7 +1346,7 @@ public class StringSubstitutor {
continue;
}
buf.deleteCharAt(pos - 1);
- chars = buf.buffer; // in case buffer was altered
+ chars = buf.toCharArray(); // in case buffer was altered
lengthChange--;
altered = true;
bufEnd--;
@@ -1432,7 +1432,7 @@ public class StringSubstitutor {
pos += change;
bufEnd += change;
lengthChange += change;
- chars = buf.buffer; // in case buffer was altered
+ chars = buf.toCharArray(); // in case buffer was altered
} else if (undefinedVariableException) {
throw new IllegalArgumentException(String.format(
"Cannot resolve variable '%s' (enableSubstitutionInVariables=%s).", varName,
- Run tests
- Notice
StringIndexOutOfBoundsExceptionis thrown at
if (priorVariables == null) {
priorVariables = new ArrayList<>();
priorVariables.add(new String(chars, offset, length));
}
- Understand "length" points passed the character array but since
charsis implicitly relying onTextStringBuilderallocating behavior so the current implementation does not throw exception. - The real length is
length + lengthChange
I think this would still require a change, as it appears to prevent an error you had (and which users may have as well). Trivial changes are more javadocs, style changes, rename a local variable, fix unused imports, etc. Anything that doesn't affect users regarding backward compatibility (binary or behaviour wise), and also don't add any new feature.
It's a logic bug that can't manifest in commons-text is due to the reliance on internal TextStringBuilder#buffer and how it's implemented. So the number of users effected by this bug is 0. I only came across the bug when a I needed to apply some changes and created the diff posted above.
Let me know if you still want me to create a JIRA ticket 😄
I would like feedback from the community on whether or not this should be merged. A failing test would make this a no-brainer of course but I understand this might not be possible here.