@@ -43,6 +43,11 @@ use crate::common::{
4343use crate :: header:: HeadersCache ;
4444use crate :: util:: logv;
4545
46+ /// Creates the `Config` instance for this invocation of compiletest.
47+ ///
48+ /// The config mostly reflects command-line arguments, but there might also be
49+ /// some code here that inspects environment variables or even runs executables
50+ /// (e.g. when discovering debugger versions).
4651pub fn parse_config ( args : Vec < String > ) -> Config {
4752 let mut opts = Options :: new ( ) ;
4853 opts. reqopt ( "" , "compile-lib-path" , "path to host shared libraries" , "PATH" )
@@ -413,6 +418,7 @@ pub fn opt_str2(maybestr: Option<String>) -> String {
413418 }
414419}
415420
421+ /// Called by `main` after the config has been parsed.
416422pub fn run_tests ( config : Arc < Config > ) {
417423 // If we want to collect rustfix coverage information,
418424 // we first make sure that the coverage file does not exist.
@@ -454,6 +460,8 @@ pub fn run_tests(config: Arc<Config>) {
454460 configs. push ( config. clone ( ) ) ;
455461 } ;
456462
463+ // Discover all of the tests in the test suite directory, and build a libtest
464+ // structure for each test (or each revision of a multi-revision test).
457465 let mut tests = Vec :: new ( ) ;
458466 for c in configs {
459467 let mut found_paths = HashSet :: new ( ) ;
@@ -463,7 +471,12 @@ pub fn run_tests(config: Arc<Config>) {
463471
464472 tests. sort_by ( |a, b| a. desc . name . as_slice ( ) . cmp ( & b. desc . name . as_slice ( ) ) ) ;
465473
474+ // Delegate to libtest to filter and run the big list of structures created
475+ // during test discovery. When libtest decides to run a test, it will invoke
476+ // the corresponding closure created by `make_test_closure`.
466477 let res = test:: run_tests_console ( & opts, tests) ;
478+
479+ // Check the outcome reported by libtest.
467480 match res {
468481 Ok ( true ) => { }
469482 Ok ( false ) => {
@@ -532,6 +545,11 @@ pub fn test_opts(config: &Config) -> test::TestOpts {
532545 }
533546}
534547
548+ /// Creates libtest structures for every test/revision in the test suite directory.
549+ ///
550+ /// This always inspects _all_ test files in the suite (e.g. all 17k+ ui tests),
551+ /// regardless of whether any filters/tests were specified on the command-line,
552+ /// because filtering is handled later by libtest.
535553pub fn make_tests (
536554 config : Arc < Config > ,
537555 tests : & mut Vec < test:: TestDescAndFn > ,
@@ -610,10 +628,17 @@ fn common_inputs_stamp(config: &Config) -> Stamp {
610628 stamp
611629}
612630
631+ /// Returns a list of modified/untracked test files that should be run when
632+ /// the `--only-modified` flag is in use.
633+ ///
634+ /// (Might be inaccurate in some cases.)
613635fn modified_tests ( config : & Config , dir : & Path ) -> Result < Vec < PathBuf > , String > {
636+ // If `--only-modified` wasn't passed, the list of modified tests won't be
637+ // used for anything, so avoid some work and just return an empty list.
614638 if !config. only_modified {
615639 return Ok ( vec ! [ ] ) ;
616640 }
641+
617642 let files =
618643 get_git_modified_files ( & config. git_config ( ) , Some ( dir) , & vec ! [ "rs" , "stderr" , "fixed" ] ) ?
619644 . unwrap_or ( vec ! [ ] ) ;
@@ -634,6 +659,8 @@ fn modified_tests(config: &Config, dir: &Path) -> Result<Vec<PathBuf>, String> {
634659 Ok ( full_paths)
635660}
636661
662+ /// Recursively scans a directory to find test files and create test structures
663+ /// that will be handed over to libtest.
637664fn collect_tests_from_dir (
638665 config : Arc < Config > ,
639666 cache : & HeadersCache ,
@@ -650,6 +677,8 @@ fn collect_tests_from_dir(
650677 return Ok ( ( ) ) ;
651678 }
652679
680+ // For run-make tests, a "test file" is actually a directory that contains
681+ // an `rmake.rs` or `Makefile`"
653682 if config. mode == Mode :: RunMake {
654683 if dir. join ( "Makefile" ) . exists ( ) && dir. join ( "rmake.rs" ) . exists ( ) {
655684 return Err ( io:: Error :: other (
@@ -663,6 +692,7 @@ fn collect_tests_from_dir(
663692 relative_dir : relative_dir_path. parent ( ) . unwrap ( ) . to_path_buf ( ) ,
664693 } ;
665694 tests. extend ( make_test ( config, cache, & paths, inputs, poisoned) ) ;
695+ // This directory is a test, so don't try to find other tests inside it.
666696 return Ok ( ( ) ) ;
667697 }
668698 }
@@ -677,22 +707,27 @@ fn collect_tests_from_dir(
677707 fs:: create_dir_all ( & build_dir) . unwrap ( ) ;
678708
679709 // Add each `.rs` file as a test, and recurse further on any
680- // subdirectories we find, except for `aux ` directories.
710+ // subdirectories we find, except for `auxiliary ` directories.
681711 // FIXME: this walks full tests tree, even if we have something to ignore
682712 // use walkdir/ignore like in tidy?
683713 for file in fs:: read_dir ( dir) ? {
684714 let file = file?;
685715 let file_path = file. path ( ) ;
686716 let file_name = file. file_name ( ) ;
717+
687718 if is_test ( & file_name) && ( !config. only_modified || modified_tests. contains ( & file_path) ) {
719+ // We found a test file, so create the corresponding libtest structures.
688720 debug ! ( "found test file: {:?}" , file_path. display( ) ) ;
721+
722+ // Record the stem of the test file, to check for overlaps later.
689723 let rel_test_path = relative_dir_path. join ( file_path. file_stem ( ) . unwrap ( ) ) ;
690724 found_paths. insert ( rel_test_path) ;
725+
691726 let paths =
692727 TestPaths { file : file_path, relative_dir : relative_dir_path. to_path_buf ( ) } ;
693-
694728 tests. extend ( make_test ( config. clone ( ) , cache, & paths, inputs, poisoned) )
695729 } else if file_path. is_dir ( ) {
730+ // Recurse to find more tests in a subdirectory.
696731 let relative_file_path = relative_dir_path. join ( file. file_name ( ) ) ;
697732 if & file_name != "auxiliary" {
698733 debug ! ( "found directory: {:?}" , file_path. display( ) ) ;
@@ -728,13 +763,18 @@ pub fn is_test(file_name: &OsString) -> bool {
728763 !invalid_prefixes. iter ( ) . any ( |p| file_name. starts_with ( p) )
729764}
730765
766+ /// For a single test file, creates one or more test structures (one per revision)
767+ /// that can be handed over to libtest to run, possibly in parallel.
731768fn make_test (
732769 config : Arc < Config > ,
733770 cache : & HeadersCache ,
734771 testpaths : & TestPaths ,
735772 inputs : & Stamp ,
736773 poisoned : & mut bool ,
737774) -> Vec < test:: TestDescAndFn > {
775+ // For run-make tests, each "test file" is actually a _directory_ containing
776+ // an `rmake.rs` or `Makefile`. But for the purposes of directive parsing,
777+ // we want to look at that recipe file, not the directory itself.
738778 let test_path = if config. mode == Mode :: RunMake {
739779 if testpaths. file . join ( "rmake.rs" ) . exists ( ) && testpaths. file . join ( "Makefile" ) . exists ( ) {
740780 panic ! ( "run-make tests cannot have both `rmake.rs` and `Makefile`" ) ;
@@ -750,45 +790,66 @@ fn make_test(
750790 } else {
751791 PathBuf :: from ( & testpaths. file )
752792 } ;
793+
794+ // Scan the test file to discover its revisions, if any.
753795 let early_props = EarlyProps :: from_file ( & config, & test_path) ;
754796
755- // Incremental tests are special, they inherently cannot be run in parallel.
756- // `runtest::run` will be responsible for iterating over revisions.
797+ // Normally we create one libtest structure per revision, with two exceptions:
798+ // - If a test doesn't use revisions, create a dummy revision (None) so that
799+ // the test can still run.
800+ // - Incremental tests inherently can't run their revisions in parallel, so
801+ // we treat them like non-revisioned tests here. Incremental revisions are
802+ // handled internally by `runtest::run` instead.
757803 let revisions = if early_props. revisions . is_empty ( ) || config. mode == Mode :: Incremental {
758804 vec ! [ None ]
759805 } else {
760806 early_props. revisions . iter ( ) . map ( |r| Some ( r. as_str ( ) ) ) . collect ( )
761807 } ;
762808
809+ // For each revision (or the sole dummy revision), create and return a
810+ // `test::TestDescAndFn` that can be handed over to libtest.
763811 revisions
764812 . into_iter ( )
765813 . map ( |revision| {
814+ // Create a test name and description to hand over to libtest.
766815 let src_file =
767816 std:: fs:: File :: open ( & test_path) . expect ( "open test file to parse ignores" ) ;
768817 let test_name = crate :: make_test_name ( & config, testpaths, revision) ;
818+ // Create a libtest description for the test/revision.
819+ // This is where `ignore-*`/`only-*`/`needs-*` directives are handled,
820+ // because they need to set the libtest ignored flag.
769821 let mut desc = make_test_description (
770822 & config, cache, test_name, & test_path, src_file, revision, poisoned,
771823 ) ;
772- // Ignore tests that already run and are up to date with respect to inputs.
824+
825+ // If a test's inputs haven't changed since the last time it ran,
826+ // mark it as ignored so that libtest will skip it.
773827 if !config. force_rerun
774828 && is_up_to_date ( & config, testpaths, & early_props, revision, inputs)
775829 {
776830 desc. ignore = true ;
777831 // Keep this in sync with the "up-to-date" message detected by bootstrap.
778832 desc. ignore_message = Some ( "up-to-date" ) ;
779833 }
780- test:: TestDescAndFn {
781- desc,
782- testfn : make_test_closure ( config. clone ( ) , testpaths, revision) ,
783- }
834+
835+ // Create the callback that will run this test/revision when libtest calls it.
836+ let testfn = make_test_closure ( config. clone ( ) , testpaths, revision) ;
837+
838+ test:: TestDescAndFn { desc, testfn }
784839 } )
785840 . collect ( )
786841}
787842
843+ /// The path of the `stamp` file that gets created or updated whenever a
844+ /// particular test completes successfully.
788845fn stamp ( config : & Config , testpaths : & TestPaths , revision : Option < & str > ) -> PathBuf {
789846 output_base_dir ( config, testpaths, revision) . join ( "stamp" )
790847}
791848
849+ /// Returns a list of files that, if modified, would cause this test to no
850+ /// longer be up-to-date.
851+ ///
852+ /// (Might be inaccurate in some cases.)
792853fn files_related_to_test (
793854 config : & Config ,
794855 testpaths : & TestPaths ,
@@ -824,53 +885,71 @@ fn files_related_to_test(
824885 related
825886}
826887
888+ /// Checks whether a particular test/revision is "up-to-date", meaning that no
889+ /// relevant files/settings have changed since the last time the test succeeded.
890+ ///
891+ /// (This is not very reliable in some circumstances, so the `--force-rerun`
892+ /// flag can be used to ignore up-to-date checking and always re-run tests.)
827893fn is_up_to_date (
828894 config : & Config ,
829895 testpaths : & TestPaths ,
830896 props : & EarlyProps ,
831897 revision : Option < & str > ,
832- inputs : & Stamp ,
898+ inputs : & Stamp , // Last-modified timestamp of the compiler, compiletest etc
833899) -> bool {
834900 let stamp_name = stamp ( config, testpaths, revision) ;
835- // Check hash.
901+ // Check the config hash inside the stamp file .
836902 let contents = match fs:: read_to_string ( & stamp_name) {
837903 Ok ( f) => f,
838904 Err ( ref e) if e. kind ( ) == ErrorKind :: InvalidData => panic ! ( "Can't read stamp contents" ) ,
905+ // The test hasn't succeeded yet, so it is not up-to-date.
839906 Err ( _) => return false ,
840907 } ;
841908 let expected_hash = runtest:: compute_stamp_hash ( config) ;
842909 if contents != expected_hash {
910+ // Some part of compiletest configuration has changed since the test
911+ // last succeeded, so it is not up-to-date.
843912 return false ;
844913 }
845914
846- // Check timestamps.
915+ // Check the timestamp of the stamp file against the last modified time
916+ // of all files known to be relevant to the test.
847917 let mut inputs = inputs. clone ( ) ;
848918 for path in files_related_to_test ( config, testpaths, props, revision) {
849919 inputs. add_path ( & path) ;
850920 }
851921
922+ // If no relevant files have been modified since the stamp file was last
923+ // written, the test is up-to-date.
852924 inputs < Stamp :: from_path ( & stamp_name)
853925}
854926
927+ /// The maximum of a set of file-modified timestamps.
855928#[ derive( Clone , Debug , PartialEq , Eq , PartialOrd , Ord ) ]
856929struct Stamp {
857930 time : SystemTime ,
858931}
859932
860933impl Stamp {
934+ /// Creates a timestamp holding the last-modified time of the specified file.
861935 fn from_path ( path : & Path ) -> Self {
862936 let mut stamp = Stamp { time : SystemTime :: UNIX_EPOCH } ;
863937 stamp. add_path ( path) ;
864938 stamp
865939 }
866940
941+ /// Updates this timestamp to the last-modified time of the specified file,
942+ /// if it is later than the currently-stored timestamp.
867943 fn add_path ( & mut self , path : & Path ) {
868944 let modified = fs:: metadata ( path)
869945 . and_then ( |metadata| metadata. modified ( ) )
870946 . unwrap_or ( SystemTime :: UNIX_EPOCH ) ;
871947 self . time = self . time . max ( modified) ;
872948 }
873949
950+ /// Updates this timestamp to the most recent last-modified time of all files
951+ /// recursively contained in the given directory, if it is later than the
952+ /// currently-stored timestamp.
874953 fn add_dir ( & mut self , path : & Path ) {
875954 for entry in WalkDir :: new ( path) {
876955 let entry = entry. unwrap ( ) ;
@@ -886,6 +965,7 @@ impl Stamp {
886965 }
887966}
888967
968+ /// Creates a name for this test/revision that can be handed over to libtest.
889969fn make_test_name (
890970 config : & Config ,
891971 testpaths : & TestPaths ,
@@ -914,20 +994,41 @@ fn make_test_name(
914994 ) )
915995}
916996
997+ /// Creates a callback for this test/revision that libtest will call when it
998+ /// decides to actually run the underlying test.
917999fn make_test_closure (
9181000 config : Arc < Config > ,
9191001 testpaths : & TestPaths ,
9201002 revision : Option < & str > ,
9211003) -> test:: TestFn {
922- let config = config. clone ( ) ;
9231004 let testpaths = testpaths. clone ( ) ;
9241005 let revision = revision. map ( str:: to_owned) ;
1006+
1007+ // This callback is the link between compiletest's test discovery code,
1008+ // and the parts of compiletest that know how to run an individual test.
9251009 test:: DynTestFn ( Box :: new ( move || {
9261010 runtest:: run ( config, & testpaths, revision. as_deref ( ) ) ;
9271011 Ok ( ( ) )
9281012 } ) )
9291013}
9301014
1015+ /// Checks that test discovery didn't find any tests whose name stem is a prefix
1016+ /// of some other tests's name.
1017+ ///
1018+ /// For example, suppose the test suite contains these two test files:
1019+ /// - `tests/rustdoc/primitive.rs`
1020+ /// - `tests/rustdoc/primitive/no_std.rs`
1021+ ///
1022+ /// The test runner might put the output from those tests in these directories:
1023+ /// - `$build/test/rustdoc/primitive/`
1024+ /// - `$build/test/rustdoc/primitive/no_std/`
1025+ ///
1026+ /// Because one output path is a subdirectory of the other, the two tests might
1027+ /// interfere with each other in unwanted ways, especially if the test runner
1028+ /// decides to delete test output directories to clean them between runs.
1029+ /// To avoid problems, we forbid test names from overlapping in this way.
1030+ ///
1031+ /// See <https://github.com/rust-lang/rust/pull/109509> for more context.
9311032fn check_overlapping_tests ( found_paths : & HashSet < PathBuf > ) {
9321033 let mut collisions = Vec :: new ( ) ;
9331034 for path in found_paths {
0 commit comments