@@ -33,6 +33,7 @@ use std::{env, fs, vec};
3333use build_helper:: git:: { get_git_modified_files, get_git_untracked_files} ;
3434use camino:: { Utf8Path , Utf8PathBuf } ;
3535use getopts:: Options ;
36+ use rayon:: iter:: { ParallelBridge , ParallelIterator } ;
3637use tracing:: * ;
3738use walkdir:: WalkDir ;
3839
@@ -641,6 +642,18 @@ struct TestCollector {
641642 poisoned : bool ,
642643}
643644
645+ impl TestCollector {
646+ fn new ( ) -> Self {
647+ TestCollector { tests : vec ! [ ] , found_path_stems : HashSet :: new ( ) , poisoned : false }
648+ }
649+
650+ fn merge ( & mut self , mut other : Self ) {
651+ self . tests . append ( & mut other. tests ) ;
652+ self . found_path_stems . extend ( other. found_path_stems ) ;
653+ self . poisoned |= other. poisoned ;
654+ }
655+ }
656+
644657/// Creates test structures for every test/revision in the test suite directory.
645658///
646659/// This always inspects _all_ test files in the suite (e.g. all 17k+ ui tests),
@@ -659,10 +672,7 @@ pub(crate) fn collect_and_make_tests(config: Arc<Config>) -> Vec<CollectedTest>
659672 let cache = HeadersCache :: load ( & config) ;
660673
661674 let cx = TestCollectorCx { config, cache, common_inputs_stamp, modified_tests } ;
662- let mut collector =
663- TestCollector { tests : vec ! [ ] , found_path_stems : HashSet :: new ( ) , poisoned : false } ;
664-
665- collect_tests_from_dir ( & cx, & mut collector, & cx. config . src_test_suite_root , Utf8Path :: new ( "" ) )
675+ let collector = collect_tests_from_dir ( & cx, & cx. config . src_test_suite_root , Utf8Path :: new ( "" ) )
666676 . unwrap_or_else ( |reason| {
667677 panic ! ( "Could not read tests from {}: {reason}" , cx. config. src_test_suite_root)
668678 } ) ;
@@ -768,25 +778,25 @@ fn modified_tests(config: &Config, dir: &Utf8Path) -> Result<Vec<Utf8PathBuf>, S
768778/// that will be handed over to libtest.
769779fn collect_tests_from_dir (
770780 cx : & TestCollectorCx ,
771- collector : & mut TestCollector ,
772781 dir : & Utf8Path ,
773782 relative_dir_path : & Utf8Path ,
774- ) -> io:: Result < ( ) > {
783+ ) -> io:: Result < TestCollector > {
775784 // Ignore directories that contain a file named `compiletest-ignore-dir`.
776785 if dir. join ( "compiletest-ignore-dir" ) . exists ( ) {
777- return Ok ( ( ) ) ;
786+ return Ok ( TestCollector :: new ( ) ) ;
778787 }
779788
780789 // For run-make tests, a "test file" is actually a directory that contains an `rmake.rs`.
781790 if cx. config . mode == Mode :: RunMake {
791+ let mut collector = TestCollector :: new ( ) ;
782792 if dir. join ( "rmake.rs" ) . exists ( ) {
783793 let paths = TestPaths {
784794 file : dir. to_path_buf ( ) ,
785795 relative_dir : relative_dir_path. parent ( ) . unwrap ( ) . to_path_buf ( ) ,
786796 } ;
787- make_test ( cx, collector, & paths) ;
797+ make_test ( cx, & mut collector, & paths) ;
788798 // This directory is a test, so don't try to find other tests inside it.
789- return Ok ( ( ) ) ;
799+ return Ok ( collector ) ;
790800 }
791801 }
792802
@@ -803,36 +813,47 @@ fn collect_tests_from_dir(
803813 // subdirectories we find, except for `auxiliary` directories.
804814 // FIXME: this walks full tests tree, even if we have something to ignore
805815 // use walkdir/ignore like in tidy?
806- for file in fs:: read_dir ( dir. as_std_path ( ) ) ? {
807- let file = file?;
808- let file_path = Utf8PathBuf :: try_from ( file. path ( ) ) . unwrap ( ) ;
809- let file_name = file_path. file_name ( ) . unwrap ( ) ;
810-
811- if is_test ( file_name)
812- && ( !cx. config . only_modified || cx. modified_tests . contains ( & file_path) )
813- {
814- // We found a test file, so create the corresponding libtest structures.
815- debug ! ( %file_path, "found test file" ) ;
816-
817- // Record the stem of the test file, to check for overlaps later.
818- let rel_test_path = relative_dir_path. join ( file_path. file_stem ( ) . unwrap ( ) ) ;
819- collector. found_path_stems . insert ( rel_test_path) ;
820-
821- let paths =
822- TestPaths { file : file_path, relative_dir : relative_dir_path. to_path_buf ( ) } ;
823- make_test ( cx, collector, & paths) ;
824- } else if file_path. is_dir ( ) {
825- // Recurse to find more tests in a subdirectory.
826- let relative_file_path = relative_dir_path. join ( file_name) ;
827- if file_name != "auxiliary" {
828- debug ! ( %file_path, "found directory" ) ;
829- collect_tests_from_dir ( cx, collector, & file_path, & relative_file_path) ?;
816+ fs:: read_dir ( dir. as_std_path ( ) ) ?
817+ . par_bridge ( )
818+ . map ( |file| {
819+ let mut collector = TestCollector :: new ( ) ;
820+ let file = file?;
821+ let file_path = Utf8PathBuf :: try_from ( file. path ( ) ) . unwrap ( ) ;
822+ let file_name = file_path. file_name ( ) . unwrap ( ) ;
823+
824+ if is_test ( file_name)
825+ && ( !cx. config . only_modified || cx. modified_tests . contains ( & file_path) )
826+ {
827+ // We found a test file, so create the corresponding libtest structures.
828+ debug ! ( %file_path, "found test file" ) ;
829+
830+ // Record the stem of the test file, to check for overlaps later.
831+ let rel_test_path = relative_dir_path. join ( file_path. file_stem ( ) . unwrap ( ) ) ;
832+ collector. found_path_stems . insert ( rel_test_path) ;
833+
834+ let paths =
835+ TestPaths { file : file_path, relative_dir : relative_dir_path. to_path_buf ( ) } ;
836+ make_test ( cx, & mut collector, & paths) ;
837+ } else if file_path. is_dir ( ) {
838+ // Recurse to find more tests in a subdirectory.
839+ let relative_file_path = relative_dir_path. join ( file_name) ;
840+ if file_name != "auxiliary" {
841+ debug ! ( %file_path, "found directory" ) ;
842+ collector. merge ( collect_tests_from_dir ( cx, & file_path, & relative_file_path) ?) ;
843+ }
844+ } else {
845+ debug ! ( %file_path, "found other file/directory" ) ;
830846 }
831- } else {
832- debug ! ( %file_path, "found other file/directory" ) ;
833- }
834- }
835- Ok ( ( ) )
847+ Ok ( collector)
848+ } )
849+ . reduce (
850+ || Ok ( TestCollector :: new ( ) ) ,
851+ |a, b| {
852+ let mut a = a?;
853+ a. merge ( b?) ;
854+ Ok ( a)
855+ } ,
856+ )
836857}
837858
838859/// Returns true if `file_name` looks like a proper test file name.
0 commit comments