@ -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
@ -307,9 +317,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 ) )
@ -333,7 +345,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
@ -346,7 +358,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 )
@ -404,11 +416,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 )
@ -423,17 +437,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
el if 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 ) :