Revert "Revert "Add dex file writer to dexlayout tool.""

This reverts commit fd1a6c2a08ca3e2476b7424b9b0fa58e73b29e87.

Fixed output being clobbered during DexLayoutTest.DexFileOutput.
Option added to put dex output file in scratch directory.

Bug: 29921113
Test: mm test-art-host-gtest-dexlayout_test

Change-Id: I9e6b139cf06aaa39c83ad1e74329db266464a8e4
diff --git a/dexlayout/dexlayout_test.cc b/dexlayout/dexlayout_test.cc
index 42b64c3..89544d7 100644
--- a/dexlayout/dexlayout_test.cc
+++ b/dexlayout/dexlayout_test.cc
@@ -31,43 +31,83 @@
  protected:
   virtual void SetUp() {
     CommonRuntimeTest::SetUp();
-    // TODO: Test with other dex files for improved coverage.
-    // Dogfood our own lib core dex file.
-    dex_file_ = GetLibCoreDexFileNames()[0];
   }
 
-  // Runs test with given arguments.
-  bool Exec(std::string* error_msg) {
+  // Runs FullPlainOutput test.
+  bool FullPlainOutputExec(std::string* error_msg) {
     // TODO: dexdump2 -> dexdump ?
     ScratchFile dexdump_output;
     std::string dexdump_filename = dexdump_output.GetFilename();
     std::string dexdump = GetTestAndroidRoot() + "/bin/dexdump2";
     EXPECT_TRUE(OS::FileExists(dexdump.c_str())) << dexdump << " should be a valid file path";
-    std::vector<std::string> dexdump_exec_argv =
-        { dexdump, "-d", "-f", "-h", "-l", "plain", "-o", dexdump_filename, dex_file_ };
 
     ScratchFile dexlayout_output;
     std::string dexlayout_filename = dexlayout_output.GetFilename();
     std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
     EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
-    std::vector<std::string> dexlayout_exec_argv =
-        { dexlayout, "-d", "-f", "-h", "-l", "plain", "-o", dexlayout_filename, dex_file_ };
 
-    if (!::art::Exec(dexdump_exec_argv, error_msg)) {
-      return false;
-    }
-    if (!::art::Exec(dexlayout_exec_argv, error_msg)) {
-      return false;
-    }
-    std::vector<std::string> diff_exec_argv =
-        { "/usr/bin/diff", dexdump_filename, dexlayout_filename };
-    if (!::art::Exec(diff_exec_argv, error_msg)) {
-      return false;
+    for (const std::string &dex_file : GetLibCoreDexFileNames()) {
+      std::vector<std::string> dexdump_exec_argv =
+          { dexdump, "-d", "-f", "-h", "-l", "plain", "-o", dexdump_filename, dex_file };
+      std::vector<std::string> dexlayout_exec_argv =
+          { dexlayout, "-d", "-f", "-h", "-l", "plain", "-o", dexlayout_filename, dex_file };
+
+      if (!::art::Exec(dexdump_exec_argv, error_msg)) {
+        return false;
+      }
+      if (!::art::Exec(dexlayout_exec_argv, error_msg)) {
+        return false;
+      }
+      std::vector<std::string> diff_exec_argv =
+          { "/usr/bin/diff", dexdump_filename, dexlayout_filename };
+      if (!::art::Exec(diff_exec_argv, error_msg)) {
+        return false;
+      }
     }
     return true;
   }
 
-  std::string dex_file_;
+  // Runs DexFileOutput test.
+  bool DexFileOutputExec(std::string* error_msg) {
+    ScratchFile tmp_file;
+    std::string tmp_name = tmp_file.GetFilename();
+    size_t tmp_last_slash = tmp_name.rfind("/");
+    std::string tmp_dir = tmp_name.substr(0, tmp_last_slash + 1);
+    std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
+    EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
+
+    for (const std::string &dex_file : GetLibCoreDexFileNames()) {
+      std::vector<std::string> dexlayout_exec_argv =
+          { dexlayout, "-d", "-f", "-h", "-l", "plain", "-w", tmp_dir, "-o", tmp_name, dex_file };
+
+      if (!::art::Exec(dexlayout_exec_argv, error_msg)) {
+        return false;
+      }
+
+      size_t dex_file_last_slash = dex_file.rfind("/");
+      std::string dex_file_name = dex_file.substr(dex_file_last_slash + 1);
+      std::vector<std::string> unzip_exec_argv =
+          { "/usr/bin/unzip", dex_file, "classes.dex", "-d", tmp_dir};
+      if (!::art::Exec(unzip_exec_argv, error_msg)) {
+        return false;
+      }
+      std::vector<std::string> diff_exec_argv =
+          { "/usr/bin/diff", tmp_dir + "classes.dex" , tmp_dir + dex_file_name };
+      if (!::art::Exec(diff_exec_argv, error_msg)) {
+        return false;
+      }
+      std::vector<std::string> rm_zip_exec_argv = { "/bin/rm", tmp_dir + "classes.dex" };
+      if (!::art::Exec(rm_zip_exec_argv, error_msg)) {
+        return false;
+      }
+      std::vector<std::string> rm_out_exec_argv = { "/bin/rm", tmp_dir + dex_file_name };
+      if (!::art::Exec(rm_out_exec_argv, error_msg)) {
+        return false;
+      }
+    }
+
+    return true;
+  }
 };
 
 
@@ -75,7 +115,14 @@
   // Disable test on target.
   TEST_DISABLED_FOR_TARGET();
   std::string error_msg;
-  ASSERT_TRUE(Exec(&error_msg)) << error_msg;
+  ASSERT_TRUE(FullPlainOutputExec(&error_msg)) << error_msg;
+}
+
+TEST_F(DexLayoutTest, DexFileOutput) {
+  // Disable test on target.
+  TEST_DISABLED_FOR_TARGET();
+  std::string error_msg;
+  ASSERT_TRUE(DexFileOutputExec(&error_msg)) << error_msg;
 }
 
 }  // namespace art