11use std:: collections:: BTreeSet ;
2- use std:: env;
32use std:: fs:: { File , remove_file} ;
43use std:: io:: Write ;
54use std:: path:: Path ;
5+ use std:: { env, fs} ;
66
77use build_helper:: ci:: CiEnv ;
88use clap:: CommandFactory ;
@@ -23,6 +23,18 @@ pub(crate) fn parse(config: &str) -> Config {
2323 )
2424}
2525
26+ fn get_toml ( file : & Path ) -> Result < TomlConfig , toml:: de:: Error > {
27+ let contents = std:: fs:: read_to_string ( file) . unwrap ( ) ;
28+ toml:: from_str ( & contents) . and_then ( |table : toml:: Value | TomlConfig :: deserialize ( table) )
29+ }
30+
31+ /// Returns the name of the currently running test formatted to be used as a directory name.
32+ fn test_specific_dirname ( ) -> String {
33+ let current = std:: thread:: current ( ) ;
34+ // Replace "::" with "_" to make it safe for directory names on Windows systems
35+ current. name ( ) . unwrap ( ) . replace ( "::" , "_" )
36+ }
37+
2638#[ test]
2739fn download_ci_llvm ( ) {
2840 let config = parse ( "llvm.download-ci-llvm = false" ) ;
@@ -539,3 +551,210 @@ fn test_ci_flag() {
539551 let config = Config :: parse_inner ( Flags :: parse ( & [ "check" . into ( ) ] ) , |& _| toml:: from_str ( "" ) ) ;
540552 assert_eq ! ( config. is_running_on_ci, CiEnv :: is_ci( ) ) ;
541553}
554+
555+ #[ test]
556+ fn test_precedence_of_includes ( ) {
557+ let testdir = parse ( "" ) . tempdir ( ) . join ( test_specific_dirname ( ) ) ;
558+
559+ // clean up any old test files
560+ let _ = fs:: remove_dir_all ( & testdir) ;
561+ let _ = fs:: create_dir_all ( & testdir) ;
562+
563+ let root_config = testdir. join ( "config.toml" ) ;
564+ let root_config_content = br#"
565+ include = ["./extension.toml"]
566+
567+ [llvm]
568+ link-jobs = 2
569+ "# ;
570+ File :: create ( & root_config) . unwrap ( ) . write_all ( root_config_content) . unwrap ( ) ;
571+
572+ let extension = testdir. join ( "extension.toml" ) ;
573+ let extension_content = br#"
574+ change-id=543
575+ include = ["./extension2.toml"]
576+ "# ;
577+ File :: create ( extension) . unwrap ( ) . write_all ( extension_content) . unwrap ( ) ;
578+
579+ let extension = testdir. join ( "extension2.toml" ) ;
580+ let extension_content = br#"
581+ change-id=742
582+
583+ [llvm]
584+ link-jobs = 10
585+
586+ [build]
587+ description = "Some creative description"
588+ "# ;
589+ File :: create ( extension) . unwrap ( ) . write_all ( extension_content) . unwrap ( ) ;
590+
591+ let config = Config :: parse_inner (
592+ Flags :: parse ( & [ "check" . to_owned ( ) , format ! ( "--config={}" , root_config. to_str( ) . unwrap( ) ) ] ) ,
593+ get_toml,
594+ ) ;
595+
596+ assert_eq ! ( config. change_id. unwrap( ) , ChangeId :: Id ( 543 ) ) ;
597+ assert_eq ! ( config. llvm_link_jobs. unwrap( ) , 2 ) ;
598+ assert_eq ! ( config. description. unwrap( ) , "Some creative description" ) ;
599+ }
600+
601+ #[ test]
602+ #[ should_panic( expected = "Cyclic inclusion detected" ) ]
603+ fn test_cyclic_include_direct ( ) {
604+ let testdir = parse ( "" ) . tempdir ( ) . join ( test_specific_dirname ( ) ) ;
605+
606+ // clean up any old test files
607+ let _ = fs:: remove_dir_all ( & testdir) ;
608+ let _ = fs:: create_dir_all ( & testdir) ;
609+
610+ let root_config = testdir. join ( "config.toml" ) ;
611+ let root_config_content = br#"
612+ include = ["./extension.toml"]
613+ "# ;
614+ File :: create ( & root_config) . unwrap ( ) . write_all ( root_config_content) . unwrap ( ) ;
615+
616+ let extension = testdir. join ( "extension.toml" ) ;
617+ let extension_content = br#"
618+ include = ["./config.toml"]
619+ "# ;
620+ File :: create ( extension) . unwrap ( ) . write_all ( extension_content) . unwrap ( ) ;
621+
622+ let config = Config :: parse_inner (
623+ Flags :: parse ( & [ "check" . to_owned ( ) , format ! ( "--config={}" , root_config. to_str( ) . unwrap( ) ) ] ) ,
624+ get_toml,
625+ ) ;
626+ }
627+
628+ #[ test]
629+ #[ should_panic( expected = "Cyclic inclusion detected" ) ]
630+ fn test_cyclic_include_indirect ( ) {
631+ let testdir = parse ( "" ) . tempdir ( ) . join ( test_specific_dirname ( ) ) ;
632+
633+ // clean up any old test files
634+ let _ = fs:: remove_dir_all ( & testdir) ;
635+ let _ = fs:: create_dir_all ( & testdir) ;
636+
637+ let root_config = testdir. join ( "config.toml" ) ;
638+ let root_config_content = br#"
639+ include = ["./extension.toml"]
640+ "# ;
641+ File :: create ( & root_config) . unwrap ( ) . write_all ( root_config_content) . unwrap ( ) ;
642+
643+ let extension = testdir. join ( "extension.toml" ) ;
644+ let extension_content = br#"
645+ include = ["./extension2.toml"]
646+ "# ;
647+ File :: create ( extension) . unwrap ( ) . write_all ( extension_content) . unwrap ( ) ;
648+
649+ let extension = testdir. join ( "extension2.toml" ) ;
650+ let extension_content = br#"
651+ include = ["./extension3.toml"]
652+ "# ;
653+ File :: create ( extension) . unwrap ( ) . write_all ( extension_content) . unwrap ( ) ;
654+
655+ let extension = testdir. join ( "extension3.toml" ) ;
656+ let extension_content = br#"
657+ include = ["./extension.toml"]
658+ "# ;
659+ File :: create ( extension) . unwrap ( ) . write_all ( extension_content) . unwrap ( ) ;
660+
661+ let config = Config :: parse_inner (
662+ Flags :: parse ( & [ "check" . to_owned ( ) , format ! ( "--config={}" , root_config. to_str( ) . unwrap( ) ) ] ) ,
663+ get_toml,
664+ ) ;
665+ }
666+
667+ #[ test]
668+ fn test_include_absolute_paths ( ) {
669+ let testdir = parse ( "" ) . tempdir ( ) . join ( test_specific_dirname ( ) ) ;
670+
671+ // clean up any old test files
672+ let _ = fs:: remove_dir_all ( & testdir) ;
673+ let _ = fs:: create_dir_all ( & testdir) ;
674+
675+ let extension = testdir. join ( "extension.toml" ) ;
676+ File :: create ( & extension) . unwrap ( ) . write_all ( & [ ] ) . unwrap ( ) ;
677+
678+ let root_config = testdir. join ( "config.toml" ) ;
679+ let root_config_content =
680+ format ! ( "include = [\" {}\" ]" , extension. canonicalize( ) . unwrap( ) . to_str( ) . unwrap( ) ) ;
681+ File :: create ( & root_config) . unwrap ( ) . write_all ( root_config_content. as_bytes ( ) ) . unwrap ( ) ;
682+
683+ let config = Config :: parse_inner (
684+ Flags :: parse ( & [ "check" . to_owned ( ) , format ! ( "--config={}" , root_config. to_str( ) . unwrap( ) ) ] ) ,
685+ get_toml,
686+ ) ;
687+ }
688+
689+ #[ test]
690+ fn test_include_relative_paths ( ) {
691+ let testdir = parse ( "" ) . tempdir ( ) . join ( test_specific_dirname ( ) ) ;
692+
693+ // clean up any old test files
694+ let _ = fs:: remove_dir_all ( & testdir) ;
695+ let _ = fs:: create_dir_all ( & testdir. join ( "subdir/another_subdir" ) ) ;
696+
697+ let root_config = testdir. join ( "config.toml" ) ;
698+ let root_config_content = br#"
699+ include = ["./subdir/extension.toml"]
700+ "# ;
701+ File :: create ( & root_config) . unwrap ( ) . write_all ( root_config_content) . unwrap ( ) ;
702+
703+ let extension = testdir. join ( "subdir/extension.toml" ) ;
704+ let extension_content = br#"
705+ include = ["../extension2.toml"]
706+ "# ;
707+ File :: create ( extension) . unwrap ( ) . write_all ( extension_content) . unwrap ( ) ;
708+
709+ let extension = testdir. join ( "extension2.toml" ) ;
710+ let extension_content = br#"
711+ include = ["./subdir/another_subdir/extension3.toml"]
712+ "# ;
713+ File :: create ( extension) . unwrap ( ) . write_all ( extension_content) . unwrap ( ) ;
714+
715+ let extension = testdir. join ( "subdir/another_subdir/extension3.toml" ) ;
716+ let extension_content = br#"
717+ include = ["../../extension4.toml"]
718+ "# ;
719+ File :: create ( extension) . unwrap ( ) . write_all ( extension_content) . unwrap ( ) ;
720+
721+ let extension = testdir. join ( "extension4.toml" ) ;
722+ File :: create ( extension) . unwrap ( ) . write_all ( & [ ] ) . unwrap ( ) ;
723+
724+ let config = Config :: parse_inner (
725+ Flags :: parse ( & [ "check" . to_owned ( ) , format ! ( "--config={}" , root_config. to_str( ) . unwrap( ) ) ] ) ,
726+ get_toml,
727+ ) ;
728+ }
729+
730+ #[ test]
731+ fn test_include_precedence_over_profile ( ) {
732+ let testdir = parse ( "" ) . tempdir ( ) . join ( test_specific_dirname ( ) ) ;
733+
734+ // clean up any old test files
735+ let _ = fs:: remove_dir_all ( & testdir) ;
736+ let _ = fs:: create_dir_all ( & testdir) ;
737+
738+ let root_config = testdir. join ( "config.toml" ) ;
739+ let root_config_content = br#"
740+ profile = "dist"
741+ include = ["./extension.toml"]
742+ "# ;
743+ File :: create ( & root_config) . unwrap ( ) . write_all ( root_config_content) . unwrap ( ) ;
744+
745+ let extension = testdir. join ( "extension.toml" ) ;
746+ let extension_content = br#"
747+ [rust]
748+ channel = "dev"
749+ "# ;
750+ File :: create ( extension) . unwrap ( ) . write_all ( extension_content) . unwrap ( ) ;
751+
752+ let config = Config :: parse_inner (
753+ Flags :: parse ( & [ "check" . to_owned ( ) , format ! ( "--config={}" , root_config. to_str( ) . unwrap( ) ) ] ) ,
754+ get_toml,
755+ ) ;
756+
757+ // "dist" profile would normally set the channel to "auto-detect", but includes should
758+ // override profile settings, so we expect this to be "dev" here.
759+ assert_eq ! ( config. channel, "dev" ) ;
760+ }
0 commit comments