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());
   }