]> git.lizzy.rs Git - rust.git/blob - tests/compiletest.rs
Get the test suite working inside the rustc test suite
[rust.git] / tests / compiletest.rs
1 #![feature(slice_concat_ext)]
2
3 extern crate compiletest_rs as compiletest;
4
5 use std::slice::SliceConcatExt;
6 use std::path::{PathBuf, Path};
7 use std::io::Write;
8
9 macro_rules! eprintln {
10     ($($arg:tt)*) => {
11         let stderr = std::io::stderr();
12         writeln!(stderr.lock(), $($arg)*).unwrap();
13     }
14 }
15
16 fn miri_path() -> PathBuf {
17     if rustc_test_suite().is_some() {
18         PathBuf::from(option_env!("MIRI_PATH").unwrap())
19     } else {
20         PathBuf::from(concat!("target/", env!("PROFILE"), "/miri"))
21     }
22 }
23
24 fn rustc_test_suite() -> Option<PathBuf> {
25     option_env!("RUSTC_TEST_SUITE").map(PathBuf::from)
26 }
27
28 fn rustc_lib_path() -> PathBuf {
29     option_env!("RUSTC_LIB_PATH").unwrap().into()
30 }
31
32 fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, fullmir: bool) {
33     eprintln!(
34         "## Running compile-fail tests in {} against miri for target {}",
35         path,
36         target
37     );
38     let mut config = compiletest::default_config();
39     config.mode = "compile-fail".parse().expect("Invalid mode");
40     config.rustc_path = miri_path();
41     let mut flags = Vec::new();
42     if rustc_test_suite().is_some() {
43         config.run_lib_path = rustc_lib_path();
44         config.compile_lib_path = rustc_lib_path();
45     }
46     // if we are building as part of the rustc test suite, we already have fullmir for everything
47     if fullmir && rustc_test_suite().is_none() {
48         if host != target {
49             // skip fullmir on nonhost
50             return;
51         }
52         let sysroot = Path::new(&std::env::var("HOME").unwrap())
53             .join(".xargo")
54             .join("HOST");
55         config.target_rustcflags = Some(format!("--sysroot {}", sysroot.to_str().unwrap()));
56         config.src_base = PathBuf::from(path.to_string());
57     } else {
58         config.target_rustcflags = Some(format!("--sysroot {}", sysroot.to_str().unwrap()));
59         config.src_base = PathBuf::from(path.to_string());
60     }
61     flags.push("-Zmir-emit-validate=1".to_owned());
62     config.target_rustcflags = Some(flags.join(" "));
63     config.target = target.to_owned();
64     compiletest::run_tests(&config);
65 }
66
67 fn run_pass(path: &str) {
68     eprintln!("## Running run-pass tests in {} against rustc", path);
69     let mut config = compiletest::default_config();
70     config.mode = "run-pass".parse().expect("Invalid mode");
71     config.src_base = PathBuf::from(path);
72     if let Some(rustc_path) = rustc_test_suite() {
73         config.rustc_path = rustc_path;
74         config.run_lib_path = rustc_lib_path();
75         config.compile_lib_path = rustc_lib_path();
76     }
77     config.target_rustcflags = Some(format!("-Dwarnings --sysroot {}", get_sysroot().display()));
78     config.host_rustcflags = Some("-Dwarnings".to_string());
79     compiletest::run_tests(&config);
80 }
81
82 fn miri_pass(path: &str, target: &str, host: &str, fullmir: bool, opt: bool) {
83     let opt_str = if opt { " with optimizations" } else { "" };
84     eprintln!(
85         "## Running run-pass tests in {} against miri for target {}{}",
86         path,
87         target,
88         opt_str
89     );
90     let mut config = compiletest::default_config();
91     config.mode = "mir-opt".parse().expect("Invalid mode");
92     config.src_base = PathBuf::from(path);
93     config.target = target.to_owned();
94     config.host = host.to_owned();
95     config.rustc_path = miri_path();
96     if rustc_test_suite().is_some() {
97         config.run_lib_path = rustc_lib_path();
98         config.compile_lib_path = rustc_lib_path();
99     }
100     let mut flags = Vec::new();
101     // if we are building as part of the rustc test suite, we already have fullmir for everything
102     if fullmir && rustc_test_suite().is_none() {
103         if host != target {
104             // skip fullmir on nonhost
105             return;
106         }
107         let sysroot = Path::new(&std::env::var("HOME").unwrap())
108             .join(".xargo")
109             .join("HOST");
110         flags.push(format!("--sysroot {}", sysroot.to_str().unwrap()));
111     }
112     if opt {
113         flags.push("-Zmir-opt-level=3".to_owned());
114     } else {
115         flags.push("-Zmir-opt-level=0".to_owned());
116         // For now, only validate without optimizations.  Inlining breaks validation.
117         flags.push("-Zmir-emit-validate=1".to_owned());
118     }
119     config.target_rustcflags = Some(flags.join(" "));
120     // don't actually execute the final binary, it might be for other targets and we only care
121     // about running miri, not the binary.
122     config.runtool = Some("echo \"\" || ".to_owned());
123     if target == host {
124         std::env::set_var("MIRI_HOST_TARGET", "yes");
125     }
126     compiletest::run_tests(&config);
127     std::env::set_var("MIRI_HOST_TARGET", "");
128 }
129
130 fn is_target_dir<P: Into<PathBuf>>(path: P) -> bool {
131     let mut path = path.into();
132     path.push("lib");
133     path.metadata().map(|m| m.is_dir()).unwrap_or(false)
134 }
135
136 fn for_all_targets<F: FnMut(String)>(sysroot: &Path, mut f: F) {
137     let target_dir = sysroot.join("lib").join("rustlib");
138     for entry in std::fs::read_dir(target_dir).expect("invalid sysroot") {
139         let entry = entry.unwrap();
140         if !is_target_dir(entry.path()) {
141             continue;
142         }
143         let target = entry.file_name().into_string().unwrap();
144         f(target);
145     }
146 }
147
148 fn get_sysroot() -> PathBuf {
149     let sysroot = std::env::var("MIRI_SYSROOT").unwrap_or_else(|_| {
150         let sysroot = std::process::Command::new("rustc")
151             .arg("--print")
152             .arg("sysroot")
153             .output()
154             .expect("rustc not found")
155             .stdout;
156         String::from_utf8(sysroot).expect("sysroot is not utf8")
157     });
158     PathBuf::from(sysroot.trim())
159 }
160
161 fn get_host() -> String {
162     let host = std::process::Command::new("rustc")
163         .arg("-vV")
164         .output()
165         .expect("rustc not found for -vV")
166         .stdout;
167     let host = std::str::from_utf8(&host).expect("sysroot is not utf8");
168     let host = host.split("\nhost: ").nth(1).expect(
169         "no host: part in rustc -vV",
170     );
171     let host = host.split('\n').next().expect("no \n after host");
172     String::from(host)
173 }
174
175 #[test]
176 fn run_pass_miri() {
177     let sysroot = get_sysroot();
178     let host = get_host();
179
180     for &opt in [false, true].iter() {
181         for_all_targets(&sysroot, |target| {
182             miri_pass("tests/run-pass", &target, &host, false, opt);
183         });
184         miri_pass("tests/run-pass-fullmir", &host, &host, true, opt);
185     }
186 }
187
188 #[test]
189 fn run_pass_rustc() {
190     run_pass("tests/run-pass");
191     run_pass("tests/run-pass-fullmir");
192 }
193
194 #[test]
195 fn compile_fail_miri() {
196     let sysroot = get_sysroot();
197     let host = get_host();
198
199     for_all_targets(&sysroot, |target| {
200         compile_fail(&sysroot, "tests/compile-fail", &target, &host, false);
201     });
202     compile_fail(&sysroot, "tests/compile-fail-fullmir", &host, &host, true);
203 }