2929from io import StringIO
3030from pathlib import Path , PurePath , PureWindowsPath
3131from queue import Queue
32- from typing import TextIO
3332
3433cwd = os .getcwd ()
3534debug : str | None = None
@@ -575,38 +574,34 @@ def footer(self, f):
575574 del os .environ ['_JAVA_OPTIONS' ]
576575
577576
578- # ---[ test discovery ]------------------------------------
579- # This section figures out which tests to run.
577+ # ---[ Test Discovery ]------------------------------------
578+ # This section determines which tests to run based on three
579+ # mutually exclusive options:
580+ # 1. Reading test paths from a testlist file (--file or --retry option)
581+ # 2. Using test paths given as command line arguments
582+ # 3. Automatically finding all tests (--all option)
580583#
581- # The initial testlist is made by reading from the testlistfile,
582- # if supplied, or by looking at the test arguments, if supplied,
583- # or by looking for all test files if the "all" argument is supplied.
584- # One of the three is required.
584+ # Test paths can specify either individual test files, or directories to
585+ # scan for tests. The following test types are recognized:
585586#
586- # Each test path, whichever of the three sources it comes from,
587- # specifies either a test file or a directory to search for
588- # SCons tests. SCons code layout assumes that any file under the 'SCons'
589- # subdirectory that ends with 'Tests.py' is a unit test, and any Python
590- # script (*.py) under the 'test' subdirectory is an end-to-end test.
591- # We need to track these because they are invoked differently.
592- # find_unit_tests and find_e2e_tests are used for this searching.
587+ # - Unit tests: Files ending in 'Tests.py' under the 'SCons' directory
588+ # - End-to-end tests: Python scripts (*.py) under the 'test' directory
589+ # - External tests: End-to-end tests in paths containing a 'test'
590+ # component (not expected to be local)
593591#
594- # Note that there are some tests under 'SCons' that *begin* with
595- # 'test_', but they're packaging and installation tests, not
596- # functional tests, so we don't execute them by default. (They can
597- # still be executed by hand, though).
592+ # find_unit_tests() and find_e2e_tests() perform the directory scanning.
598593#
599- # Test exclusions, if specified, are then applied.
600-
594+ # After the initial test list is built, any test exclusions specified via
595+ # --exclude-list are applied to produce the final test set.
601596
602597def scanlist (testfile ):
603598 """ Process a testlist file """
604599 data = StringIO (testfile .read_text ())
605600 tests = [t .strip () for t in data .readlines () if not t .startswith ('#' )]
606601 # in order to allow scanned lists to work whether they use forward or
607- # backward slashes, first create the object as a PureWindowsPath which
608- # accepts either, then use that to make a Path object to use for
609- # comparisons like "file in scanned_list".
602+ # backward slashes, on non-Windows first create the object as a
603+ # PureWindowsPath which accepts either, then use that to make a Path
604+ # object for use in comparisons like "if file in scanned_list".
610605 if sys .platform == 'win32' :
611606 return [Path (t ) for t in tests if t ]
612607 else :
@@ -635,7 +630,7 @@ def find_e2e_tests(directory):
635630 if 'sconstest.skip' in filenames :
636631 continue
637632
638- # Slurp in any tests in exclude lists
633+ # Gather up the data from any exclude lists
639634 excludes = []
640635 if ".exclude_tests" in filenames :
641636 excludefile = Path (dirpath , ".exclude_tests" ).resolve ()
@@ -648,8 +643,7 @@ def find_e2e_tests(directory):
648643 return sorted (result )
649644
650645
651- # initial selection:
652- # if we have a testlist file read that, else hunt for tests.
646+ # Initial test selection:
653647unittests = []
654648endtests = []
655649if args .testlistfile :
@@ -668,15 +662,16 @@ def find_e2e_tests(directory):
668662 # Clean up path removing leading ./ or .\
669663 name = str (path )
670664 if name .startswith ('.' ) and name [1 ] in (os .sep , os .altsep ):
671- path = path .with_name (tn [2 :])
665+ path = path .with_name (name [2 :])
672666
673667 if path .exists ():
674668 if path .is_dir ():
675669 if path .parts [0 ] == "SCons" or path .parts [0 ] == "testing" :
676670 unittests .extend (find_unit_tests (path ))
677671 elif path .parts [0 ] == 'test' :
678672 endtests .extend (find_e2e_tests (path ))
679- # else: TODO: what if user pointed to a dir outside scons tree?
673+ elif args .external and 'test' in path .parts :
674+ endtests .extend (find_e2e_tests (path ))
680675 else :
681676 if path .match ("*Tests.py" ):
682677 unittests .append (path )
@@ -703,7 +698,7 @@ def find_e2e_tests(directory):
703698""" )
704699 sys .exit (1 )
705700
706- # ---[ test processing ]-----------------------------------
701+ # ---[ Test Processing ]-----------------------------------
707702tests = [Test (t ) for t in tests ]
708703
709704if args .list_only :
@@ -826,10 +821,11 @@ def run_test(t, io_lock=None, run_async=True):
826821
827822
828823class RunTest (threading .Thread ):
829- """ Test Runner class .
824+ """Test Runner thread .
830825
831- One instance will be created for each job thread in multi-job mode
826+ One will be created for each job in multi-job mode
832827 """
828+
833829 def __init__ (self , queue = None , io_lock = None , group = None , target = None , name = None ):
834830 super ().__init__ (group = group , target = target , name = name )
835831 self .queue = queue
0 commit comments