compiletest/runtest/
mir_opt.rs
1use std::fs;
2use std::path::{Path, PathBuf};
3
4use glob::glob;
5use miropt_test_tools::{MiroptTest, MiroptTestFile, files_for_miropt_test};
6use tracing::debug;
7
8use super::{Emit, TestCx, WillExecute};
9use crate::compute_diff::write_diff;
10
11impl TestCx<'_> {
12 pub(super) fn run_mir_opt_test(&self) {
13 let pm = self.pass_mode();
14 let should_run = self.should_run(pm);
15
16 let mut test_info = files_for_miropt_test(
17 &self.testpaths.file,
18 self.config.get_pointer_width(),
19 self.config.target_cfg().panic.for_miropt_test_tools(),
20 );
21
22 let passes = std::mem::take(&mut test_info.passes);
23
24 let proc_res = self.compile_test_with_passes(should_run, Emit::Mir, passes);
25 if !proc_res.status.success() {
26 self.fatal_proc_rec("compilation failed!", &proc_res);
27 }
28 self.check_mir_dump(test_info);
29
30 if let WillExecute::Yes = should_run {
31 let proc_res = self.exec_compiled_test();
32
33 if !proc_res.status.success() {
34 self.fatal_proc_rec("test run failed!", &proc_res);
35 }
36 }
37 }
38
39 fn check_mir_dump(&self, test_info: MiroptTest) {
40 let test_dir = self.testpaths.file.parent().unwrap();
41 let test_crate =
42 self.testpaths.file.file_stem().unwrap().to_str().unwrap().replace('-', "_");
43
44 let MiroptTest { run_filecheck, suffix, files, passes: _ } = test_info;
45
46 if self.config.bless {
47 for e in
48 glob(&format!("{}/{}.*{}.mir", test_dir.display(), test_crate, suffix)).unwrap()
49 {
50 fs::remove_file(e.unwrap()).unwrap();
51 }
52 for e in
53 glob(&format!("{}/{}.*{}.diff", test_dir.display(), test_crate, suffix)).unwrap()
54 {
55 fs::remove_file(e.unwrap()).unwrap();
56 }
57 }
58
59 for MiroptTestFile { from_file, to_file, expected_file } in files {
60 let dumped_string = if let Some(after) = to_file {
61 self.diff_mir_files(from_file.into(), after.into())
62 } else {
63 let mut output_file = PathBuf::new();
64 output_file.push(self.get_mir_dump_dir());
65 output_file.push(&from_file);
66 debug!(
67 "comparing the contents of: {} with {}",
68 output_file.display(),
69 expected_file.display()
70 );
71 if !output_file.exists() {
72 panic!(
73 "Output file `{}` from test does not exist, available files are in `{}`",
74 output_file.display(),
75 output_file.parent().unwrap().display()
76 );
77 }
78 self.check_mir_test_timestamp(&from_file, &output_file);
79 let dumped_string = fs::read_to_string(&output_file).unwrap();
80 self.normalize_output(&dumped_string, &[])
81 };
82
83 if self.config.bless {
84 let _ = fs::remove_file(&expected_file);
85 fs::write(expected_file, dumped_string.as_bytes()).unwrap();
86 } else {
87 if !expected_file.exists() {
88 panic!("Output file `{}` from test does not exist", expected_file.display());
89 }
90 let expected_string = fs::read_to_string(&expected_file).unwrap();
91 if dumped_string != expected_string {
92 print!("{}", write_diff(&expected_string, &dumped_string, 3));
93 panic!(
94 "Actual MIR output differs from expected MIR output {}",
95 expected_file.display()
96 );
97 }
98 }
99 }
100
101 if run_filecheck {
102 let output_path = self.output_base_name().with_extension("mir");
103 let proc_res = self.verify_with_filecheck(&output_path);
104 if !proc_res.status.success() {
105 self.fatal_proc_rec("verification with 'FileCheck' failed", &proc_res);
106 }
107 }
108 }
109
110 fn diff_mir_files(&self, before: PathBuf, after: PathBuf) -> String {
111 let to_full_path = |path: PathBuf| {
112 let full = self.get_mir_dump_dir().join(&path);
113 if !full.exists() {
114 panic!(
115 "the mir dump file for {} does not exist (requested in {})",
116 path.display(),
117 self.testpaths.file.display(),
118 );
119 }
120 full
121 };
122 let before = to_full_path(before);
123 let after = to_full_path(after);
124 debug!("comparing the contents of: {} with {}", before.display(), after.display());
125 let before = fs::read_to_string(before).unwrap();
126 let after = fs::read_to_string(after).unwrap();
127 let before = self.normalize_output(&before, &[]);
128 let after = self.normalize_output(&after, &[]);
129 let mut dumped_string = String::new();
130 for result in diff::lines(&before, &after) {
131 use std::fmt::Write;
132 match result {
133 diff::Result::Left(s) => writeln!(dumped_string, "- {}", s).unwrap(),
134 diff::Result::Right(s) => writeln!(dumped_string, "+ {}", s).unwrap(),
135 diff::Result::Both(s, _) => writeln!(dumped_string, " {}", s).unwrap(),
136 }
137 }
138 dumped_string
139 }
140
141 fn check_mir_test_timestamp(&self, test_name: &str, output_file: &Path) {
142 let t = |file| fs::metadata(file).unwrap().modified().unwrap();
143 let source_file = &self.testpaths.file;
144 let output_time = t(output_file);
145 let source_time = t(source_file);
146 if source_time > output_time {
147 debug!("source file time: {:?} output file time: {:?}", source_time, output_time);
148 panic!(
149 "test source file `{}` is newer than potentially stale output file `{}`.",
150 source_file.display(),
151 test_name
152 );
153 }
154 }
155}