Merge "Test verification behavior of dex move instructions."
diff --git a/src/test/java/com/android/tools/r8/smali/DexMoveInstructionsTest.java b/src/test/java/com/android/tools/r8/smali/DexMoveInstructionsTest.java
new file mode 100644
index 0000000..c92b73b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/smali/DexMoveInstructionsTest.java
@@ -0,0 +1,95 @@
+// Copyright (c) 2018, 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.smali;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.utils.DescriptorUtils;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import org.junit.Test;
+
+public class DexMoveInstructionsTest extends SmaliTestBase {
+
+  public static final String CLASS = "Test";
+
+  @Test
+  public void testValidObjectMoves() throws Throwable {
+    ProcessResult result = testMoves("ExpectedToPass", "Ljava/lang/String;", Arrays.asList(
+        "move-object",
+        "move-object/from16",
+        "move-object/16"));
+    assertEquals(result.toString(), 0, result.exitCode);
+  }
+
+  @Test
+  public void testInvalidObjectMoves() throws Throwable {
+    ProcessResult result = testMoves("ExpectedToFail", "Ljava/lang/String;", Arrays.asList(
+        "move",
+        "move/from16",
+        "move/16"));
+    assertEquals(result.toString(), 1, result.exitCode);
+    assertTrue("Did not find 'Verification error' in " + result.stderr,
+        result.stderr.contains("Verification error") || result.stderr.contains("VerifyError"));
+  }
+
+  @Test
+  public void testValidSingleMoves() throws Throwable {
+    ProcessResult result = testMoves("ExpectedToPass", "I", Arrays.asList(
+        "move",
+        "move/from16",
+        "move/16"));
+    assertEquals(result.toString(), 0, result.exitCode);
+  }
+
+  @Test
+  public void testInvalidSingleMoves() throws Throwable {
+    ProcessResult result = testMoves("ExpectedToFail", "I", Arrays.asList(
+        "move-object",
+        "move-object/from16",
+        "move-object/16"));
+    assertEquals(result.toString(), 1, result.exitCode);
+    assertTrue("Did not find 'Verification error' in " + result.stderr,
+        result.stderr.contains("Verification error") || result.stderr.contains("VerifyError"));
+  }
+
+  private ProcessResult testMoves(String clazz, String typeDesc, List<String> moveOps)
+      throws Throwable {
+    String typeName = DescriptorUtils.descriptorToJavaType(typeDesc);
+
+    SmaliBuilder builder = new SmaliBuilder(clazz);
+    int i = 0;
+    for (String moveOp : moveOps) {
+      builder.addStaticMethod(typeName, "test" + i++, Collections.singletonList(typeName),
+          1,
+          "    " + moveOp + " v0, p0",
+          typeDesc.startsWith("L") ? "return-object v0" : "    return v0"
+      );
+    }
+
+    List<String> main = new ArrayList<>();
+    main.add("  sget-object         v0, Ljava/lang/System;->out:Ljava/io/PrintStream;");
+    main.add("  const v2, 0");
+    i = 0;
+    for (String moveOp : moveOps) {
+      main.add("  invoke-static { v2 }, L" + clazz + ";->test" + i++
+          + "(" + typeDesc + ")" + typeDesc);
+      if (typeDesc.startsWith("L")) {
+        main.add("  move-result-object v1");
+      } else {
+        main.add("  move-result v1");
+      }
+      main.add("  invoke-virtual { v0, v1 }, Ljava/io/PrintStream;->print(" + typeDesc + ")V");
+    }
+    main.add("  return-void");
+    builder.addMainMethod(3, main.toArray(new String[0]));
+
+    return runOnArtRaw(builder.build(), clazz);
+  }
+}