Factor out common test primitives. NFCI.

Create an LLVMTestCase class that will contain common helpers for
writing tests for llvm.py subcommands.

Change-Id: Ie1fe9dad9c9aeb9eb673726c80077d26739c0697
diff --git a/tests/cli/llvmtestcase.py b/tests/cli/llvmtestcase.py
new file mode 100644
index 0000000..b2fc765
--- /dev/null
+++ b/tests/cli/llvmtestcase.py
@@ -0,0 +1,106 @@
+"""Common TestCase used for testing llvm.py subcommands."""
+
+import shutil
+import os
+import subprocess
+import unittest
+
+from tempfile import mkdtemp
+from uuid import uuid4
+
+from linaropy.cd import cd
+
+
+# TODO: move this somewhere more public (maybe linaropy?)
+def debug(test):
+    """
+    Decorator that dumps the output of any subprocess.CalledProcessError
+    exception. Use this to decorate a test function when you can't tell what the
+    problem is.
+    """
+    def wrapper(*args, **kwargs):
+        # Catch any exceptions so we can dump all the output
+        try:
+            test(*args, **kwargs)
+        except subprocess.CalledProcessError as exc:
+            print("Error in {}:".format(test.__name__))
+            print("Command {} exited with error code {}:\n{}".format(
+                exc.cmd, exc.returncode, exc.output))
+    return wrapper
+
+
+class LLVMTestCase(unittest.TestCase):
+    python = "python3"
+    script = os.path.join("scripts", "llvm.py")
+
+    @classmethod
+    def create_dummy_commit(cls):
+        filename = "filethatshouldntexist"
+        cls.run_quietly(["touch", filename])
+        cls.run_quietly(["git", "add", filename])
+        cls.run_quietly(["git", "commit", "-m", "Dummy commit"])
+
+    @classmethod
+    def create_dummy_repo(cls, repopath):
+        if not os.path.isdir(repopath):
+            os.makedirs(repopath)
+
+        with cd(repopath):
+            cls.run_quietly(["git", "init"])
+            cls.create_dummy_commit()
+
+    @classmethod
+    def add_worktree(cls, repopath, worktreepath, branch):
+        with cd(repopath):
+            cls.run_quietly(["git", "worktree", "add", worktreepath,
+                             "-b", branch])
+
+    @classmethod
+    def get_subproj_repo(cls, subproj):
+        return os.path.join(cls.repos, subproj)
+
+    @staticmethod
+    def run_with_output(*args, **kwargs):
+        """Helper for running a command and capturing stdout and stderr"""
+        kwargs["stderr"] = subprocess.STDOUT
+        return str(subprocess.check_output(*args, **kwargs), 'utf-8')
+
+    @staticmethod
+    def run_quietly(*args, **kwargs):
+        """
+        Helper for running a command and ignoring stdout and stderr. Exceptions
+        are still thrown if something goes wrong
+        """
+        kwargs["stdout"] = subprocess.DEVNULL
+        kwargs["stderr"] = subprocess.DEVNULL
+        return subprocess.check_call(*args, **kwargs)
+
+    @classmethod
+    def command_with_defaults(cls, subcommand, *args, **kwargs):
+        """
+        Build a list representing a llvm subcommand with the given
+        args. Unless otherwise specified in kwargs, this uses the values for
+        repos and env that it finds in cls.
+        """
+        command = [cls.python, cls.script]
+
+        repos = cls.repos
+        if "repos" in kwargs:
+            repos = kwargs["repos"]
+        if repos:
+            command.append("--repos")
+            command.append(repos)
+
+        env = cls.env
+        if "env" in kwargs:
+            env = kwargs["env"]
+        if env:
+            command.append("--env")
+            command.append(env)
+
+        command.append(subcommand)
+
+        if len(args):
+            command.extend(args)
+
+        return command
diff --git a/tests/cli/testllvmprojects.py b/tests/cli/testllvmprojects.py
index c0c1f26..394f3ac 100644
--- a/tests/cli/testllvmprojects.py
+++ b/tests/cli/testllvmprojects.py
@@ -14,101 +14,14 @@
 from uuid import uuid4
 
 from linaropy.cd import cd
+from llvmtestcase import LLVMTestCase
 
 
-# TODO: move this somewhere more public (maybe linaropy?)
-def debug(test):
-    """
-    Decorator that dumps the output of any subprocess.CalledProcessError
-    exception. Use this to decorate a test function when you can't tell what the
-    problem is.
-    """
-    def wrapper(*args, **kwargs):
-        # Catch any exceptions so we can dump all the output
-        try:
-            test(*args, **kwargs)
-        except subprocess.CalledProcessError as exc:
-            print("Error in {}:".format(test.__name__))
-            print("Command {} exited with error code {}:\n{}".format(
-                exc.cmd, exc.returncode, exc.output))
-    return wrapper
-
-
-class Testllvmprojs(unittest.TestCase):
-    python = "python3"
-    script = os.path.join("scripts", "llvm.py")
-
-    @classmethod
-    def __create_dummy_commit(cls):
-        filename = "filethatshouldntexist"
-        cls.run_quietly(["touch", filename])
-        cls.run_quietly(["git", "add", filename])
-        cls.run_quietly(["git", "commit", "-m", "Dummy commit"])
-
-    @classmethod
-    def __create_dummy_repo(cls, repopath):
-        if not os.path.isdir(repopath):
-            os.makedirs(repopath)
-
-        with cd(repopath):
-            cls.run_quietly(["git", "init"])
-            cls.__create_dummy_commit()
-
-    @classmethod
-    def __add_worktree(cls, repopath, worktreepath, branch):
-        with cd(repopath):
-            cls.run_quietly(["git", "worktree", "add", worktreepath,
-                             "-b", branch])
-
-    @classmethod
-    def __get_subproj_repo(cls, subproj):
-        return os.path.join(cls.repos, subproj)
-
-    @staticmethod
-    def run_with_output(*args, **kwargs):
-        """Helper for running a command and capturing stdout and stderr"""
-        kwargs["stderr"] = subprocess.STDOUT
-        return str(subprocess.check_output(*args, **kwargs), 'utf-8')
-
-    @staticmethod
-    def run_quietly(*args, **kwargs):
-        """
-        Helper for running a command and ignoring stdout and stderr. Exceptions
-        are still thrown if something goes wrong
-        """
-        kwargs["stdout"] = subprocess.DEVNULL
-        kwargs["stderr"] = subprocess.DEVNULL
-        return subprocess.check_call(*args, **kwargs)
+class Testllvmprojs(LLVMTestCase):
 
     @classmethod
     def llvm_projects(cls, *args, **kwargs):
-        """
-        Build a list representing a llvm projects subcommand with the given
-        args. Unless otherwise specified in kwargs, this uses the values for
-        repos and env that it finds in cls.
-        """
-        command = [cls.python, cls.script]
-
-        repos = cls.repos
-        if "repos" in kwargs:
-            repos = kwargs["repos"]
-        if repos:
-            command.append("--repos")
-            command.append(repos)
-
-        env = cls.env
-        if "env" in kwargs:
-            env = kwargs["env"]
-        if env:
-            command.append("--env")
-            command.append(env)
-
-        command.append("projects")
-
-        if len(args):
-            command.extend(args)
-
-        return command
+        return cls.command_with_defaults("projects", *args, **kwargs)
 
     @classmethod
     def setUpClass(cls):
@@ -121,7 +34,7 @@
 
         # Create dummy repos
         for reponame in cls.all_repos:
-            cls.__create_dummy_repo(cls.__get_subproj_repo(reponame))
+            cls.create_dummy_repo(cls.get_subproj_repo(reponame))
 
     @classmethod
     def tearDownClass(cls):
@@ -134,8 +47,8 @@
 
         # Create LLVM worktree
         cls.branch = "br" + str(uuid4())
-        cls.__add_worktree(cls.__get_subproj_repo("llvm"), cls.llvm_src,
-                           cls.branch)
+        cls.add_worktree(cls.get_subproj_repo("llvm"), cls.llvm_src,
+                         cls.branch)
 
     @classmethod
     def tearDown(cls):
@@ -151,7 +64,7 @@
 
         # Run prune on the original repos, to remove any dangling worktrees.
         for reponame in cls.all_repos:
-            repopath = cls.__get_subproj_repo(reponame)
+            repopath = cls.get_subproj_repo(reponame)
             with cd(repopath):
                 cls.run_quietly(["git", "worktree", "prune"])
 
@@ -305,11 +218,11 @@
         was added by our script or manually) or remove a subproject that doesn't
         exist.
         """
-        self.__add_worktree(self.__get_subproj_repo("clang"),
-                            os.path.join(self.llvm_src, "tools", "clang"),
-                            self.branch)
-        self.__add_worktree(
-            self.__get_subproj_repo("compiler-rt"),
+        self.add_worktree(self.get_subproj_repo("clang"),
+                          os.path.join(self.llvm_src, "tools", "clang"),
+                          self.branch)
+        self.add_worktree(
+            self.get_subproj_repo("compiler-rt"),
             os.path.join(self.llvm_src, "projects", "compiler-rt"),
             self.branch)
 
@@ -361,8 +274,8 @@
 
         # Try something a bit more complicated and make sure we're not touching
         # anything
-        self.__add_worktree(
-            self.__get_subproj_repo("lld"),
+        self.add_worktree(
+            self.get_subproj_repo("lld"),
             os.path.join(self.llvm_src, "tools", "lld"),
             self.branch)
 
@@ -456,8 +369,8 @@
         # Create a separate environment
         new_env = mkdtemp()
         new_branch = "br" + str(uuid4())
-        self.__add_worktree(self.__get_subproj_repo("llvm"),
-                            os.path.join(new_env, "llvm"), new_branch)
+        self.add_worktree(self.get_subproj_repo("llvm"),
+                          os.path.join(new_env, "llvm"), new_branch)
 
         # Check that we start with a clean slate in both the new environment and
         # the one that's already set up