2424 --builddir DIR Directory in which packages were built.
2525 -d --debug Run test scripts under the Python debugger.
2626 -D --devmode Run tests in Python's development mode (3.7+ only)
27+ --e2e-only Run only the end-to-end tests
2728 -e --external Run the script in external mode (for external Tools)
2829 -f --file FILE Only run tests listed in FILE.
2930 -j --jobs JOBS Run tests in JOBS parallel jobs.
5455 and a percentage value, based on the total and
5556 current number of tests.
5657 -t --time Print test execution time.
58+ --unit-only Run only the unit tests
5759 -v VERSION Specify the SCons version.
5860 --verbose=LEVEL Set verbose level:
5961 1 = print executed commands,
110112allow_pipe_files = True
111113quit_on_failure = False
112114excludelistfile = None
115+ e2e_only = unit_only = False
113116
114117script = sys .argv [0 ].split ("/" )[- 1 ]
115118usagestr = """\
@@ -175,6 +178,8 @@ def _process_short_opts(self, rargs, values):
175178 "exec=" ,
176179 "verbose=" ,
177180 "exclude-list=" ,
181+ "e2e-only" ,
182+ "unit-only" ,
178183 ],
179184)
180185
@@ -241,6 +246,10 @@ def _process_short_opts(self, rargs, values):
241246 scons = a
242247 elif o in ['--exclude-list' ]:
243248 excludelistfile = a
249+ elif o in ['--e2e-only' ]:
250+ e2e_only = True
251+ elif o in ['--unit-only' ]:
252+ unit_only = True
244253
245254
246255class Unbuffered ():
@@ -553,6 +562,27 @@ def footer(self, f):
553562
554563
555564# ---[ test discovery ]------------------------------------
565+ # This section figures which tests to run.
566+ #
567+ # The initial testlist is made by reading from the testlistfile,
568+ # if supplied, or by looking at the test arguments, if supplied,
569+ # or by looking for all test files if the "all" argument is supplied.
570+ # One of the three is required.
571+ #
572+ # Each test path, whichever of the three sources it comes from,
573+ # specifies either a test file or a directory to search for
574+ # SCons tests. SCons code layout assumes that any file under the 'src'
575+ # subdirectory that ends with 'Tests.py' is a unit test, and any Python
576+ # script (*.py) under the 'test' subdirectory is an end-to-end test.
577+ # We need to track these because they are invoked differently.
578+ # find_unit_tests and find_e2e_tests are used for this searching.
579+ #
580+ # Note that there are some tests under 'src' that *begin* with
581+ # 'test_', but they're packaging and installation tests, not
582+ # functional tests, so we don't execute them by default. (They can
583+ # still be executed by hand, though).
584+ #
585+ # Test exclusions, if specified, are then applied.
556586
557587tests = []
558588excludetests = []
@@ -594,25 +624,10 @@ def find_e2e_tests(directory):
594624
595625if testlistfile :
596626 with open (testlistfile , 'r' ) as f :
597- tests = f .readlines ()
598- tests = [x for x in tests if x [0 ] != '#' ]
599- tests = [x [:- 1 ] for x in tests ]
600- tests = [x .strip () for x in tests ]
627+ tests = [x [:- 1 ].strip () for x in f if not x .startswith ('#' )]
601628 tests = [x for x in tests if x ]
602629else :
603630 testpaths = []
604-
605- # Each test path specifies a test file, or a directory to search for
606- # SCons tests. SCons code layout assumes that any file under the 'SCons'
607- # subdirectory that ends with 'Tests.py' is a unit test, and any Python
608- # script (*.py) under the 'test' subdirectory an end-to-end test.
609- # We need to track these because they are invoked differently.
610- #
611- # Note that there are some tests under 'SCons' that *begin* with
612- # 'test_', but they're packaging and installation tests, not
613- # functional tests, so we don't execute them by default. (They can
614- # still be executed by hand, though).
615-
616631 if options .all :
617632 testpaths = ['SCons' , 'test' ]
618633 elif args :
@@ -622,24 +637,25 @@ def find_e2e_tests(directory):
622637 # Clean up path so it can match startswith's below
623638 # sys.stderr.write("Changed:%s->"%tp)
624639 # remove leading ./ or .\
625- if tp [ 0 ] == '.' and tp [1 ] in (os .sep , os .altsep ):
640+ if tp . startswith ( '.' ) and tp [1 ] in (os .sep , os .altsep ):
626641 tp = tp [2 :]
627642 # tp = os.path.normpath(tp)
628643 # sys.stderr.write('->%s<-'%tp)
629644 # sys.stderr.write("to:%s\n"%tp)
630645 for path in glob .glob (tp ):
631646 if os .path .isdir (path ):
632- if path .startswith ('SCons' ) or path . startswith ( 'testing' ):
647+ if path .startswith (( 'SCons' , 'testing' )) and not e2e_only :
633648 for p in find_unit_tests (path ):
634649 unittests .append (p )
635- elif path .startswith ('test' ):
650+ elif path .startswith ('test' ) and not unit_only :
636651 for p in find_e2e_tests (path ):
637652 endtests .append (p )
638653 else :
639- if path .endswith ("Tests.py" ):
654+ if path .endswith ("Tests.py" ) and not e2e_only :
640655 unittests .append (path )
641656 else :
642- endtests .append (path )
657+ if not unit_only :
658+ endtests .append (path )
643659
644660 tests .extend (unittests )
645661 tests .extend (endtests )
@@ -697,10 +713,9 @@ def log_result(t, io_lock=None):
697713 we need to lock access to the log to avoid interleaving. The same
698714 would apply if output was a file.
699715
700- :param t: a completed testcase
701- :type t: Test
702- :param io_lock:
703- :type io_lock: threading.Lock
716+ Args:
717+ t (Test): (completed) testcase instance
718+ io_lock (threading.lock): (optional) lock to use
704719 """
705720
706721 # there is no lock in single-job run, which includes
@@ -727,6 +742,18 @@ def log_result(t, io_lock=None):
727742
728743
729744def run_test (t , io_lock = None , run_async = True ):
745+ """ Run a testcase.
746+
747+ Builds the command line to give to execute().
748+ Also the best place to record some information that will be
749+ used in output, which in some conditions is printed here.
750+
751+ Args:
752+ t (Test): testcase instance
753+ io_lock (threading.Lock): (optional) lock to use
754+ run_async (bool): whether to run asynchronously
755+ """
756+
730757 t .headline = ""
731758 command_args = []
732759 if debug :
@@ -738,7 +765,7 @@ def run_test(t, io_lock=None, run_async=True):
738765 # For example --runner TestUnit.TAPTestRunner
739766 command_args .append ('--runner ' + options .runner )
740767 t .command_args = [escape (python )] + command_args
741- t .command_str = " " .join ([ escape ( python )] + command_args )
768+ t .command_str = " " .join (t . command_args )
742769 if printcommand :
743770 if print_progress :
744771 t .headline += "%d/%d (%.2f%s) %s\n " % (
@@ -753,7 +780,7 @@ def run_test(t, io_lock=None, run_async=True):
753780 if not suppress_output and not catch_output :
754781 # defer printing the headline until test is done
755782 sys .stdout .write (t .headline )
756- head , tail = os .path .split (t .abspath )
783+ head , _ = os .path .split (t .abspath )
757784 fixture_dirs = []
758785 if head :
759786 fixture_dirs .append (head )
@@ -775,7 +802,7 @@ class RunTest(threading.Thread):
775802 """
776803 def __init__ (self , queue = None , io_lock = None ,
777804 group = None , target = None , name = None , args = (), kwargs = None ):
778- super (RunTest , self ).__init__ (group = group , target = target , name = name )
805+ super ().__init__ (group = group , target = target , name = name )
779806 self .queue = queue
780807 self .io_lock = io_lock
781808
@@ -856,6 +883,7 @@ def run(self):
856883if fail :
857884 sys .exit (1 )
858885elif no_result :
886+ # if no fails, but skips were found
859887 sys .exit (2 )
860888else :
861889 sys .exit (0 )
0 commit comments