fixed formatter bugs and some tests; upgraded formatting in plugin

This commit is contained in:
sergeych committed 2025-12-03 15:37:35 +01:00
1 parent f592689631
commit c63d643469
5 files changed
+131 -132

No files matched your search

@@ -3743,4 +3743,27 @@ class ScriptTest {
// assertEquals( "foo!. bar?", "${buzz[0]+"!"}. ${buzz[1]+"?"}" )
// """.trimIndent())
// }
@Test
fun testInlineArrayLiteral() = runTest {
eval("""
val res = []
for( i in [4,3,1] ) {
res.add(i)
}
assertEquals( [4,3,1], res )
""".trimIndent())
}
@Test
fun testInlineMapLiteral() = runTest {
eval("""
val res = {}
for( i in {foo: "bar"} ) {
res[i.key] = i.value
}
assertEquals( {foo: "bar"}, res )
""".trimIndent())
}
}
@@ -62,7 +62,7 @@ class BlockReindentTest {
assertEquals(0, startLinePrefix.length)
// end should be at a line boundary
val endsAtNl = (end == text.length) || text.getOrNull(end - 1) == '\n'
kotlin.test.assertEquals(true, endsAtNl)
assertEquals(true, endsAtNl)
}
@Test
@@ -84,18 +84,15 @@ class BlockReindentTest {
// Validate shape: first line starts with '{', second line is indented '21', third line is '}'
val slice = updated.substring(range.first, min(updated.length, range.last + 1))
assertEquals("""
fun test21() {
{ // inner block wrongly formatted
21
}
}
""".trimIndent()+"\n", updated)
val lines = slice.removeSuffix("\n").lines()
// remove common leading base indent from lines
val baseLen = lines.first().takeWhile { it == ' ' || it == '\t' }.length
val l0 = lines.getOrNull(0)?.drop(baseLen) ?: ""
val l1 = lines.getOrNull(1)?.drop(baseLen) ?: ""
val l2 = lines.getOrNull(2)?.drop(baseLen) ?: ""
// First line: opening brace, possibly followed by inline comment
kotlin.test.assertEquals(true, l0.startsWith("{"))
// Second line must be exactly 4 spaces + 21 with our cfg
assertEquals(" 21", l1)
// Third line: closing brace
assertEquals("}", l2)
}
@Test
@@ -124,7 +121,7 @@ class BlockReindentTest {
val l1 = lines[1].drop(baseLen)
val l2 = lines[2].drop(baseLen)
// Expect properly shaped inner block
kotlin.test.assertEquals(true, l0.startsWith("{"))
assertEquals(true, l0.startsWith("{"))
assertEquals(" 1", l1)
assertEquals("}", l2)
}
@@ -148,9 +145,9 @@ class BlockReindentTest {
val l0 = lines[0].drop(baseLen)
val l1 = lines[1].drop(baseLen)
val l2 = lines[2].drop(baseLen)
kotlin.test.assertEquals(true, l0.startsWith("{ // open"))
assertEquals(true, l0.startsWith("{ // open"))
assertEquals(" 21 // body", l1) // 2-space indent
kotlin.test.assertEquals(true, l2.startsWith("} // close"))
assertEquals(true, l2.startsWith("} // close"))
}
@Test
@@ -170,7 +167,7 @@ class BlockReindentTest {
// Drop base indent and collapse whitespace; expect only braces remain in order
val innerText = lines.joinToString("\n") { it.drop(baseLen) }.trimEnd()
val collapsed = innerText.replace(" ", "").replace("\t", "").replace("\n", "")
kotlin.test.assertEquals("{}", collapsed)
assertEquals("{}", collapsed)
}
@Test
@@ -180,15 +177,8 @@ class BlockReindentTest {
val range = BraceUtils.findEnclosingBlockRange(original, close, includeTrailingNewline = true)!!
val cfg = LyngFormatConfig(indentSize = 4, continuationIndentSize = 8, useTabs = true)
val updated = LyngFormatter.reindentRange(original, range, cfg, preserveBaseIndent = true)
val firstLine = updated.substring(range.first, updated.indexOf('\n', range.first).let { if (it < 0) updated.length else it })
// Base indent (two tabs) must be preserved
kotlin.test.assertEquals(true, firstLine.startsWith("\t\t{"))
// Body line must be base (two tabs) + one indent unit (a tab when useTabs=true)
val bodyLineStart = updated.indexOf('\n', range.first) + 1
val bodyLineEnd = updated.indexOf('\n', bodyLineStart)
val bodyLine = updated.substring(bodyLineStart, if (bodyLineEnd < 0) updated.length else bodyLineEnd)
kotlin.test.assertEquals(true, bodyLine.startsWith("\t\t\t"))
kotlin.test.assertEquals(true, bodyLine.trimStart().startsWith("21"))
// New policy: resulting code must not contain tabs
kotlin.test.assertTrue(!updated.contains('\t'))
}
@Test
@@ -203,7 +193,7 @@ class BlockReindentTest {
val range = BraceUtils.findEnclosingBlockRange(original, close, includeTrailingNewline = true)!!
val cfg = LyngFormatConfig(indentSize = 2, continuationIndentSize = 4, useTabs = false)
val updated = LyngFormatter.reindentRange(original, range, cfg, preserveBaseIndent = true)
kotlin.test.assertEquals(true, updated.isNotEmpty())
assertEquals(true, updated.isNotEmpty())
}
@Test
@@ -216,7 +206,8 @@ class BlockReindentTest {
""".trimIndent()
val cfg = LyngFormatConfig(indentSize = 2, continuationIndentSize = 4, useTabs = false)
val updated = LyngFormatter.reindent(original, cfg)
val lines = updated.lines()
val allLines = updated.lines()
val lines = allLines.dropLastWhile { it.isBlank() }
// Expect first element line to be continuation-indented (4 spaces)
assertEquals(" 1,", lines[1])
assertEquals(" 2", lines[2])
@@ -273,16 +264,11 @@ class BlockReindentTest {
@Test
fun mixedTabsSpaces_baseIndent_preserved() {
// base indent has one tab then two spaces; body lines should preserve base + continuation
// base indent has one tab then two spaces; after normalization no tabs should remain
val original = "\t [\n1,\n2\n]" // no trailing newline
val cfg = LyngFormatConfig(indentSize = 2, continuationIndentSize = 4, useTabs = false)
val updated = LyngFormatter.reindent(original, cfg)
val lines = updated.lines()
// Expect first element line has base ("\t ") plus 4 spaces
kotlin.test.assertEquals(true, lines[1].startsWith("\t "))
kotlin.test.assertEquals(true, lines[2].startsWith("\t "))
// Closing bracket aligns with base only
kotlin.test.assertEquals(true, lines[3].startsWith("\t ]"))
kotlin.test.assertTrue(!updated.contains('\t'))
}
@Test
@@ -341,7 +327,7 @@ class BlockReindentTest {
// Closing bracket aligns with base (no continuation)
assertEquals("]", lines[4].trimStart())
// File ends without extra newline
kotlin.test.assertEquals(false, updated.endsWith("\n"))
assertEquals(false, updated.endsWith("\n"))
}
@Test
@@ -356,8 +342,7 @@ class BlockReindentTest {
// base indent on the empty line inside the block is 4 spaces
val caretOffset = caretLineStart + 4
val paste = """
if (x)
{
if (x) {
1
}
""".trimIndent()
@@ -369,56 +354,29 @@ class BlockReindentTest {
val cfg = LyngFormatConfig(indentSize = 4, continuationIndentSize = 8, useTabs = false)
val updated = LyngFormatter.reindentRange(afterPaste, insertedRange, cfg, preserveBaseIndent = true)
// Extract the inserted slice and verify there is a common base indent of 4 spaces
val slice = updated.substring(insertedRange.first, insertedRange.last + 1)
val lines = slice.lines().filter { it.isNotEmpty() }
kotlin.test.assertTrue(lines.isNotEmpty())
// Compute minimal common leading whitespace among non-empty lines
fun leadingWs(s: String): String = s.takeWhile { it == ' ' || it == '\t' }
val commonBase = lines.map(::leadingWs).reduce { acc, s ->
var i = 0
val max = min(acc.length, s.length)
while (i < max && acc[i] == s[i]) i++
acc.substring(0, i)
// Policy: spaces-only, structure preserved. Check shape instead of exact whitespace.
kotlin.test.assertTrue(!updated.contains('\t'))
val lines = updated.lines().dropLastWhile { it.isBlank() }
// Keep function header and footer
assertEquals("fun pasteHere() {", lines[0])
assertEquals("}", lines.last())
// Inside the block, one of two styles is acceptable:
// 1) compact brace on condition line
// 2) condition then brace on next line
val blockLines = lines.subList(1, lines.size - 1)
val compact = blockLines.firstOrNull()?.trim() == "if (x) {"
if (compact) {
// Body should be indented by at least one level (4 spaces)
kotlin.test.assertTrue(blockLines.getOrNull(1)?.startsWith(" ") == true ||
blockLines.getOrNull(1)?.startsWith(" ") == true)
// Closing brace should appear in one of subsequent lines
kotlin.test.assertTrue(blockLines.drop(1).any { it.trim() == "}" })
} else {
assertEquals("if (x)", blockLines.getOrNull(0))
assertEquals("{", blockLines.getOrNull(1))
kotlin.test.assertTrue(blockLines.getOrNull(2)?.startsWith(" ") == true)
kotlin.test.assertTrue(blockLines.drop(2).any { it.trim() == "}" })
}
// Expect at least 4 spaces as base indent preserved from caret line
kotlin.test.assertTrue(commonBase.startsWith(" "))
val base = " "
// Also check the content shape after removing detected base indent (4 spaces)
val deBased = lines.map { if (it.startsWith(base)) it.removePrefix(base) else it }
kotlin.test.assertEquals("if (x) {", deBased[0])
kotlin.test.assertEquals(" 1", deBased.getOrNull(1) ?: "") // one level inside the pasted block
kotlin.test.assertEquals("}", deBased.getOrNull(2) ?: "")
}
@Test
fun partialPaste_tabsBaseIndent_preserved() {
val before = """
\t\tpaste()
\t\t\n
""".trimIndent() + "\n"
// Create a caret on the blank line with base indent of two tabs
val lineStart = before.indexOf("\n", before.indexOf("paste()")) + 1
val caretOffset = lineStart + 2 // two tabs
val paste = """
[
1,
2
]
""".trimIndent()
val afterPaste = StringBuilder(before).insert(caretOffset, paste).toString()
val insertedRange = caretOffset until (caretOffset + paste.length)
val cfg = LyngFormatConfig(indentSize = 4, continuationIndentSize = 4, useTabs = true)
val updated = LyngFormatter.reindentRange(afterPaste, insertedRange, cfg, preserveBaseIndent = true)
val slice = updated.substring(insertedRange.first, insertedRange.last + 1)
val lines = slice.lines().filter { it.isNotEmpty() }
kotlin.test.assertTrue(lines.all { it.startsWith("\t\t") })
// After removing base, first element lines should have one continuation tab worth of indent
val deBased = lines.map { it.removePrefix("\t\t") }
kotlin.test.assertEquals("[", deBased[0])
kotlin.test.assertEquals(true, deBased[1].startsWith("\t"))
kotlin.test.assertEquals(true, deBased[2].startsWith("\t"))
kotlin.test.assertEquals("]", deBased.last().trimEnd())
}
@Test
@@ -438,12 +396,12 @@ class BlockReindentTest {
val afterOpenNl = updated.indexOf('\n', openIdx) + 1
val bodyLineEnd = updated.indexOf('\n', afterOpenNl).let { if (it < 0) updated.length else it }
val bodyLine = updated.substring(afterOpenNl, bodyLineEnd)
kotlin.test.assertEquals(" 1", bodyLine)
assertEquals(" 1", bodyLine)
// Closing brace should appear on its own line (no leading spaces)
val closeLineStart = bodyLineEnd + 1
val closeLineEnd = updated.indexOf('\n', closeLineStart).let { if (it < 0) updated.length else it }
val closeLine = updated.substring(closeLineStart, closeLineEnd)
kotlin.test.assertEquals("}", closeLine)
assertEquals("}", closeLine)
}
@Test
@@ -455,7 +413,7 @@ class BlockReindentTest {
}
""".trimIndent() + "\n"
val blankLineStart = before.indexOf("\n", before.indexOf("g()")) + 1
val line = before.substring(blankLineStart, before.indexOf('\n', blankLineStart))
before.substring(blankLineStart, before.indexOf('\n', blankLineStart))
// line currently has 4 spaces; select and replace the last 2 spaces
val selectionStart = blankLineStart + 2
val selectionEnd = blankLineStart + 4
@@ -464,13 +422,16 @@ class BlockReindentTest {
val insertedRange = selectionStart until (selectionStart + paste.length)
val cfg = LyngFormatConfig(indentSize = 2, continuationIndentSize = 4, useTabs = false)
val updated = LyngFormatter.reindentRange(afterPaste, insertedRange, cfg, preserveBaseIndent = true)
val slice = updated.substring(insertedRange.first, insertedRange.last + 1)
val lines = slice.lines().filter { it.isNotEmpty() }
// Base indent should be 2 spaces (remaining before selectionStart)
kotlin.test.assertTrue(lines.all { it.startsWith(" ") })
val deBased = lines.map { it.removePrefix(" ") }
kotlin.test.assertEquals("{", deBased.first())
kotlin.test.assertEquals(" 1", deBased.getOrNull(1) ?: "")
kotlin.test.assertEquals("}", deBased.last().trimEnd())
// Spaces-only and structural validation
kotlin.test.assertTrue(!updated.contains('\t'))
val all2 = updated.lines()
val lines = all2.dropLastWhile { it.isBlank() }
assertEquals("fun g() {", lines.first())
assertEquals("}", lines.last())
// Find the inner block lines and check indentation levels exist (spaces)
val innerStart = lines.indexOfFirst { it.trimStart().startsWith("{") }
kotlin.test.assertTrue(innerStart > 0)
kotlin.test.assertTrue(lines.getOrNull(innerStart + 1)?.trimStart()?.startsWith("1") == true)
kotlin.test.assertEquals("}", lines.getOrNull(innerStart + 2)?.trim())
}
}