Add value parameterized test support for runtime tests

Usage is demonstrated in type_lookup_table_test.

Bug: 10245322

Change-Id: Ife6eb1ed57cb12edecce9ef101215ff15ae032e1
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index 2184f0a..e89c5af 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -117,14 +117,15 @@
 
 static bool unstarted_initialized_ = false;
 
-CommonRuntimeTest::CommonRuntimeTest() {}
-CommonRuntimeTest::~CommonRuntimeTest() {
+CommonRuntimeTestImpl::CommonRuntimeTestImpl() {}
+
+CommonRuntimeTestImpl::~CommonRuntimeTestImpl() {
   // Ensure the dex files are cleaned up before the runtime.
   loaded_dex_files_.clear();
   runtime_.reset();
 }
 
-void CommonRuntimeTest::SetUpAndroidRoot() {
+void CommonRuntimeTestImpl::SetUpAndroidRoot() {
   if (IsHost()) {
     // $ANDROID_ROOT is set on the device, but not necessarily on the host.
     // But it needs to be set so that icu4c can find its locale data.
@@ -166,7 +167,7 @@
   }
 }
 
-void CommonRuntimeTest::SetUpAndroidData(std::string& android_data) {
+void CommonRuntimeTestImpl::SetUpAndroidData(std::string& android_data) {
   // On target, Cannot use /mnt/sdcard because it is mounted noexec, so use subdir of dalvik-cache
   if (IsHost()) {
     const char* tmpdir = getenv("TMPDIR");
@@ -185,7 +186,8 @@
   setenv("ANDROID_DATA", android_data.c_str(), 1);
 }
 
-void CommonRuntimeTest::TearDownAndroidData(const std::string& android_data, bool fail_on_error) {
+void CommonRuntimeTestImpl::TearDownAndroidData(const std::string& android_data,
+                                                bool fail_on_error) {
   if (fail_on_error) {
     ASSERT_EQ(rmdir(android_data.c_str()), 0);
   } else {
@@ -235,13 +237,13 @@
   return founddir;
 }
 
-std::string CommonRuntimeTest::GetAndroidHostToolsDir() {
+std::string CommonRuntimeTestImpl::GetAndroidHostToolsDir() {
   return GetAndroidToolsDir("prebuilts/gcc/linux-x86/host",
                             "x86_64-linux-glibc2.15",
                             "x86_64-linux");
 }
 
-std::string CommonRuntimeTest::GetAndroidTargetToolsDir(InstructionSet isa) {
+std::string CommonRuntimeTestImpl::GetAndroidTargetToolsDir(InstructionSet isa) {
   switch (isa) {
     case kArm:
     case kThumb2:
@@ -269,15 +271,16 @@
   return "";
 }
 
-std::string CommonRuntimeTest::GetCoreArtLocation() {
+std::string CommonRuntimeTestImpl::GetCoreArtLocation() {
   return GetCoreFileLocation("art");
 }
 
-std::string CommonRuntimeTest::GetCoreOatLocation() {
+std::string CommonRuntimeTestImpl::GetCoreOatLocation() {
   return GetCoreFileLocation("oat");
 }
 
-std::unique_ptr<const DexFile> CommonRuntimeTest::LoadExpectSingleDexFile(const char* location) {
+std::unique_ptr<const DexFile> CommonRuntimeTestImpl::LoadExpectSingleDexFile(
+    const char* location) {
   std::vector<std::unique_ptr<const DexFile>> dex_files;
   std::string error_msg;
   MemMap::Init();
@@ -290,7 +293,7 @@
   }
 }
 
-void CommonRuntimeTest::SetUp() {
+void CommonRuntimeTestImpl::SetUp() {
   SetUpAndroidRoot();
   SetUpAndroidData(android_data_);
   dalvik_cache_.append(android_data_.c_str());
@@ -345,7 +348,7 @@
   FinalizeSetup();
 }
 
-void CommonRuntimeTest::FinalizeSetup() {
+void CommonRuntimeTestImpl::FinalizeSetup() {
   // Initialize maps for unstarted runtime. This needs to be here, as running clinits needs this
   // set up.
   if (!unstarted_initialized_) {
@@ -369,7 +372,7 @@
   runtime_->GetHeap()->SetMinIntervalHomogeneousSpaceCompactionByOom(0U);
 }
 
-void CommonRuntimeTest::ClearDirectory(const char* dirpath) {
+void CommonRuntimeTestImpl::ClearDirectory(const char* dirpath) {
   ASSERT_TRUE(dirpath != nullptr);
   DIR* dir = opendir(dirpath);
   ASSERT_TRUE(dir != nullptr);
@@ -396,7 +399,7 @@
   closedir(dir);
 }
 
-void CommonRuntimeTest::TearDown() {
+void CommonRuntimeTestImpl::TearDown() {
   const char* android_data = getenv("ANDROID_DATA");
   ASSERT_TRUE(android_data != nullptr);
   ClearDirectory(dalvik_cache_.c_str());
@@ -453,12 +456,12 @@
   return StringPrintf("%s/framework/%s%s.jar", path.c_str(), jar_prefix.c_str(), suffix.c_str());
 }
 
-std::vector<std::string> CommonRuntimeTest::GetLibCoreDexFileNames() {
+std::vector<std::string> CommonRuntimeTestImpl::GetLibCoreDexFileNames() {
   return std::vector<std::string>({GetDexFileName("core-oj", IsHost()),
                                    GetDexFileName("core-libart", IsHost())});
 }
 
-std::string CommonRuntimeTest::GetTestAndroidRoot() {
+std::string CommonRuntimeTestImpl::GetTestAndroidRoot() {
   if (IsHost()) {
     const char* host_dir = getenv("ANDROID_HOST_OUT");
     CHECK(host_dir != nullptr);
@@ -478,7 +481,7 @@
 #define ART_TARGET_NATIVETEST_DIR_STRING ""
 #endif
 
-std::string CommonRuntimeTest::GetTestDexFileName(const char* name) {
+std::string CommonRuntimeTestImpl::GetTestDexFileName(const char* name) {
   CHECK(name != nullptr);
   std::string filename;
   if (IsHost()) {
@@ -493,7 +496,8 @@
   return filename;
 }
 
-std::vector<std::unique_ptr<const DexFile>> CommonRuntimeTest::OpenTestDexFiles(const char* name) {
+std::vector<std::unique_ptr<const DexFile>> CommonRuntimeTestImpl::OpenTestDexFiles(
+    const char* name) {
   std::string filename = GetTestDexFileName(name);
   std::string error_msg;
   std::vector<std::unique_ptr<const DexFile>> dex_files;
@@ -506,13 +510,13 @@
   return dex_files;
 }
 
-std::unique_ptr<const DexFile> CommonRuntimeTest::OpenTestDexFile(const char* name) {
+std::unique_ptr<const DexFile> CommonRuntimeTestImpl::OpenTestDexFile(const char* name) {
   std::vector<std::unique_ptr<const DexFile>> vector = OpenTestDexFiles(name);
   EXPECT_EQ(1U, vector.size());
   return std::move(vector[0]);
 }
 
-std::vector<const DexFile*> CommonRuntimeTest::GetDexFiles(jobject jclass_loader) {
+std::vector<const DexFile*> CommonRuntimeTestImpl::GetDexFiles(jobject jclass_loader) {
   std::vector<const DexFile*> ret;
 
   ScopedObjectAccess soa(Thread::Current());
@@ -572,7 +576,7 @@
   return ret;
 }
 
-const DexFile* CommonRuntimeTest::GetFirstDexFile(jobject jclass_loader) {
+const DexFile* CommonRuntimeTestImpl::GetFirstDexFile(jobject jclass_loader) {
   std::vector<const DexFile*> tmp(GetDexFiles(jclass_loader));
   DCHECK(!tmp.empty());
   const DexFile* ret = tmp[0];
@@ -580,7 +584,7 @@
   return ret;
 }
 
-jobject CommonRuntimeTest::LoadDex(const char* dex_name) {
+jobject CommonRuntimeTestImpl::LoadDex(const char* dex_name) {
   std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles(dex_name);
   std::vector<const DexFile*> class_path;
   CHECK_NE(0U, dex_files.size());
@@ -596,7 +600,7 @@
   return class_loader;
 }
 
-std::string CommonRuntimeTest::GetCoreFileLocation(const char* suffix) {
+std::string CommonRuntimeTestImpl::GetCoreFileLocation(const char* suffix) {
   CHECK(suffix != nullptr);
 
   std::string location;
diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h
index 7223b6e..0ce40e8 100644
--- a/runtime/common_runtime_test.h
+++ b/runtime/common_runtime_test.h
@@ -64,8 +64,10 @@
   std::unique_ptr<File> file_;
 };
 
-class CommonRuntimeTest : public testing::Test {
+class CommonRuntimeTestImpl {
  public:
+  CommonRuntimeTestImpl();
+  virtual ~CommonRuntimeTestImpl();
   static void SetUpAndroidRoot();
 
   // Note: setting up ANDROID_DATA may create a temporary directory. If this is used in a
@@ -74,19 +76,25 @@
 
   static void TearDownAndroidData(const std::string& android_data, bool fail_on_error);
 
-  CommonRuntimeTest();
-  ~CommonRuntimeTest();
-
   // Gets the paths of the libcore dex files.
   static std::vector<std::string> GetLibCoreDexFileNames();
 
   // Returns bin directory which contains host's prebuild tools.
   static std::string GetAndroidHostToolsDir();
 
-  // Returns bin directory which contains target's prebuild tools.
+  // Returns bin directory wahich contains target's prebuild tools.
   static std::string GetAndroidTargetToolsDir(InstructionSet isa);
 
  protected:
+  // Allow subclases such as CommonCompilerTest to add extra options.
+  virtual void SetUpRuntimeOptions(RuntimeOptions* options ATTRIBUTE_UNUSED) {}
+
+  // Called before the runtime is created.
+  virtual void PreRuntimeCreate() {}
+
+  // Called after the runtime is created.
+  virtual void PostRuntimeCreate() {}
+
   static bool IsHost() {
     return !kIsTargetBuild;
   }
@@ -99,25 +107,8 @@
 
   std::unique_ptr<const DexFile> LoadExpectSingleDexFile(const char* location);
 
-  virtual void SetUp();
-
-  // Allow subclases such as CommonCompilerTest to add extra options.
-  virtual void SetUpRuntimeOptions(RuntimeOptions* options ATTRIBUTE_UNUSED) {}
-
   void ClearDirectory(const char* dirpath);
 
-  virtual void TearDown();
-
-  // Called before the runtime is created.
-  virtual void PreRuntimeCreate() {}
-
-  // Called after the runtime is created.
-  virtual void PostRuntimeCreate() {}
-
-  // Called to finish up runtime creation and filling test fields. By default runs root
-  // initializers, initialize well-known classes, and creates the heap thread pool.
-  virtual void FinalizeSetup();
-
   std::string GetTestAndroidRoot();
 
   std::string GetTestDexFileName(const char* name);
@@ -150,12 +141,45 @@
 
   std::unique_ptr<CompilerCallbacks> callbacks_;
 
+  void SetUp();
+
+  void TearDown();
+
+  void FinalizeSetup();
+
  private:
   static std::string GetCoreFileLocation(const char* suffix);
 
   std::vector<std::unique_ptr<const DexFile>> loaded_dex_files_;
 };
 
+template <typename TestType>
+class CommonRuntimeTestBase : public TestType, public CommonRuntimeTestImpl {
+ public:
+  CommonRuntimeTestBase() {}
+  virtual ~CommonRuntimeTestBase() {}
+
+ protected:
+  virtual void SetUp() {
+    CommonRuntimeTestImpl::SetUp();
+  }
+
+  virtual void TearDown() {
+    CommonRuntimeTestImpl::TearDown();
+  }
+
+  // Called to finish up runtime creation and filling test fields. By default runs root
+  // initializers, initialize well-known classes, and creates the heap thread pool.
+  virtual void FinalizeSetup() {
+    CommonRuntimeTestImpl::FinalizeSetup();
+  }
+};
+
+using CommonRuntimeTest = CommonRuntimeTestBase<testing::Test>;
+
+template <typename Param>
+using CommonRuntimeTestWithParam = CommonRuntimeTestBase<testing::TestWithParam<Param>>;
+
 // Sets a CheckJni abort hook to catch failures. Note that this will cause CheckJNI to carry on
 // rather than aborting, so be careful!
 class CheckJniAbortCatcher {
diff --git a/runtime/type_lookup_table_test.cc b/runtime/type_lookup_table_test.cc
index 7f500cc..ea4d8b5 100644
--- a/runtime/type_lookup_table_test.cc
+++ b/runtime/type_lookup_table_test.cc
@@ -25,10 +25,10 @@
 
 namespace art {
 
-class TypeLookupTableTest : public CommonRuntimeTest {
- public:
-  size_t kDexNoIndex = DexFile::kDexNoIndex;  // Make copy to prevent linking errors.
-};
+static const size_t kDexNoIndex = DexFile::kDexNoIndex;  // Make copy to prevent linking errors.
+
+using DescriptorClassDefIdxPair = std::pair<const char*, uint32_t>;
+class TypeLookupTableTest : public CommonRuntimeTestWithParam<DescriptorClassDefIdxPair> {};
 
 TEST_F(TypeLookupTableTest, CreateLookupTable) {
   ScopedObjectAccess soa(Thread::Current());
@@ -39,48 +39,28 @@
   ASSERT_EQ(32U, table->RawDataLength());
 }
 
-TEST_F(TypeLookupTableTest, FindNonExistingClassWithoutCollisions) {
+TEST_P(TypeLookupTableTest, Find) {
   ScopedObjectAccess soa(Thread::Current());
   std::unique_ptr<const DexFile> dex_file(OpenTestDexFile("Lookup"));
   std::unique_ptr<TypeLookupTable> table(TypeLookupTable::Create(*dex_file));
   ASSERT_NE(nullptr, table.get());
-  const char* descriptor = "LBA;";
+  auto pair = GetParam();
+  const char* descriptor = pair.first;
   size_t hash = ComputeModifiedUtf8Hash(descriptor);
   uint32_t class_def_idx = table->Lookup(descriptor, hash);
-  ASSERT_EQ(kDexNoIndex, class_def_idx);
+  ASSERT_EQ(pair.second, class_def_idx);
 }
 
-TEST_F(TypeLookupTableTest, FindNonExistingClassWithCollisions) {
-  ScopedObjectAccess soa(Thread::Current());
-  std::unique_ptr<const DexFile> dex_file(OpenTestDexFile("Lookup"));
-  std::unique_ptr<TypeLookupTable> table(TypeLookupTable::Create(*dex_file));
-  ASSERT_NE(nullptr, table.get());
-  const char* descriptor = "LDA;";
-  size_t hash = ComputeModifiedUtf8Hash(descriptor);
-  uint32_t class_def_idx = table->Lookup(descriptor, hash);
-  ASSERT_EQ(kDexNoIndex, class_def_idx);
-}
-
-TEST_F(TypeLookupTableTest, FindClassNoCollisions) {
-  ScopedObjectAccess soa(Thread::Current());
-  std::unique_ptr<const DexFile> dex_file(OpenTestDexFile("Lookup"));
-  std::unique_ptr<TypeLookupTable> table(TypeLookupTable::Create(*dex_file));
-  ASSERT_NE(nullptr, table.get());
-  const char* descriptor = "LC;";
-  size_t hash = ComputeModifiedUtf8Hash(descriptor);
-  uint32_t class_def_idx = table->Lookup(descriptor, hash);
-  ASSERT_EQ(2U, class_def_idx);
-}
-
-TEST_F(TypeLookupTableTest, FindClassWithCollisions) {
-  ScopedObjectAccess soa(Thread::Current());
-  std::unique_ptr<const DexFile> dex_file(OpenTestDexFile("Lookup"));
-  std::unique_ptr<TypeLookupTable> table(TypeLookupTable::Create(*dex_file));
-  ASSERT_NE(nullptr, table.get());
-  const char* descriptor = "LAB;";
-  size_t hash = ComputeModifiedUtf8Hash(descriptor);
-  uint32_t class_def_idx = table->Lookup(descriptor, hash);
-  ASSERT_EQ(1U, class_def_idx);
-}
-
+INSTANTIATE_TEST_CASE_P(FindNonExistingClassWithoutCollisions,
+                        TypeLookupTableTest,
+                        testing::Values(DescriptorClassDefIdxPair("LAB;", 1U)));
+INSTANTIATE_TEST_CASE_P(FindNonExistingClassWithCollisions,
+                        TypeLookupTableTest,
+                        testing::Values(DescriptorClassDefIdxPair("LDA;", kDexNoIndex)));
+INSTANTIATE_TEST_CASE_P(FindClassNoCollisions,
+                        TypeLookupTableTest,
+                        testing::Values(DescriptorClassDefIdxPair("LC;", 2U)));
+INSTANTIATE_TEST_CASE_P(FindClassWithCollisions,
+                        TypeLookupTableTest,
+                        testing::Values(DescriptorClassDefIdxPair("LAB;", 1U)));
 }  // namespace art