1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
"""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
|