| """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: |
| self = args[0] |
| self.maxDiff = None # So we can see large diffs between |
| # expected/actual |
| 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 |
| |
| |
| def require_command_arg(requiredArg): |
| """ |
| Decorator that simplifies writing CLI tests that check that 'requiredArg' is |
| in fact required (i.e. that the command that we're testing will blow up if |
| we don't pass it the required argument). |
| |
| Use this to decorate test functions, e.g: |
| |
| @require_command_arg("--my-required-arg") |
| def test_my_required_arg_is_compulsory(self): |
| run_command_without_my_required_arg() |
| """ |
| def decorate(test): |
| def wrapper(*args, **kwargs): |
| self = args[0] |
| with self.assertRaises(subprocess.CalledProcessError) as context: |
| test(*args, **kwargs) |
| |
| self.assertRegex(str(context.exception.output), |
| "(.*\n)*the following arguments are required: {}(.*\n)*".format(requiredArg)) |
| return wrapper |
| return decorate |
| |
| |
| class LLVMTestCase(unittest.TestCase): |
| python = "python3" |
| script = os.path.join("scripts", "llvm.py") |
| |
| @classmethod |
| def create_dummy_commit(cls, commitMessage="Dummy commit"): |
| filename = "filethatshouldntexist" + str(uuid4()) |
| cls.run_quietly(["touch", filename]) |
| try: |
| cls.run_quietly(["git", "add", filename]) |
| cls.run_quietly(["git", "commit", "-m", commitMessage]) |
| except subprocess.CalledProcessError as exc: |
| print("Command {} exited with error code {}:\n{}".format( |
| exc.cmd, exc.returncode, exc.output)) |
| |
| @classmethod |
| def create_dummy_repo(cls, repopath, originpath=None): |
| if originpath is not None: |
| cls.run_quietly(["git", "clone", originpath, repopath]) |
| else: |
| if not os.path.isdir(repopath): |
| os.makedirs(repopath) |
| |
| with cd(repopath): |
| cls.run_quietly(["git", "init"]) |
| |
| with cd(repopath): |
| cls.create_dummy_commit() |
| |
| @classmethod |
| def add_worktree(cls, repopath, worktreepath, branch): |
| with cd(repopath): |
| cls.run_quietly(["git", "worktree", "add", worktreepath, |
| "-b", branch]) |
| |
| @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 an llvm subcommand with the given args.""" |
| command = [cls.python, cls.script] |
| |
| command.append(subcommand) |
| |
| if len(args): |
| command.extend(args) |
| |
| return command |