Skip to content

Commit 35d652e

Browse files
alhudzgarydgregory
andauthored
Fix Strings.CI.indexOf returning out-of-range index for empty search (#1737)
* fix Strings.CI.indexOf returning out-of-range index for empty search * Refactor test, add assertions. --------- Co-authored-by: Gary Gregory <garydgregory@users.noreply.github.com>
1 parent ae85262 commit 35d652e

2 files changed

Lines changed: 21 additions & 1 deletion

File tree

src/main/java/org/apache/commons/lang3/Strings.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ public int indexOf(final CharSequence str, final CharSequence searchStr, int sta
152152
startPos = 0;
153153
}
154154
final int endLimit = str.length() - searchStr.length() + 1;
155-
if (startPos > endLimit) {
155+
if (startPos >= endLimit) {
156156
return INDEX_NOT_FOUND;
157157
}
158158
if (searchStr.length() == 0) {

src/test/java/org/apache/commons/lang3/StringsTest.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,26 @@ void testCaseInsensitiveConstant() {
5959
assertFalse(Strings.CI.isCaseSensitive());
6060
}
6161

62+
/**
63+
* For an empty search the case-insensitive {@code indexOf} returned {@code startPos} unchanged once it reached
64+
* {@code str.length() + 1}, so a start position one past the end yielded an index beyond the string instead of
65+
* {@code -1}.
66+
*/
67+
@Test
68+
void testCaseInsensitiveIndexOfEmptyOutOfRange() {
69+
// repro: returned 4 (past the end of a length-3 string) before the fix
70+
final String emptySearch = StringUtils.EMPTY;
71+
assertEquals(-1, Strings.CI.indexOf("abc", emptySearch, 4));
72+
// documented out-of-range example, also -1
73+
assertEquals(-1, Strings.CI.indexOf("abc", emptySearch, 9));
74+
// the end position is still a valid empty match
75+
assertEquals(3, Strings.CI.indexOf("abc", emptySearch, 3));
76+
assertEquals(2, Strings.CI.indexOf("aabaabaa", emptySearch, 2));
77+
assertEquals(0, Strings.CI.indexOf(emptySearch, emptySearch, 0));
78+
assertEquals(0, Strings.CI.indexOf(emptySearch, emptySearch, -1));
79+
assertEquals(0, Strings.CI.indexOf("a", emptySearch, -1));
80+
}
81+
6282
/**
6383
* {@code U+0130} lower-cases to the two-char sequence {@code "i̇"} outside Turkish locales, so pre-lower-casing the
6484
* search argument made the case-insensitive replace look for a two-char needle that no longer matches the single source

0 commit comments

Comments
 (0)