package io.github.kotlin.fibonacci import kotlinx.coroutines.test.runTest import net.sergeych.lyng.* import kotlin.test.* class ScriptTest { @Test fun testVersion() { println("--------------------------------------------") println("version = ${LyngVersion}") } @Test fun parseNewlines() { fun check(expected: String, type: Token.Type, row: Int, col: Int, src: String, offset: Int = 0) { val source = src.toSource() assertEquals( Token(expected, source.posAt(row, col), type), parseLing(source)[offset] ) } check("1", Token.Type.INT, 0, 0, "1 + x\n2", 0) check("+", Token.Type.PLUS, 0, 2, "1 + x\n2", 1) check("x", Token.Type.ID, 0, 4, "1 + x\n2", 2) check("\n", Token.Type.NEWLINE, 0, 5, "1 + x\n2", 3) // check("2", Token.Type.INT, 1, 0, "1 + x\n2", 4) // check("", Token.Type.EOF, 1, 0, "1 + x\n2", 5) } @Test fun parseNumbersTest() { fun check(expected: String, type: Token.Type, row: Int, col: Int, src: String, offset: Int = 0) { val source = src.toSource() assertEquals( Token(expected, source.posAt(row, col), type), parseLing(source)[offset] ) } check("1", Token.Type.INT, 0, 0, "1") check("7", Token.Type.INT, 0, 0, "7") check("17", Token.Type.INT, 0, 0, "17") check("17", Token.Type.INT, 0, 0, "17.") check(".", Token.Type.DOT, 0, 2, "17.", 1) // decimals check("17.2", Token.Type.REAL, 0, 0, "17.2") check("17.2", Token.Type.REAL, 0, 0, "17.2") check("17.2", Token.Type.REAL, 0, 0, "17.2 ") check("17.2", Token.Type.REAL, 0, 1, " 17.2") check("17.2", Token.Type.REAL, 0, 2, " 17.2 ") check("17.2e0", Token.Type.REAL, 0, 0, "17.2e0") check("17.2e-22", Token.Type.REAL, 0, 0, "17.2e-22") check("17.2e22", Token.Type.REAL, 0, 0, "17.2e+22") check("17.2e22", Token.Type.REAL, 0, 0, "17.2E+22") check("17.2e22", Token.Type.REAL, 0, 0, "17.2E22") check("17.2e-22", Token.Type.REAL, 0, 0, "17.2E-22") // hex check("1", Token.Type.HEX, 0, 0, "0x1") check("12", Token.Type.HEX, 0, 0, "0x12") check("12abcdef", Token.Type.HEX, 0, 0, "0x12abcdef.gh") check(".", Token.Type.DOT, 0, 10, "0x12abcdef.gh", 1) check("gh", Token.Type.ID, 0, 11, "0x12abcdef.gh", 2) check("5", Token.Type.INT, 0, 0, "5 6") check("6", Token.Type.INT, 0, 2, "5 6", 1) } @Test fun parseRangeTest() { var tt = parseLing("5 .. 4".toSource()) assertEquals(Token.Type.INT, tt[0].type) assertEquals(Token.Type.DOTDOT, tt[1].type) assertEquals(Token.Type.INT, tt[2].type) tt = parseLing("5 ..< 4".toSource()) assertEquals(Token.Type.INT, tt[0].type) assertEquals(Token.Type.DOTDOTLT, tt[1].type) assertEquals(Token.Type.INT, tt[2].type) } @Test fun parseInTest() { var tt = parseLing("5 in 4".toSource()) assertEquals(Token.Type.INT, tt[0].type) assertEquals(Token.Type.IN, tt[1].type) assertEquals(Token.Type.INT, tt[2].type) tt = parseLing("5 ..< 4".toSource()) assertEquals(Token.Type.INT, tt[0].type) assertEquals(Token.Type.DOTDOTLT, tt[1].type) assertEquals(Token.Type.INT, tt[2].type) } @Test fun parserLabelsTest() { val src = "label@ break@label".toSource() val tt = parseLing(src) assertEquals(Token("label", src.posAt(0, 0), Token.Type.LABEL), tt[0]) assertEquals(Token("break", src.posAt(0, 7), Token.Type.ID), tt[1]) assertEquals(Token("label", src.posAt(0, 12), Token.Type.ATLABEL), tt[2]) } @Test fun parse0Test() { val src = """ println("Hello") println( "world" ) """.trimIndent().toSource() val p = parseLing(src).listIterator() assertEquals(Token("println", src.posAt(0, 0), Token.Type.ID), p.next()) assertEquals(Token("(", src.posAt(0, 7), Token.Type.LPAREN), p.next()) assertEquals(Token("Hello", src.posAt(0, 8), Token.Type.STRING), p.next()) assertEquals(Token(")", src.posAt(0, 15), Token.Type.RPAREN), p.next()) assertEquals(Token("\n", src.posAt(0, 16), Token.Type.NEWLINE), p.next()) assertEquals(Token("println", src.posAt(1, 0), Token.Type.ID), p.next()) assertEquals(Token("(", src.posAt(1, 7), Token.Type.LPAREN), p.next()) assertEquals(Token("world", src.posAt(1, 9), Token.Type.STRING), p.next()) assertEquals(Token(")", src.posAt(1, 17), Token.Type.RPAREN), p.next()) } @Test fun parse1Test() { val src = "2 + 7".toSource() val p = parseLing(src).listIterator() assertEquals(Token("2", src.posAt(0, 0), Token.Type.INT), p.next()) assertEquals(Token("+", src.posAt(0, 2), Token.Type.PLUS), p.next()) assertEquals(Token("7", src.posAt(0, 4), Token.Type.INT), p.next()) } @Test fun compileNumbersTest() = runTest { assertEquals(ObjInt(17), eval("17")) assertEquals(ObjInt(17), eval("+17")) assertEquals(ObjInt(-17), eval("-17")) assertEquals(ObjInt(1970), eval("1900 + 70")) assertEquals(ObjInt(1970), eval("2000 - 30")) // assertEquals(ObjReal(3.14), eval("3.14")) assertEquals(ObjReal(314.0), eval("3.14e2")) assertEquals(ObjReal(314.0), eval("100 3.14e2")) assertEquals(ObjReal(314.0), eval("100\n 3.14e2")) } @Test fun compileBuiltinCallsTest() = runTest { // println(eval("π")) // val pi = eval("Math.PI") // assertIs(pi) // assertTrue(pi.value - PI < 0.000001) // assertTrue(eval("Math.PI+1").toDouble() - PI - 1.0 < 0.000001) // assertTrue(eval("sin(Math.PI)").toDouble() - 1 < 0.000001) assertTrue(eval("sin(π)").toDouble() - 1 < 0.000001) } @Test fun varsAndConstsTest() = runTest { val context = Context(pos = Pos.builtIn) assertEquals( ObjVoid, context.eval( """ val a = 17 var b = 3 """.trimIndent() ) ) assertEquals(17, context.eval("a").toInt()) assertEquals(20, context.eval("b + a").toInt()) assertFailsWith { context.eval("a = 10") } assertEquals(17, context.eval("a").toInt()) assertEquals(5, context.eval("b = a - 7 - 5").toInt()) assertEquals(5, context.eval("b").toInt()) } @Test fun functionTest() = runTest { val context = Context(pos = Pos.builtIn) context.eval( """ fun foo(a, b) { a + b } """.trimIndent() ) assertEquals(17, context.eval("foo(3,14)").toInt()) assertFailsWith { assertEquals(17, context.eval("foo(3)").toInt()) } context.eval( """ fn bar(a, b=10) { a + b + 1 } """.trimIndent() ) assertEquals(10, context.eval("bar(3, 6)").toInt()) assertEquals(14, context.eval("bar(3)").toInt()) } @Test fun simpleClosureTest() = runTest { val context = Context(pos = Pos.builtIn) context.eval( """ var global = 10 fun foo(a, b) { global + a + b } """.trimIndent() ) assertEquals(27, context.eval("foo(3,14)").toInt()) context.eval("global = 20") assertEquals(37, context.eval("foo(3,14)").toInt()) } @Test fun nullAndVoidTest() = runTest { val context = Context(pos = Pos.builtIn) assertEquals(ObjVoid, context.eval("void")) assertEquals(ObjNull, context.eval("null")) } @Test fun arithmeticOperatorsTest() = runTest { assertEquals(2, eval("5/2").toInt()) assertEquals(2.5, eval("5.0/2").toDouble()) assertEquals(2.5, eval("5/2.0").toDouble()) assertEquals(2.5, eval("5.0/2.0").toDouble()) assertEquals(1, eval("5%2").toInt()) assertEquals(1.0, eval("5.0%2").toDouble()) assertEquals(77, eval("11 * 7").toInt()) assertEquals(2.0, eval("floor(5.0/2)").toDouble()) assertEquals(3, eval("ceil(5.0/2)").toInt()) assertEquals(2.0, eval("round(4.7/2)").toDouble()) assertEquals(3.0, eval("round(5.1/2)").toDouble()) } @Test fun arithmetics() = runTest { // integer assertEquals(17, eval("2 + 3 * 5").toInt()) assertEquals(4, eval("5-1").toInt()) assertEquals(2, eval("8/4").toInt()) assertEquals(2, eval("8 % 3").toInt()) // int-real assertEquals(9.5, eval("2 + 3 * 2.5").toDouble()) assertEquals(4.5, eval("5 - 0.5").toDouble()) assertEquals(2.5, eval("5 / 2.0").toDouble()) assertEquals(2.5, eval("5.0 / 2.0").toDouble()) // real assertEquals(7.5, eval("2.5 + 5.0").toDouble()) assertEquals(4.5, eval("5.0 - 0.5").toDouble()) assertEquals(12.5, eval("5.0 * 2.5").toDouble()) assertEquals(2.5, eval("5.0 / 2.0").toDouble()) } @Test fun arithmeticParenthesisTest() = runTest { assertEquals(17, eval("2.0 + 3 * 5").toInt()) assertEquals(17, eval("2 + (3 * 5)").toInt()) assertEquals(25, eval("(2 + 3) * 5").toInt()) assertEquals(24, eval("(2 + 3) * 5 -1").toInt()) } @Test fun stringOpTest() = runTest { assertEquals("foobar", eval(""" "foo" + "bar" """).toString()) assertEquals("foo17", eval(""" "foo" + 17 """).toString()) } @Test fun eqNeqTest() = runTest { assertEquals(ObjBool(true), eval("val x = 2; x == 2")) assertEquals(ObjBool(false), eval("val x = 3; x == 2")) assertEquals(ObjBool(true), eval("val x = 3; x != 2")) assertEquals(ObjBool(false), eval("val x = 3; x != 3")) assertTrue { eval("1 == 1").toBool() } assertTrue { eval("true == true").toBool() } assertTrue { eval("true != false").toBool() } assertFalse { eval("true == false").toBool() } assertFalse { eval("false != false").toBool() } assertTrue { eval("2 == 2 && 3 != 4").toBool() } } @Test fun logicTest() = runTest { assertEquals(ObjBool(false), eval("true && false")) assertEquals(ObjBool(false), eval("false && false")) assertEquals(ObjBool(false), eval("false && true")) assertEquals(ObjBool(true), eval("true && true")) assertEquals(ObjBool(true), eval("true || false")) assertEquals(ObjBool(false), eval("false || false")) assertEquals(ObjBool(true), eval("false || true")) assertEquals(ObjBool(true), eval("true || true")) assertEquals(ObjBool(false), eval("!true")) assertEquals(ObjBool(true), eval("!false")) } @Test fun gtLtTest() = runTest { assertTrue { eval("3 > 2").toBool() } assertFalse { eval("3 > 3").toBool() } assertTrue { eval("3 >= 2").toBool() } assertFalse { eval("3 >= 4").toBool() } assertFalse { eval("3 < 2").toBool() } assertFalse { eval("3 <= 2").toBool() } assertTrue { eval("3 <= 3").toBool() } assertTrue { eval("3 <= 4").toBool() } assertTrue { eval("3 < 4").toBool() } assertFalse { eval("4 < 3").toBool() } assertFalse { eval("4 <= 3").toBool() } } @Test fun ifTest() = runTest { // if - single line var context = Context(pos = Pos.builtIn) context.eval( """ fn test1(n) { var result = "more" if( n >= 10 ) result = "enough" result } """.trimIndent() ) assertEquals("enough", context.eval("test1(11)").toString()) assertEquals("more", context.eval("test1(1)").toString()) // if - multiline (block) context = Context(pos = Pos.builtIn) context.eval( """ fn test1(n) { var prefix = "answer: " var result = "more" if( n >= 10 ) { var prefix = "bad:" // local prefix prefix = "too bad:" result = "enough" } prefix + result } """.trimIndent() ) assertEquals("answer: enough", context.eval("test1(11)").toString()) assertEquals("answer: more", context.eval("test1(1)").toString()) // else single line1 context = Context(pos = Pos.builtIn) context.eval( """ fn test1(n) { if( n >= 10 ) "enough" else "more" } """.trimIndent() ) assertEquals("enough", context.eval("test1(11)").toString()) assertEquals("more", context.eval("test1(1)").toString()) // if/else with blocks context = Context(pos = Pos.builtIn) context.eval( """ fn test1(n) { if( n > 20 ) { "too much" } else if( n >= 10 ) { "enough" } else { "more" } } """.trimIndent() ) assertEquals("enough", context.eval("test1(11)").toString()) assertEquals("more", context.eval("test1(1)").toString()) assertEquals("too much", context.eval("test1(100)").toString()) } @Test fun lateInitTest() = runTest { assertEquals( "ok", eval( """ var late fun init() { late = "ok" } init() late """.trimIndent() ).toString() ) } @Test fun whileTest() = runTest { assertEquals( 5.0, eval( """ var acc = 0 while( acc < 5 ) acc = acc + 0.5 acc """ ).toDouble() ) assertEquals( 5.0, eval( """ var acc = 0 // return from while while( acc < 5 ) { acc = acc + 0.5 acc } """ ).toDouble() ) assertEquals( 3.0, eval( """ var acc = 0 while( acc < 5 ) { acc = acc + 0.5 if( acc >= 3 ) break } acc """ ).toDouble() ) assertEquals( 17.0, eval( """ var acc = 0 while( acc < 5 ) { acc = acc + 0.5 if( acc >= 3 ) break 17 } """ ).toDouble() ) } @Test fun testWhileBlockIsolation1() = runTest { eval( """ var x = 100 var cnt = 2 while( cnt-- > 0 ) { var x = cnt + 1 assert(x == cnt + 1) } assert( x == 100 ) assert( cnt == -1 ) """.trimIndent() ) } @Test fun testWhileBlockIsolation2() = runTest { assertFails { eval( """ var cnt = 2 while( cnt-- > 0 ) { var inner = cnt + 1 assert(inner == cnt + 1) } println("inner "+inner) """.trimIndent() ) } } @Test fun testWhileBlockIsolation3() = runTest { eval( """ var outer = 7 var sum = 0 var cnt1 = 0 val initialForCnt2 = 0 while( ++cnt1 < 3 ) { var cnt2 = initialForCnt2 assert(cnt2 == 0) assert(outer == 7) while(++cnt2 < 5) { assert(initialForCnt2 == 0) var outer = 1 sum = sum + outer } } println("sum "+sum) """.trimIndent() ) } @Test fun whileNonLocalBreakTest() = runTest { assertEquals( "ok2:3:7", eval( """ var t1 = 10 outer@ while( t1 > 0 ) { var t2 = 10 println("starting t2 = " + t2) while( t2 > 0 ) { t2 = t2 - 1 println("t2 " + t2 + " t1 " + t1) if( t2 == 3 && t1 == 7) { println("will break") break@outer "ok2:"+t2+":"+t1 } } println("next t1") t1 = t1 - 1 println("t1 now "+t1) t1 } """.trimIndent() ).toString() ) } @Test fun bookTest0() = runTest { assertEquals( "just 3", eval( """ val count = 3 val res = if( count > 10 ) "too much" else "just " + count println(count) println(res) res """.trimIndent() ) .toString() ) assertEquals( "just 3", eval( """ val count = 3 var res = if( count > 10 ) "too much" else "it's " + count res = if( count > 10 ) "too much" else "just " + count res """.trimIndent() ) .toString() ) } @Test fun testIncr() = runTest { val c = Context() c.eval("var x = 10") assertEquals(10, c.eval("x++").toInt()) assertEquals(11, c.eval("x++").toInt()) assertEquals(12, c.eval("x").toInt()) assertEquals(12, c.eval("x").toInt()) assertEquals(12, c.eval("x").toInt()) } @Test fun testDecr() = runTest { val c = Context() c.eval("var x = 9") assertEquals(9, c.eval("x--").toInt()) assertEquals(8, c.eval("x--").toInt()) assertEquals(7, c.eval("x--").toInt()) assertEquals(6, c.eval("x--").toInt()) assertEquals(5, c.eval("x").toInt()) } @Test fun testDecrIncr() = runTest { val c = Context() c.eval("var x = 9") assertEquals(9, c.eval("x++").toInt()) assertEquals(10, c.eval("x++").toInt()) assertEquals(11, c.eval("x").toInt()) assertEquals(11, c.eval("x--").toInt()) assertEquals(10, c.eval("x--").toInt()) assertEquals(9, c.eval("x--").toInt()) assertEquals(8, c.eval("x--").toInt()) assertEquals(7, c.eval("x + 0").toInt()) } @Test fun testDecrIncr2() = runTest { val c = Context() c.eval("var x = 9") assertEquals(9, c.eval("x--").toInt()) assertEquals(8, c.eval("x--").toInt()) assertEquals(7, c.eval("x--").toInt()) assertEquals(6, c.eval("x").toInt()) assertEquals(6, c.eval("x++").toInt()) assertEquals(7, c.eval("x++").toInt()) assertEquals(8, c.eval("x") .also { println("${it.toDouble()} ${it.toInt()} ${it.toLong()} ${it.toInt()}") } .toInt()) } @Test fun testDecrIncr3() = runTest { val c = Context() c.eval("var x = 9") assertEquals(9, c.eval("x++").toInt()) assertEquals(10, c.eval("x++").toInt()) assertEquals(11, c.eval("x++").toInt()) assertEquals(12, c.eval("x").toInt()) assertEquals(12, c.eval("x--").toInt()) assertEquals(11, c.eval("x").toInt()) } @Test fun testIncrAndDecr() = runTest { val c = Context() assertEquals( "8", c.eval( """ var x = 5 x-- x-- x++ x * 2 """ ).toString() ) assertEquals("4", c.eval("x").toString()) // assertEquals( "8", c.eval("x*2").toString()) // assertEquals( "4", c.eval("x+0").toString()) } @Test fun bookTest2() = runTest { val src = """ fn check(amount, prefix = "answer: ") { prefix + if( amount > 100 ) "enough" else "more" } """.trimIndent() eval(src) } @Test fun testAssign1() = runTest { assertEquals(10, eval("var x = 5; x=10; x").toInt()) val ctx = Context() ctx.eval( """ var a = 1 var b = 1 """.trimIndent() ) assertEquals(3, ctx.eval("a + a + 1").toInt()) assertEquals(12, ctx.eval("a + (b = 10) + 1").toInt()) assertEquals(10, ctx.eval("b").toInt()) } @Test fun testAssign2() = runTest { val ctx = Context() ctx.eval("var x = 10") assertEquals(14, ctx.eval("x += 4").toInt()) assertEquals(14, ctx.eval("x").toInt()) assertEquals(12, ctx.eval("x -= 2").toInt()) assertEquals(12, ctx.eval("x").toInt()) assertEquals(24, ctx.eval("x *= 2").toInt()) assertEquals(24, ctx.eval("x").toInt()) assertEquals(12, ctx.eval("x /= 2").toInt()) assertEquals(12, ctx.eval("x").toInt()) assertEquals(2, ctx.eval("x %= 5").toInt()) } @Test fun testVals() = runTest { val cxt = Context() cxt.eval("val x = 11") assertEquals(11, cxt.eval("x").toInt()) assertFails { cxt.eval("x = 12") } assertFails { cxt.eval("x += 12") } assertFails { cxt.eval("x -= 12") } assertFails { cxt.eval("x *= 2") } assertFails { cxt.eval("x /= 2") } assertFails { cxt.eval("x++") } assertFails { cxt.eval("++x") } assertFails { cxt.eval("x--") } assertFails { cxt.eval("--x") } assertEquals(11, cxt.eval("x").toInt()) } @Test fun testValVarConverting() = runTest { eval( """ val x = 5 var y = x y = 1 assert(x == 5) """.trimIndent() ) assertFails { eval( """ val x = 5 fun fna(t) { t = 11 } fna(1) """.trimIndent() ) } eval( """ var x = 5 val y = x x = 10 assert(y == 5) assert(x == 10) """.trimIndent() ) } @Test fun testListLiteral() = runTest { eval( """ val list = [1,22,3] assert(list[0] == 1) assert(list[1] == 22) assert(list[2] == 3) """.trimIndent() ) eval( """ val x0 = 100 val list = [x0 + 1, x0 * 10, 3] assert(list[0] == 101) assert(list[1] == 1000) assert(list[2] == 3) """.trimIndent() ) eval( """ val x0 = 100 val list = [x0 + 1, x0 * 10, if(x0 < 100) "low" else "high", 5] assert(list[0] == 101) assert(list[1] == 1000) assert(list[2] == "high") assert(list[3] == 5) """.trimIndent() ) } @Test fun testListLiteralSpread() = runTest { eval( """ val list1 = [1,22,3] val list = ["start", ...list1, "end"] assert(list[0] == "start") assert(list[1] == 1) assert(list[2] == 22) assert(list[3] == 3) assert(list[4] == "end") """.trimIndent() ) } @Test fun testListSize() = runTest { eval( """ val a = [4,3] assert(a.size == 2) assert( 3 == a[1] ) """.trimIndent() ) } @Test fun testArrayCompare() = runTest { eval( """ val a = [4,3] val b = [4,3] assert(a == b) assert( a === a ) assert( !(a === b) ) assert( a !== b ) """.trimIndent() ) } @Test fun forLoop1() = runTest { eval( """ var sum = 0 for(i in [1,2,3]) { println(i) sum += i } assert(sum == 6) """.trimIndent() ) eval( """ fun test1(array) { var sum = 0 for(i in array) { if( i > 2 ) break "too much" sum += i } } println("result=",test1([1,2])) println("result=",test1([1,2,3])) """.trimIndent() ) } @Test fun forLoop2() = runTest { println( eval( """ fun search(haystack, needle) { for(ch in haystack) { if( ch == needle) break "found" } else null } assert( search("hello", 'l') == "found") assert( search("hello", 'z') == null) """.trimIndent() ).toString() ) } @Test fun testIntOpenRangeInclusive() = runTest { eval( """ val r = 10 .. 20 assert( r::class == Range) assert(r.isOpen == false) assert(r.start == 10) assert(r.end == 20) assert(r.isEndInclusive == true) assert(r.isIntRange) assert(12 in r) assert(10 in r) assert(20 in r) assert(9 !in r) assert(21 !in r) assert( (11..12) in r) assert( (10..11) in r) assert( (11..20) in r) assert( (10..20) in r) assert( (9..12) !in r) assert( (1..9) !in r) assert( (17..22) !in r) assert( (21..22) !in r) // assert(r.size == 11) """.trimIndent() ) } @Test fun testIntOpenRangeExclusive() = runTest { eval( """ val r = 10 ..< 20 assert( r::class == Range) assert(r.isOpen == false) assert(r.start == 10) assert(r.end == 20) assert(r.isEndInclusive == false) assert(r.isIntRange) assert(12 in r) assert(10 in r) assert(20 !in r) assert(9 !in r) assert(21 !in r) assert( (11..12) in r) assert( (10..11) in r) assert( (11..20) !in r) assert( (10..20) !in r) assert( (10..<20) in r) assert( (9..12) !in r) assert( (1..9) !in r) assert( (17..22) !in r) assert( (21..22) !in r) """.trimIndent() ) } @Test fun testIntOpenRangeInExclusive() = runTest { eval( """ assert( (1..3) !in (1..<3) ) assert( (1..<3) in (1..3) ) """.trimIndent() ) } @Test fun testCharacterRange() = runTest { eval( """ val x = '0'..'9' println(x) assert( '5' in x) assert( 'z' !in x) for( ch in x ) println(ch) """.trimIndent() ) } @Test fun testIs() = runTest { eval( """ val x = 1..10 assert( x is Range ) assert( x is Iterable ) assert( x !is String) assert( "foo" is String) assert( x is Iterable ) """.trimIndent() ) } @Test fun testForRange() = runTest { eval( """ val x = 1..3 val result = [] for( i in x ) { println(i) result += (i*10) } assert( result == [10,20,30] ) """.trimIndent() ) val a = mutableListOf(1, 2) val b = listOf(3, 4) a += 10 a += b println(a) } @Test fun iterableList() = runTest { // 473 eval( """ for( i in 0..<1024 ) { val list = (1..1024).toList() assert(list.size == 1024) assert(list[0] == 1) assert(list[-1] == 1024) } """.trimIndent() ) } @Test fun testLambdaWithIt1() = runTest { eval( """ val x = { it + "!" } val y = if( 4 < 3 ) "NG" else "OK" assert( x::class == Callable) assert( x is Callable) assert(y == "OK") assert( x("hello") == "hello!") """.trimIndent() ) } @Test fun testLambdaWithIt2() = runTest { eval( """ val x = { assert(it == void) } assert( x() == void) """.trimIndent() ) } @Test fun testLambdaWithIt3() = runTest { eval( """ val x = { assert( it == [1,2,"end"]) } println("0----") assert( x(1, 2, "end") == void) """.trimIndent() ) } @Test fun testLambdaWithArgs() = runTest { eval( """ val x = { x, y, z -> assert( [x, y, z] == [1,2,"end"]) } assert( x(1, 2, "end") == void) """.trimIndent() ) } @Test fun testLambdaWithArgsEllipsis() = runTest { eval( """ val x = { x, y... -> println("-- y=",y) println(":: "+y::class) assert( [x, ...y] == [1,2,"end"]) } assert( x(1, 2, "end") == void) assert( x(1, ...[2, "end"]) == void) """.trimIndent() ) } @Test fun testLambdaWithBadArgs() = runTest { assertFails { eval( """ val x = { x, y -> void } assert( x(1, 2) == void) assert( x(1, ...[2, "end"]) == void) """.trimIndent() ) } } @Test fun testWhileExecuteElseIfNotExecuted() = runTest { assertEquals( "ok", eval( """ while( 5 < 1 ) { "bad" } else "ok" """.trimIndent() ).toString() ) } @Test fun testIsPrimeSampleBug() = runTest { eval( """ fun naive_is_prime(candidate) { val x = if( candidate !is Int) candidate.toInt() else candidate var divisor = 1 println("start with ",x) while( ++divisor < x/2 && divisor != 2 ) { println("x=", x, " // ", divisor, " :: ", x % divisor) if( x % divisor == 0 ) break false } else true } naive_is_prime(4) """.trimIndent() ) } @Test fun testLambdaAsFnCallArg() = runTest { eval( """ fun mapValues(iterable, transform) { var result = [] for( x in iterable ) result += transform(x) } assert( [11, 21, 31] == mapValues( if( true) [1,2,3] else [10], { it*10+1 })) """.trimIndent() ) } @Test fun testSpoilArgsBug() = runTest { eval( """ fun fnb(a,b) { a + b } fun fna(a, b) { val a0 = a val b0 = b fnb(a + 1, b + 1) assert( a0 == a ) assert( b0 == b ) } fna(5,6) """ ) } }