DocsPanelCodeLinksSmokeTest.kt
src/jvmMain/kotlin/afield/examples/DocsPanelCodeLinksSmokeTest.kt · 110 lines
package afield.examples
import afield.runtime.completion.KotlinCompletionSupport
FIELD_TEST id: examples.docs-panel-code-links.smoke runner: jvm-main entrypoint: afield.examples.DocsPanelCodeLinksSmokeTest tags: [smoke, completion, docs, code-links] timeoutSec: 30 expect: exitCode: 0 stdoutContains: - "DocsPanelCodeLinksSmokeTest ok"
object DocsPanelCodeLinksSmokeTest
Exercises the documentation-panel code-link backend against the real Kotlin
source index (~/.afield/filestore/kotlin_source_index.json): KDoc [Symbol](../../../../../reference/source/jvmMain/afield/document/persistence/edn.md#L45)
linkification and source-card resolution. No GPU/UI — pure index + source
reads — so it runs in a fresh JVM.
object DocsPanelCodeLinksSmokeTest {
fun main(args: Array<String>)
body — 84 lines, from line 26
@JvmStatic
fun main(args: Array<String>) {
val failures = mutableListOf<String>()
fun check(label: String, condition: Boolean) {
if (condition) println(" ok: $label") else failures += label
}
// 1. Linkify a real KDoc body: [Vec2] resolves (project typealias), [Float]
// (classpath-only) stays literal — no dead links.
val kdoc = "Creates a mutable 2D [Vec2] from numeric coordinates, converting each component to [Float]."
val linked = KotlinCompletionSupport.linkifyKDocSymbols(kdoc)
println("linkify -> $linked")
check("[Vec2] became a field-source link", linked.contains("[Vec2](field-source:"))
check("field-source href carries a path", linked.contains("path="))
check("[Float] stayed literal (no dead link)", !linked.contains("[Float]("))
// 2. Fenced code blocks are never linkified.
val fenced = "```kotlin\nval x: [Vec2] = z\n```"
check("code fences untouched", KotlinCompletionSupport.linkifyKDocSymbols(fenced) == fenced)
// 2b. Inline `code` spans are never linkified either, even for a symbol
// that resolves outside code (regression: inline spans were linkified).
val inline = "See `[Vec2]` for the type; [Vec2] here is a real link."
val inlineLinked = KotlinCompletionSupport.linkifyKDocSymbols(inline)
println("inline -> $inlineLinked")
check("inline `[Vec2]` stays literal", inlineLinked.contains("`[Vec2]`"))
check("bare [Vec2] outside code still links", inlineLinked.contains("[Vec2](field-source:"))
// 2c. KDoc `[display][Target]` alternate-link: display text is NOT linkified
// on its own; the whole thing links once to the target symbol.
val alt = "Prefer the [2D vector][Vec2] helper."
val altLinked = KotlinCompletionSupport.linkifyKDocSymbols(alt)
println("alt-link -> $altLinked")
check("[display][Target] links display text to target", altLinked.contains("[2D vector](field-source:"))
check("[display][Target] emits no stray [Vec2] link", !altLinked.contains("[Vec2]("))
check("[display][Target] leaves no raw ][ residue", !altLinked.contains("][Vec2]"))
// 2d. Generic targets like [Foo<Bar>] never match the regex -> stay literal.
val generic = "A [List<Vec2>] of points."
val genericLinked = KotlinCompletionSupport.linkifyKDocSymbols(generic)
check("generic [List<Vec2>] stays literal", genericLinked == generic)
// 2e. Qualified target [Vec2.x]: the member `x` exists in the index but under
// an unrelated owner (MutablePointCloud), so owner verification must leave
// it literal rather than emit a wrong link (regression: it linked to the
// unrelated member). Never a dead/garbled/wrong link.
val qualified = "Access [Vec2.x] for the component."
val qualifiedLinked = KotlinCompletionSupport.linkifyKDocSymbols(qualified)
println("qualified -> $qualifiedLinked")
check("qualified [Vec2.x] with non-matching owner stays literal", qualifiedLinked == qualified)
// 3. Resolve the Vec2 typealias card by symbol name.
val vec2 = KotlinCompletionSupport.resolveSourceCard("Vec2", null, -1)
println("Vec2 card -> found=${vec2.found} ${vec2.sourcePath}:${vec2.sourceLine}")
check("Vec2 resolved", vec2.found)
check("Vec2 points at linalg.kt", vec2.sourcePath.endsWith("linalg.kt"))
check("Vec2 title", vec2.title == "Vec2")
check("Vec2 card has a signature block", vec2.documentation.contains("```kotlin"))
check("Vec2 card mentions typealias", vec2.documentation.contains("typealias Vec2"))
// 4. Resolve a vec() overload card. Name-only resolution is intentionally free to choose
// any indexed overload, so its KDoc is not required to mention a particular vector type.
val vec = KotlinCompletionSupport.resolveSourceCard("vec", null, -1)
println("vec card -> found=${vec.found} ${vec.sourcePath}:${vec.sourceLine}")
check("vec resolved", vec.found)
check("vec card shows a fun signature", vec.documentation.contains("fun vec"))
// 5. Resolve by path+line (the source-line link path).
val byLoc = KotlinCompletionSupport.resolveSourceCard(null, vec2.sourcePath, vec2.sourceLine)
check("resolve by path+line works", byLoc.found && byLoc.title == "Vec2")
// 6. Unknown symbol resolves to not-found (so the client shows no card).
val missing = KotlinCompletionSupport.resolveSourceCard("NotARealSymbolXYZ", null, -1)
check("unknown symbol -> not found", !missing.found)
if (failures.isEmpty()) {
println("DocsPanelCodeLinksSmokeTest ok")
} else {
System.err.println("DocsPanelCodeLinksSmokeTest FAILED:")
failures.forEach { System.err.println(" - $it") }
kotlin.system.exitProcess(1)
}
}
}