96 lines
3.1 KiB
Python
96 lines
3.1 KiB
Python
|
import collections
|
||
|
import re
|
||
|
import os
|
||
|
import subprocess
|
||
|
import sys
|
||
|
|
||
|
testresult = collections.namedtuple('testresult', ['exitcode', 'output'])
|
||
|
|
||
|
|
||
|
def cat(filename):
|
||
|
with open(filename, "rb") as f:
|
||
|
for line in f:
|
||
|
sys.stdout.buffer.write(line)
|
||
|
|
||
|
|
||
|
class TestExpectPragmas(object):
|
||
|
"""Base class for tests that read the expected result as annotations
|
||
|
in test files.
|
||
|
|
||
|
get_expect(file) will parse the file, looking EXPECT and EXITCODE
|
||
|
pragmas.
|
||
|
|
||
|
run_command(command) is a wrapper around subprocess.check_output()
|
||
|
that extracts the output and exit code.
|
||
|
|
||
|
"""
|
||
|
def get_expect(self, filename):
|
||
|
"""Parse "filename" looking for EXPECT and EXITCODE annotations.
|
||
|
|
||
|
Look for a line "EXPECTED" (possibly with whitespaces and
|
||
|
comments). Text after this "EXPECTED" line is the expected
|
||
|
output.
|
||
|
|
||
|
The file may also contain a line like "EXITCODE <n>" where <n>
|
||
|
is an integer, and is the expected exitcode of the command.
|
||
|
|
||
|
The result is cached to avoid re-parsing the file multiple
|
||
|
times.
|
||
|
"""
|
||
|
if filename not in self.__expect:
|
||
|
self.__expect[filename] = self._extract_expect(filename)
|
||
|
return self.__expect[filename]
|
||
|
|
||
|
def remove(self, file):
|
||
|
"""Like os.remove(), but ignore errors, e.g. don't complain if the
|
||
|
file doesn't exist.
|
||
|
"""
|
||
|
try:
|
||
|
os.remove(file)
|
||
|
except OSError:
|
||
|
pass
|
||
|
|
||
|
def run_command(self, cmd):
|
||
|
"""Run the command cmd (given as [command, arg1, arg2, ...]), and
|
||
|
return testresult(exitcode=..., output=...) containing the
|
||
|
exit code of the command it its standard output + standard error.
|
||
|
"""
|
||
|
try:
|
||
|
output = subprocess.check_output(cmd, timeout=60,
|
||
|
stderr=subprocess.STDOUT)
|
||
|
exitcode = 0
|
||
|
except subprocess.CalledProcessError as e:
|
||
|
output = e.output
|
||
|
exitcode = e.returncode
|
||
|
return testresult(exitcode=exitcode, output=output.decode())
|
||
|
|
||
|
__expect = {}
|
||
|
|
||
|
def _extract_expect(self, file):
|
||
|
exitcode = 0
|
||
|
inside_expected = False
|
||
|
expected_lines = []
|
||
|
with open(file, encoding="utf-8") as f:
|
||
|
for line in f.readlines():
|
||
|
# Ignore non-comments
|
||
|
if not re.match(r'\s*//', line):
|
||
|
continue
|
||
|
# Cleanup comment start and whitespaces
|
||
|
line = re.sub(r'\s*//\s*', '', line)
|
||
|
line = re.sub(r'\s*$', '', line)
|
||
|
|
||
|
if line == 'END EXPECTED':
|
||
|
inside_expected = False
|
||
|
elif line.startswith('EXITCODE'):
|
||
|
words = line.split(' ')
|
||
|
assert len(words) == 2
|
||
|
exitcode = int(words[1])
|
||
|
elif line == 'EXPECTED':
|
||
|
inside_expected = True
|
||
|
elif inside_expected:
|
||
|
expected_lines.append(line)
|
||
|
|
||
|
expected_lines.append('')
|
||
|
return testresult(exitcode=exitcode,
|
||
|
output=os.linesep.join(expected_lines))
|