From 304a90186ac06b77cbcc955ebbe71d9416ad297d Mon Sep 17 00:00:00 2001 From: Hy4ri <41645758+Hy4ri@users.noreply.github.com> Date: Thu, 17 Sep 2026 14:21:38 +0000 Subject: [PATCH] Fix: Avoid eager List allocation in countDiffLineStats for large diffs Replaced `diff.split("\n")` with `diff.lineSequence()` in `FileRenderers.kt`'s `countDiffLineStats()` method. This prevents massive `ArrayList` allocations on the heap when processing multi-thousand-line diffs during tool card rendering, improving memory efficiency by evaluating the lines lazily. Added comprehensive unit tests in `FileEditSupportTest.kt` covering empty diffs, header filtering, CRLF handling, and large multi-line diffs. --- .../ui/chat/tool/render/FileRenderers.kt | 2 +- .../chat/tool/render/FileEditSupportTest.kt | 54 +++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 app/src/test/java/com/m57/hermescontrol/ui/chat/tool/render/FileEditSupportTest.kt diff --git a/app/src/main/java/com/m57/hermescontrol/ui/chat/tool/render/FileRenderers.kt b/app/src/main/java/com/m57/hermescontrol/ui/chat/tool/render/FileRenderers.kt index eb8501c2..e053079d 100644 --- a/app/src/main/java/com/m57/hermescontrol/ui/chat/tool/render/FileRenderers.kt +++ b/app/src/main/java/com/m57/hermescontrol/ui/chat/tool/render/FileRenderers.kt @@ -79,7 +79,7 @@ internal object FileEditSupport { var added = 0 var removed = 0 - for (line in diff.split("\n")) { + for (line in diff.lineSequence()) { when { line.startsWith("+") && !line.startsWith("+++") -> added += 1 line.startsWith("-") && !line.startsWith("---") -> removed += 1 diff --git a/app/src/test/java/com/m57/hermescontrol/ui/chat/tool/render/FileEditSupportTest.kt b/app/src/test/java/com/m57/hermescontrol/ui/chat/tool/render/FileEditSupportTest.kt new file mode 100644 index 00000000..eefed8a2 --- /dev/null +++ b/app/src/test/java/com/m57/hermescontrol/ui/chat/tool/render/FileEditSupportTest.kt @@ -0,0 +1,54 @@ +package com.m57.hermescontrol.ui.chat.tool.render + +import org.junit.Assert.assertEquals +import org.junit.Test + +class FileEditSupportTest { + @Test + fun testCountDiffLineStats_emptyDiff() { + val stats = FileEditSupport.countDiffLineStats("") + assertEquals(0, stats.added) + assertEquals(0, stats.removed) + } + + @Test + fun testCountDiffLineStats_headerFiltering() { + val diff = + """ + --- a/file.txt + +++ b/file.txt + @@ -1,5 +1,5 @@ + unchanged + -removed line + +added line + """.trimIndent() + val stats = FileEditSupport.countDiffLineStats(diff) + assertEquals(1, stats.added) + assertEquals(1, stats.removed) + } + + @Test + fun testCountDiffLineStats_crlfHandling() { + val diff = "---\r\n+++\r\n+added\r\n-removed\r\n+another\r\n" + val stats = FileEditSupport.countDiffLineStats(diff) + assertEquals(2, stats.added) + assertEquals(1, stats.removed) + } + + @Test + fun testCountDiffLineStats_largeDiff() { + val sb = java.lang.StringBuilder() + sb.append("--- a/file.txt\n") + sb.append("+++ b/file.txt\n") + + val count = 5000 + for (i in 0 until count) { + sb.append("-old line $i\n") + sb.append("+new line $i\n") + } + + val stats = FileEditSupport.countDiffLineStats(sb.toString()) + assertEquals(count, stats.added) + assertEquals(count, stats.removed) + } +}