1 use std::error::Error;
2 use std::path::{Path, PathBuf};
3 use walkdir::WalkDir;
4 
5 #[test]
trybuild()6 fn trybuild() {
7     let directory = PathBuf::from("tests/try_build");
8 
9     let mut _renamer = None;
10 
11     let compile_fail_dir = directory.join("compile_fail");
12 
13     // Sometimes error messages change on beta/nightly - allow alternate errors on those.
14     _renamer = Some(Renamer::rename(compile_fail_dir.clone()).unwrap());
15 
16     let fail = trybuild::TestCases::new();
17     fail.compile_fail(compile_fail_dir.join("*.rs"));
18     add_feature_dirs(&compile_fail_dir, &fail, ExpectedResult::Fail);
19 
20     let pass = trybuild::TestCases::new();
21     let pass_dir = directory.join("pass");
22     pass.pass(pass_dir.join("*.rs"));
23     add_feature_dirs(&pass_dir, &pass, ExpectedResult::Pass);
24 }
25 
26 enum ExpectedResult {
27     Pass,
28     Fail,
29 }
30 
add_feature_dirs( parent_dir: &Path, test_cases: &trybuild::TestCases, expected_result: ExpectedResult, )31 fn add_feature_dirs(
32     parent_dir: &Path,
33     test_cases: &trybuild::TestCases,
34     expected_result: ExpectedResult,
35 ) {
36     let features_dir = parent_dir.join("features");
37     let feature_specific_dir = if cfg!(feature = "complex-expressions") {
38         features_dir.join("complex-expressions")
39     } else {
40         features_dir.join("!complex-expressions")
41     };
42     let tests = feature_specific_dir.join("*.rs");
43     match expected_result {
44         ExpectedResult::Pass => test_cases.pass(tests),
45         ExpectedResult::Fail => test_cases.compile_fail(tests),
46     }
47 }
48 
49 struct Renamer(Vec<PathBuf>);
50 
51 impl Renamer {
52     const STDERR_EXTENSION: &'static str = "stderr";
53 
54     #[rustversion::all(beta)]
55     const VERSION_SPECIFIC_EXTENSION: &'static str = "stderr_beta";
56 
57     #[rustversion::all(nightly)]
58     const VERSION_SPECIFIC_EXTENSION: &'static str = "stderr_nightly";
59 
60     #[rustversion::all(not(beta), not(nightly))]
61     const VERSION_SPECIFIC_EXTENSION: &'static str = "stderr_doesnotexist";
62 
63     const NON_VERSION_SPECIFIC_BACKUP_EXTENSION: &'static str =
64         "stderr_non_version_specific_backup";
65 
rename(dir: PathBuf) -> anyhow::Result<Self>66     fn rename(dir: PathBuf) -> anyhow::Result<Self> {
67         let nightly_paths = WalkDir::new(dir)
68             .max_depth(1)
69             .into_iter()
70             .filter_map(|dir_entry| {
71                 let dir_entry = match dir_entry {
72                     Ok(dir_entry) => dir_entry,
73                     Err(err) => return Some(Err(err)),
74                 };
75                 let path = dir_entry.path();
76                 if let Some(file_name) = path.file_name() {
77                     if Path::new(file_name).extension()
78                         == Some(Renamer::VERSION_SPECIFIC_EXTENSION.as_ref())
79                     {
80                         return Some(Ok(path.to_path_buf()));
81                     }
82                 }
83                 None
84             })
85             .collect::<Result<Vec<_>, _>>()?;
86         // Create early so that if we end up returning an error this gets dropped and undoes any
87         // already-done renames.
88         let renamer = Renamer(nightly_paths);
89 
90         for nightly_path in &renamer.0 {
91             std::fs::rename(
92                 nightly_path.with_extension(Renamer::STDERR_EXTENSION),
93                 nightly_path.with_extension(Renamer::NON_VERSION_SPECIFIC_BACKUP_EXTENSION),
94             )?;
95             std::fs::rename(
96                 nightly_path.with_extension(Renamer::VERSION_SPECIFIC_EXTENSION),
97                 nightly_path.with_extension(Renamer::STDERR_EXTENSION),
98             )?;
99         }
100         Ok(renamer)
101     }
102 }
103 
104 impl Drop for Renamer {
drop(&mut self)105     fn drop(&mut self) {
106         for path in &self.0 {
107             ignore_error(std::fs::rename(
108                 path.with_extension(Renamer::STDERR_EXTENSION),
109                 path.with_extension(Renamer::VERSION_SPECIFIC_EXTENSION),
110             ));
111             ignore_error(std::fs::rename(
112                 path.with_extension(Renamer::NON_VERSION_SPECIFIC_BACKUP_EXTENSION),
113                 path.with_extension(Renamer::STDERR_EXTENSION),
114             ));
115         }
116     }
117 }
118 
ignore_error<T, E: Error>(result: Result<T, E>)119 fn ignore_error<T, E: Error>(result: Result<T, E>) {
120     if let Err(err) = result {
121         eprintln!("Ignoring error: {}", err);
122     }
123 }
124