@@ -543,6 +543,21 @@ pub fn test_opts(config: &Config) -> test::TestOpts {
543
543
}
544
544
}
545
545
546
+ /// Read-only context data used during test collection.
547
+ struct TestCollectorCx {
548
+ config : Arc < Config > ,
549
+ cache : HeadersCache ,
550
+ inputs : Stamp ,
551
+ modified_tests : Vec < PathBuf > ,
552
+ }
553
+
554
+ /// Mutable state used during test collection.
555
+ struct TestCollector {
556
+ tests : Vec < test:: TestDescAndFn > ,
557
+ found_paths : HashSet < PathBuf > ,
558
+ poisoned : bool ,
559
+ }
560
+
546
561
/// Creates libtest structures for every test/revision in the test suite directory.
547
562
///
548
563
/// This always inspects _all_ test files in the suite (e.g. all 17k+ ui tests),
@@ -556,24 +571,16 @@ pub fn collect_and_make_tests(config: Arc<Config>) -> Vec<test::TestDescAndFn> {
556
571
} ) ;
557
572
let cache = HeadersCache :: load ( & config) ;
558
573
559
- let mut tests = vec ! [ ] ;
560
- let mut found_paths = HashSet :: new ( ) ;
561
- let mut poisoned = false ;
562
-
563
- collect_tests_from_dir (
564
- config. clone ( ) ,
565
- & cache,
566
- & config. src_base ,
567
- & PathBuf :: new ( ) ,
568
- & inputs,
569
- & mut tests,
570
- & mut found_paths,
571
- & modified_tests,
572
- & mut poisoned,
573
- )
574
- . unwrap_or_else ( |reason| {
575
- panic ! ( "Could not read tests from {}: {reason}" , config. src_base. display( ) )
576
- } ) ;
574
+ let cx = TestCollectorCx { config, cache, inputs, modified_tests } ;
575
+ let mut collector =
576
+ TestCollector { tests : vec ! [ ] , found_paths : HashSet :: new ( ) , poisoned : false } ;
577
+
578
+ collect_tests_from_dir ( & cx, & mut collector, & cx. config . src_base , & PathBuf :: new ( ) )
579
+ . unwrap_or_else ( |reason| {
580
+ panic ! ( "Could not read tests from {}: {reason}" , cx. config. src_base. display( ) )
581
+ } ) ;
582
+
583
+ let TestCollector { tests, found_paths, poisoned } = collector;
577
584
578
585
if poisoned {
579
586
eprintln ! ( ) ;
@@ -663,15 +670,10 @@ fn modified_tests(config: &Config, dir: &Path) -> Result<Vec<PathBuf>, String> {
663
670
/// Recursively scans a directory to find test files and create test structures
664
671
/// that will be handed over to libtest.
665
672
fn collect_tests_from_dir (
666
- config : Arc < Config > ,
667
- cache : & HeadersCache ,
673
+ cx : & TestCollectorCx ,
674
+ collector : & mut TestCollector ,
668
675
dir : & Path ,
669
676
relative_dir_path : & Path ,
670
- inputs : & Stamp ,
671
- tests : & mut Vec < test:: TestDescAndFn > ,
672
- found_paths : & mut HashSet < PathBuf > ,
673
- modified_tests : & Vec < PathBuf > ,
674
- poisoned : & mut bool ,
675
677
) -> io:: Result < ( ) > {
676
678
// Ignore directories that contain a file named `compiletest-ignore-dir`.
677
679
if dir. join ( "compiletest-ignore-dir" ) . exists ( ) {
@@ -680,7 +682,7 @@ fn collect_tests_from_dir(
680
682
681
683
// For run-make tests, a "test file" is actually a directory that contains
682
684
// an `rmake.rs` or `Makefile`"
683
- if config. mode == Mode :: RunMake {
685
+ if cx . config . mode == Mode :: RunMake {
684
686
if dir. join ( "Makefile" ) . exists ( ) && dir. join ( "rmake.rs" ) . exists ( ) {
685
687
return Err ( io:: Error :: other (
686
688
"run-make tests cannot have both `Makefile` and `rmake.rs`" ,
@@ -692,7 +694,7 @@ fn collect_tests_from_dir(
692
694
file : dir. to_path_buf ( ) ,
693
695
relative_dir : relative_dir_path. parent ( ) . unwrap ( ) . to_path_buf ( ) ,
694
696
} ;
695
- tests . extend ( make_test ( config , cache , & paths, inputs , poisoned ) ) ;
697
+ make_test ( cx , collector , & paths) ;
696
698
// This directory is a test, so don't try to find other tests inside it.
697
699
return Ok ( ( ) ) ;
698
700
}
@@ -704,7 +706,7 @@ fn collect_tests_from_dir(
704
706
// sequential loop because otherwise, if we do it in the
705
707
// tests themselves, they race for the privilege of
706
708
// creating the directories and sometimes fail randomly.
707
- let build_dir = output_relative_path ( & config, relative_dir_path) ;
709
+ let build_dir = output_relative_path ( & cx . config , relative_dir_path) ;
708
710
fs:: create_dir_all ( & build_dir) . unwrap ( ) ;
709
711
710
712
// Add each `.rs` file as a test, and recurse further on any
@@ -716,33 +718,25 @@ fn collect_tests_from_dir(
716
718
let file_path = file. path ( ) ;
717
719
let file_name = file. file_name ( ) ;
718
720
719
- if is_test ( & file_name) && ( !config. only_modified || modified_tests. contains ( & file_path) ) {
721
+ if is_test ( & file_name)
722
+ && ( !cx. config . only_modified || cx. modified_tests . contains ( & file_path) )
723
+ {
720
724
// We found a test file, so create the corresponding libtest structures.
721
725
debug ! ( "found test file: {:?}" , file_path. display( ) ) ;
722
726
723
727
// Record the stem of the test file, to check for overlaps later.
724
728
let rel_test_path = relative_dir_path. join ( file_path. file_stem ( ) . unwrap ( ) ) ;
725
- found_paths. insert ( rel_test_path) ;
729
+ collector . found_paths . insert ( rel_test_path) ;
726
730
727
731
let paths =
728
732
TestPaths { file : file_path, relative_dir : relative_dir_path. to_path_buf ( ) } ;
729
- tests . extend ( make_test ( config . clone ( ) , cache , & paths, inputs , poisoned ) )
733
+ make_test ( cx , collector , & paths) ;
730
734
} else if file_path. is_dir ( ) {
731
735
// Recurse to find more tests in a subdirectory.
732
736
let relative_file_path = relative_dir_path. join ( file. file_name ( ) ) ;
733
737
if & file_name != "auxiliary" {
734
738
debug ! ( "found directory: {:?}" , file_path. display( ) ) ;
735
- collect_tests_from_dir (
736
- config. clone ( ) ,
737
- cache,
738
- & file_path,
739
- & relative_file_path,
740
- inputs,
741
- tests,
742
- found_paths,
743
- modified_tests,
744
- poisoned,
745
- ) ?;
739
+ collect_tests_from_dir ( cx, collector, & file_path, & relative_file_path) ?;
746
740
}
747
741
} else {
748
742
debug ! ( "found other file/directory: {:?}" , file_path. display( ) ) ;
@@ -766,17 +760,11 @@ pub fn is_test(file_name: &OsString) -> bool {
766
760
767
761
/// For a single test file, creates one or more test structures (one per revision)
768
762
/// that can be handed over to libtest to run, possibly in parallel.
769
- fn make_test (
770
- config : Arc < Config > ,
771
- cache : & HeadersCache ,
772
- testpaths : & TestPaths ,
773
- inputs : & Stamp ,
774
- poisoned : & mut bool ,
775
- ) -> Vec < test:: TestDescAndFn > {
763
+ fn make_test ( cx : & TestCollectorCx , collector : & mut TestCollector , testpaths : & TestPaths ) {
776
764
// For run-make tests, each "test file" is actually a _directory_ containing
777
765
// an `rmake.rs` or `Makefile`. But for the purposes of directive parsing,
778
766
// we want to look at that recipe file, not the directory itself.
779
- let test_path = if config. mode == Mode :: RunMake {
767
+ let test_path = if cx . config . mode == Mode :: RunMake {
780
768
if testpaths. file . join ( "rmake.rs" ) . exists ( ) && testpaths. file . join ( "Makefile" ) . exists ( ) {
781
769
panic ! ( "run-make tests cannot have both `rmake.rs` and `Makefile`" ) ;
782
770
}
@@ -793,52 +781,52 @@ fn make_test(
793
781
} ;
794
782
795
783
// Scan the test file to discover its revisions, if any.
796
- let early_props = EarlyProps :: from_file ( & config, & test_path) ;
784
+ let early_props = EarlyProps :: from_file ( & cx . config , & test_path) ;
797
785
798
786
// Normally we create one libtest structure per revision, with two exceptions:
799
787
// - If a test doesn't use revisions, create a dummy revision (None) so that
800
788
// the test can still run.
801
789
// - Incremental tests inherently can't run their revisions in parallel, so
802
790
// we treat them like non-revisioned tests here. Incremental revisions are
803
791
// handled internally by `runtest::run` instead.
804
- let revisions = if early_props. revisions . is_empty ( ) || config. mode == Mode :: Incremental {
792
+ let revisions = if early_props. revisions . is_empty ( ) || cx . config . mode == Mode :: Incremental {
805
793
vec ! [ None ]
806
794
} else {
807
795
early_props. revisions . iter ( ) . map ( |r| Some ( r. as_str ( ) ) ) . collect ( )
808
796
} ;
809
797
810
- // For each revision (or the sole dummy revision), create and return a
798
+ // For each revision (or the sole dummy revision), create and append a
811
799
// `test::TestDescAndFn` that can be handed over to libtest.
812
- revisions
813
- . into_iter ( )
814
- . map ( |revision| {
815
- // Create a test name and description to hand over to libtest.
816
- let src_file =
817
- std:: fs:: File :: open ( & test_path) . expect ( "open test file to parse ignores" ) ;
818
- let test_name = crate :: make_test_name ( & config, testpaths, revision) ;
819
- // Create a libtest description for the test/revision.
820
- // This is where `ignore-*`/`only-*`/`needs-*` directives are handled,
821
- // because they need to set the libtest ignored flag.
822
- let mut desc = make_test_description (
823
- & config, cache, test_name, & test_path, src_file, revision, poisoned,
824
- ) ;
800
+ collector. tests . extend ( revisions. into_iter ( ) . map ( |revision| {
801
+ // Create a test name and description to hand over to libtest.
802
+ let src_file = fs:: File :: open ( & test_path) . expect ( "open test file to parse ignores" ) ;
803
+ let test_name = make_test_name ( & cx. config , testpaths, revision) ;
804
+ // Create a libtest description for the test/revision.
805
+ // This is where `ignore-*`/`only-*`/`needs-*` directives are handled,
806
+ // because they need to set the libtest ignored flag.
807
+ let mut desc = make_test_description (
808
+ & cx. config ,
809
+ & cx. cache ,
810
+ test_name,
811
+ & test_path,
812
+ src_file,
813
+ revision,
814
+ & mut collector. poisoned ,
815
+ ) ;
825
816
826
- // If a test's inputs haven't changed since the last time it ran,
827
- // mark it as ignored so that libtest will skip it.
828
- if !config. force_rerun
829
- && is_up_to_date ( & config, testpaths, & early_props, revision, inputs)
830
- {
831
- desc. ignore = true ;
832
- // Keep this in sync with the "up-to-date" message detected by bootstrap.
833
- desc. ignore_message = Some ( "up-to-date" ) ;
834
- }
817
+ // If a test's inputs haven't changed since the last time it ran,
818
+ // mark it as ignored so that libtest will skip it.
819
+ if !cx. config . force_rerun && is_up_to_date ( cx, testpaths, & early_props, revision) {
820
+ desc. ignore = true ;
821
+ // Keep this in sync with the "up-to-date" message detected by bootstrap.
822
+ desc. ignore_message = Some ( "up-to-date" ) ;
823
+ }
835
824
836
- // Create the callback that will run this test/revision when libtest calls it.
837
- let testfn = make_test_closure ( config . clone ( ) , testpaths, revision) ;
825
+ // Create the callback that will run this test/revision when libtest calls it.
826
+ let testfn = make_test_closure ( Arc :: clone ( & cx . config ) , testpaths, revision) ;
838
827
839
- test:: TestDescAndFn { desc, testfn }
840
- } )
841
- . collect ( )
828
+ test:: TestDescAndFn { desc, testfn }
829
+ } ) ) ;
842
830
}
843
831
844
832
/// The path of the `stamp` file that gets created or updated whenever a
@@ -892,21 +880,20 @@ fn files_related_to_test(
892
880
/// (This is not very reliable in some circumstances, so the `--force-rerun`
893
881
/// flag can be used to ignore up-to-date checking and always re-run tests.)
894
882
fn is_up_to_date (
895
- config : & Config ,
883
+ cx : & TestCollectorCx ,
896
884
testpaths : & TestPaths ,
897
885
props : & EarlyProps ,
898
886
revision : Option < & str > ,
899
- inputs : & Stamp , // Last-modified timestamp of the compiler, compiletest etc
900
887
) -> bool {
901
- let stamp_name = stamp ( config, testpaths, revision) ;
888
+ let stamp_name = stamp ( & cx . config , testpaths, revision) ;
902
889
// Check the config hash inside the stamp file.
903
890
let contents = match fs:: read_to_string ( & stamp_name) {
904
891
Ok ( f) => f,
905
892
Err ( ref e) if e. kind ( ) == ErrorKind :: InvalidData => panic ! ( "Can't read stamp contents" ) ,
906
893
// The test hasn't succeeded yet, so it is not up-to-date.
907
894
Err ( _) => return false ,
908
895
} ;
909
- let expected_hash = runtest:: compute_stamp_hash ( config) ;
896
+ let expected_hash = runtest:: compute_stamp_hash ( & cx . config ) ;
910
897
if contents != expected_hash {
911
898
// Some part of compiletest configuration has changed since the test
912
899
// last succeeded, so it is not up-to-date.
@@ -915,8 +902,8 @@ fn is_up_to_date(
915
902
916
903
// Check the timestamp of the stamp file against the last modified time
917
904
// of all files known to be relevant to the test.
918
- let mut inputs = inputs. clone ( ) ;
919
- for path in files_related_to_test ( config, testpaths, props, revision) {
905
+ let mut inputs = cx . inputs . clone ( ) ;
906
+ for path in files_related_to_test ( & cx . config , testpaths, props, revision) {
920
907
inputs. add_path ( & path) ;
921
908
}
922
909
0 commit comments