use std::error::Error; use std::path::{Path, PathBuf}; use walkdir::WalkDir; #[test] fn trybuild() { let directory = PathBuf::from("tests/try_build"); let mut _renamer = None; let compile_fail_dir = directory.join("compile_fail"); // Sometimes error messages change on beta/nightly - allow alternate errors on those. _renamer = Some(Renamer::rename(compile_fail_dir.clone()).unwrap()); let fail = trybuild::TestCases::new(); fail.compile_fail(compile_fail_dir.join("*.rs")); add_feature_dirs(&compile_fail_dir, &fail, ExpectedResult::Fail); let pass = trybuild::TestCases::new(); let pass_dir = directory.join("pass"); pass.pass(pass_dir.join("*.rs")); add_feature_dirs(&pass_dir, &pass, ExpectedResult::Pass); } enum ExpectedResult { Pass, Fail, } fn add_feature_dirs( parent_dir: &Path, test_cases: &trybuild::TestCases, expected_result: ExpectedResult, ) { let features_dir = parent_dir.join("features"); let feature_specific_dir = if cfg!(feature = "complex-expressions") { features_dir.join("complex-expressions") } else { features_dir.join("!complex-expressions") }; let tests = feature_specific_dir.join("*.rs"); match expected_result { ExpectedResult::Pass => test_cases.pass(tests), ExpectedResult::Fail => test_cases.compile_fail(tests), } } struct Renamer(Vec); impl Renamer { const STDERR_EXTENSION: &'static str = "stderr"; #[rustversion::all(beta)] const VERSION_SPECIFIC_EXTENSION: &'static str = "stderr_beta"; #[rustversion::all(nightly)] const VERSION_SPECIFIC_EXTENSION: &'static str = "stderr_nightly"; #[rustversion::all(not(beta), not(nightly))] const VERSION_SPECIFIC_EXTENSION: &'static str = "stderr_doesnotexist"; const NON_VERSION_SPECIFIC_BACKUP_EXTENSION: &'static str = "stderr_non_version_specific_backup"; fn rename(dir: PathBuf) -> anyhow::Result { let nightly_paths = WalkDir::new(dir) .max_depth(1) .into_iter() .filter_map(|dir_entry| { let dir_entry = match dir_entry { Ok(dir_entry) => dir_entry, Err(err) => return Some(Err(err)), }; let path = dir_entry.path(); if let Some(file_name) = path.file_name() { if Path::new(file_name).extension() == Some(Renamer::VERSION_SPECIFIC_EXTENSION.as_ref()) { return Some(Ok(path.to_path_buf())); } } None }) .collect::, _>>()?; // Create early so that if we end up returning an error this gets dropped and undoes any // already-done renames. let renamer = Renamer(nightly_paths); for nightly_path in &renamer.0 { std::fs::rename( nightly_path.with_extension(Renamer::STDERR_EXTENSION), nightly_path.with_extension(Renamer::NON_VERSION_SPECIFIC_BACKUP_EXTENSION), )?; std::fs::rename( nightly_path.with_extension(Renamer::VERSION_SPECIFIC_EXTENSION), nightly_path.with_extension(Renamer::STDERR_EXTENSION), )?; } Ok(renamer) } } impl Drop for Renamer { fn drop(&mut self) { for path in &self.0 { ignore_error(std::fs::rename( path.with_extension(Renamer::STDERR_EXTENSION), path.with_extension(Renamer::VERSION_SPECIFIC_EXTENSION), )); ignore_error(std::fs::rename( path.with_extension(Renamer::NON_VERSION_SPECIFIC_BACKUP_EXTENSION), path.with_extension(Renamer::STDERR_EXTENSION), )); } } } fn ignore_error(result: Result) { if let Err(err) = result { eprintln!("Ignoring error: {}", err); } }