|
|
|
import hashlib
|
|
|
|
import os
|
|
|
|
import platform
|
|
|
|
import re
|
|
|
|
import shlex
|
|
|
|
import shutil
|
|
|
|
import subprocess
|
|
|
|
|
|
|
|
|
|
|
|
# The configuration parameters for bash test
|
|
|
|
# The function configure_suite() in system_tests.py will override these parameters
|
|
|
|
EXIV2_DIR = os.path.normpath(os.path.join(os.path.abspath(__file__), '../../../'))
|
|
|
|
BIN_DIR = os.path.join(EXIV2_DIR, 'build/bin')
|
|
|
|
DATA_DIR = os.path.join(EXIV2_DIR, 'test/data')
|
|
|
|
TEST_DIR = os.path.join(EXIV2_DIR, 'test/tmp')
|
|
|
|
ENCODING = 'utf-8'
|
|
|
|
PLATFORM = platform.system() or 'Unknown'
|
|
|
|
os.makedirs(TEST_DIR, exist_ok=True)
|
|
|
|
|
|
|
|
|
|
|
|
class Log:
|
|
|
|
_buffer = ['']
|
|
|
|
|
|
|
|
def _add_msg(self, msg):
|
|
|
|
self._buffer.append(msg)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def buffer(self):
|
|
|
|
return '\n'.join(self._buffer)
|
|
|
|
|
|
|
|
def info(self, msg, index=None):
|
|
|
|
self._add_msg('[INFO] {}'.format(msg))
|
|
|
|
|
|
|
|
def warn(self, msg):
|
|
|
|
self._add_msg('[WARN] {}'.format(msg))
|
|
|
|
|
|
|
|
def error(self, msg):
|
|
|
|
self._add_msg('[ERROR] {}'.format(msg))
|
|
|
|
|
|
|
|
|
|
|
|
log = Log()
|
|
|
|
|
|
|
|
|
|
|
|
def cp(src, dest):
|
|
|
|
""" It is used to copy one file, cannot handle directories """
|
|
|
|
shutil.copy(src, dest)
|
|
|
|
|
|
|
|
|
|
|
|
def rm(*files):
|
|
|
|
""" It is used to remove files, cannot handle directories """
|
|
|
|
for i in files:
|
|
|
|
try:
|
|
|
|
os.remove(i)
|
|
|
|
except FileNotFoundError:
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
|
|
def cat(*files, encoding=ENCODING):
|
|
|
|
text = ''
|
|
|
|
for i in files:
|
|
|
|
with open(i, 'r', encoding=encoding) as f:
|
|
|
|
text += f.read()
|
|
|
|
return text
|
|
|
|
|
|
|
|
|
|
|
|
def grep(pattern, *files, encoding=ENCODING):
|
|
|
|
result = ''
|
|
|
|
pattern = '.*{}.*'.format(pattern)
|
|
|
|
for i in files:
|
|
|
|
text = cat(i, encoding=encoding)
|
|
|
|
result += '\n'.join(re.findall(pattern, text))
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
|
|
def save(text, filename, encoding=ENCODING):
|
|
|
|
with open(filename, 'w', encoding=encoding) as f:
|
|
|
|
f.write(text)
|
|
|
|
|
|
|
|
|
|
|
|
def diff(file1, file2):
|
|
|
|
list1 = cat(file1).split('\n')
|
|
|
|
list2 = cat(file2).split('\n')
|
|
|
|
if list1 == list2:
|
|
|
|
return
|
|
|
|
report = []
|
|
|
|
report += ['{}: {} lines'.format(file1, len(list1))]
|
|
|
|
report += ['{}: {} lines'.format(file2, len(list2))]
|
|
|
|
max_lines = max(len(list1), len(list2))
|
|
|
|
for i in [list1, list2]:
|
|
|
|
i += [''] * (max_lines - len(i)) # Make them have the same number of lines
|
|
|
|
for i in range(max_lines):
|
|
|
|
if list1[i] != list2[i]:
|
|
|
|
report += ['The first mismatch is in line {}:'.format(i + 1)]
|
|
|
|
report += ['- {}'.format(list1[i])]
|
|
|
|
report += ['+ {}'.format(list2[i])]
|
|
|
|
break
|
|
|
|
return '\n'.join(report)
|
|
|
|
|
|
|
|
|
|
|
|
def copyTestFile(src, dest=''):
|
|
|
|
""" Copy one test file from DATA_DIR to TEST_DIR """
|
|
|
|
if not dest:
|
|
|
|
dest = src
|
|
|
|
shutil.copy(os.path.join(DATA_DIR, src),
|
|
|
|
os.path.join(TEST_DIR, dest))
|
|
|
|
|
|
|
|
|
|
|
|
def copyTestFiles(*files):
|
|
|
|
""" Copy one or more test files from DATA_DIR to TEST_DIR """
|
|
|
|
for i in files:
|
|
|
|
copyTestFile(i)
|
|
|
|
|
|
|
|
|
|
|
|
def is_same_file(file1, file2):
|
|
|
|
""" Check whether the two files are the same """
|
|
|
|
with open(file1, "rb") as f1, open(file2, "rb") as f2:
|
|
|
|
h1 = hashlib.md5(f1.read()).digest()
|
|
|
|
h2 = hashlib.md5(f2.read()).digest()
|
|
|
|
return h1 == h2
|
|
|
|
|
|
|
|
|
|
|
|
def runTest(cmd: str, vars_dict=dict(), expected_returncodes=[0], encoding=ENCODING) -> list:
|
|
|
|
""" Execute a file in the exiv2 bin directory and return its stdout. """
|
|
|
|
cmd = cmd.format(**vars_dict)
|
|
|
|
args = shlex.split(cmd)
|
|
|
|
args[0] = os.path.join(BIN_DIR, args[0])
|
|
|
|
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=TEST_DIR)
|
|
|
|
stdout, stderr = p.communicate()
|
|
|
|
output = (stdout + stderr).decode(encoding).rstrip('\n')
|
|
|
|
if p.returncode not in expected_returncodes:
|
|
|
|
log.error('Failed to excute: {}'.format(cmd))
|
|
|
|
log.error('The expected return code is {}, but get {}'.format(str(expected_returncodes), p.returncode))
|
|
|
|
log.info('OUTPUT:\n{}'.format(output))
|
|
|
|
raise RuntimeError(log.buffer)
|
|
|
|
return output.split('\n') if output else []
|
|
|
|
|
|
|
|
|
|
|
|
def reportTest(testname, output, encoding=ENCODING):
|
|
|
|
""" If the output of the test case is correct, this function returns None. Otherwise print its error. """
|
|
|
|
if not isinstance(output, str):
|
|
|
|
output = '\n'.join(output)
|
|
|
|
reference_file = os.path.join(DATA_DIR, '{}.out'.format(testname))
|
|
|
|
reference_output = cat(reference_file, encoding=encoding)
|
|
|
|
if reference_output == output:
|
|
|
|
return
|
|
|
|
log.error('The output of the testcase mismatch the reference')
|
|
|
|
output_file = os.path.join(TEST_DIR, '{}.out'.format(testname))
|
|
|
|
save(output, output_file, encoding=encoding)
|
|
|
|
log.info('The output has been saved to file {}'.format(output_file))
|
|
|
|
log.error('diff:\n' + diff(reference_file, output_file))
|
|
|
|
raise RuntimeError(log.buffer)
|
|
|
|
|
|
|
|
|
|
|
|
def ioTest(filename):
|
|
|
|
src = os.path.join(DATA_DIR, filename)
|
|
|
|
out1 = os.path.join(TEST_DIR, '{}.1'.format(filename))
|
|
|
|
out2 = os.path.join(TEST_DIR, '{}.2'.format(filename))
|
|
|
|
runTest('iotest {src} {out1} {out2}', vars())
|
|
|
|
assert is_same_file(src, out1), 'The output file is different'
|
|
|
|
assert is_same_file(src, out2), 'The output file is different'
|