lyng/lynglib/src/commonTest/kotlin/BindingTest.kt

135 lines
4.1 KiB
Kotlin

/*
* Copyright 2026 Sergey S. Chernov real.sergeych@gmail.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/*
* Mini binding tests for highlighting/editor features
*/
package net.sergeych.lyng
import kotlinx.coroutines.test.runTest
import net.sergeych.lyng.binding.Binder
import net.sergeych.lyng.miniast.MiniAstBuilder
import kotlin.test.Ignore
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
@Ignore
class BindingTest {
private suspend fun bind(code: String): net.sergeych.lyng.binding.BindingSnapshot {
val src = code.trimIndent()
val sink = MiniAstBuilder()
Compiler.compileWithMini(src, sink)
val mini = sink.build()
assertNotNull(mini, "MiniScript should be built")
return Binder.bind(src, mini)
}
@Test
fun binds_params_and_locals() = runTest {
val snap = bind(
"""
fun f(a:Int){
val x = 1
a + x
}
"""
)
// Expect at least one Parameter symbol "a" and one Value symbol "x"
val aIds = snap.symbols.filter { it.name == "a" }.map { it.id }
val xIds = snap.symbols.filter { it.name == "x" }.map { it.id }
assertTrue(aIds.isNotEmpty())
assertTrue(xIds.isNotEmpty())
// Both should have at least one reference across any symbol with that name
val aRefs = snap.references.count { it.symbolId in aIds }
val xRefs = snap.references.count { it.symbolId in xIds }
assertEquals(1, aRefs)
assertEquals(1, xRefs)
}
@Test
fun binds_top_level_val_usage() = runTest {
val snap = bind(
"""
val x = 1
x + 1
"""
)
val xSym = snap.symbols.firstOrNull { it.name == "x" }
assertNotNull(xSym)
// One reference usage to top-level x
val refs = snap.references.filter { it.symbolId == xSym.id }
assertEquals(1, refs.size)
}
@Test
fun shadowing_scopes() = runTest {
val snap = bind(
"""
val x = 1
fun f(){
val x = 2
x
}
"""
)
val allX = snap.symbols.filter { it.name == "x" }
// Expect at least two x symbols (top-level and local)
assertEquals(true, allX.size >= 2)
// The single reference inside f body should bind to the inner x (containerId != null)
val localXs = allX.filter { it.containerId != null }
assertEquals(true, localXs.isNotEmpty())
val localX = localXs.maxBy { it.declStart }
val refsToLocal = snap.references.count { it.symbolId == localX.id }
assertEquals(1, refsToLocal)
}
@Test
fun class_fields_basic() = runTest {
val snap = bind(
"""
class C {
val foo = 1
fun bar(){ foo }
}
"""
)
val fooField = snap.symbols.firstOrNull { it.name == "foo" }
assertNotNull(fooField)
// Should have at least one reference (usage in bar)
val refs = snap.references.count { it.symbolId == fooField.id }
assertEquals(1, refs)
}
@Test
fun ctor_params_as_fields() = runTest {
val snap = bind(
"""
class C(val x:Int){
fun f(){ x }
}
"""
)
val xField = snap.symbols.firstOrNull { it.name == "x" }
assertNotNull(xField)
val refs = snap.references.count { it.symbolId == xField.id }
assertEquals(1, refs)
}
}