Add regression test for vdex + layout combination

Test compiling with vdex + layout.

Test failure example:
dex2oatd F 03-01 15:19:22 68522 68522 oat_writer.cc:2269] Check failed: oat_dex_file->source_.IsRawFile()

Bug: 35761072

Test: test-art-host-gtest-dex2oat_test

Change-Id: Ieefda4b2992cfc4eaf77c7c61062e825e3c5456f
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index 2c0b125..b79050e 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -37,6 +37,8 @@
 
 namespace art {
 
+using android::base::StringPrintf;
+
 class Dex2oatTest : public Dex2oatEnvironmentTest {
  public:
   virtual void TearDown() OVERRIDE {
@@ -52,10 +54,18 @@
                            const std::string& odex_location,
                            CompilerFilter::Filter filter,
                            const std::vector<std::string>& extra_args = {},
-                           bool expect_success = true) {
+                           bool expect_success = true,
+                           bool use_fd = false) {
+    std::unique_ptr<File> oat_file;
     std::vector<std::string> args;
     args.push_back("--dex-file=" + dex_location);
-    args.push_back("--oat-file=" + odex_location);
+    if (use_fd) {
+      oat_file.reset(OS::CreateEmptyFile(odex_location.c_str()));
+      CHECK(oat_file != nullptr) << odex_location;
+      args.push_back("--oat-fd=" + std::to_string(oat_file->Fd()));
+    } else {
+      args.push_back("--oat-file=" + odex_location);
+    }
     args.push_back("--compiler-filter=" + CompilerFilter::NameOfFilter(filter));
     args.push_back("--runtime-arg");
     args.push_back("-Xnorelocate");
@@ -64,6 +74,9 @@
 
     std::string error_msg;
     bool success = Dex2Oat(args, &error_msg);
+    if (oat_file != nullptr) {
+      ASSERT_EQ(oat_file->FlushClose(), 0) << "Could not flush and close oat file";
+    }
 
     if (expect_success) {
       ASSERT_TRUE(success) << error_msg << std::endl << output_;
@@ -582,12 +595,11 @@
     ASSERT_TRUE(result);
   }
 
-  void RunTest() {
-    std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
-    std::string profile_location = GetScratchDir() + "/primary.prof";
-    std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
-
-    Copy(GetDexSrc2(), dex_location);
+  void CompileProfileOdex(const std::string& dex_location,
+                          const std::string& odex_location,
+                          bool use_fd,
+                          const std::vector<std::string>& extra_args = {}) {
+    const std::string profile_location = GetScratchDir() + "/primary.prof";
     const char* location = dex_location.c_str();
     std::string error_msg;
     std::vector<std::unique_ptr<const DexFile>> dex_files;
@@ -595,14 +607,61 @@
     EXPECT_EQ(dex_files.size(), 1U);
     std::unique_ptr<const DexFile>& dex_file = dex_files[0];
     GenerateProfile(profile_location, dex_location, dex_file->GetLocationChecksum());
+    std::vector<std::string> copy(extra_args);
+    copy.push_back("--profile-file=" + profile_location);
+    GenerateOdexForTest(dex_location,
+                        odex_location,
+                        CompilerFilter::kSpeedProfile,
+                        copy,
+                        /* expect_success */ true,
+                        use_fd);
+  }
 
-    const std::vector<std::string>& extra_args = { "--profile-file=" + profile_location };
-    GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeedProfile, extra_args);
+  void RunTest() {
+    std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
+    std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
+    Copy(GetDexSrc2(), dex_location);
+
+    CompileProfileOdex(dex_location, odex_location, /* use_fd */ false);
 
     CheckValidity();
     ASSERT_TRUE(success_);
     CheckResult(dex_location, odex_location);
   }
+
+  void RunTestVDex() {
+    std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
+    std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
+    std::string vdex_location = GetOdexDir() + "/DexOdexNoOat.vdex";
+    Copy(GetDexSrc2(), dex_location);
+
+    std::unique_ptr<File> vdex_file1(OS::CreateEmptyFile(vdex_location.c_str()));
+    CHECK(vdex_file1 != nullptr) << vdex_location;
+    ScratchFile vdex_file2;
+    {
+      std::string input_vdex = "--input-vdex-fd=-1";
+      std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file1->Fd());
+      CompileProfileOdex(dex_location,
+                         odex_location,
+                         /* use_fd */ true,
+                         { input_vdex, output_vdex });
+      EXPECT_GT(vdex_file1->GetLength(), 0u);
+    }
+    {
+      std::string input_vdex = StringPrintf("--input-vdex-fd=%d", vdex_file1->Fd());
+      std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file2.GetFd());
+      CompileProfileOdex(dex_location,
+                         odex_location,
+                         /* use_fd */ true,
+                         { input_vdex, output_vdex });
+      EXPECT_GT(vdex_file2.GetFile()->GetLength(), 0u);
+    }
+    ASSERT_EQ(vdex_file1->FlushCloseOrErase(), 0) << "Could not flush and close vdex file";
+    CheckValidity();
+    ASSERT_TRUE(success_);
+    CheckResult(dex_location, odex_location);
+  }
+
   void CheckResult(const std::string& dex_location, const std::string& odex_location) {
     // Host/target independent checks.
     std::string error_msg;
@@ -641,29 +700,33 @@
     EXPECT_EQ(odex_file->GetCompilerFilter(), CompilerFilter::kSpeedProfile);
   }
 
-    // Check whether the dex2oat run was really successful.
-    void CheckValidity() {
-      if (kIsTargetBuild) {
-        CheckTargetValidity();
-      } else {
-        CheckHostValidity();
-      }
+  // Check whether the dex2oat run was really successful.
+  void CheckValidity() {
+    if (kIsTargetBuild) {
+      CheckTargetValidity();
+    } else {
+      CheckHostValidity();
     }
+  }
 
-    void CheckTargetValidity() {
-      // TODO: Ignore for now.
-    }
+  void CheckTargetValidity() {
+    // TODO: Ignore for now.
+  }
 
-    // On the host, we can get the dex2oat output. Here, look for "dex2oat took."
-    void CheckHostValidity() {
-      EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_;
-    }
-  };
+  // On the host, we can get the dex2oat output. Here, look for "dex2oat took."
+  void CheckHostValidity() {
+    EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_;
+  }
+};
 
 TEST_F(Dex2oatLayoutTest, TestLayout) {
   RunTest();
 }
 
+TEST_F(Dex2oatLayoutTest, TestVdexLayout) {
+  RunTestVDex();
+}
+
 class Dex2oatWatchdogTest : public Dex2oatTest {
  protected:
   void RunTest(bool expect_success, const std::vector<std::string>& extra_args = {}) {