diff --git a/Foundation/org.egovframe.rte.fdl.string/src/main/java/org/egovframe/rte/fdl/string/EgovStringUtil.java b/Foundation/org.egovframe.rte.fdl.string/src/main/java/org/egovframe/rte/fdl/string/EgovStringUtil.java index d3db1630..0498ba31 100755 --- a/Foundation/org.egovframe.rte.fdl.string/src/main/java/org/egovframe/rte/fdl/string/EgovStringUtil.java +++ b/Foundation/org.egovframe.rte.fdl.string/src/main/java/org/egovframe/rte/fdl/string/EgovStringUtil.java @@ -282,6 +282,13 @@ public static String toSubString(String source, int beginIndex) { * search */ public static int search(String source, String target) { + // source 또는 target이 null/빈 문자열이면 셀 대상이 없으므로 0을 반환한다. + // 특히 target이 빈 문자열이면 indexOf("")가 항상 0을 반환해 + // i가 0에 고정되어 무한 루프에 빠지므로 반드시 먼저 걸러낸다. + if (source == null || source.isEmpty() || target == null || target.isEmpty()) { + return 0; + } + int result = 0; String strCheck = source; for (int i = 0; i < source.length(); ) { diff --git a/Foundation/org.egovframe.rte.fdl.string/src/test/java/org/egovframe/rte/fdl/string/EgovStringUtilTest.java b/Foundation/org.egovframe.rte.fdl.string/src/test/java/org/egovframe/rte/fdl/string/EgovStringUtilTest.java index 6ce10bee..7090a8f9 100755 --- a/Foundation/org.egovframe.rte.fdl.string/src/test/java/org/egovframe/rte/fdl/string/EgovStringUtilTest.java +++ b/Foundation/org.egovframe.rte.fdl.string/src/test/java/org/egovframe/rte/fdl/string/EgovStringUtilTest.java @@ -4,6 +4,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.test.context.junit.jupiter.SpringExtension; +import java.time.Duration; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -406,4 +407,34 @@ public void testGetTokens() { assertEquals(4, EgovStringUtil.getTokens(str).size()); } + /** + * search는 source 안에서 target이 나타나는 횟수를 센다. + */ + @Test + public void testSearchCount() { + assertEquals(2, EgovStringUtil.search("aXbXc", "X")); + assertEquals(0, EgovStringUtil.search("abc", "z")); + assertEquals(2, EgovStringUtil.search("aaaa", "aa")); + } + + /** + * target이 빈 문자열이면 indexOf("")가 항상 0을 반환해 + * 기존 구현은 무한 루프에 빠졌다. 이제는 0을 반환해야 한다. + */ + @Test + public void testSearchEmptyTargetDoesNotLoop() { + assertTimeoutPreemptively(Duration.ofSeconds(2), + () -> assertEquals(0, EgovStringUtil.search("abc", ""))); + } + + /** + * null 입력은 NPE 없이 0을 반환해야 한다. + */ + @Test + public void testSearchNullInputs() { + assertEquals(0, EgovStringUtil.search(null, "a")); + assertEquals(0, EgovStringUtil.search("abc", null)); + assertEquals(0, EgovStringUtil.search("", "a")); + } + }