Update kotlin debug test cases
Separate simple Kotlin tests from inline ones for better readability.
Change-Id: Icd87ba66c6bc7dcd854843a994e7e9fc189ae44b
diff --git a/src/test/debugTestResourcesKotlin/KotlinApp.kt b/src/test/debugTestResourcesKotlin/KotlinApp.kt
index 7fa2be1..094407b 100644
--- a/src/test/debugTestResourcesKotlin/KotlinApp.kt
+++ b/src/test/debugTestResourcesKotlin/KotlinApp.kt
@@ -3,42 +3,27 @@
// BSD-style license that can be found in the LICENSE file.
class KotlinApp {
+
+ fun ifElse(cond: Boolean) {
+ val a = 10
+ if (cond) {
+ val b = a * 2
+ printInt(b)
+ } else {
+ val c = a / 2
+ print(c)
+ }
+ }
+
+ fun printInt(i: Int) {
+ println(i)
+ }
+
companion object {
@JvmStatic fun main(args: Array<String>) {
- println("Hello world!")
val instance = KotlinApp()
- instance.processObject(instance, instance::printObject)
- instance.invokeInlinedFunctions()
+ instance.ifElse(true)
+ instance.ifElse(false)
}
}
-
- fun processObject(obj: Any, func: (Any) -> Unit) {
- func(obj)
- }
-
- fun printObject(obj: Any) {
- println(obj)
- }
-
- fun invokeInlinedFunctions() {
- inlinedA {
- val inA = 1
- inlinedB {
- val inB = 2
- foo(inA, inB)
- }
- }
- }
-
- inline fun inlinedA(f: () -> Unit) {
- f()
- }
-
- inline fun inlinedB(f: () -> Unit) {
- f()
- }
-
- fun foo(a: Int, b: Int) {
- println("a=$a, b=$b")
- }
}
\ No newline at end of file
diff --git a/src/test/debugTestResourcesKotlin/KotlinInline.kt b/src/test/debugTestResourcesKotlin/KotlinInline.kt
new file mode 100644
index 0000000..7f914e4
--- /dev/null
+++ b/src/test/debugTestResourcesKotlin/KotlinInline.kt
@@ -0,0 +1,59 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class KotlinInline {
+
+ fun processObject(obj: Any, func: (Any) -> Unit) {
+ func(obj)
+ }
+
+ fun printObject(obj: Any) {
+ println(obj)
+ }
+
+ fun invokeInlinedFunctions() {
+ inlinedA {
+ val inA = 1
+ inlinedB {
+ val inB = 2
+ foo(inA, inB)
+ }
+ }
+ }
+
+ inline fun inlinedA(f: () -> Unit) {
+ f()
+ }
+
+ inline fun inlinedB(f: () -> Unit) {
+ f()
+ }
+
+ fun foo(a: Int, b: Int) {
+ println("a=$a, b=$b")
+ }
+
+ fun emptyMethod(unused: Int) {
+ }
+
+ fun singleInline() {
+ emptyMethod(0)
+ inlined()
+ emptyMethod(1)
+ }
+
+ inline fun inlined() {
+ emptyMethod(-1)
+ }
+
+ companion object {
+ @JvmStatic fun main(args: Array<String>) {
+ println("Hello world!")
+ val instance = KotlinInline()
+ instance.processObject(instance, instance::printObject)
+ instance.invokeInlinedFunctions()
+ instance.singleInline()
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/android/tools/r8/debug/KotlinInlineTest.java b/src/test/java/com/android/tools/r8/debug/KotlinInlineTest.java
new file mode 100644
index 0000000..e62a17b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/debug/KotlinInlineTest.java
@@ -0,0 +1,172 @@
+// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.debug;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.harmony.jpda.tests.framework.jdwp.Value;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class KotlinInlineTest extends DebugTestBase {
+
+ @Ignore("Requires kotlin-specific stepping behavior")
+ @Test
+ public void testStepOverInline() throws Throwable {
+ String methodName = "singleInline";
+ runDebugTestKotlin("KotlinInline",
+ breakpoint("KotlinInline", methodName),
+ run(),
+ inspect(s -> {
+ assertEquals("KotlinInline", s.getClassName());
+ assertEquals(methodName, s.getMethodName());
+ assertEquals("KotlinInline.kt", s.getSourceFile());
+ assertEquals(41, s.getLineNumber());
+ s.checkLocal("this");
+ }),
+ // TODO(shertz) stepping over must take kotlin inline range into account.
+ stepOver(),
+ inspect(s -> {
+ assertEquals("KotlinInline", s.getClassName());
+ assertEquals(methodName, s.getMethodName());
+ assertEquals("KotlinInline.kt", s.getSourceFile());
+ assertEquals(42, s.getLineNumber());
+ s.checkLocal("this");
+ }),
+ stepOver(),
+ inspect(s -> {
+ assertEquals("KotlinInline", s.getClassName());
+ assertEquals(methodName, s.getMethodName());
+ assertEquals("KotlinInline.kt", s.getSourceFile());
+ assertEquals(43, s.getLineNumber());
+ s.checkLocal("this");
+ }),
+ run());
+ }
+
+ @Ignore("Requires kotlin-specific stepping behavior")
+ @Test
+ public void testStepIntoInline() throws Throwable {
+ String methodName = "singleInline";
+ runDebugTestKotlin("KotlinInline",
+ breakpoint("KotlinInline", methodName),
+ run(),
+ inspect(s -> {
+ assertEquals("KotlinInline", s.getClassName());
+ assertEquals(methodName, s.getMethodName());
+ assertEquals("KotlinInline.kt", s.getSourceFile());
+ assertEquals(41, s.getLineNumber());
+ s.checkLocal("this");
+ }),
+ // TODO(shertz) stepping over must take kotlin inline range into account.
+ stepInto(),
+ inspect(s -> {
+ assertEquals("KotlinInline", s.getClassName());
+ assertEquals(methodName, s.getMethodName());
+ assertEquals("KotlinInline.kt", s.getSourceFile());
+ // The actual line number (the one encoded in debug information) is different than the
+ // source file one.
+ // TODO(shertz) extract original line number from JSR-45's SMAP (only supported on
+ // Android O+).
+ assertTrue(42 != s.getLineNumber());
+ s.checkLocal("this");
+ }),
+ run());
+ }
+
+ @Ignore("Requires kotlin-specific stepping behavior")
+ @Test
+ public void testStepOutInline() throws Throwable {
+ String methodName = "singleInline";
+ runDebugTestKotlin("KotlinInline",
+ breakpoint("KotlinInline", methodName),
+ run(),
+ inspect(s -> {
+ assertEquals("KotlinInline", s.getClassName());
+ assertEquals(methodName, s.getMethodName());
+ assertEquals("KotlinInline.kt", s.getSourceFile());
+ assertEquals(41, s.getLineNumber());
+ s.checkLocal("this");
+ }),
+ // TODO(shertz) stepping out must take kotlin inline range into account.
+ stepInto(),
+ inspect(s -> {
+ assertEquals("KotlinInline", s.getClassName());
+ assertEquals(methodName, s.getMethodName());
+ }),
+ stepOut(),
+ inspect(s -> {
+ assertEquals("KotlinInline", s.getClassName());
+ assertEquals(methodName, s.getMethodName());
+ assertEquals("KotlinInline.kt", s.getSourceFile());
+ assertEquals(43, s.getLineNumber());
+ s.checkLocal("this");
+ }),
+ run());
+ }
+
+ @Test
+ public void testKotlinInline() throws Throwable {
+ final String inliningMethodName = "invokeInlinedFunctions";
+ runDebugTestKotlin("KotlinInline",
+ breakpoint("KotlinInline", inliningMethodName),
+ run(),
+ inspect(s -> {
+ assertEquals(inliningMethodName, s.getMethodName());
+ assertEquals(16, s.getLineNumber());
+ s.checkLocal("this");
+ }),
+ stepInto(),
+ inspect(s -> {
+ // We must have stepped into the code of the inlined method but the actual current method
+ // did not change.
+ assertEquals(inliningMethodName, s.getMethodName());
+ // TODO(shertz) get the original line if JSR45 is supported by the targeted ART runtime.
+ s.checkLocal("this");
+ }),
+ stepInto(),
+ inspect(s -> {
+ assertEquals(inliningMethodName, s.getMethodName());
+ assertEquals(17, s.getLineNumber());
+ s.checkLocal("this");
+ }),
+ stepInto(),
+ inspect(s -> {
+ assertEquals(inliningMethodName, s.getMethodName());
+ assertEquals(18, s.getLineNumber());
+ s.checkLocal("this");
+ s.checkLocal("inA", Value.createInt(1));
+ // This is a "hidden" lv added by Kotlin (which is neither initialized nor used).
+ s.checkLocal("$i$f$inlinedA");
+ s.checkLocal("$i$a$1$inlinedA");
+ }),
+ stepInto(),
+ inspect(s -> {
+ // We must have stepped into the code of the second inlined method but the actual current
+ // method did not change.
+ assertEquals(inliningMethodName, s.getMethodName());
+ // TODO(shertz) get the original line if JSR45 is supported by the targeted ART runtime.
+ s.checkLocal("this");
+ }),
+ stepInto(),
+ inspect(s -> {
+ assertEquals(inliningMethodName, s.getMethodName());
+ assertEquals(19, s.getLineNumber());
+ s.checkLocal("this");
+ }),
+ stepInto(),
+ inspect(s -> {
+ assertEquals(inliningMethodName, s.getMethodName());
+ assertEquals(20, s.getLineNumber());
+ s.checkLocal("this");
+ s.checkLocal("inB", Value.createInt(2));
+ // This is a "hidden" lv added by Kotlin (which is neither initialized nor used).
+ s.checkLocal("$i$f$inlinedB");
+ s.checkLocal("$i$a$1$inlinedB");
+ }),
+ run());
+ }
+
+}
diff --git a/src/test/java/com/android/tools/r8/debug/KotlinTest.java b/src/test/java/com/android/tools/r8/debug/KotlinTest.java
index 8caa3c1..a6b57b8 100644
--- a/src/test/java/com/android/tools/r8/debug/KotlinTest.java
+++ b/src/test/java/com/android/tools/r8/debug/KotlinTest.java
@@ -3,97 +3,160 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.debug;
+import static org.junit.Assert.assertEquals;
+
import org.apache.harmony.jpda.tests.framework.jdwp.Value;
-import org.junit.Assert;
import org.junit.Test;
public class KotlinTest extends DebugTestBase {
+ // TODO(shertz) simplify test
+ // TODO(shertz) add more variables ?
@Test
- public void testKotlinApp() throws Throwable {
- final String inliningMethodName = "invokeInlinedFunctions";
+ public void testStepOver() throws Throwable {
runDebugTestKotlin("KotlinApp",
breakpoint("KotlinApp$Companion", "main"),
run(),
inspect(s -> {
- Assert.assertEquals("KotlinApp.kt", s.getSourceFile());
- Assert.assertEquals(8, s.getLineNumber());
+ assertEquals("KotlinApp$Companion", s.getClassName());
+ assertEquals("KotlinApp.kt", s.getSourceFile());
+ assertEquals(24, s.getLineNumber());
s.checkLocal("this");
s.checkLocal("args");
+ checkNoLocal("instance");
}),
stepOver(),
inspect(s -> {
- Assert.assertEquals(9, s.getLineNumber());
- s.checkLocal("this");
- s.checkLocal("args");
- }),
- stepOver(),
- inspect(s -> {
- Assert.assertEquals(10, s.getLineNumber());
+ assertEquals(25, s.getLineNumber());
s.checkLocal("this");
s.checkLocal("args");
s.checkLocal("instance");
}),
stepOver(),
inspect(s -> {
- Assert.assertEquals(11, s.getLineNumber());
+ assertEquals(26, s.getLineNumber());
s.checkLocal("this");
s.checkLocal("args");
s.checkLocal("instance");
}),
+ run());
+ }
+
+ @Test
+ public void testStepIntoAndOut() throws Throwable {
+ runDebugTestKotlin("KotlinApp",
+ breakpoint("KotlinApp$Companion", "main"),
+ run(),
+ inspect(s -> {
+ assertEquals("KotlinApp$Companion", s.getClassName());
+ assertEquals("KotlinApp.kt", s.getSourceFile());
+ assertEquals(24, s.getLineNumber());
+ s.checkLocal("this");
+ s.checkLocal("args");
+ checkNoLocal("instance");
+ }),
+ stepOver(),
+ inspect(s -> {
+ assertEquals(25, s.getLineNumber());
+ s.checkLocal("this");
+ s.checkLocal("args");
+ s.checkLocal("instance");
+ }),
+ // Step into 1st invoke of ifElse
stepInto(),
inspect(s -> {
- Assert.assertEquals(inliningMethodName, s.getMethodName());
- Assert.assertEquals(24, s.getLineNumber());
+ assertEquals("KotlinApp", s.getClassName());
+ assertEquals("KotlinApp.kt", s.getSourceFile());
+ assertEquals(8, s.getLineNumber());
s.checkLocal("this");
+ s.checkLocal("cond", Value.createBoolean(true));
+ checkNoLocal("a");
+ checkNoLocal("b");
+ checkNoLocal("c");
}),
stepInto(),
inspect(s -> {
- // We must have stepped into the code of the inlined method but the actual current method
- // did not change.
- Assert.assertEquals(inliningMethodName, s.getMethodName());
- // TODO(shertz) get the original line if JSR45 is supported by the targeted ART runtime.
+ assertEquals("KotlinApp", s.getClassName());
+ assertEquals(9, s.getLineNumber());
s.checkLocal("this");
+ s.checkLocal("cond", Value.createBoolean(true));
+ s.checkLocal("a", Value.createInt(10));
+ checkNoLocal("b");
+ checkNoLocal("c");
}),
stepInto(),
inspect(s -> {
- Assert.assertEquals(inliningMethodName, s.getMethodName());
- Assert.assertEquals(25, s.getLineNumber());
+ // We should be into the 'then' statement.
+ assertEquals("KotlinApp", s.getClassName());
+ assertEquals(10, s.getLineNumber());
s.checkLocal("this");
+ s.checkLocal("cond", Value.createBoolean(true));
+ s.checkLocal("a", Value.createInt(10));
+ checkNoLocal("b");
+ checkNoLocal("c");
}),
stepInto(),
inspect(s -> {
- Assert.assertEquals(inliningMethodName, s.getMethodName());
- Assert.assertEquals(26, s.getLineNumber());
+ assertEquals("KotlinApp", s.getClassName());
+ assertEquals(11, s.getLineNumber());
s.checkLocal("this");
- s.checkLocal("inA", Value.createInt(1));
- // This is a "hidden" lv added by Kotlin (which is neither initialized nor used).
- s.checkLocal("$i$f$inlinedA");
- s.checkLocal("$i$a$1$inlinedA");
+ s.checkLocal("cond", Value.createBoolean(true));
+ s.checkLocal("a", Value.createInt(10));
+ s.checkLocal("b", Value.createInt(20));
+ checkNoLocal("c");
+ }),
+ // Go back to the main method
+ stepOut(),
+ inspect(s -> {
+ assertEquals("KotlinApp$Companion", s.getClassName());
+ assertEquals("KotlinApp.kt", s.getSourceFile());
+ assertEquals(26, s.getLineNumber());
+ s.checkLocal("this");
+ s.checkLocal("args");
+ checkNoLocal("instance");
+ }),
+ // Step into 2nd invoke of ifElse
+ stepInto(),
+ inspect(s -> {
+ assertEquals("KotlinApp", s.getClassName());
+ assertEquals("KotlinApp.kt", s.getSourceFile());
+ assertEquals(8, s.getLineNumber());
+ s.checkLocal("this");
+ s.checkLocal("cond", Value.createBoolean(false));
+ checkNoLocal("a");
+ checkNoLocal("b");
+ checkNoLocal("c");
}),
stepInto(),
inspect(s -> {
- // We must have stepped into the code of the second inlined method but the actual current
- // method did not change.
- Assert.assertEquals(inliningMethodName, s.getMethodName());
- // TODO(shertz) get the original line if JSR45 is supported by the targeted ART runtime.
+ assertEquals("KotlinApp", s.getClassName());
+ assertEquals(9, s.getLineNumber());
s.checkLocal("this");
+ s.checkLocal("cond", Value.createBoolean(false));
+ s.checkLocal("a", Value.createInt(10));
+ checkNoLocal("b");
+ checkNoLocal("c");
}),
stepInto(),
inspect(s -> {
- Assert.assertEquals(inliningMethodName, s.getMethodName());
- Assert.assertEquals(27, s.getLineNumber());
+ // We should be into the 'else' statement this time.
+ assertEquals("KotlinApp", s.getClassName());
+ assertEquals(13, s.getLineNumber());
s.checkLocal("this");
+ s.checkLocal("cond", Value.createBoolean(false));
+ s.checkLocal("a", Value.createInt(10));
+ checkNoLocal("b");
+ checkNoLocal("c");
}),
stepInto(),
inspect(s -> {
- Assert.assertEquals(inliningMethodName, s.getMethodName());
- Assert.assertEquals(28, s.getLineNumber());
+ assertEquals("KotlinApp", s.getClassName());
+ assertEquals(14, s.getLineNumber());
s.checkLocal("this");
- s.checkLocal("inB", Value.createInt(2));
- // This is a "hidden" lv added by Kotlin (which is neither initialized nor used).
- s.checkLocal("$i$f$inlinedB");
- s.checkLocal("$i$a$1$inlinedB");
+ s.checkLocal("cond", Value.createBoolean(false));
+ s.checkLocal("a", Value.createInt(10));
+ checkNoLocal("b");
+ s.checkLocal("c", Value.createInt(5));
}),
run());
}