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

261 lines
8.3 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.
*
*/
package net.sergeych.lyng
import kotlinx.coroutines.test.runTest
import net.sergeych.lyng.obj.*
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue
class WebsiteSamplesTest {
@Test
fun testEverythingIsAnExpression() = runTest {
val scope = Script.newScope()
val result = scope.eval("""
// Everything is an expression
val x: Int = 10
val status: String = if (x > 0) "Positive" else "Zero or Negative"
// Even loops return values!
val result = for (i in 1..5) {
if (i == 3) break "Found 3!"
} else "Not found"
result
""".trimIndent())
assertEquals("Found 3!", (result as ObjString).value)
}
@Test
fun testFunctionalPower() = runTest {
val scope = Script.newScope()
val result = scope.eval("""
// Functional power with generics and collections
val squares: List<Int> = (1..10)
.filter { it % 2 == 0 }
.map { it * it }
squares
""".trimIndent())
assertTrue(result is ObjList)
val list = (result as ObjList).list.map { (it as ObjInt).value }
assertEquals(listOf(4L, 16L, 36L, 64L, 100L), list)
}
@Test
fun testGenericsAndTypeAliases() = runTest {
val scope = Script.newScope()
val result = scope.eval("""
// Generics and type aliases
type Num = Int | Real
class Box<out T: Num>(val value: T) {
fun get(): T = value
}
val intBox = Box(42)
val realBox = Box(3.14)
[intBox.get(), realBox.get()]
""".trimIndent())
assertTrue(result is ObjList)
val l = (result as ObjList).list
assertEquals(42L, (l[0] as ObjInt).value)
assertEquals(3.14, (l[1] as ObjReal).value)
}
@Test
fun testStrictCompileTimeTypes() = runTest {
val scope = Script.newScope()
scope.eval("""
// Strict compile-time types and symbol resolution
fun greet(name: String, count: Int) {
for (i in 1..count) {
println("Hello, " + name + "!")
}
}
greet("Lyng", 3)
""".trimIndent())
}
@Test
fun testFlexibleMapLiterals() = runTest {
val scope = Script.newScope()
val result = scope.eval("""
// Flexible map literals and shorthands
val id = 101
val name = "Lyng"
val base = { id:, name: } // Shorthand for id: id, name: name
val full = { ...base, version: "1.5.0-SNAPSHOT", status: "active" }
full
""".trimIndent())
assertTrue(result is ObjMap)
val m = (result as ObjMap).map
assertEquals(101L, (m[ObjString("id")] as ObjInt).value)
assertEquals("Lyng", (m[ObjString("name")] as ObjString).value)
assertEquals("1.5.0-SNAPSHOT", (m[ObjString("version")] as ObjString).value)
assertEquals("active", (m[ObjString("status")] as ObjString).value)
}
@Test
fun testModernNullSafety() = runTest {
val scope = Script.newScope()
val result = scope.eval("""
// Modern null safety
var config: Map<String, Int>? = null
config ?= { timeout: 30 } // Assign only if null
val timeout = config?["timeout"] ?: 60
timeout
""".trimIndent())
assertEquals(30L, (result as ObjInt).value)
}
@Test
fun testDestructuringWithSplat() = runTest {
val scope = Script.newScope()
val result = scope.eval("""
// Destructuring with splat operator
val [first, middle..., last] = [1, 2, 3, 4, 5, 6]
[first, middle, last]
""".trimIndent())
assertTrue(result is ObjList)
val rl = (result as ObjList).list
assertEquals(1L, (rl[0] as ObjInt).value)
val middle = rl[1] as ObjList
assertEquals(listOf(2L, 3L, 4L, 5L), middle.list.map { (it as ObjInt).value })
assertEquals(6L, (rl[2] as ObjInt).value)
}
@Test
fun testDiamondSafeMultipleInheritance() = runTest {
val scope = Script.newScope()
scope.eval("""
// Diamond-safe Multiple Inheritance (C3 MRO)
interface Logger {
fun log(m: String) = println("[LOG] " + m)
}
interface Auth {
fun login(u: String) = println("Login: " + u)
}
class App() : Logger, Auth {
override fun run() {
log("Starting...")
login("admin")
}
}
App().run()
""".trimIndent())
}
@Test
fun testExtensionFunctionsAndProperties() = runTest {
val scope = Script.newScope()
val result = scope.eval("""
// Extension functions and properties
fun String.shout(): String = this.uppercase() + "!!!"
val List<T>.second: T get() = this[1]
["hello".shout(), [10, 20, 30].second]
""".trimIndent())
assertTrue(result is ObjList)
val el = (result as ObjList).list
assertEquals("HELLO!!!", (el[0] as ObjString).value)
assertEquals(20L, (el[1] as ObjInt).value)
}
@Test
fun testNonLocalReturns() = runTest {
val scope = Script.newScope()
val result = scope.eval("""
// Non-local returns from closures
fun findFirst<T>(list: Iterable<T>, predicate: (T)->Bool): T? {
list.forEach {
if (predicate(it)) return@findFirst it
}
null
}
val found: Int? = findFirst([1, 5, 8, 12]) { it > 10 }
found
""".trimIndent())
assertEquals(12L, (result as ObjInt).value)
}
@Test
fun testEasyOperatorOverloading() = runTest {
val scope = Script.newScope()
val result = scope.eval("""
// Easy operator overloading
class Vector(val x: Real, val y: Real) {
fun plus(other: Vector): Vector = Vector(x + other.x, y + other.y)
override fun toString(): String = "Vector(%g, %g)"(x, y)
}
val v1 = Vector(1, 2)
val v2 = Vector(3, 4)
(v1 + v2).toString()
""".trimIndent())
assertEquals("Vector(4, 6)", (result as ObjString).value)
}
@Test
fun testPropertyDelegationToMap() = runTest {
val scope = Script.newScope()
val result = scope.eval("""
// Property delegation to Map
class User() {
var name: String by Map()
}
val u = User()
u.name = "Sergey"
u.name
""".trimIndent())
assertEquals("Sergey", (result as ObjString).value)
}
@Test
fun testImplicitCoroutines() = runTest {
val scope = Script.newScope()
val result = scope.eval("""
// Implicit coroutines: parallelism without ceremony
// import lyng.time // we don't need it for delay if it's available globally
val d1 = launch {
delay(100.milliseconds)
"Task A finished"
}
val d2 = launch {
delay(50.milliseconds)
"Task B finished"
}
[d1.await(), d2.await()]
""".trimIndent())
assertTrue(result is ObjList)
val dl = (result as ObjList).list
assertEquals("Task A finished", (dl[0] as ObjString).value)
assertEquals("Task B finished", (dl[1] as ObjString).value)
}
}