Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 2024-06-21 - Regex Compilation in Loops
**Learning:** In Kotlin, compiling regular expressions (`.toRegex()`) inside a loop over files is a significant O(N * M) performance bottleneck when processing ignore files (N files * M rules).
**Action:** Always map string rules to compiled `Regex` objects outside of the file iteration loop (O(M) compilation) to avoid unnecessary regex re-compilations.

## 2024-06-28 - String Concatenation in Loops
**Learning:** In `html4tree`, using `+=` string concatenation inside a loop over directory files causes unnecessary intermediate object creation and memory overhead, resulting in O(N^2) complexity. The Jacoco plugin configuration treats the implicit null check on `.listFiles()?.toMutableList()` as a partially missed branch, causing test coverage issues.
**Action:** Use `StringBuilder` for loop string building (O(N)), and split `curr_dir.listFiles()` into a clear `if (files != null)` check to satisfy Jacoco branch coverage to maintain 100%.
10 changes: 6 additions & 4 deletions src/main/kotlin/html4tree/main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -124,18 +124,20 @@ fun process_dir(curr_dir: File){
"""

val index_middle = fun():String{
var l=""
// 성능 향상: 반복문 내 문자열 연결(concatenation)을 StringBuilder로 변경하여 메모리 할당 및 복사 오버헤드 감소 (O(N^2) -> O(N))
val sb = StringBuilder()

val dir_files: MutableList<File> = curr_dir.listFiles()?.toMutableList() ?: mutableListOf()
val files = curr_dir.listFiles()
val dir_files: MutableList<File> = if (files != null) files.toMutableList() else mutableListOf()
dir_files.sortWith(compareBy ({it.name}) )
dir_files.forEach {
val isLinkedDirectory = it.isDirectory() && !java.nio.file.Files.isSymbolicLink(it.toPath())
if((it.getName() !in exclude) && (isLinkedDirectory || !it.isDirectory())) {
l += """ <li><a style="display:block; width:100%" href="${if (isLinkedDirectory) { "./${it.getName().urlEncodePath()}/" } else { "./${it.getName().urlEncodePath()}" }}">${if (isLinkedDirectory) { "&#128193;" } else { "&rtrif;" }} ${it.getName().escapeHtml()}</a></li>"""+"\n"
sb.append(""" <li><a style="display:block; width:100%" href="${if (isLinkedDirectory) { "./${it.getName().urlEncodePath()}/" } else { "./${it.getName().urlEncodePath()}" }}">${if (isLinkedDirectory) { "&#128193;" } else { "&rtrif;" }} ${it.getName().escapeHtml()}</a></li>""").append("\n")
}
}

return l;
return sb.toString()
}

val index_bottom="""
Expand Down
40 changes: 40 additions & 0 deletions src/test/kotlin/html4tree/MainTest2.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package html4tree

import org.junit.After
import org.junit.Before
import org.junit.Test
import java.io.File
import java.nio.file.Files
import kotlin.test.assertTrue

class MainTest2 {
private lateinit var tempDir: File

@Before
fun setup() {
tempDir = Files.createTempDirectory("html4tree-test2-").toFile()
}

@After
fun teardown() {
if (tempDir.exists()) {
tempDir.deleteRecursively()
}
}

@Test
fun testProcessDirListFilesNull() {
val unreadableDir = File(tempDir, "unreadable2")
unreadableDir.mkdir()
unreadableDir.setReadable(false, false)
try {
process_dir(unreadableDir)
val indexFile = File(unreadableDir, "index.html")
assertTrue(indexFile.exists())
} finally {
unreadableDir.setReadable(true, false)
unreadableDir.setWritable(true, false)
unreadableDir.setExecutable(true, false)
}
}
}