247 lines
7.7 KiB
Python
247 lines
7.7 KiB
Python
#!/usr/bin/env python
|
|
from __future__ import print_function
|
|
|
|
import os
|
|
import subprocess
|
|
import doctest
|
|
import re
|
|
|
|
FIRST_SCRIPT = 'prepare'
|
|
LAST_SCRIPT = 'cleanup'
|
|
|
|
PRE_EXTENSION = '.pre'
|
|
POST_EXTENSION = '.post'
|
|
|
|
PYTHON_TEST_EXTENSION = '.pytest'
|
|
BASH_TEST_EXTENSION = '.shtest'
|
|
|
|
|
|
class RunTest:
|
|
'''Runs the tests'''
|
|
|
|
def __init__(self):
|
|
self.path = os.path.abspath('.')
|
|
|
|
# Only no-hide files
|
|
self.all_files = [filename for filename in os.listdir(self.path)
|
|
if filename[0] != '.' and os.path.isfile(filename)]
|
|
|
|
self.all_files = sorted(self.all_files)
|
|
|
|
self.python_tests = []
|
|
self.bash_tests = []
|
|
self.script_tests = []
|
|
self.first_script = ''
|
|
self.last_script = ''
|
|
self.pre_scripts = []
|
|
self.post_scripts = []
|
|
|
|
for filename in self.all_files:
|
|
if filename.endswith(PYTHON_TEST_EXTENSION):
|
|
self.python_tests.append(filename)
|
|
|
|
elif filename.endswith(BASH_TEST_EXTENSION):
|
|
self.bash_tests.append(filename)
|
|
|
|
elif os.access(filename, os.X_OK):
|
|
basename, extension = os.path.splitext(filename)
|
|
if basename == FIRST_SCRIPT:
|
|
if self.first_script:
|
|
raise MoreThanOneFirstScript()
|
|
self.first_script = filename
|
|
elif basename == LAST_SCRIPT:
|
|
if self.last_script:
|
|
raise MoreThanOneLastScript()
|
|
self.last_script = filename
|
|
elif extension == PRE_EXTENSION:
|
|
self.pre_scripts.append(filename)
|
|
elif extension == POST_EXTENSION:
|
|
self.post_scripts.append(filename)
|
|
else:
|
|
self.script_tests.append(filename)
|
|
|
|
self.fails = 0
|
|
|
|
def run_script(self, script):
|
|
'''Run a script test'''
|
|
path_script = os.path.join(self.path, script)
|
|
proc = subprocess.Popen((path_script), shell=True, stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE)
|
|
return_value = proc.wait()
|
|
if return_value != 0:
|
|
self.fails += 1
|
|
stdout, stderr = proc.communicate()
|
|
print("*******************************************************")
|
|
print("Error %d in %s:" % (return_value, script))
|
|
print(stdout.decode(), end='')
|
|
print(stderr.decode(), end='')
|
|
|
|
return return_value
|
|
|
|
def run_bash_test(self, script):
|
|
'''Run bash test'''
|
|
#import pdb; pdb.set_trace()
|
|
path_script = os.path.join(self.path, script)
|
|
errors = 0
|
|
test_no = 0
|
|
|
|
for command, result, line in read_bash_tests(path_script):
|
|
test_no += 1
|
|
try:
|
|
proc = subprocess.Popen(('/bin/bash', '-c', command),
|
|
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
|
stdout = proc.communicate()[0]
|
|
except OSError as exc:
|
|
print('File "%s" line %d:' % (script, line))
|
|
print('Failed example:')
|
|
print(' ' + command)
|
|
print("Exception was raised:")
|
|
print(" ", end="")
|
|
print(exc)
|
|
print("*******************************************************")
|
|
errors += 1
|
|
|
|
else:
|
|
if result != stdout.decode():
|
|
print('File "%s" line %d:' % (script, line))
|
|
print('Failed example:')
|
|
print(' ' + command)
|
|
print("Expected:")
|
|
for l in result.split('\n')[:-1]:
|
|
print(' ' + l)
|
|
print("Got:")
|
|
for l in stdout.decode().split('\n')[:-1]:
|
|
print(' ' + l)
|
|
errors += 1
|
|
print("*******************************************************")
|
|
|
|
if errors != 0:
|
|
print("%d items had failures:" % errors)
|
|
print(" %d of %d in %s" % (errors, test_no, script))
|
|
print("***Test failed***")
|
|
else:
|
|
print("%3d tests PASSED in %s" % (test_no, script))
|
|
|
|
return errors
|
|
|
|
|
|
def run_pre_test(self, test):
|
|
'''Run the pre-test of a test'''
|
|
pre_test = test + PRE_EXTENSION
|
|
return_value = 0
|
|
if pre_test in self.pre_scripts:
|
|
return_value = self.run_script(pre_test)
|
|
if return_value:
|
|
print("No running: %s %s" % (test, test + POST_EXTENSION))
|
|
|
|
return return_value
|
|
|
|
def run_post_test(self, test):
|
|
'''Run the post-test of a test'''
|
|
post_test = test + POST_EXTENSION
|
|
if post_test in self.post_scripts:
|
|
return self.run_script(post_test)
|
|
|
|
def run_tests(self):
|
|
'''Run the tests in the correct order'''
|
|
if self.first_script:
|
|
if self.run_script(self.first_script) != 0:
|
|
print('*Error in prepare script. Aborting.*')
|
|
return self.show_errors()
|
|
|
|
all_tests = sorted(self.script_tests + self.python_tests + self.bash_tests)
|
|
for test in all_tests:
|
|
if self.run_pre_test(test) != 0:
|
|
continue
|
|
|
|
if test in self.script_tests:
|
|
self.run_script(test)
|
|
elif test in self.bash_tests:
|
|
fails = self.run_bash_test(test)
|
|
self.fails += fails
|
|
elif test in self.python_tests:
|
|
fails, n_tests = doctest.testfile(test, module_relative=False)
|
|
self.fails += fails
|
|
|
|
self.run_post_test(test)
|
|
|
|
if self.last_script:
|
|
self.run_script(self.last_script)
|
|
|
|
return self.show_errors()
|
|
|
|
def show_errors(self):
|
|
'''Show the total errors'''
|
|
if self.fails:
|
|
print("*******************************************************")
|
|
print("Total errors: %d" % self.fails)
|
|
|
|
return self.fails
|
|
|
|
class MoreThanOneFirstScript(Exception):
|
|
def __init__(self):
|
|
super(MoreThanOneFirstScript, self).__init__(
|
|
"More than one %s script" % FIRST_SCRIPT)
|
|
|
|
class MoreThanOneLastScript(Exception):
|
|
def __init__(self):
|
|
super(MoreThanOneLastScript, self).__init__(
|
|
"More than one %s script" % LAST_SCRIPT)
|
|
|
|
|
|
def read_bash_tests(file_name):
|
|
'''Iterator that yields the found tests'''
|
|
fd = open(file_name)
|
|
command = ''
|
|
result = ''
|
|
tests = []
|
|
line_no = 0
|
|
command_line = 0
|
|
command_re = re.compile("^\$ (.*)\n")
|
|
|
|
for line in fd.readlines():
|
|
line_no += 1
|
|
|
|
match = command_re.match(line)
|
|
if match:
|
|
# Is it a command?
|
|
if command:
|
|
# If it is a command but we have a previous command to send
|
|
yield (command, result, command_line)
|
|
result = ''
|
|
|
|
command = match.group(1)
|
|
command_line = line_no
|
|
|
|
elif command:
|
|
# If not a command but we have a previous command
|
|
if line != "\n":
|
|
# It's a part of the result
|
|
if line == "<BLANKLINE>\n":
|
|
result += '\n'
|
|
else:
|
|
result += line
|
|
|
|
else:
|
|
# Or it's the end of the result, yielding
|
|
|
|
yield (command, result, command_line)
|
|
command = ''
|
|
result = ''
|
|
|
|
|
|
else:
|
|
# This line is a comment
|
|
pass
|
|
|
|
if command:
|
|
# Cheking if the last command was sent
|
|
yield (command, result, command_line)
|
|
|
|
fd.close()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
r = RunTest()
|
|
r.run_tests()
|