From a48dc25c4670d4a58c3ad1fe31042dffa2dd9579 Mon Sep 17 00:00:00 2001 From: Zalim Bashorov Date: Wed, 26 Feb 2014 16:04:33 +0400 Subject: [PATCH] JS backend: added more tests for closures. --- .../k2js/test/semantics/ClosureTest.java | 65 ++++++++++++++++++- .../closure/cases/closureArrayListInstance.kt | 27 ++++++++ .../closure/cases/closureGenericTypeValue.kt | 18 +++++ .../closureInFewFunctionWithDifferentName.kt | 33 ++++++++++ .../testData/closure/cases/closureInObject.kt | 27 ++++++++ .../cases/closureLocalInNestedObject.kt | 13 ++++ ...osureReceiverInLocalExtFunByLocalExtFun.kt | 15 +++++ .../closure/cases/closureReferencingMember.kt | 16 ++++- .../closure/cases/closureThisAndReceiver.kt | 39 +++++++++++ ...closureThisByUsingMethodFromParentClass.kt | 61 +++++++++++++++++ ...isInFunctionWhichNamedSameAsParentClass.kt | 19 ++++++ .../cases/closureThisInLocalFunction.kt | 22 +++++++ ...losureValToScopeWithSameNameDeclaration.kt | 30 +++++++++ ...losureVarToScopeWithSameNameDeclaration.kt | 31 +++++++++ .../closure/cases/recursiveExtFunction.kt | 39 +++++++++++ ...impleRecursion.kt => recursiveFunction.kt} | 0 ...ecursiveFunctionWithSameNameDeclaration.kt | 43 ++++++++++++ ...ManyClosuresInNestedFunctionsAndObjects.kt | 25 +++++++ 18 files changed, 518 insertions(+), 5 deletions(-) create mode 100644 js/js.translator/testData/closure/cases/closureArrayListInstance.kt create mode 100644 js/js.translator/testData/closure/cases/closureGenericTypeValue.kt create mode 100644 js/js.translator/testData/closure/cases/closureInFewFunctionWithDifferentName.kt create mode 100644 js/js.translator/testData/closure/cases/closureInObject.kt create mode 100644 js/js.translator/testData/closure/cases/closureLocalInNestedObject.kt create mode 100644 js/js.translator/testData/closure/cases/closureReceiverInLocalExtFunByLocalExtFun.kt create mode 100644 js/js.translator/testData/closure/cases/closureThisAndReceiver.kt create mode 100644 js/js.translator/testData/closure/cases/closureThisByUsingMethodFromParentClass.kt create mode 100644 js/js.translator/testData/closure/cases/closureThisInFunctionWhichNamedSameAsParentClass.kt create mode 100644 js/js.translator/testData/closure/cases/closureThisInLocalFunction.kt create mode 100644 js/js.translator/testData/closure/cases/closureValToScopeWithSameNameDeclaration.kt create mode 100644 js/js.translator/testData/closure/cases/closureVarToScopeWithSameNameDeclaration.kt create mode 100644 js/js.translator/testData/closure/cases/recursiveExtFunction.kt rename js/js.translator/testData/closure/cases/{simpleRecursion.kt => recursiveFunction.kt} (100%) create mode 100644 js/js.translator/testData/closure/cases/recursiveFunctionWithSameNameDeclaration.kt create mode 100644 js/js.translator/testData/closure/cases/withManyClosuresInNestedFunctionsAndObjects.kt diff --git a/js/js.tests/test/org/jetbrains/k2js/test/semantics/ClosureTest.java b/js/js.tests/test/org/jetbrains/k2js/test/semantics/ClosureTest.java index fe880217ae2..c9c208415a0 100644 --- a/js/js.tests/test/org/jetbrains/k2js/test/semantics/ClosureTest.java +++ b/js/js.tests/test/org/jetbrains/k2js/test/semantics/ClosureTest.java @@ -52,7 +52,15 @@ public final class ClosureTest extends SingleFileTranslationTest { fooBoxTest(); } - public void testSimpleRecursion() throws Exception { + public void testRecursiveFunction() throws Exception { + checkFooBoxIsOk(); + } + + public void testRecursiveFunctionWithSameNameDeclaration() throws Exception { + checkFooBoxIsOk(); + } + + public void testRecursiveExtFunction() throws Exception { checkFooBoxIsOk(); } @@ -64,8 +72,7 @@ public final class ClosureTest extends SingleFileTranslationTest { checkFooBoxIsOk(); } - // TODO: fix - public void igonre_testClosureLocalFunctionByInnerFunctionInConstrunctor() throws Exception { + public void testClosureLocalFunctionByInnerFunctionInConstructor() throws Exception { checkFooBoxIsOk(); } @@ -84,4 +91,56 @@ public final class ClosureTest extends SingleFileTranslationTest { public void testClosureLocalLiteralFunction() throws Exception { checkFooBoxIsOk(); } + + public void testClosureThisInLocalFunction() throws Exception { + checkFooBoxIsOk(); + } + + public void testClosureValToScopeWithSameNameDeclaration() throws Exception { + checkFooBoxIsOk(); + } + + public void testClosureVarToScopeWithSameNameDeclaration() throws Exception { + checkFooBoxIsOk(); + } + + public void testClosureLocalInNestedObject() throws Exception { + checkFooBoxIsOk(); + } + + public void testClosureThisAndReceiver() throws Exception { + checkFooBoxIsOk(); + } + + public void testClosureGenericTypeValue() throws Exception { + checkFooBoxIsOk(); + } + + public void testClosureInObject() throws Exception { + checkFooBoxIsOk(); + } + + public void testWithManyClosuresInNestedFunctionsAndObjects() throws Exception { + checkFooBoxIsOk(); + } + + public void testClosureReceiverInLocalExtFunByLocalExtFun() throws Exception { + checkFooBoxIsOk(); + } + + public void testClosureArrayListInstance() throws Exception { + checkFooBoxIsOk(); + } + + public void testClosureThisByUsingMethodFromParentClass() throws Exception { + checkFooBoxIsOk(); + } + + public void testClosureThisInFunctionWhichNamedSameAsParentClass() throws Exception { + checkFooBoxIsOk(); + } + + public void testClosureInFewFunctionWithDifferentName() throws Exception { + checkFooBoxIsOk(); + } } diff --git a/js/js.translator/testData/closure/cases/closureArrayListInstance.kt b/js/js.translator/testData/closure/cases/closureArrayListInstance.kt new file mode 100644 index 00000000000..128dbe78f98 --- /dev/null +++ b/js/js.translator/testData/closure/cases/closureArrayListInstance.kt @@ -0,0 +1,27 @@ +package foo + +import java.util.ArrayList + +fun test(f: () -> String): String { + val funLit = { f() } + return funLit() +} + + +fun box(): String { + val l = ArrayList() + l.add("1 ") + l.add("foobar ") + l.add("baz") + + val f = { + var s = "" + for (e in l) s += e + s + } + + val r = f() + if (r != "1 foobar baz") return "$r" + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/closure/cases/closureGenericTypeValue.kt b/js/js.translator/testData/closure/cases/closureGenericTypeValue.kt new file mode 100644 index 00000000000..f65abd96054 --- /dev/null +++ b/js/js.translator/testData/closure/cases/closureGenericTypeValue.kt @@ -0,0 +1,18 @@ +package foo + +class A(val a: T) { + val foo = { a } +} + +fun T.bar() = { this } + +fun assertEquals(expected: String, actual: String) { + if (expected != actual) throw Exception("Expected: $expected, actual: $actual") +} + +fun box(): String { + assertEquals("ok", A("ok").foo()) + assertEquals("a42", "a42".bar()()) + + return "OK" +} diff --git a/js/js.translator/testData/closure/cases/closureInFewFunctionWithDifferentName.kt b/js/js.translator/testData/closure/cases/closureInFewFunctionWithDifferentName.kt new file mode 100644 index 00000000000..2b2bd863b7a --- /dev/null +++ b/js/js.translator/testData/closure/cases/closureInFewFunctionWithDifferentName.kt @@ -0,0 +1,33 @@ +package foo + +fun box(): String { + val bar = 12 + + val baz = { + var result = "test1 " + if (true) { + val bar = "some text" + result += bar + } + result += bar + result + } + + val r1 = baz() + if (r1 != "test1 some text12") return "r1 = $r1"; + + val boo = { + var result = "test2 " + result += bar + if (true) { + val bar = 4 + result += bar + } + result + } + + val r2 = boo() + if (r2 != "test2 124") return "r2 = $r2"; + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/closure/cases/closureInObject.kt b/js/js.translator/testData/closure/cases/closureInObject.kt new file mode 100644 index 00000000000..9be41734929 --- /dev/null +++ b/js/js.translator/testData/closure/cases/closureInObject.kt @@ -0,0 +1,27 @@ +package foo + +object A { + val a = 1 + fun foo() = 31 + + val f = { a + foo() } +} + +class B { + class object { + val a = 21 + fun foo() = 3 + + val f = { this.a + this.foo() } + } +} + +fun box(): String { + val a = A.f() + if (a != 32) return "a != 32, a = $a" + + val b = B.f() + if (b != 24) return "b != 24, b = $b" + + return "OK" +} diff --git a/js/js.translator/testData/closure/cases/closureLocalInNestedObject.kt b/js/js.translator/testData/closure/cases/closureLocalInNestedObject.kt new file mode 100644 index 00000000000..7ad0004e8e6 --- /dev/null +++ b/js/js.translator/testData/closure/cases/closureLocalInNestedObject.kt @@ -0,0 +1,13 @@ +package foo + +fun box(): String { + var boo = "OK" + var foo = object { + object bar { + val baz = boo + } + } + + return foo.bar.baz +} + diff --git a/js/js.translator/testData/closure/cases/closureReceiverInLocalExtFunByLocalExtFun.kt b/js/js.translator/testData/closure/cases/closureReceiverInLocalExtFunByLocalExtFun.kt new file mode 100644 index 00000000000..9102fc4cff8 --- /dev/null +++ b/js/js.translator/testData/closure/cases/closureReceiverInLocalExtFunByLocalExtFun.kt @@ -0,0 +1,15 @@ +package foo + +fun box(): String { + + fun Int.foo(): Boolean { + fun Int.bar() = this == 2 && this@foo == 1 + val b = { this == 1 } + + return this == 1 && 2.bar() && b() + } + + if (!1.foo()) return "Failed" + + return "OK" +} diff --git a/js/js.translator/testData/closure/cases/closureReferencingMember.kt b/js/js.translator/testData/closure/cases/closureReferencingMember.kt index 2580f667fbf..d1d08c5b8e5 100644 --- a/js/js.translator/testData/closure/cases/closureReferencingMember.kt +++ b/js/js.translator/testData/closure/cases/closureReferencingMember.kt @@ -3,15 +3,27 @@ package foo class A() { var i = 0 + fun boo() = 1 + fun f() { for (j in 0..2) { foo { - i += j + i += j + boo() } } } } +fun A.bar(): Int { + for (u in 4..7) { + foo { + i += u + boo() + } + } + + return i +} + fun foo(f: () -> Unit) { f() } @@ -19,5 +31,5 @@ fun foo(f: () -> Unit) { fun box(): Boolean { val a = A() a.f() - return a.i == 3 + return a.i == 6 && a.bar() == 32 } diff --git a/js/js.translator/testData/closure/cases/closureThisAndReceiver.kt b/js/js.translator/testData/closure/cases/closureThisAndReceiver.kt new file mode 100644 index 00000000000..3c6301dfff9 --- /dev/null +++ b/js/js.translator/testData/closure/cases/closureThisAndReceiver.kt @@ -0,0 +1,39 @@ +package foo + +class A(val a: String) { + fun A.foo() = { a + this.a + this@foo.a + this@A.a }() + fun bar(a: A) = this.foo() + " " + a.foo() + + fun A.boo() = { array(this, this@boo, this@A) }() + fun baz(a: A) = this.boo().stringify() + " " + a.boo().stringify() + + fun Array.stringify(): String { + var result = "" + for (a in this) { + result += a.a + } + + return result + } +} + +fun assertEquals(expected: String, actual: String) { + if (expected != actual) throw Exception("Expected: $expected, actual: $actual") +} + +fun box(): String { + val a = A("a") + val b = A("b") + + assertEquals("aaaa aaaa", a.bar(a)) + assertEquals("aaaa bbba", a.bar(b)) + assertEquals("bbbb aaab", b.bar(a)) + assertEquals("bbbb bbbb", b.bar(b)) + + assertEquals("aaa aaa", a.baz(a)) + assertEquals("aaa bba", a.baz(b)) + assertEquals("bbb aab", b.baz(a)) + assertEquals("bbb bbb", b.baz(b)) + + return "OK" +} diff --git a/js/js.translator/testData/closure/cases/closureThisByUsingMethodFromParentClass.kt b/js/js.translator/testData/closure/cases/closureThisByUsingMethodFromParentClass.kt new file mode 100644 index 00000000000..1179315c8d0 --- /dev/null +++ b/js/js.translator/testData/closure/cases/closureThisByUsingMethodFromParentClass.kt @@ -0,0 +1,61 @@ +package foo + +// HACKS + +native +val ROOT = "Kotlin.modules.JS_TESTS" +native +val PATH_TO_F_CREATOR = "foo.B.B\$f" +native +val PATH_TO_G_CREATOR = "foo.B.B\$f_0" + +native("$ROOT.$PATH_TO_F_CREATOR") +val F_CREATOR: Any = noImpl +native("$ROOT.$PATH_TO_G_CREATOR") +val G_CREATOR: Any = noImpl + + +// Test + +open class A { + fun foo() = "A::foo" +} + +class B : A() { + fun boo() = "B::boo" + + val f = { foo() } + val g = { boo() } +} + + +fun box(): String { + val b = B() + val f = b.f + val g = b.g + + assertEquals("A::foo", f()) + assertEquals("B::boo", g()) + + val fs = F_CREATOR.toString() + val gs = G_CREATOR.toString().replaceAll("boo", "foo") + + assertEquals(gs, fs) + + return "OK" +} + + +// Helpers + +fun assertEquals(expected: T, actual: T) { + if (expected != actual) throw Exception("expected: $expected, actual: $actual"); +} + +native +fun String.replace(regexp: RegExp, replacement: String): String = noImpl + +fun String.replaceAll(regexp: String, replacement: String): String = replace(RegExp(regexp, "g"), replacement) + +native +class RegExp(regexp: String, flags: String) \ No newline at end of file diff --git a/js/js.translator/testData/closure/cases/closureThisInFunctionWhichNamedSameAsParentClass.kt b/js/js.translator/testData/closure/cases/closureThisInFunctionWhichNamedSameAsParentClass.kt new file mode 100644 index 00000000000..bcf53c13e1d --- /dev/null +++ b/js/js.translator/testData/closure/cases/closureThisInFunctionWhichNamedSameAsParentClass.kt @@ -0,0 +1,19 @@ +package foo + +class B(val b: String) + +class A(val a: String) { + fun B.A() = { a + b } + + fun foo(a: B) = a.A()() +} + +fun box(): String { + val bar = A("bar") + val baz = B("baz") + + val r = bar.foo(baz) + if (r != "barbaz") return "$r"; + + return "OK" +} \ No newline at end of file diff --git a/js/js.translator/testData/closure/cases/closureThisInLocalFunction.kt b/js/js.translator/testData/closure/cases/closureThisInLocalFunction.kt new file mode 100644 index 00000000000..e78a4362078 --- /dev/null +++ b/js/js.translator/testData/closure/cases/closureThisInLocalFunction.kt @@ -0,0 +1,22 @@ +package foo + +class Foo { + val o = "O" + val k = "K" + fun test(): String { + fun bar() = o + fun Int.baz() = k + this + + val boo = { k } + val cux: Int.()->String = { o + this } + + return bar() + 17.baz() + 23.cux() + boo() + } +} + +fun box(): String { + val a = Foo().test() + if (a != "OK17O23K") return "$a" + + return "OK" +} diff --git a/js/js.translator/testData/closure/cases/closureValToScopeWithSameNameDeclaration.kt b/js/js.translator/testData/closure/cases/closureValToScopeWithSameNameDeclaration.kt new file mode 100644 index 00000000000..897541c65da --- /dev/null +++ b/js/js.translator/testData/closure/cases/closureValToScopeWithSameNameDeclaration.kt @@ -0,0 +1,30 @@ +package foo + +val f = true + +fun box(): String { + val bar = "test " + val boo = "another " + + fun baz(): String { + var result = bar + + if (f) { + val bar = 42 + result += bar + + val boo = 7 + result += boo + } + + result += boo + result += bar + + return result + } + + val r = baz() + if (r != "test 427another test ") return r; + + return "OK" +} diff --git a/js/js.translator/testData/closure/cases/closureVarToScopeWithSameNameDeclaration.kt b/js/js.translator/testData/closure/cases/closureVarToScopeWithSameNameDeclaration.kt new file mode 100644 index 00000000000..53c08f70499 --- /dev/null +++ b/js/js.translator/testData/closure/cases/closureVarToScopeWithSameNameDeclaration.kt @@ -0,0 +1,31 @@ +package foo + +val f = true + +fun box(): String { + var bar = "" + var boo = 23 + + fun baz() { + bar += "test " + + if (f) { + val v1 = 42 + var bar = 12 + bar += v1 + + val v2 = 7 + var boo = "" + boo += v2 + } + + boo += 7 + bar += "text" + } + + baz() + if (bar != "test text") return "bar != \"test text\", bar = \"$bar\""; + if (boo != 30) return "boo != 61, boo = $boo"; + + return "OK" +} diff --git a/js/js.translator/testData/closure/cases/recursiveExtFunction.kt b/js/js.translator/testData/closure/cases/recursiveExtFunction.kt new file mode 100644 index 00000000000..92fd0167eef --- /dev/null +++ b/js/js.translator/testData/closure/cases/recursiveExtFunction.kt @@ -0,0 +1,39 @@ +package foo + +fun Int.foo(a: Int): Int { + if (a == 0) { + return this.foo(4) + foo(7) + this + } + + return a +} + +fun assertEquals(expected: T, actual: T) { + if (expected != actual) throw Exception("expected: $expected, actual, $actual") +} + +fun box(): String { + assertEquals(34, 23.foo(0)) + + fun Int.bar(a: Int): Int { + if (a == 0) { + return this.bar(12) + bar(4) + this + } + + return a + } + assertEquals(19, 3.bar(0)) + + fun f() = 11 + val v = 3 + fun Int.baz(a: Int): Int { + if (a == 0) { + return this.baz(v) + baz(f()) + this + } + + return a + } + assertEquals(21, 7.baz(0)) + + return "OK" +} diff --git a/js/js.translator/testData/closure/cases/simpleRecursion.kt b/js/js.translator/testData/closure/cases/recursiveFunction.kt similarity index 100% rename from js/js.translator/testData/closure/cases/simpleRecursion.kt rename to js/js.translator/testData/closure/cases/recursiveFunction.kt diff --git a/js/js.translator/testData/closure/cases/recursiveFunctionWithSameNameDeclaration.kt b/js/js.translator/testData/closure/cases/recursiveFunctionWithSameNameDeclaration.kt new file mode 100644 index 00000000000..17a66eadd98 --- /dev/null +++ b/js/js.translator/testData/closure/cases/recursiveFunctionWithSameNameDeclaration.kt @@ -0,0 +1,43 @@ +package foo + +fun bar(i: Int = 0): Int { + if (i == 7) { + val bar = i + return bar + } + else { + return bar(i - 1) + } +} + +fun box(): String { + val a = bar(10) + if (a != 7) return "bar(10) = $a, but expected 7" + + fun boo(i: Int = 0): Int { + if (i == 4) { + val boo = i + return boo + } else { + return boo(i - 1) + } + } + val b = boo(17) + if (b != 4) return "boo(17) = $b, but expected 4" + + fun f() = 1 + val v = 3 + fun baz(i: Int = 0): Int { + if (i == v) { + val baz = f() + v + return baz + } else { + return baz(i - 1) + } + } + + val c = baz(10) + if (c != 4) return "baz(10) = $c, but expected 4" + + return "OK" +} diff --git a/js/js.translator/testData/closure/cases/withManyClosuresInNestedFunctionsAndObjects.kt b/js/js.translator/testData/closure/cases/withManyClosuresInNestedFunctionsAndObjects.kt new file mode 100644 index 00000000000..75975c3d6d8 --- /dev/null +++ b/js/js.translator/testData/closure/cases/withManyClosuresInNestedFunctionsAndObjects.kt @@ -0,0 +1,25 @@ +package foo + +fun run(f: ()->T) = f() + +fun box(): String { + val t = run { + object { + fun foo() = "3" + + fun boo(param: String): String { + val a = object { + fun bar() = "57" + fun b(): String = run { param + bar() + foo() } + } + + return a.b() + } + } + } + + val r = t.boo("OK") + if (r != "OK573") return "r != \"OK573\", r = \"$r\"" + + return "OK" +}