1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10 pub use self::Mode::*;
11 
12 use std::env;
13 use std::fmt;
14 use std::fs::{read_dir, remove_file};
15 use std::str::FromStr;
16 use std::path::PathBuf;
17 #[cfg(feature = "rustc")]
18 use rustc_session;
19 
20 use test::ColorConfig;
21 use runtest::dylib_env_var;
22 
23 #[derive(Clone, Copy, PartialEq, Debug)]
24 pub enum Mode {
25     CompileFail,
26     ParseFail,
27     RunFail,
28     RunPass,
29     RunPassValgrind,
30     Pretty,
31     DebugInfoGdb,
32     DebugInfoLldb,
33     Codegen,
34     Rustdoc,
35     CodegenUnits,
36     Incremental,
37     RunMake,
38     Ui,
39     MirOpt,
40     Assembly,
41 }
42 
43 impl Mode {
disambiguator(self) -> &'static str44     pub fn disambiguator(self) -> &'static str {
45         // Run-pass and pretty run-pass tests could run concurrently, and if they do,
46         // they need to keep their output segregated. Same is true for debuginfo tests that
47         // can be run both on gdb and lldb.
48         match self {
49             Pretty => ".pretty",
50             DebugInfoGdb => ".gdb",
51             DebugInfoLldb => ".lldb",
52             _ => "",
53         }
54     }
55 }
56 
57 impl FromStr for Mode {
58     type Err = ();
from_str(s: &str) -> Result<Mode, ()>59     fn from_str(s: &str) -> Result<Mode, ()> {
60         match s {
61             "compile-fail" => Ok(CompileFail),
62             "parse-fail" => Ok(ParseFail),
63             "run-fail" => Ok(RunFail),
64             "run-pass" => Ok(RunPass),
65             "run-pass-valgrind" => Ok(RunPassValgrind),
66             "pretty" => Ok(Pretty),
67             "debuginfo-lldb" => Ok(DebugInfoLldb),
68             "debuginfo-gdb" => Ok(DebugInfoGdb),
69             "codegen" => Ok(Codegen),
70             "rustdoc" => Ok(Rustdoc),
71             "codegen-units" => Ok(CodegenUnits),
72             "incremental" => Ok(Incremental),
73             "run-make" => Ok(RunMake),
74             "ui" => Ok(Ui),
75             "mir-opt" => Ok(MirOpt),
76             "assembly" => Ok(Assembly),
77             _ => Err(()),
78         }
79     }
80 }
81 
82 impl fmt::Display for Mode {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result83     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
84         fmt::Display::fmt(match *self {
85                               CompileFail => "compile-fail",
86                               ParseFail => "parse-fail",
87                               RunFail => "run-fail",
88                               RunPass => "run-pass",
89                               RunPassValgrind => "run-pass-valgrind",
90                               Pretty => "pretty",
91                               DebugInfoGdb => "debuginfo-gdb",
92                               DebugInfoLldb => "debuginfo-lldb",
93                               Codegen => "codegen",
94                               Rustdoc => "rustdoc",
95                               CodegenUnits => "codegen-units",
96                               Incremental => "incremental",
97                               RunMake => "run-make",
98                               Ui => "ui",
99                               MirOpt => "mir-opt",
100                               Assembly => "assembly",
101                           },
102                           f)
103     }
104 }
105 
106 #[derive(Clone)]
107 pub struct Config {
108     /// `true` to overwrite stderr/stdout/fixed files instead of complaining about changes in output.
109     pub bless: bool,
110 
111     /// The library paths required for running the compiler
112     pub compile_lib_path: PathBuf,
113 
114     /// The library paths required for running compiled programs
115     pub run_lib_path: PathBuf,
116 
117     /// The rustc executable
118     pub rustc_path: PathBuf,
119 
120     /// The rustdoc executable
121     pub rustdoc_path: Option<PathBuf>,
122 
123     /// The python executable to use for LLDB
124     pub lldb_python: String,
125 
126     /// The python executable to use for htmldocck
127     pub docck_python: String,
128 
129     /// The llvm FileCheck binary path
130     pub llvm_filecheck: Option<PathBuf>,
131 
132     /// The valgrind path
133     pub valgrind_path: Option<String>,
134 
135     /// Whether to fail if we can't run run-pass-valgrind tests under valgrind
136     /// (or, alternatively, to silently run them like regular run-pass tests).
137     pub force_valgrind: bool,
138 
139     /// The directory containing the tests to run
140     pub src_base: PathBuf,
141 
142     /// The directory where programs should be built
143     pub build_base: PathBuf,
144 
145     /// The name of the stage being built (stage1, etc)
146     pub stage_id: String,
147 
148     /// The test mode, compile-fail, run-fail, run-pass
149     pub mode: Mode,
150 
151     /// Run ignored tests
152     pub run_ignored: bool,
153 
154     /// Only run tests that match these filters
155     pub filters: Vec<String>,
156 
157     /// Exactly match the filter, rather than a substring
158     pub filter_exact: bool,
159 
160     /// Write out a parseable log of tests that were run
161     pub logfile: Option<PathBuf>,
162 
163     /// A command line to prefix program execution with,
164     /// for running under valgrind
165     pub runtool: Option<String>,
166 
167     /// Flags to pass to the compiler when building for the host
168     pub host_rustcflags: Option<String>,
169 
170     /// Flags to pass to the compiler when building for the target
171     pub target_rustcflags: Option<String>,
172 
173     /// Target system to be tested
174     pub target: String,
175 
176     /// Host triple for the compiler being invoked
177     pub host: String,
178 
179     /// Path to / name of the GDB executable
180     pub gdb: Option<String>,
181 
182     /// Version of GDB, encoded as ((major * 1000) + minor) * 1000 + patch
183     pub gdb_version: Option<u32>,
184 
185     /// Whether GDB has native rust support
186     pub gdb_native_rust: bool,
187 
188     /// Version of LLDB
189     pub lldb_version: Option<String>,
190 
191     /// Version of LLVM
192     pub llvm_version: Option<String>,
193 
194     /// Is LLVM a system LLVM
195     pub system_llvm: bool,
196 
197     /// Path to the android tools
198     pub android_cross_path: PathBuf,
199 
200     /// Extra parameter to run adb on arm-linux-androideabi
201     pub adb_path: String,
202 
203     /// Extra parameter to run test suite on arm-linux-androideabi
204     pub adb_test_dir: String,
205 
206     /// status whether android device available or not
207     pub adb_device_status: bool,
208 
209     /// the path containing LLDB's Python module
210     pub lldb_python_dir: Option<String>,
211 
212     /// Explain what's going on
213     pub verbose: bool,
214 
215     /// Print one character per test instead of one line
216     pub quiet: bool,
217 
218     /// Whether to use colors in test.
219     pub color: ColorConfig,
220 
221     /// where to find the remote test client process, if we're using it
222     pub remote_test_client: Option<PathBuf>,
223 
224     /// If true, this will generate a coverage file with UI test files that run `MachineApplicable`
225     /// diagnostics but are missing `run-rustfix` annotations. The generated coverage file is
226     /// created in `/<build_base>/rustfix_missing_coverage.txt`
227     pub rustfix_coverage: bool,
228 
229     /// The default Rust edition
230     pub edition: Option<String>,
231 
232     // Configuration for various run-make tests frobbing things like C compilers
233     // or querying about various LLVM component information.
234     pub cc: String,
235     pub cxx: String,
236     pub cflags: String,
237     pub ar: String,
238     pub linker: Option<String>,
239     pub llvm_components: String,
240     pub llvm_cxxflags: String,
241     pub nodejs: Option<String>,
242 }
243 
244 #[derive(Clone)]
245 pub struct TestPaths {
246     pub file: PathBuf,         // e.g., compile-test/foo/bar/baz.rs
247     pub base: PathBuf,         // e.g., compile-test, auxiliary
248     pub relative_dir: PathBuf, // e.g., foo/bar
249 }
250 
251 /// Used by `ui` tests to generate things like `foo.stderr` from `foo.rs`.
expected_output_path( testpaths: &TestPaths, revision: Option<&str>, kind: &str, ) -> PathBuf252 pub fn expected_output_path(
253     testpaths: &TestPaths,
254     revision: Option<&str>,
255     kind: &str,
256 ) -> PathBuf {
257     assert!(UI_EXTENSIONS.contains(&kind));
258     let mut parts = Vec::new();
259 
260     if let Some(x) = revision {
261         parts.push(x);
262     }
263     parts.push(kind);
264 
265     let extension = parts.join(".");
266     testpaths.file.with_extension(extension)
267 }
268 
269 pub const UI_EXTENSIONS: &[&str] = &[UI_STDERR, UI_STDOUT, UI_FIXED];
270 pub const UI_STDERR: &str = "stderr";
271 pub const UI_STDOUT: &str = "stdout";
272 pub const UI_FIXED: &str = "fixed";
273 
274 impl Config {
275     /// Add rustc flags to link with the crate's dependencies in addition to the crate itself
link_deps(&mut self)276     pub fn link_deps(&mut self) {
277         let varname = dylib_env_var();
278 
279         // Dependencies can be found in the environment variable. Throw everything there into the
280         // link flags
281         let lib_paths = env::var(varname).unwrap_or_else(|err| match err {
282             env::VarError::NotPresent => String::new(),
283             err => panic!("can't get {} environment variable: {}", varname, err),
284         });
285 
286         // Append to current flags if any are set, otherwise make new String
287         let mut flags = self.target_rustcflags.take().unwrap_or_else(String::new);
288         if !lib_paths.is_empty() {
289             for p in env::split_paths(&lib_paths) {
290                 flags += " -L ";
291                 flags += p.to_str().unwrap(); // Can't fail. We already know this is unicode
292             }
293         }
294 
295         self.target_rustcflags = Some(flags);
296     }
297 
298     /// Remove rmeta files from target `deps` directory
299     ///
300     /// These files are created by `cargo check`, and conflict with
301     /// `cargo build` rlib files, causing E0464 for tests which use
302     /// the parent crate.
clean_rmeta(&self)303     pub fn clean_rmeta(&self) {
304         if self.target_rustcflags.is_some() {
305             for directory in self.target_rustcflags
306                 .as_ref()
307                 .unwrap()
308                 .split_whitespace()
309                 .filter(|s| s.ends_with("/deps"))
310             {
311                 if let Ok(mut entries) = read_dir(directory) {
312                     while let Some(Ok(entry)) = entries.next() {
313                         if entry.file_name().to_string_lossy().ends_with(".rmeta") {
314                             let _ = remove_file(entry.path());
315                         }
316                     }
317                 }
318             }
319         }
320     }
321 
322     #[cfg(feature = "tmp")]
tempdir(mut self) -> ConfigWithTemp323     pub fn tempdir(mut self) -> ConfigWithTemp {
324         let tmp = tempfile::Builder::new().prefix("compiletest").tempdir()
325             .expect("failed to create temporary directory");
326         self.build_base = tmp.path().to_owned();
327         config_tempdir::ConfigWithTemp {
328             config: self,
329             tempdir: tmp,
330         }
331     }
332 }
333 
334 #[cfg(feature = "tmp")]
335 mod config_tempdir {
336     use tempfile;
337     use std::ops;
338 
339     pub struct ConfigWithTemp {
340         pub config: super::Config,
341         pub tempdir: tempfile::TempDir,
342     }
343 
344     impl ops::Deref for ConfigWithTemp {
345         type Target = super::Config;
346 
deref(&self) -> &Self::Target347         fn deref(&self) -> &Self::Target {
348             &self.config
349         }
350     }
351 
352     impl ops::DerefMut for ConfigWithTemp {
deref_mut(&mut self) -> &mut Self::Target353         fn deref_mut(&mut self) -> &mut Self::Target {
354             &mut self.config
355         }
356     }
357 }
358 
359 #[cfg(feature = "tmp")]
360 pub use self::config_tempdir::ConfigWithTemp;
361 
362 
363 impl Default for Config {
default() -> Config364     fn default() -> Config {
365         #[cfg(feature = "rustc")]
366         let platform = rustc_session::config::host_triple().to_string();
367 
368         Config {
369             bless: false,
370             compile_lib_path: PathBuf::from(""),
371             run_lib_path: PathBuf::from(""),
372             rustc_path: PathBuf::from("rustc"),
373             rustdoc_path: None,
374             lldb_python: "python".to_owned(),
375             docck_python: "docck-python".to_owned(),
376             valgrind_path: None,
377             force_valgrind: false,
378             llvm_filecheck: None,
379             src_base: PathBuf::from("tests/run-pass"),
380             build_base: env::temp_dir(),
381             stage_id: "stage-id".to_owned(),
382             mode: Mode::RunPass,
383             run_ignored: false,
384             filters: vec![],
385             filter_exact: false,
386             logfile: None,
387             runtool: None,
388             host_rustcflags: None,
389             target_rustcflags: None,
390             #[cfg(feature = "rustc")]
391             target: platform.clone(),
392             #[cfg(not(feature = "rustc"))]
393             target: env!("TARGET").to_string(),
394             #[cfg(feature = "rustc")]
395             host: platform.clone(),
396             #[cfg(not(feature = "rustc"))]
397             host: env!("HOST").to_string(),
398             rustfix_coverage: false,
399             gdb: None,
400             gdb_version: None,
401             gdb_native_rust: false,
402             lldb_version: None,
403             llvm_version: None,
404             system_llvm: false,
405             android_cross_path: PathBuf::from("android-cross-path"),
406             adb_path: "adb-path".to_owned(),
407             adb_test_dir: "adb-test-dir/target".to_owned(),
408             adb_device_status: false,
409             lldb_python_dir: None,
410             verbose: false,
411             quiet: false,
412             color: ColorConfig::AutoColor,
413             remote_test_client: None,
414             cc: "cc".to_string(),
415             cxx: "cxx".to_string(),
416             cflags: "cflags".to_string(),
417             ar: "ar".to_string(),
418             linker: None,
419             llvm_components: "llvm-components".to_string(),
420             llvm_cxxflags: "llvm-cxxflags".to_string(),
421             nodejs: None,
422             edition: None,
423         }
424     }
425 }
426