|
|
@ -27,8 +27,7 @@ import tempfile |
|
|
|
import re |
|
|
|
import re |
|
|
|
import logging |
|
|
|
import logging |
|
|
|
|
|
|
|
|
|
|
|
# Formatting. Default colors to empty strings. |
|
|
|
# Formatting. |
|
|
|
BOLD, BLUE, RED, GREY = ("", ""), ("", ""), ("", ""), ("", "") |
|
|
|
|
|
|
|
try: |
|
|
|
try: |
|
|
|
# Make sure python thinks it can write unicode to its stdout |
|
|
|
# Make sure python thinks it can write unicode to its stdout |
|
|
|
"\u2713".encode("utf_8").decode(sys.stdout.encoding) |
|
|
|
"\u2713".encode("utf_8").decode(sys.stdout.encoding) |
|
|
@ -40,17 +39,28 @@ except UnicodeDecodeError: |
|
|
|
CROSS = "x " |
|
|
|
CROSS = "x " |
|
|
|
CIRCLE = "o " |
|
|
|
CIRCLE = "o " |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Default colors to empty strings. |
|
|
|
|
|
|
|
BOLD, BLUE, RED, GREY, MAGENTA = [("", "")] * 5 |
|
|
|
if os.name == 'posix': |
|
|
|
if os.name == 'posix': |
|
|
|
# primitive formatting on supported |
|
|
|
# primitive formatting on supported |
|
|
|
# terminal via ANSI escape sequences: |
|
|
|
# terminal via ANSI escape sequences: |
|
|
|
BOLD = ('\033[0m', '\033[1m') |
|
|
|
BOLD = ('\033[0m', '\033[1m') |
|
|
|
BLUE = ('\033[0m', '\033[0;34m') |
|
|
|
|
|
|
|
RED = ('\033[0m', '\033[0;31m') |
|
|
|
|
|
|
|
GREY = ('\033[0m', '\033[1;30m') |
|
|
|
GREY = ('\033[0m', '\033[1;30m') |
|
|
|
|
|
|
|
RED = ('\033[0m', '\033[0;31m') |
|
|
|
|
|
|
|
BLUE = ('\033[0m', '\033[0;34m') |
|
|
|
|
|
|
|
MAGENTA = ('\033[0m', '\033[0;35m') |
|
|
|
|
|
|
|
|
|
|
|
TEST_EXIT_PASSED = 0 |
|
|
|
TEST_EXIT_PASSED = 0 |
|
|
|
TEST_EXIT_SKIPPED = 77 |
|
|
|
TEST_EXIT_SKIPPED = 77 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
STATUS_PASSED = "Passed" |
|
|
|
|
|
|
|
STATUS_PASSED_WITH_WARNINGS = "Passed with warnings" |
|
|
|
|
|
|
|
STATUS_SKIPPED = "Skipped" |
|
|
|
|
|
|
|
STATUS_FAILED = "Failed" |
|
|
|
|
|
|
|
STATUSES = [STATUS_PASSED, STATUS_PASSED_WITH_WARNINGS, STATUS_SKIPPED, STATUS_FAILED] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
STATUS_MAX_LEN = max([len(st) for st in STATUSES]) |
|
|
|
|
|
|
|
|
|
|
|
BASE_SCRIPTS= [ |
|
|
|
BASE_SCRIPTS= [ |
|
|
|
# Scripts that are run by the travis build process. |
|
|
|
# Scripts that are run by the travis build process. |
|
|
|
# Longest test should go first, to favor running tests in parallel |
|
|
|
# Longest test should go first, to favor running tests in parallel |
|
|
@ -306,9 +316,11 @@ def run_tests(test_list, src_dir, build_dir, exeext, tmpdir, jobs=1, enable_cove |
|
|
|
test_result, stdout, stderr = job_queue.get_next() |
|
|
|
test_result, stdout, stderr = job_queue.get_next() |
|
|
|
test_results.append(test_result) |
|
|
|
test_results.append(test_result) |
|
|
|
|
|
|
|
|
|
|
|
if test_result.status == "Passed": |
|
|
|
if test_result.status == STATUS_PASSED: |
|
|
|
logging.debug("\n%s%s%s passed, Duration: %s s" % (BOLD[1], test_result.name, BOLD[0], test_result.time)) |
|
|
|
logging.debug("\n%s%s%s passed, Duration: %s s" % (BOLD[1], test_result.name, BOLD[0], test_result.time)) |
|
|
|
elif test_result.status == "Skipped": |
|
|
|
elif test_result.status == STATUS_PASSED_WITH_WARNINGS: |
|
|
|
|
|
|
|
logging.debug("\n%s%s%s passed with warnings, Duration: %s s" % (BOLD[1], test_result.name, BOLD[0], test_result.time)) |
|
|
|
|
|
|
|
elif test_result.status == STATUS_SKIPPED: |
|
|
|
logging.debug("\n%s%s%s skipped" % (BOLD[1], test_result.name, BOLD[0])) |
|
|
|
logging.debug("\n%s%s%s skipped" % (BOLD[1], test_result.name, BOLD[0])) |
|
|
|
else: |
|
|
|
else: |
|
|
|
print("\n%s%s%s failed, Duration: %s s\n" % (BOLD[1], test_result.name, BOLD[0], test_result.time)) |
|
|
|
print("\n%s%s%s failed, Duration: %s s\n" % (BOLD[1], test_result.name, BOLD[0], test_result.time)) |
|
|
@ -332,7 +344,7 @@ def run_tests(test_list, src_dir, build_dir, exeext, tmpdir, jobs=1, enable_cove |
|
|
|
sys.exit(not all_passed) |
|
|
|
sys.exit(not all_passed) |
|
|
|
|
|
|
|
|
|
|
|
def print_results(test_results, max_len_name, runtime): |
|
|
|
def print_results(test_results, max_len_name, runtime): |
|
|
|
results = "\n" + BOLD[1] + "%s | %s | %s\n\n" % ("TEST".ljust(max_len_name), "STATUS ", "DURATION") + BOLD[0] |
|
|
|
results = "\n" + BOLD[1] + "%s | %s | %s\n\n" % ("TEST".ljust(max_len_name), " STATUS".ljust(STATUS_MAX_LEN + 2), "DURATION") + BOLD[0] |
|
|
|
|
|
|
|
|
|
|
|
test_results.sort(key=lambda result: result.name.lower()) |
|
|
|
test_results.sort(key=lambda result: result.name.lower()) |
|
|
|
all_passed = True |
|
|
|
all_passed = True |
|
|
@ -345,7 +357,7 @@ def print_results(test_results, max_len_name, runtime): |
|
|
|
results += str(test_result) |
|
|
|
results += str(test_result) |
|
|
|
|
|
|
|
|
|
|
|
status = TICK + "Passed" if all_passed else CROSS + "Failed" |
|
|
|
status = TICK + "Passed" if all_passed else CROSS + "Failed" |
|
|
|
results += BOLD[1] + "\n%s | %s | %s s (accumulated) \n" % ("ALL".ljust(max_len_name), status.ljust(9), time_sum) + BOLD[0] |
|
|
|
results += BOLD[1] + "\n%s | %s | %s s (accumulated) \n" % ("ALL".ljust(max_len_name), status.ljust(STATUS_MAX_LEN + 2), time_sum) + BOLD[0] |
|
|
|
results += "Runtime: %s s\n" % (runtime) |
|
|
|
results += "Runtime: %s s\n" % (runtime) |
|
|
|
print(results) |
|
|
|
print(results) |
|
|
|
|
|
|
|
|
|
|
@ -403,11 +415,13 @@ class TestHandler: |
|
|
|
[stdout, stderr] = [l.read().decode('utf-8') for l in (log_out, log_err)] |
|
|
|
[stdout, stderr] = [l.read().decode('utf-8') for l in (log_out, log_err)] |
|
|
|
log_out.close(), log_err.close() |
|
|
|
log_out.close(), log_err.close() |
|
|
|
if proc.returncode == TEST_EXIT_PASSED and stderr == "": |
|
|
|
if proc.returncode == TEST_EXIT_PASSED and stderr == "": |
|
|
|
status = "Passed" |
|
|
|
status = STATUS_PASSED |
|
|
|
|
|
|
|
elif proc.returncode == TEST_EXIT_PASSED: |
|
|
|
|
|
|
|
status = STATUS_PASSED_WITH_WARNINGS |
|
|
|
elif proc.returncode == TEST_EXIT_SKIPPED: |
|
|
|
elif proc.returncode == TEST_EXIT_SKIPPED: |
|
|
|
status = "Skipped" |
|
|
|
status = STATUS_SKIPPED |
|
|
|
else: |
|
|
|
else: |
|
|
|
status = "Failed" |
|
|
|
status = STATUS_FAILED |
|
|
|
self.num_running -= 1 |
|
|
|
self.num_running -= 1 |
|
|
|
self.jobs.remove(j) |
|
|
|
self.jobs.remove(j) |
|
|
|
|
|
|
|
|
|
|
@ -422,17 +436,20 @@ class TestResult(): |
|
|
|
self.padding = 0 |
|
|
|
self.padding = 0 |
|
|
|
|
|
|
|
|
|
|
|
def __repr__(self): |
|
|
|
def __repr__(self): |
|
|
|
if self.status == "Passed": |
|
|
|
if self.status == STATUS_PASSED: |
|
|
|
color = BLUE |
|
|
|
color = BLUE |
|
|
|
glyph = TICK |
|
|
|
glyph = TICK |
|
|
|
elif self.status == "Failed": |
|
|
|
if self.status == STATUS_PASSED_WITH_WARNINGS: |
|
|
|
color = RED |
|
|
|
color = MAGENTA |
|
|
|
glyph = CROSS |
|
|
|
glyph = TICK |
|
|
|
elif self.status == "Skipped": |
|
|
|
elif self.status == STATUS_SKIPPED: |
|
|
|
color = GREY |
|
|
|
color = GREY |
|
|
|
glyph = CIRCLE |
|
|
|
glyph = CIRCLE |
|
|
|
|
|
|
|
elif self.status == STATUS_FAILED: |
|
|
|
|
|
|
|
color = RED |
|
|
|
|
|
|
|
glyph = CROSS |
|
|
|
|
|
|
|
|
|
|
|
return color[1] + "%s | %s%s | %s s\n" % (self.name.ljust(self.padding), glyph, self.status.ljust(7), self.time) + color[0] |
|
|
|
return color[1] + "%s | %s%s | %s s\n" % (self.name.ljust(self.padding), glyph, self.status.ljust(STATUS_MAX_LEN), self.time) + color[0] |
|
|
|
|
|
|
|
|
|
|
|
@property |
|
|
|
@property |
|
|
|
def was_successful(self): |
|
|
|
def was_successful(self): |
|
|
|