6
6
import platform
7
7
import argparse
8
8
import inspect
9
+ import json
9
10
import re
10
11
from glob import glob
11
12
import multiprocessing
@@ -47,6 +48,8 @@ def base_path(*p):
47
48
# (not site packages which may clash with u-module names), and improve start up time.
48
49
CPYTHON3_CMD = [CPYTHON3 , "-BS" ]
49
50
51
+ # File with the test results.
52
+ RESULTS_FILE = "_results.json"
50
53
51
54
# For diff'ing test output
52
55
DIFF = os .getenv ("MICROPY_DIFF" , "diff -u" )
@@ -770,7 +773,7 @@ def run_one_test(test_file):
770
773
with open (filename_mupy , "wb" ) as f :
771
774
f .write (output_mupy )
772
775
print ("FAIL " , test_file )
773
- failed_tests .append (test_name )
776
+ failed_tests .append (( test_name , test_file ) )
774
777
775
778
test_count .increment ()
776
779
@@ -784,6 +787,7 @@ def run_one_test(test_file):
784
787
for test in tests :
785
788
run_one_test (test )
786
789
790
+ # Leave RESULTS_FILE untouched here for future runs.
787
791
if args .list_tests :
788
792
return True
789
793
@@ -798,8 +802,26 @@ def run_one_test(test_file):
798
802
if len (skipped_tests ) > 0 :
799
803
print ("{} tests skipped: {}" .format (len (skipped_tests ), " " .join (skipped_tests )))
800
804
failed_tests = sorted (failed_tests .value )
805
+
806
+ # Serialize regex added by append_filter.
807
+ def to_json (obj ):
808
+ if isinstance (obj , re .Pattern ):
809
+ return obj .pattern
810
+ return obj
811
+
812
+ with open (os .path .join (result_dir , RESULTS_FILE ), "w" ) as f :
813
+ json .dump (
814
+ {"args" : vars (args ), "failed_tests" : [test [1 ] for test in failed_tests ]},
815
+ f ,
816
+ default = to_json ,
817
+ )
818
+
801
819
if len (failed_tests ) > 0 :
802
- print ("{} tests failed: {}" .format (len (failed_tests ), " " .join (failed_tests )))
820
+ print (
821
+ "{} tests failed: {}" .format (
822
+ len (failed_tests ), " " .join (test [0 ] for test in failed_tests )
823
+ )
824
+ )
803
825
return False
804
826
805
827
# all tests succeeded
@@ -915,6 +937,11 @@ def main():
915
937
action = "store_true" ,
916
938
help = "delete the .exp and .out files from failed tests and exit" ,
917
939
)
940
+ cmd_parser .add_argument (
941
+ "--run-failures" ,
942
+ action = "store_true" ,
943
+ help = "re-run only the failed tests" ,
944
+ )
918
945
args = cmd_parser .parse_args ()
919
946
920
947
if args .print_failures :
@@ -931,6 +958,7 @@ def main():
931
958
os .path .join (args .result_dir , "*.out" )
932
959
):
933
960
os .remove (f )
961
+ rm_f (os .path .join (args .result_dir , RESULTS_FILE ))
934
962
935
963
sys .exit (0 )
936
964
@@ -979,7 +1007,19 @@ def main():
979
1007
else :
980
1008
raise ValueError ("target must be one of %s" % ", " .join (LOCAL_TARGETS + EXTERNAL_TARGETS ))
981
1009
982
- if len (args .files ) == 0 :
1010
+ if args .run_failures and (any (args .files ) or args .test_dirs is not None ):
1011
+ raise ValueError (
1012
+ "--run-failures cannot be used together with files or --test-dirs arguments"
1013
+ )
1014
+
1015
+ if args .run_failures :
1016
+ results_file = os .path .join (args .result_dir , RESULTS_FILE )
1017
+ if os .path .exists (results_file ):
1018
+ with open (results_file , "r" ) as f :
1019
+ tests = json .load (f )["failed_tests" ]
1020
+ else :
1021
+ tests = []
1022
+ elif len (args .files ) == 0 :
983
1023
if args .test_dirs is None :
984
1024
test_dirs = (
985
1025
"basics" ,
0 commit comments