1 //! `bless` updates the reference files in the repo with changed output files
2 //! from the last test run.
6 use std::lazy::SyncLazy;
7 use std::path::{Path, PathBuf};
10 use crate::clippy_project_root;
12 static CLIPPY_BUILD_TIME: SyncLazy<Option<std::time::SystemTime>> = SyncLazy::new(|| {
13 let mut path = std::env::current_exe().unwrap();
14 path.set_file_name("cargo-clippy");
15 fs::metadata(path).ok()?.modified().ok()
20 /// Panics if the path to a test file is broken
21 pub fn bless(ignore_timestamp: bool) {
22 let test_suite_dirs = [
23 clippy_project_root().join("tests").join("ui"),
24 clippy_project_root().join("tests").join("ui-internal"),
25 clippy_project_root().join("tests").join("ui-toml"),
26 clippy_project_root().join("tests").join("ui-cargo"),
28 for test_suite_dir in &test_suite_dirs {
29 WalkDir::new(test_suite_dir)
31 .filter_map(Result::ok)
32 .filter(|f| f.path().extension() == Some(OsStr::new("rs")))
34 let test_name = f.path().strip_prefix(test_suite_dir).unwrap();
35 for &ext in &["stdout", "stderr", "fixed"] {
36 let test_name_ext = format!("stage-id.{}", ext);
37 update_reference_file(
38 f.path().with_extension(ext),
39 test_name.with_extension(test_name_ext),
47 fn update_reference_file(reference_file_path: PathBuf, test_name: PathBuf, ignore_timestamp: bool) {
48 let test_output_path = build_dir().join(test_name);
49 let relative_reference_file_path = reference_file_path.strip_prefix(clippy_project_root()).unwrap();
51 // If compiletest did not write any changes during the test run,
52 // we don't have to update anything
53 if !test_output_path.exists() {
57 // If the test output was not updated since the last clippy build, it may be outdated
58 if !ignore_timestamp && !updated_since_clippy_build(&test_output_path).unwrap_or(true) {
62 let test_output_file = fs::read(&test_output_path).expect("Unable to read test output file");
63 let reference_file = fs::read(&reference_file_path).unwrap_or_default();
65 if test_output_file != reference_file {
66 // If a test run caused an output file to change, update the reference file
67 println!("updating {}", &relative_reference_file_path.display());
68 fs::copy(test_output_path, &reference_file_path).expect("Could not update reference file");
70 // We need to re-read the file now because it was potentially updated from copying
71 let reference_file = fs::read(&reference_file_path).unwrap_or_default();
73 if reference_file.is_empty() {
74 // If we copied over an empty output file, we remove the now empty reference file
75 println!("removing {}", &relative_reference_file_path.display());
76 fs::remove_file(reference_file_path).expect("Could not remove reference file");
81 fn updated_since_clippy_build(path: &Path) -> Option<bool> {
82 let clippy_build_time = (*CLIPPY_BUILD_TIME)?;
83 let modified = fs::metadata(path).ok()?.modified().ok()?;
84 Some(modified >= clippy_build_time)
87 fn build_dir() -> PathBuf {
88 let mut path = std::env::current_exe().unwrap();
89 path.set_file_name("test");