]> git.lizzy.rs Git - rust.git/blob - src/compiletest/runtest.rs
5293eee9459cf1728f4964084ce15b0bc6dba80c
[rust.git] / src / compiletest / runtest.rs
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
11 use common::Config;
12 use common::{CompileFail, ParseFail, Pretty, RunFail, RunPass, RunPassValgrind};
13 use common::{Codegen, DebugInfoLldb, DebugInfoGdb, Rustdoc, CodegenUnits};
14 use errors::{self, ErrorKind};
15 use header::TestProps;
16 use header;
17 use procsrv;
18 use test::TestPaths;
19 use util::logv;
20
21 use std::env;
22 use std::collections::HashSet;
23 use std::fmt;
24 use std::fs::{self, File};
25 use std::io::BufReader;
26 use std::io::prelude::*;
27 use std::net::TcpStream;
28 use std::path::{Path, PathBuf, Component};
29 use std::process::{Command, Output, ExitStatus};
30
31 pub fn run(config: Config, testpaths: &TestPaths) {
32     match &*config.target {
33
34         "arm-linux-androideabi" | "aarch64-linux-android" => {
35             if !config.adb_device_status {
36                 panic!("android device not available");
37             }
38         }
39
40         _=> { }
41     }
42
43     if config.verbose {
44         // We're going to be dumping a lot of info. Start on a new line.
45         print!("\n\n");
46     }
47     debug!("running {:?}", testpaths.file.display());
48     let props = header::load_props(&testpaths.file);
49     debug!("loaded props");
50     match config.mode {
51         CompileFail => run_cfail_test(&config, &props, &testpaths),
52         ParseFail => run_cfail_test(&config, &props, &testpaths),
53         RunFail => run_rfail_test(&config, &props, &testpaths),
54         RunPass => run_rpass_test(&config, &props, &testpaths),
55         RunPassValgrind => run_valgrind_test(&config, &props, &testpaths),
56         Pretty => run_pretty_test(&config, &props, &testpaths),
57         DebugInfoGdb => run_debuginfo_gdb_test(&config, &props, &testpaths),
58         DebugInfoLldb => run_debuginfo_lldb_test(&config, &props, &testpaths),
59         Codegen => run_codegen_test(&config, &props, &testpaths),
60         Rustdoc => run_rustdoc_test(&config, &props, &testpaths),
61         CodegenUnits => run_codegen_units_test(&config, &props, &testpaths),
62     }
63 }
64
65 fn get_output(props: &TestProps, proc_res: &ProcRes) -> String {
66     if props.check_stdout {
67         format!("{}{}", proc_res.stdout, proc_res.stderr)
68     } else {
69         proc_res.stderr.clone()
70     }
71 }
72
73
74 fn for_each_revision<OP>(config: &Config, props: &TestProps, testpaths: &TestPaths,
75                          mut op: OP)
76     where OP: FnMut(&Config, &TestProps, &TestPaths, Option<&str>)
77 {
78     if props.revisions.is_empty() {
79         op(config, props, testpaths, None)
80     } else {
81         for revision in &props.revisions {
82             let mut revision_props = props.clone();
83             header::load_props_into(&mut revision_props,
84                                     &testpaths.file,
85                                     Some(&revision));
86             revision_props.compile_flags.extend(vec![
87                 format!("--cfg"),
88                 format!("{}", revision),
89             ]);
90             op(config, &revision_props, testpaths, Some(revision));
91         }
92     }
93 }
94
95 fn run_cfail_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
96     for_each_revision(config, props, testpaths, run_cfail_test_revision);
97 }
98
99 fn run_cfail_test_revision(config: &Config,
100                            props: &TestProps,
101                            testpaths: &TestPaths,
102                            revision: Option<&str>) {
103     let proc_res = compile_test(config, props, testpaths);
104
105     if proc_res.status.success() {
106         fatal_proc_rec(
107             revision,
108             &format!("{} test compiled successfully!", config.mode)[..],
109             &proc_res);
110     }
111
112     check_correct_failure_status(revision, &proc_res);
113
114     if proc_res.status.success() {
115         fatal(revision, "process did not return an error status");
116     }
117
118     let output_to_check = get_output(props, &proc_res);
119     let expected_errors = errors::load_errors(&testpaths.file, revision);
120     if !expected_errors.is_empty() {
121         if !props.error_patterns.is_empty() {
122             fatal(revision, "both error pattern and expected errors specified");
123         }
124         check_expected_errors(revision, expected_errors, testpaths, &proc_res);
125     } else {
126         check_error_patterns(revision, props, testpaths, &output_to_check, &proc_res);
127     }
128     check_no_compiler_crash(revision, &proc_res);
129     check_forbid_output(revision, props, &output_to_check, &proc_res);
130 }
131
132 fn run_rfail_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
133     for_each_revision(config, props, testpaths, run_rfail_test_revision);
134 }
135
136 fn run_rfail_test_revision(config: &Config,
137                            props: &TestProps,
138                            testpaths: &TestPaths,
139                            revision: Option<&str>) {
140     let proc_res = compile_test(config, props, testpaths);
141
142     if !proc_res.status.success() {
143         fatal_proc_rec(revision, "compilation failed!", &proc_res);
144     }
145
146     let proc_res = exec_compiled_test(config, props, testpaths);
147
148     // The value our Makefile configures valgrind to return on failure
149     const VALGRIND_ERR: i32 = 100;
150     if proc_res.status.code() == Some(VALGRIND_ERR) {
151         fatal_proc_rec(revision, "run-fail test isn't valgrind-clean!", &proc_res);
152     }
153
154     let output_to_check = get_output(props, &proc_res);
155     check_correct_failure_status(revision, &proc_res);
156     check_error_patterns(revision, props, testpaths, &output_to_check, &proc_res);
157 }
158
159 fn check_correct_failure_status(revision: Option<&str>, proc_res: &ProcRes) {
160     // The value the rust runtime returns on failure
161     const RUST_ERR: i32 = 101;
162     if proc_res.status.code() != Some(RUST_ERR) {
163         fatal_proc_rec(
164             revision,
165             &format!("failure produced the wrong error: {}",
166                      proc_res.status),
167             proc_res);
168     }
169 }
170
171 fn run_rpass_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
172     for_each_revision(config, props, testpaths, run_rpass_test_revision);
173 }
174
175 fn run_rpass_test_revision(config: &Config,
176                            props: &TestProps,
177                            testpaths: &TestPaths,
178                            revision: Option<&str>) {
179     let proc_res = compile_test(config, props, testpaths);
180
181     if !proc_res.status.success() {
182         fatal_proc_rec(revision, "compilation failed!", &proc_res);
183     }
184
185     let proc_res = exec_compiled_test(config, props, testpaths);
186
187     if !proc_res.status.success() {
188         fatal_proc_rec(revision, "test run failed!", &proc_res);
189     }
190 }
191
192 fn run_valgrind_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
193     assert!(props.revisions.is_empty(), "revisions not relevant here");
194
195     if config.valgrind_path.is_none() {
196         assert!(!config.force_valgrind);
197         return run_rpass_test(config, props, testpaths);
198     }
199
200     let mut proc_res = compile_test(config, props, testpaths);
201
202     if !proc_res.status.success() {
203         fatal_proc_rec(None, "compilation failed!", &proc_res);
204     }
205
206     let mut new_config = config.clone();
207     new_config.runtool = new_config.valgrind_path.clone();
208     proc_res = exec_compiled_test(&new_config, props, testpaths);
209
210     if !proc_res.status.success() {
211         fatal_proc_rec(None, "test run failed!", &proc_res);
212     }
213 }
214
215 fn run_pretty_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
216     for_each_revision(config, props, testpaths, run_pretty_test_revision);
217 }
218
219 fn run_pretty_test_revision(config: &Config,
220                             props: &TestProps,
221                             testpaths: &TestPaths,
222                             revision: Option<&str>) {
223     if props.pp_exact.is_some() {
224         logv(config, "testing for exact pretty-printing".to_owned());
225     } else {
226         logv(config, "testing for converging pretty-printing".to_owned());
227     }
228
229     let rounds =
230         match props.pp_exact { Some(_) => 1, None => 2 };
231
232     let mut src = String::new();
233     File::open(&testpaths.file).unwrap().read_to_string(&mut src).unwrap();
234     let mut srcs = vec!(src);
235
236     let mut round = 0;
237     while round < rounds {
238         logv(config, format!("pretty-printing round {} revision {:?}",
239                              round, revision));
240         let proc_res = print_source(config,
241                                     props,
242                                     testpaths,
243                                     srcs[round].to_owned(),
244                                     &props.pretty_mode);
245
246         if !proc_res.status.success() {
247             fatal_proc_rec(revision,
248                            &format!("pretty-printing failed in round {} revision {:?}",
249                                     round, revision),
250                            &proc_res);
251         }
252
253         let ProcRes{ stdout, .. } = proc_res;
254         srcs.push(stdout);
255         round += 1;
256     }
257
258     let mut expected = match props.pp_exact {
259         Some(ref file) => {
260             let filepath = testpaths.file.parent().unwrap().join(file);
261             let mut s = String::new();
262             File::open(&filepath).unwrap().read_to_string(&mut s).unwrap();
263             s
264         }
265         None => { srcs[srcs.len() - 2].clone() }
266     };
267     let mut actual = srcs[srcs.len() - 1].clone();
268
269     if props.pp_exact.is_some() {
270         // Now we have to care about line endings
271         let cr = "\r".to_owned();
272         actual = actual.replace(&cr, "").to_owned();
273         expected = expected.replace(&cr, "").to_owned();
274     }
275
276     compare_source(revision, &expected, &actual);
277
278     // If we're only making sure that the output matches then just stop here
279     if props.pretty_compare_only { return; }
280
281     // Finally, let's make sure it actually appears to remain valid code
282     let proc_res = typecheck_source(config, props, testpaths, actual);
283     if !proc_res.status.success() {
284         fatal_proc_rec(revision, "pretty-printed source does not typecheck", &proc_res);
285     }
286
287     if !props.pretty_expanded { return }
288
289     // additionally, run `--pretty expanded` and try to build it.
290     let proc_res = print_source(config, props, testpaths, srcs[round].clone(), "expanded");
291     if !proc_res.status.success() {
292         fatal_proc_rec(revision, "pretty-printing (expanded) failed", &proc_res);
293     }
294
295     let ProcRes{ stdout: expanded_src, .. } = proc_res;
296     let proc_res = typecheck_source(config, props, testpaths, expanded_src);
297     if !proc_res.status.success() {
298         fatal_proc_rec(
299             revision,
300             "pretty-printed source (expanded) does not typecheck",
301             &proc_res);
302     }
303
304     return;
305
306     fn print_source(config: &Config,
307                     props: &TestProps,
308                     testpaths: &TestPaths,
309                     src: String,
310                     pretty_type: &str) -> ProcRes {
311         let aux_dir = aux_output_dir_name(config, testpaths);
312         compose_and_run(config,
313                         testpaths,
314                         make_pp_args(config,
315                                      props,
316                                      testpaths,
317                                      pretty_type.to_owned()),
318                         props.exec_env.clone(),
319                         &config.compile_lib_path,
320                         Some(aux_dir.to_str().unwrap()),
321                         Some(src))
322     }
323
324     fn make_pp_args(config: &Config,
325                     props: &TestProps,
326                     testpaths: &TestPaths,
327                     pretty_type: String) -> ProcArgs {
328         let aux_dir = aux_output_dir_name(config, testpaths);
329         // FIXME (#9639): This needs to handle non-utf8 paths
330         let mut args = vec!("-".to_owned(),
331                             "-Zunstable-options".to_owned(),
332                             "--unpretty".to_owned(),
333                             pretty_type,
334                             format!("--target={}", config.target),
335                             "-L".to_owned(),
336                             aux_dir.to_str().unwrap().to_owned());
337         args.extend(split_maybe_args(&config.target_rustcflags));
338         args.extend(props.compile_flags.iter().cloned());
339         return ProcArgs {
340             prog: config.rustc_path.to_str().unwrap().to_owned(),
341             args: args,
342         };
343     }
344
345     fn compare_source(revision: Option<&str>, expected: &str, actual: &str) {
346         if expected != actual {
347             error(revision, "pretty-printed source does not match expected source");
348             println!("\n\
349 expected:\n\
350 ------------------------------------------\n\
351 {}\n\
352 ------------------------------------------\n\
353 actual:\n\
354 ------------------------------------------\n\
355 {}\n\
356 ------------------------------------------\n\
357 \n",
358                      expected, actual);
359             panic!();
360         }
361     }
362
363     fn typecheck_source(config: &Config, props: &TestProps,
364                         testpaths: &TestPaths, src: String) -> ProcRes {
365         let args = make_typecheck_args(config, props, testpaths);
366         compose_and_run_compiler(config, props, testpaths, args, Some(src))
367     }
368
369     fn make_typecheck_args(config: &Config, props: &TestProps, testpaths: &TestPaths) -> ProcArgs {
370         let aux_dir = aux_output_dir_name(config, testpaths);
371         let target = if props.force_host {
372             &*config.host
373         } else {
374             &*config.target
375         };
376         // FIXME (#9639): This needs to handle non-utf8 paths
377         let mut args = vec!("-".to_owned(),
378                             "-Zno-trans".to_owned(),
379                             format!("--target={}", target),
380                             "-L".to_owned(),
381                             config.build_base.to_str().unwrap().to_owned(),
382                             "-L".to_owned(),
383                             aux_dir.to_str().unwrap().to_owned());
384         args.extend(split_maybe_args(&config.target_rustcflags));
385         args.extend(props.compile_flags.iter().cloned());
386         // FIXME (#9639): This needs to handle non-utf8 paths
387         return ProcArgs {
388             prog: config.rustc_path.to_str().unwrap().to_owned(),
389             args: args,
390         };
391     }
392 }
393
394 fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
395     assert!(props.revisions.is_empty(), "revisions not relevant here");
396
397     let mut config = Config {
398         target_rustcflags: cleanup_debug_info_options(&config.target_rustcflags),
399         host_rustcflags: cleanup_debug_info_options(&config.host_rustcflags),
400         .. config.clone()
401     };
402
403     let config = &mut config;
404     let DebuggerCommands {
405         commands,
406         check_lines,
407         breakpoint_lines
408     } = parse_debugger_commands(testpaths, "gdb");
409     let mut cmds = commands.join("\n");
410
411     // compile test file (it should have 'compile-flags:-g' in the header)
412     let compiler_run_result = compile_test(config, props, testpaths);
413     if !compiler_run_result.status.success() {
414         fatal_proc_rec(None, "compilation failed!", &compiler_run_result);
415     }
416
417     let exe_file = make_exe_name(config, testpaths);
418
419     let debugger_run_result;
420     match &*config.target {
421         "arm-linux-androideabi" | "aarch64-linux-android" => {
422
423             cmds = cmds.replace("run", "continue");
424
425             // write debugger script
426             let mut script_str = String::with_capacity(2048);
427             script_str.push_str(&format!("set charset {}\n", charset()));
428             script_str.push_str(&format!("file {}\n", exe_file.to_str().unwrap()));
429             script_str.push_str("target remote :5039\n");
430             script_str.push_str(&format!("set solib-search-path \
431                                          ./{}/stage2/lib/rustlib/{}/lib/\n",
432                                          config.host, config.target));
433             for line in &breakpoint_lines {
434                 script_str.push_str(&format!("break {:?}:{}\n",
435                                              testpaths.file
436                                                       .file_name()
437                                                       .unwrap()
438                                                       .to_string_lossy(),
439                                              *line)[..]);
440             }
441             script_str.push_str(&cmds);
442             script_str.push_str("\nquit\n");
443
444             debug!("script_str = {}", script_str);
445             dump_output_file(config,
446                              testpaths,
447                              &script_str,
448                              "debugger.script");
449
450
451             procsrv::run("",
452                          &config.adb_path,
453                          None,
454                          &[
455                             "push".to_owned(),
456                             exe_file.to_str().unwrap().to_owned(),
457                             config.adb_test_dir.clone()
458                          ],
459                          vec!(("".to_owned(), "".to_owned())),
460                          Some("".to_owned()))
461                 .expect(&format!("failed to exec `{:?}`", config.adb_path));
462
463             procsrv::run("",
464                          &config.adb_path,
465                          None,
466                          &[
467                             "forward".to_owned(),
468                             "tcp:5039".to_owned(),
469                             "tcp:5039".to_owned()
470                          ],
471                          vec!(("".to_owned(), "".to_owned())),
472                          Some("".to_owned()))
473                 .expect(&format!("failed to exec `{:?}`", config.adb_path));
474
475             let adb_arg = format!("export LD_LIBRARY_PATH={}; \
476                                    gdbserver{} :5039 {}/{}",
477                                   config.adb_test_dir.clone(),
478                                   if config.target.contains("aarch64")
479                                   {"64"} else {""},
480                                   config.adb_test_dir.clone(),
481                                   exe_file.file_name().unwrap().to_str()
482                                           .unwrap());
483
484             let mut process = procsrv::run_background("",
485                                                       &config.adb_path
486                                                             ,
487                                                       None,
488                                                       &[
489                                                         "shell".to_owned(),
490                                                         adb_arg.clone()
491                                                       ],
492                                                       vec!(("".to_owned(),
493                                                             "".to_owned())),
494                                                       Some("".to_owned()))
495                 .expect(&format!("failed to exec `{:?}`", config.adb_path));
496             loop {
497                 //waiting 1 second for gdbserver start
498                 ::std::thread::sleep(::std::time::Duration::new(1,0));
499                 if TcpStream::connect("127.0.0.1:5039").is_ok() {
500                     break
501                 }
502             }
503
504             let tool_path = match config.android_cross_path.to_str() {
505                 Some(x) => x.to_owned(),
506                 None => fatal(None, "cannot find android cross path")
507             };
508
509             let debugger_script = make_out_name(config, testpaths, "debugger.script");
510             // FIXME (#9639): This needs to handle non-utf8 paths
511             let debugger_opts =
512                 vec!("-quiet".to_owned(),
513                      "-batch".to_owned(),
514                      "-nx".to_owned(),
515                      format!("-command={}", debugger_script.to_str().unwrap()));
516
517             let mut gdb_path = tool_path;
518             gdb_path.push_str(&format!("/bin/{}-gdb", config.target));
519             let procsrv::Result {
520                 out,
521                 err,
522                 status
523             } = procsrv::run("",
524                              &gdb_path,
525                              None,
526                              &debugger_opts,
527                              vec!(("".to_owned(), "".to_owned())),
528                              None)
529                 .expect(&format!("failed to exec `{:?}`", gdb_path));
530             let cmdline = {
531                 let cmdline = make_cmdline("",
532                                            &format!("{}-gdb", config.target),
533                                            &debugger_opts);
534                 logv(config, format!("executing {}", cmdline));
535                 cmdline
536             };
537
538             debugger_run_result = ProcRes {
539                 status: Status::Normal(status),
540                 stdout: out,
541                 stderr: err,
542                 cmdline: cmdline
543             };
544             if process.kill().is_err() {
545                 println!("Adb process is already finished.");
546             }
547         }
548
549         _=> {
550             let rust_src_root = find_rust_src_root(config)
551                 .expect("Could not find Rust source root");
552             let rust_pp_module_rel_path = Path::new("./src/etc");
553             let rust_pp_module_abs_path = rust_src_root.join(rust_pp_module_rel_path)
554                                                        .to_str()
555                                                        .unwrap()
556                                                        .to_owned();
557             // write debugger script
558             let mut script_str = String::with_capacity(2048);
559             script_str.push_str(&format!("set charset {}\n", charset()));
560             script_str.push_str("show version\n");
561
562             match config.gdb_version {
563                 Some(ref version) => {
564                     println!("NOTE: compiletest thinks it is using GDB version {}",
565                              version);
566
567                     if header::gdb_version_to_int(version) >
568                         header::gdb_version_to_int("7.4") {
569                         // Add the directory containing the pretty printers to
570                         // GDB's script auto loading safe path
571                         script_str.push_str(
572                             &format!("add-auto-load-safe-path {}\n",
573                                      rust_pp_module_abs_path.replace(r"\", r"\\"))
574                                 );
575                     }
576                 }
577                 _ => {
578                     println!("NOTE: compiletest does not know which version of \
579                               GDB it is using");
580                 }
581             }
582
583             // The following line actually doesn't have to do anything with
584             // pretty printing, it just tells GDB to print values on one line:
585             script_str.push_str("set print pretty off\n");
586
587             // Add the pretty printer directory to GDB's source-file search path
588             script_str.push_str(&format!("directory {}\n",
589                                          rust_pp_module_abs_path));
590
591             // Load the target executable
592             script_str.push_str(&format!("file {}\n",
593                                          exe_file.to_str().unwrap()
594                                                  .replace(r"\", r"\\")));
595
596             // Add line breakpoints
597             for line in &breakpoint_lines {
598                 script_str.push_str(&format!("break '{}':{}\n",
599                                              testpaths.file.file_name().unwrap()
600                                                      .to_string_lossy(),
601                                              *line));
602             }
603
604             script_str.push_str(&cmds);
605             script_str.push_str("\nquit\n");
606
607             debug!("script_str = {}", script_str);
608             dump_output_file(config,
609                              testpaths,
610                              &script_str,
611                              "debugger.script");
612
613             // run debugger script with gdb
614             fn debugger() -> &'static str {
615                 if cfg!(windows) {"gdb.exe"} else {"gdb"}
616             }
617
618             let debugger_script = make_out_name(config, testpaths, "debugger.script");
619
620             // FIXME (#9639): This needs to handle non-utf8 paths
621             let debugger_opts =
622                 vec!("-quiet".to_owned(),
623                      "-batch".to_owned(),
624                      "-nx".to_owned(),
625                      format!("-command={}", debugger_script.to_str().unwrap()));
626
627             let proc_args = ProcArgs {
628                 prog: debugger().to_owned(),
629                 args: debugger_opts,
630             };
631
632             let environment = vec![("PYTHONPATH".to_owned(), rust_pp_module_abs_path)];
633
634             debugger_run_result = compose_and_run(config,
635                                                   testpaths,
636                                                   proc_args,
637                                                   environment,
638                                                   &config.run_lib_path,
639                                                   None,
640                                                   None);
641         }
642     }
643
644     if !debugger_run_result.status.success() {
645         fatal(None, "gdb failed to execute");
646     }
647
648     check_debugger_output(&debugger_run_result, &check_lines);
649 }
650
651 fn find_rust_src_root(config: &Config) -> Option<PathBuf> {
652     let mut path = config.src_base.clone();
653     let path_postfix = Path::new("src/etc/lldb_batchmode.py");
654
655     while path.pop() {
656         if path.join(&path_postfix).is_file() {
657             return Some(path);
658         }
659     }
660
661     return None;
662 }
663
664 fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
665     assert!(props.revisions.is_empty(), "revisions not relevant here");
666
667     if config.lldb_python_dir.is_none() {
668         fatal(None, "Can't run LLDB test because LLDB's python path is not set.");
669     }
670
671     let mut config = Config {
672         target_rustcflags: cleanup_debug_info_options(&config.target_rustcflags),
673         host_rustcflags: cleanup_debug_info_options(&config.host_rustcflags),
674         .. config.clone()
675     };
676
677     let config = &mut config;
678
679     // compile test file (it should have 'compile-flags:-g' in the header)
680     let compile_result = compile_test(config, props, testpaths);
681     if !compile_result.status.success() {
682         fatal_proc_rec(None, "compilation failed!", &compile_result);
683     }
684
685     let exe_file = make_exe_name(config, testpaths);
686
687     match config.lldb_version {
688         Some(ref version) => {
689             println!("NOTE: compiletest thinks it is using LLDB version {}",
690                      version);
691         }
692         _ => {
693             println!("NOTE: compiletest does not know which version of \
694                       LLDB it is using");
695         }
696     }
697
698     // Parse debugger commands etc from test files
699     let DebuggerCommands {
700         commands,
701         check_lines,
702         breakpoint_lines,
703         ..
704     } = parse_debugger_commands(testpaths, "lldb");
705
706     // Write debugger script:
707     // We don't want to hang when calling `quit` while the process is still running
708     let mut script_str = String::from("settings set auto-confirm true\n");
709
710     // Make LLDB emit its version, so we have it documented in the test output
711     script_str.push_str("version\n");
712
713     // Switch LLDB into "Rust mode"
714     let rust_src_root = find_rust_src_root(config)
715         .expect("Could not find Rust source root");
716     let rust_pp_module_rel_path = Path::new("./src/etc/lldb_rust_formatters.py");
717     let rust_pp_module_abs_path = rust_src_root.join(rust_pp_module_rel_path)
718                                                .to_str()
719                                                .unwrap()
720                                                .to_owned();
721
722     script_str.push_str(&format!("command script import {}\n",
723                                  &rust_pp_module_abs_path[..])[..]);
724     script_str.push_str("type summary add --no-value ");
725     script_str.push_str("--python-function lldb_rust_formatters.print_val ");
726     script_str.push_str("-x \".*\" --category Rust\n");
727     script_str.push_str("type category enable Rust\n");
728
729     // Set breakpoints on every line that contains the string "#break"
730     for line in &breakpoint_lines {
731         script_str.push_str(&format!("breakpoint set --line {}\n", line));
732     }
733
734     // Append the other commands
735     for line in &commands {
736         script_str.push_str(line);
737         script_str.push_str("\n");
738     }
739
740     // Finally, quit the debugger
741     script_str.push_str("\nquit\n");
742
743     // Write the script into a file
744     debug!("script_str = {}", script_str);
745     dump_output_file(config,
746                      testpaths,
747                      &script_str,
748                      "debugger.script");
749     let debugger_script = make_out_name(config, testpaths, "debugger.script");
750
751     // Let LLDB execute the script via lldb_batchmode.py
752     let debugger_run_result = run_lldb(config,
753                                        testpaths,
754                                        &exe_file,
755                                        &debugger_script,
756                                        &rust_src_root);
757
758     if !debugger_run_result.status.success() {
759         fatal_proc_rec(None, "Error while running LLDB", &debugger_run_result);
760     }
761
762     check_debugger_output(&debugger_run_result, &check_lines);
763
764     fn run_lldb(config: &Config,
765                 testpaths: &TestPaths,
766                 test_executable: &Path,
767                 debugger_script: &Path,
768                 rust_src_root: &Path)
769                 -> ProcRes {
770         // Prepare the lldb_batchmode which executes the debugger script
771         let lldb_script_path = rust_src_root.join("src/etc/lldb_batchmode.py");
772         cmd2procres(config,
773                     testpaths,
774                     Command::new(&config.python)
775                             .arg(&lldb_script_path)
776                             .arg(test_executable)
777                             .arg(debugger_script)
778                             .env("PYTHONPATH",
779                                  config.lldb_python_dir.as_ref().unwrap()))
780     }
781 }
782
783 fn cmd2procres(config: &Config, testpaths: &TestPaths, cmd: &mut Command)
784               -> ProcRes {
785     let (status, out, err) = match cmd.output() {
786         Ok(Output { status, stdout, stderr }) => {
787             (status,
788              String::from_utf8(stdout).unwrap(),
789              String::from_utf8(stderr).unwrap())
790         },
791         Err(e) => {
792             fatal(None, &format!("Failed to setup Python process for \
793                             LLDB script: {}", e))
794         }
795     };
796
797     dump_output(config, testpaths, &out, &err);
798     ProcRes {
799         status: Status::Normal(status),
800         stdout: out,
801         stderr: err,
802         cmdline: format!("{:?}", cmd)
803     }
804 }
805
806 struct DebuggerCommands {
807     commands: Vec<String>,
808     check_lines: Vec<String>,
809     breakpoint_lines: Vec<usize>,
810 }
811
812 fn parse_debugger_commands(testpaths: &TestPaths, debugger_prefix: &str)
813                            -> DebuggerCommands {
814     let command_directive = format!("{}-command", debugger_prefix);
815     let check_directive = format!("{}-check", debugger_prefix);
816
817     let mut breakpoint_lines = vec!();
818     let mut commands = vec!();
819     let mut check_lines = vec!();
820     let mut counter = 1;
821     let reader = BufReader::new(File::open(&testpaths.file).unwrap());
822     for line in reader.lines() {
823         match line {
824             Ok(line) => {
825                 if line.contains("#break") {
826                     breakpoint_lines.push(counter);
827                 }
828
829                 header::parse_name_value_directive(
830                         &line,
831                         &command_directive).map(|cmd| {
832                     commands.push(cmd)
833                 });
834
835                 header::parse_name_value_directive(
836                         &line,
837                         &check_directive).map(|cmd| {
838                     check_lines.push(cmd)
839                 });
840             }
841             Err(e) => {
842                 fatal(None, &format!("Error while parsing debugger commands: {}", e))
843             }
844         }
845         counter += 1;
846     }
847
848     DebuggerCommands {
849         commands: commands,
850         check_lines: check_lines,
851         breakpoint_lines: breakpoint_lines,
852     }
853 }
854
855 fn cleanup_debug_info_options(options: &Option<String>) -> Option<String> {
856     if options.is_none() {
857         return None;
858     }
859
860     // Remove options that are either unwanted (-O) or may lead to duplicates due to RUSTFLAGS.
861     let options_to_remove = [
862         "-O".to_owned(),
863         "-g".to_owned(),
864         "--debuginfo".to_owned()
865     ];
866     let mut new_options =
867         split_maybe_args(options).into_iter()
868                                  .filter(|x| !options_to_remove.contains(x))
869                                  .collect::<Vec<String>>();
870
871     let mut i = 0;
872     while i + 1 < new_options.len() {
873         if new_options[i] == "-Z" {
874             // FIXME #31005 MIR missing debuginfo currently.
875             if new_options[i + 1] == "orbit" {
876                 // Remove "-Z" and "orbit".
877                 new_options.remove(i);
878                 new_options.remove(i);
879                 continue;
880             }
881             // Always skip over -Z's argument.
882             i += 1;
883         }
884         i += 1;
885     }
886
887     Some(new_options.join(" "))
888 }
889
890 fn check_debugger_output(debugger_run_result: &ProcRes, check_lines: &[String]) {
891     let num_check_lines = check_lines.len();
892     if num_check_lines > 0 {
893         // Allow check lines to leave parts unspecified (e.g., uninitialized
894         // bits in the wrong case of an enum) with the notation "[...]".
895         let check_fragments: Vec<Vec<String>> =
896             check_lines.iter().map(|s| {
897                 s
898                  .trim()
899                  .split("[...]")
900                  .map(str::to_owned)
901                  .collect()
902             }).collect();
903         // check if each line in props.check_lines appears in the
904         // output (in order)
905         let mut i = 0;
906         for line in debugger_run_result.stdout.lines() {
907             let mut rest = line.trim();
908             let mut first = true;
909             let mut failed = false;
910             for frag in &check_fragments[i] {
911                 let found = if first {
912                     if rest.starts_with(frag) {
913                         Some(0)
914                     } else {
915                         None
916                     }
917                 } else {
918                     rest.find(frag)
919                 };
920                 match found {
921                     None => {
922                         failed = true;
923                         break;
924                     }
925                     Some(i) => {
926                         rest = &rest[(i + frag.len())..];
927                     }
928                 }
929                 first = false;
930             }
931             if !failed && rest.is_empty() {
932                 i += 1;
933             }
934             if i == num_check_lines {
935                 // all lines checked
936                 break;
937             }
938         }
939         if i != num_check_lines {
940             fatal_proc_rec(None, &format!("line not found in debugger output: {}",
941                                     check_lines.get(i).unwrap()),
942                           debugger_run_result);
943         }
944     }
945 }
946
947 fn check_error_patterns(revision: Option<&str>,
948                         props: &TestProps,
949                         testpaths: &TestPaths,
950                         output_to_check: &str,
951                         proc_res: &ProcRes) {
952     if props.error_patterns.is_empty() {
953         fatal(revision,
954               &format!("no error pattern specified in {:?}",
955                        testpaths.file.display()));
956     }
957     let mut next_err_idx = 0;
958     let mut next_err_pat = &props.error_patterns[next_err_idx];
959     let mut done = false;
960     for line in output_to_check.lines() {
961         if line.contains(next_err_pat) {
962             debug!("found error pattern {}", next_err_pat);
963             next_err_idx += 1;
964             if next_err_idx == props.error_patterns.len() {
965                 debug!("found all error patterns");
966                 done = true;
967                 break;
968             }
969             next_err_pat = &props.error_patterns[next_err_idx];
970         }
971     }
972     if done { return; }
973
974     let missing_patterns = &props.error_patterns[next_err_idx..];
975     if missing_patterns.len() == 1 {
976         fatal_proc_rec(
977             revision,
978             &format!("error pattern '{}' not found!", missing_patterns[0]),
979             proc_res);
980     } else {
981         for pattern in missing_patterns {
982             error(revision, &format!("error pattern '{}' not found!", *pattern));
983         }
984         fatal_proc_rec(revision, "multiple error patterns not found", proc_res);
985     }
986 }
987
988 fn check_no_compiler_crash(revision: Option<&str>, proc_res: &ProcRes) {
989     for line in proc_res.stderr.lines() {
990         if line.starts_with("error: internal compiler error:") {
991             fatal_proc_rec(revision,
992                            "compiler encountered internal error",
993                            proc_res);
994         }
995     }
996 }
997
998 fn check_forbid_output(revision: Option<&str>,
999                        props: &TestProps,
1000                        output_to_check: &str,
1001                        proc_res: &ProcRes) {
1002     for pat in &props.forbid_output {
1003         if output_to_check.contains(pat) {
1004             fatal_proc_rec(revision,
1005                            "forbidden pattern found in compiler output",
1006                            proc_res);
1007         }
1008     }
1009 }
1010
1011 fn check_expected_errors(revision: Option<&str>,
1012                          expected_errors: Vec<errors::ExpectedError>,
1013                          testpaths: &TestPaths,
1014                          proc_res: &ProcRes) {
1015     // true if we found the error in question
1016     let mut found_flags = vec![false; expected_errors.len()];
1017
1018     if proc_res.status.success() {
1019         fatal_proc_rec(revision, "process did not return an error status", proc_res);
1020     }
1021
1022     let prefixes = expected_errors.iter().map(|ee| {
1023         let expected = format!("{}:{}:", testpaths.file.display(), ee.line_num);
1024         // On windows just translate all '\' path separators to '/'
1025         expected.replace(r"\", "/")
1026     }).collect::<Vec<String>>();
1027
1028     // If the testcase being checked contains at least one expected "help"
1029     // message, then we'll ensure that all "help" messages are expected.
1030     // Otherwise, all "help" messages reported by the compiler will be ignored.
1031     // This logic also applies to "note" messages.
1032     let (expect_help, expect_note) =
1033         expected_errors.iter()
1034                         .fold((false, false),
1035                               |(acc_help, acc_note), ee|
1036                                   (acc_help || ee.kind == Some(ErrorKind::Help),
1037                                    acc_note || ee.kind == Some(ErrorKind::Note)));
1038
1039     // Scan and extract our error/warning messages,
1040     // which look like:
1041     //    filename:line1:col1: line2:col2: *error:* msg
1042     //    filename:line1:col1: line2:col2: *warning:* msg
1043     // where line1:col1: is the starting point, line2:col2:
1044     // is the ending point, and * represents ANSI color codes.
1045     //
1046     // This pattern is ambiguous on windows, because filename may contain
1047     // a colon, so any path prefix must be detected and removed first.
1048     let mut unexpected = 0;
1049     let mut not_found = 0;
1050     for line in proc_res.stderr.lines() {
1051         let mut was_expected = false;
1052         let mut prev = 0;
1053         for (i, ee) in expected_errors.iter().enumerate() {
1054             if !found_flags[i] {
1055                 debug!("prefix={} ee.kind={:?} ee.msg={} line={}",
1056                        prefixes[i],
1057                        ee.kind,
1058                        ee.msg,
1059                        line);
1060                 // Suggestions have no line number in their output, so take on the line number of
1061                 // the previous expected error
1062                 if ee.kind == Some(ErrorKind::Suggestion) {
1063                     assert!(expected_errors[prev].kind == Some(ErrorKind::Help),
1064                             "SUGGESTIONs must be preceded by a HELP");
1065                     if line.contains(&ee.msg) {
1066                         found_flags[i] = true;
1067                         was_expected = true;
1068                         break;
1069                     }
1070                 }
1071                 if
1072                     (prefix_matches(line, &prefixes[i]) || continuation(line)) &&
1073                     (ee.kind.is_none() || line.contains(&ee.kind.as_ref().unwrap().to_string())) &&
1074                     line.contains(&ee.msg)
1075                 {
1076                     found_flags[i] = true;
1077                     was_expected = true;
1078                     break;
1079                 }
1080             }
1081             prev = i;
1082         }
1083
1084         // ignore this msg which gets printed at the end
1085         if line.contains("aborting due to") {
1086             was_expected = true;
1087         }
1088
1089         if !was_expected && is_unexpected_compiler_message(line, expect_help, expect_note) {
1090             error(revision, &format!("unexpected compiler message: '{}'", line));
1091             unexpected += 1;
1092         }
1093     }
1094
1095     for (i, &flag) in found_flags.iter().enumerate() {
1096         if !flag {
1097             let ee = &expected_errors[i];
1098             error(revision, &format!("expected {} on line {} not found: {}",
1099                                      ee.kind.as_ref()
1100                                             .map_or("message".into(),
1101                                                     |k| k.to_string()),
1102                                      ee.line_num, ee.msg));
1103             not_found += 1;
1104         }
1105     }
1106
1107     if unexpected > 0 || not_found > 0 {
1108         fatal_proc_rec(
1109             revision,
1110             &format!("{} unexpected errors found, {} expected errors not found",
1111                      unexpected, not_found),
1112             proc_res);
1113     }
1114
1115     fn prefix_matches(line: &str, prefix: &str) -> bool {
1116         use std::ascii::AsciiExt;
1117         // On windows just translate all '\' path separators to '/'
1118         let line = line.replace(r"\", "/");
1119         if cfg!(windows) {
1120             line.to_ascii_lowercase().starts_with(&prefix.to_ascii_lowercase())
1121         } else {
1122             line.starts_with(prefix)
1123         }
1124     }
1125
1126     // A multi-line error will have followup lines which start with a space
1127     // or open paren.
1128     fn continuation( line: &str) -> bool {
1129         line.starts_with(" ") || line.starts_with("(")
1130     }
1131 }
1132
1133 fn is_unexpected_compiler_message(line: &str, expect_help: bool, expect_note: bool) -> bool {
1134     let mut c = Path::new(line).components();
1135     let line = match c.next() {
1136         Some(Component::Prefix(_)) => c.as_path().to_str().unwrap(),
1137         _ => line,
1138     };
1139
1140     let mut i = 0;
1141     return scan_until_char(line, ':', &mut i) &&
1142         scan_char(line, ':', &mut i) &&
1143         scan_integer(line, &mut i) &&
1144         scan_char(line, ':', &mut i) &&
1145         scan_integer(line, &mut i) &&
1146         scan_char(line, ':', &mut i) &&
1147         scan_char(line, ' ', &mut i) &&
1148         scan_integer(line, &mut i) &&
1149         scan_char(line, ':', &mut i) &&
1150         scan_integer(line, &mut i) &&
1151         scan_char(line, ' ', &mut i) &&
1152         (scan_string(line, "error", &mut i) ||
1153          scan_string(line, "warning", &mut i) ||
1154          (expect_help && scan_string(line, "help", &mut i)) ||
1155          (expect_note && scan_string(line, "note", &mut i))
1156         );
1157 }
1158
1159 fn scan_until_char(haystack: &str, needle: char, idx: &mut usize) -> bool {
1160     if *idx >= haystack.len() {
1161         return false;
1162     }
1163     let opt = haystack[(*idx)..].find(needle);
1164     if opt.is_none() {
1165         return false;
1166     }
1167     *idx = opt.unwrap();
1168     return true;
1169 }
1170
1171 fn scan_char(haystack: &str, needle: char, idx: &mut usize) -> bool {
1172     if *idx >= haystack.len() {
1173         return false;
1174     }
1175     let ch = haystack.char_at(*idx);
1176     if ch != needle {
1177         return false;
1178     }
1179     *idx += ch.len_utf8();
1180     return true;
1181 }
1182
1183 fn scan_integer(haystack: &str, idx: &mut usize) -> bool {
1184     let mut i = *idx;
1185     while i < haystack.len() {
1186         let ch = haystack.char_at(i);
1187         if ch < '0' || '9' < ch {
1188             break;
1189         }
1190         i += ch.len_utf8();
1191     }
1192     if i == *idx {
1193         return false;
1194     }
1195     *idx = i;
1196     return true;
1197 }
1198
1199 fn scan_string(haystack: &str, needle: &str, idx: &mut usize) -> bool {
1200     let mut haystack_i = *idx;
1201     let mut needle_i = 0;
1202     while needle_i < needle.len() {
1203         if haystack_i >= haystack.len() {
1204             return false;
1205         }
1206         let ch = haystack.char_at(haystack_i);
1207         haystack_i += ch.len_utf8();
1208         if !scan_char(needle, ch, &mut needle_i) {
1209             return false;
1210         }
1211     }
1212     *idx = haystack_i;
1213     return true;
1214 }
1215
1216 struct ProcArgs {
1217     prog: String,
1218     args: Vec<String>,
1219 }
1220
1221 struct ProcRes {
1222     status: Status,
1223     stdout: String,
1224     stderr: String,
1225     cmdline: String,
1226 }
1227
1228 enum Status {
1229     Parsed(i32),
1230     Normal(ExitStatus),
1231 }
1232
1233 impl Status {
1234     fn code(&self) -> Option<i32> {
1235         match *self {
1236             Status::Parsed(i) => Some(i),
1237             Status::Normal(ref e) => e.code(),
1238         }
1239     }
1240
1241     fn success(&self) -> bool {
1242         match *self {
1243             Status::Parsed(i) => i == 0,
1244             Status::Normal(ref e) => e.success(),
1245         }
1246     }
1247 }
1248
1249 impl fmt::Display for Status {
1250     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1251         match *self {
1252             Status::Parsed(i) => write!(f, "exit code: {}", i),
1253             Status::Normal(ref e) => e.fmt(f),
1254         }
1255     }
1256 }
1257
1258 fn compile_test(config: &Config, props: &TestProps,
1259                 testpaths: &TestPaths) -> ProcRes {
1260     let aux_dir = aux_output_dir_name(config, testpaths);
1261     // FIXME (#9639): This needs to handle non-utf8 paths
1262     let link_args = vec!("-L".to_owned(),
1263                          aux_dir.to_str().unwrap().to_owned());
1264     let args = make_compile_args(config,
1265                                  props,
1266                                  link_args,
1267                                  |a, b| TargetLocation::ThisFile(make_exe_name(a, b)), testpaths);
1268     compose_and_run_compiler(config, props, testpaths, args, None)
1269 }
1270
1271 fn document(config: &Config,
1272             props: &TestProps,
1273             testpaths: &TestPaths,
1274             out_dir: &Path)
1275             -> ProcRes {
1276     if props.build_aux_docs {
1277         for rel_ab in &props.aux_builds {
1278             let aux_testpaths = compute_aux_test_paths(config, testpaths, rel_ab);
1279             let aux_props = header::load_props(&aux_testpaths.file);
1280             let auxres = document(config, &aux_props, &aux_testpaths, out_dir);
1281             if !auxres.status.success() {
1282                 return auxres;
1283             }
1284         }
1285     }
1286
1287     let aux_dir = aux_output_dir_name(config, testpaths);
1288     let mut args = vec!["-L".to_owned(),
1289                         aux_dir.to_str().unwrap().to_owned(),
1290                         "-o".to_owned(),
1291                         out_dir.to_str().unwrap().to_owned(),
1292                         testpaths.file.to_str().unwrap().to_owned()];
1293     args.extend(props.compile_flags.iter().cloned());
1294     let args = ProcArgs {
1295         prog: config.rustdoc_path.to_str().unwrap().to_owned(),
1296         args: args,
1297     };
1298     compose_and_run_compiler(config, props, testpaths, args, None)
1299 }
1300
1301 fn exec_compiled_test(config: &Config, props: &TestProps,
1302                       testpaths: &TestPaths) -> ProcRes {
1303
1304     let env = props.exec_env.clone();
1305
1306     match &*config.target {
1307
1308         "arm-linux-androideabi" | "aarch64-linux-android" => {
1309             _arm_exec_compiled_test(config, props, testpaths, env)
1310         }
1311
1312         _=> {
1313             let aux_dir = aux_output_dir_name(config, testpaths);
1314             compose_and_run(config,
1315                             testpaths,
1316                             make_run_args(config, props, testpaths),
1317                             env,
1318                             &config.run_lib_path,
1319                             Some(aux_dir.to_str().unwrap()),
1320                             None)
1321         }
1322     }
1323 }
1324
1325 fn compute_aux_test_paths(config: &Config,
1326                           testpaths: &TestPaths,
1327                           rel_ab: &str)
1328                           -> TestPaths
1329 {
1330     let abs_ab = config.aux_base.join(rel_ab);
1331     TestPaths {
1332         file: abs_ab,
1333         base: testpaths.base.clone(),
1334         relative_dir: Path::new(rel_ab).parent()
1335                                        .map(|p| p.to_path_buf())
1336                                        .unwrap_or_else(|| PathBuf::new())
1337     }
1338 }
1339
1340 fn compose_and_run_compiler(config: &Config, props: &TestProps,
1341                             testpaths: &TestPaths, args: ProcArgs,
1342                             input: Option<String>) -> ProcRes {
1343     if !props.aux_builds.is_empty() {
1344         ensure_dir(&aux_output_dir_name(config, testpaths));
1345     }
1346
1347     let aux_dir = aux_output_dir_name(config, testpaths);
1348     // FIXME (#9639): This needs to handle non-utf8 paths
1349     let extra_link_args = vec!["-L".to_owned(),
1350                                aux_dir.to_str().unwrap().to_owned()];
1351
1352     for rel_ab in &props.aux_builds {
1353         let aux_testpaths = compute_aux_test_paths(config, testpaths, rel_ab);
1354         let aux_props = header::load_props(&aux_testpaths.file);
1355         let mut crate_type = if aux_props.no_prefer_dynamic {
1356             Vec::new()
1357         } else {
1358             // We primarily compile all auxiliary libraries as dynamic libraries
1359             // to avoid code size bloat and large binaries as much as possible
1360             // for the test suite (otherwise including libstd statically in all
1361             // executables takes up quite a bit of space).
1362             //
1363             // For targets like MUSL or Emscripten, however, there is no support for
1364             // dynamic libraries so we just go back to building a normal library. Note,
1365             // however, that for MUSL if the library is built with `force_host` then
1366             // it's ok to be a dylib as the host should always support dylibs.
1367             if (config.target.contains("musl") && !aux_props.force_host) ||
1368                 config.target.contains("emscripten")
1369             {
1370                 vec!("--crate-type=lib".to_owned())
1371             } else {
1372                 vec!("--crate-type=dylib".to_owned())
1373             }
1374         };
1375         crate_type.extend(extra_link_args.clone());
1376         let aux_args =
1377             make_compile_args(config,
1378                               &aux_props,
1379                               crate_type,
1380                               |a,b| {
1381                                   let f = make_lib_name(a, &b.file, testpaths);
1382                                   let parent = f.parent().unwrap();
1383                                   TargetLocation::ThisDirectory(parent.to_path_buf())
1384                               },
1385                               &aux_testpaths);
1386         let auxres = compose_and_run(config,
1387                                      &aux_testpaths,
1388                                      aux_args,
1389                                      Vec::new(),
1390                                      &config.compile_lib_path,
1391                                      Some(aux_dir.to_str().unwrap()),
1392                                      None);
1393         if !auxres.status.success() {
1394             fatal_proc_rec(
1395                 None,
1396                 &format!("auxiliary build of {:?} failed to compile: ",
1397                         aux_testpaths.file.display()),
1398                 &auxres);
1399         }
1400
1401         match &*config.target {
1402             "arm-linux-androideabi"  | "aarch64-linux-android" => {
1403                 _arm_push_aux_shared_library(config, testpaths);
1404             }
1405             _ => {}
1406         }
1407     }
1408
1409     compose_and_run(config,
1410                     testpaths,
1411                     args,
1412                     props.rustc_env.clone(),
1413                     &config.compile_lib_path,
1414                     Some(aux_dir.to_str().unwrap()),
1415                     input)
1416 }
1417
1418 fn ensure_dir(path: &Path) {
1419     if path.is_dir() { return; }
1420     fs::create_dir_all(path).unwrap();
1421 }
1422
1423 fn compose_and_run(config: &Config,
1424                    testpaths: &TestPaths,
1425                    ProcArgs{ args, prog }: ProcArgs,
1426                    procenv: Vec<(String, String)> ,
1427                    lib_path: &str,
1428                    aux_path: Option<&str>,
1429                    input: Option<String>) -> ProcRes {
1430     return program_output(config, testpaths, lib_path,
1431                           prog, aux_path, args, procenv, input);
1432 }
1433
1434 enum TargetLocation {
1435     ThisFile(PathBuf),
1436     ThisDirectory(PathBuf),
1437 }
1438
1439 fn make_compile_args<F>(config: &Config,
1440                         props: &TestProps,
1441                         extras: Vec<String> ,
1442                         xform: F,
1443                         testpaths: &TestPaths)
1444                         -> ProcArgs where
1445     F: FnOnce(&Config, &TestPaths) -> TargetLocation,
1446 {
1447     let xform_file = xform(config, testpaths);
1448     let target = if props.force_host {
1449         &*config.host
1450     } else {
1451         &*config.target
1452     };
1453     // FIXME (#9639): This needs to handle non-utf8 paths
1454     let mut args = vec!(testpaths.file.to_str().unwrap().to_owned(),
1455                         "-L".to_owned(),
1456                         config.build_base.to_str().unwrap().to_owned(),
1457                         format!("--target={}", target));
1458     args.extend_from_slice(&extras);
1459     if !props.no_prefer_dynamic {
1460         args.push("-C".to_owned());
1461         args.push("prefer-dynamic".to_owned());
1462     }
1463     let path = match xform_file {
1464         TargetLocation::ThisFile(path) => {
1465             args.push("-o".to_owned());
1466             path
1467         }
1468         TargetLocation::ThisDirectory(path) => {
1469             args.push("--out-dir".to_owned());
1470             path
1471         }
1472     };
1473     args.push(path.to_str().unwrap().to_owned());
1474     if props.force_host {
1475         args.extend(split_maybe_args(&config.host_rustcflags));
1476     } else {
1477         args.extend(split_maybe_args(&config.target_rustcflags));
1478     }
1479     args.extend(props.compile_flags.iter().cloned());
1480     return ProcArgs {
1481         prog: config.rustc_path.to_str().unwrap().to_owned(),
1482         args: args,
1483     };
1484 }
1485
1486 fn make_lib_name(config: &Config, auxfile: &Path, testpaths: &TestPaths) -> PathBuf {
1487     // what we return here is not particularly important, as it
1488     // happens; rustc ignores everything except for the directory.
1489     let auxname = output_testname(auxfile);
1490     aux_output_dir_name(config, testpaths).join(&auxname)
1491 }
1492
1493 fn make_exe_name(config: &Config, testpaths: &TestPaths) -> PathBuf {
1494     let mut f = output_base_name(config, testpaths);
1495     // FIXME: This is using the host architecture exe suffix, not target!
1496     if config.target == "asmjs-unknown-emscripten" {
1497         let mut fname = f.file_name().unwrap().to_os_string();
1498         fname.push(".js");
1499         f.set_file_name(&fname);
1500     } else if !env::consts::EXE_SUFFIX.is_empty() {
1501         let mut fname = f.file_name().unwrap().to_os_string();
1502         fname.push(env::consts::EXE_SUFFIX);
1503         f.set_file_name(&fname);
1504     }
1505     f
1506 }
1507
1508 fn make_run_args(config: &Config, props: &TestProps, testpaths: &TestPaths)
1509                  -> ProcArgs {
1510     // If we've got another tool to run under (valgrind),
1511     // then split apart its command
1512     let mut args = split_maybe_args(&config.runtool);
1513
1514     // If this is emscripten, then run tests under nodejs
1515     if config.target == "asmjs-unknown-emscripten" {
1516         args.push("nodejs".to_owned());
1517     }
1518
1519     let exe_file = make_exe_name(config, testpaths);
1520
1521     // FIXME (#9639): This needs to handle non-utf8 paths
1522     args.push(exe_file.to_str().unwrap().to_owned());
1523
1524     // Add the arguments in the run_flags directive
1525     args.extend(split_maybe_args(&props.run_flags));
1526
1527     let prog = args.remove(0);
1528     return ProcArgs {
1529         prog: prog,
1530         args: args,
1531     };
1532 }
1533
1534 fn split_maybe_args(argstr: &Option<String>) -> Vec<String> {
1535     match *argstr {
1536         Some(ref s) => {
1537             s
1538              .split(' ')
1539              .filter_map(|s| {
1540                  if s.chars().all(|c| c.is_whitespace()) {
1541                      None
1542                  } else {
1543                      Some(s.to_owned())
1544                  }
1545              }).collect()
1546         }
1547         None => Vec::new()
1548     }
1549 }
1550
1551 fn program_output(config: &Config, testpaths: &TestPaths, lib_path: &str, prog: String,
1552                   aux_path: Option<&str>, args: Vec<String>,
1553                   env: Vec<(String, String)>,
1554                   input: Option<String>) -> ProcRes {
1555     let cmdline =
1556         {
1557             let cmdline = make_cmdline(lib_path,
1558                                        &prog,
1559                                        &args);
1560             logv(config, format!("executing {}", cmdline));
1561             cmdline
1562         };
1563     let procsrv::Result {
1564         out,
1565         err,
1566         status
1567     } = procsrv::run(lib_path,
1568                      &prog,
1569                      aux_path,
1570                      &args,
1571                      env,
1572                      input).expect(&format!("failed to exec `{}`", prog));
1573     dump_output(config, testpaths, &out, &err);
1574     return ProcRes {
1575         status: Status::Normal(status),
1576         stdout: out,
1577         stderr: err,
1578         cmdline: cmdline,
1579     };
1580 }
1581
1582 fn make_cmdline(libpath: &str, prog: &str, args: &[String]) -> String {
1583     use util;
1584
1585     // Linux and mac don't require adjusting the library search path
1586     if cfg!(unix) {
1587         format!("{} {}", prog, args.join(" "))
1588     } else {
1589         // Build the LD_LIBRARY_PATH variable as it would be seen on the command line
1590         // for diagnostic purposes
1591         fn lib_path_cmd_prefix(path: &str) -> String {
1592             format!("{}=\"{}\"", util::lib_path_env_var(), util::make_new_path(path))
1593         }
1594
1595         format!("{} {} {}", lib_path_cmd_prefix(libpath), prog, args.join(" "))
1596     }
1597 }
1598
1599 fn dump_output(config: &Config, testpaths: &TestPaths, out: &str, err: &str) {
1600     dump_output_file(config, testpaths, out, "out");
1601     dump_output_file(config, testpaths, err, "err");
1602     maybe_dump_to_stdout(config, out, err);
1603 }
1604
1605 fn dump_output_file(config: &Config,
1606                     testpaths: &TestPaths,
1607                     out: &str,
1608                     extension: &str) {
1609     let outfile = make_out_name(config, testpaths, extension);
1610     File::create(&outfile).unwrap().write_all(out.as_bytes()).unwrap();
1611 }
1612
1613 fn make_out_name(config: &Config, testpaths: &TestPaths, extension: &str) -> PathBuf {
1614     output_base_name(config, testpaths).with_extension(extension)
1615 }
1616
1617 fn aux_output_dir_name(config: &Config, testpaths: &TestPaths) -> PathBuf {
1618     let f = output_base_name(config, testpaths);
1619     let mut fname = f.file_name().unwrap().to_os_string();
1620     fname.push(&format!(".{}.libaux", config.mode));
1621     f.with_file_name(&fname)
1622 }
1623
1624 fn output_testname(filepath: &Path) -> PathBuf {
1625     PathBuf::from(filepath.file_stem().unwrap())
1626 }
1627
1628 fn output_base_name(config: &Config, testpaths: &TestPaths) -> PathBuf {
1629     let dir = config.build_base.join(&testpaths.relative_dir);
1630
1631     // Note: The directory `dir` is created during `collect_tests_from_dir`
1632     dir
1633         .join(&output_testname(&testpaths.file))
1634         .with_extension(&config.stage_id)
1635 }
1636
1637 fn maybe_dump_to_stdout(config: &Config, out: &str, err: &str) {
1638     if config.verbose {
1639         println!("------{}------------------------------", "stdout");
1640         println!("{}", out);
1641         println!("------{}------------------------------", "stderr");
1642         println!("{}", err);
1643         println!("------------------------------------------");
1644     }
1645 }
1646
1647 fn error(revision: Option<&str>, err: &str) {
1648     match revision {
1649         Some(rev) => println!("\nerror in revision `{}`: {}", rev, err),
1650         None => println!("\nerror: {}", err)
1651     }
1652 }
1653
1654 fn fatal(revision: Option<&str>, err: &str) -> ! {
1655     error(revision, err); panic!();
1656 }
1657
1658 fn fatal_proc_rec(revision: Option<&str>, err: &str, proc_res: &ProcRes) -> ! {
1659     error(revision, err);
1660     print!("\
1661 status: {}\n\
1662 command: {}\n\
1663 stdout:\n\
1664 ------------------------------------------\n\
1665 {}\n\
1666 ------------------------------------------\n\
1667 stderr:\n\
1668 ------------------------------------------\n\
1669 {}\n\
1670 ------------------------------------------\n\
1671 \n",
1672              proc_res.status, proc_res.cmdline, proc_res.stdout,
1673              proc_res.stderr);
1674     panic!();
1675 }
1676
1677 fn _arm_exec_compiled_test(config: &Config,
1678                            props: &TestProps,
1679                            testpaths: &TestPaths,
1680                            env: Vec<(String, String)>)
1681                            -> ProcRes {
1682     let args = make_run_args(config, props, testpaths);
1683     let cmdline = make_cmdline("",
1684                                &args.prog,
1685                                &args.args);
1686
1687     // get bare program string
1688     let mut tvec: Vec<String> = args.prog
1689                                     .split('/')
1690                                     .map(str::to_owned)
1691                                     .collect();
1692     let prog_short = tvec.pop().unwrap();
1693
1694     // copy to target
1695     let copy_result = procsrv::run("",
1696                                    &config.adb_path,
1697                                    None,
1698                                    &[
1699                                     "push".to_owned(),
1700                                     args.prog.clone(),
1701                                     config.adb_test_dir.clone()
1702                                    ],
1703                                    vec!(("".to_owned(), "".to_owned())),
1704                                    Some("".to_owned()))
1705         .expect(&format!("failed to exec `{}`", config.adb_path));
1706
1707     if config.verbose {
1708         println!("push ({}) {} {} {}",
1709                  config.target,
1710                  args.prog,
1711                  copy_result.out,
1712                  copy_result.err);
1713     }
1714
1715     logv(config, format!("executing ({}) {}", config.target, cmdline));
1716
1717     let mut runargs = Vec::new();
1718
1719     // run test via adb_run_wrapper
1720     runargs.push("shell".to_owned());
1721     for (key, val) in env {
1722         runargs.push(format!("{}={}", key, val));
1723     }
1724     runargs.push(format!("{}/../adb_run_wrapper.sh", config.adb_test_dir));
1725     runargs.push(format!("{}", config.adb_test_dir));
1726     runargs.push(format!("{}", prog_short));
1727
1728     for tv in &args.args {
1729         runargs.push(tv.to_owned());
1730     }
1731     procsrv::run("",
1732                  &config.adb_path,
1733                  None,
1734                  &runargs,
1735                  vec!(("".to_owned(), "".to_owned())), Some("".to_owned()))
1736         .expect(&format!("failed to exec `{}`", config.adb_path));
1737
1738     // get exitcode of result
1739     runargs = Vec::new();
1740     runargs.push("shell".to_owned());
1741     runargs.push("cat".to_owned());
1742     runargs.push(format!("{}/{}.exitcode", config.adb_test_dir, prog_short));
1743
1744     let procsrv::Result{ out: exitcode_out, err: _, status: _ } =
1745         procsrv::run("",
1746                      &config.adb_path,
1747                      None,
1748                      &runargs,
1749                      vec!(("".to_owned(), "".to_owned())),
1750                      Some("".to_owned()))
1751         .expect(&format!("failed to exec `{}`", config.adb_path));
1752
1753     let mut exitcode: i32 = 0;
1754     for c in exitcode_out.chars() {
1755         if !c.is_numeric() { break; }
1756         exitcode = exitcode * 10 + match c {
1757             '0' ... '9' => c as i32 - ('0' as i32),
1758             _ => 101,
1759         }
1760     }
1761
1762     // get stdout of result
1763     runargs = Vec::new();
1764     runargs.push("shell".to_owned());
1765     runargs.push("cat".to_owned());
1766     runargs.push(format!("{}/{}.stdout", config.adb_test_dir, prog_short));
1767
1768     let procsrv::Result{ out: stdout_out, err: _, status: _ } =
1769         procsrv::run("",
1770                      &config.adb_path,
1771                      None,
1772                      &runargs,
1773                      vec!(("".to_owned(), "".to_owned())),
1774                      Some("".to_owned()))
1775         .expect(&format!("failed to exec `{}`", config.adb_path));
1776
1777     // get stderr of result
1778     runargs = Vec::new();
1779     runargs.push("shell".to_owned());
1780     runargs.push("cat".to_owned());
1781     runargs.push(format!("{}/{}.stderr", config.adb_test_dir, prog_short));
1782
1783     let procsrv::Result{ out: stderr_out, err: _, status: _ } =
1784         procsrv::run("",
1785                      &config.adb_path,
1786                      None,
1787                      &runargs,
1788                      vec!(("".to_owned(), "".to_owned())),
1789                      Some("".to_owned()))
1790         .expect(&format!("failed to exec `{}`", config.adb_path));
1791
1792     dump_output(config,
1793                 testpaths,
1794                 &stdout_out,
1795                 &stderr_out);
1796
1797     ProcRes {
1798         status: Status::Parsed(exitcode),
1799         stdout: stdout_out,
1800         stderr: stderr_out,
1801         cmdline: cmdline
1802     }
1803 }
1804
1805 fn _arm_push_aux_shared_library(config: &Config, testpaths: &TestPaths) {
1806     let tdir = aux_output_dir_name(config, testpaths);
1807
1808     let dirs = fs::read_dir(&tdir).unwrap();
1809     for file in dirs {
1810         let file = file.unwrap().path();
1811         if file.extension().and_then(|s| s.to_str()) == Some("so") {
1812             // FIXME (#9639): This needs to handle non-utf8 paths
1813             let copy_result = procsrv::run("",
1814                                            &config.adb_path,
1815                                            None,
1816                                            &[
1817                                             "push".to_owned(),
1818                                             file.to_str()
1819                                                 .unwrap()
1820                                                 .to_owned(),
1821                                             config.adb_test_dir.to_owned(),
1822                                            ],
1823                                            vec!(("".to_owned(),
1824                                                  "".to_owned())),
1825                                            Some("".to_owned()))
1826                 .expect(&format!("failed to exec `{}`", config.adb_path));
1827
1828             if config.verbose {
1829                 println!("push ({}) {:?} {} {}",
1830                     config.target, file.display(),
1831                     copy_result.out, copy_result.err);
1832             }
1833         }
1834     }
1835 }
1836
1837 // codegen tests (using FileCheck)
1838
1839 fn compile_test_and_save_ir(config: &Config, props: &TestProps,
1840                                  testpaths: &TestPaths) -> ProcRes {
1841     let aux_dir = aux_output_dir_name(config, testpaths);
1842     // FIXME (#9639): This needs to handle non-utf8 paths
1843     let mut link_args = vec!("-L".to_owned(),
1844                              aux_dir.to_str().unwrap().to_owned());
1845     let llvm_args = vec!("--emit=llvm-ir".to_owned(),);
1846     link_args.extend(llvm_args);
1847     let args = make_compile_args(config,
1848                                  props,
1849                                  link_args,
1850                                  |a, b| TargetLocation::ThisDirectory(
1851                                      output_base_name(a, b).parent()
1852                                         .unwrap().to_path_buf()),
1853                                  testpaths);
1854     compose_and_run_compiler(config, props, testpaths, args, None)
1855 }
1856
1857 fn check_ir_with_filecheck(config: &Config, testpaths: &TestPaths) -> ProcRes {
1858     let irfile = output_base_name(config, testpaths).with_extension("ll");
1859     let prog = config.llvm_bin_path.as_ref().unwrap().join("FileCheck");
1860     let proc_args = ProcArgs {
1861         // FIXME (#9639): This needs to handle non-utf8 paths
1862         prog: prog.to_str().unwrap().to_owned(),
1863         args: vec!(format!("-input-file={}", irfile.to_str().unwrap()),
1864                    testpaths.file.to_str().unwrap().to_owned())
1865     };
1866     compose_and_run(config, testpaths, proc_args, Vec::new(), "", None, None)
1867 }
1868
1869 fn run_codegen_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
1870     assert!(props.revisions.is_empty(), "revisions not relevant here");
1871
1872     if config.llvm_bin_path.is_none() {
1873         fatal(None, "missing --llvm-bin-path");
1874     }
1875
1876     let mut proc_res = compile_test_and_save_ir(config, props, testpaths);
1877     if !proc_res.status.success() {
1878         fatal_proc_rec(None, "compilation failed!", &proc_res);
1879     }
1880
1881     proc_res = check_ir_with_filecheck(config, testpaths);
1882     if !proc_res.status.success() {
1883         fatal_proc_rec(None,
1884                        "verification with 'FileCheck' failed",
1885                        &proc_res);
1886     }
1887 }
1888
1889 fn charset() -> &'static str {
1890     // FreeBSD 10.1 defaults to GDB 6.1.1 which doesn't support "auto" charset
1891     if cfg!(target_os = "bitrig") {
1892         "auto"
1893     } else if cfg!(target_os = "freebsd") {
1894         "ISO-8859-1"
1895     } else {
1896         "UTF-8"
1897     }
1898 }
1899
1900 fn run_rustdoc_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
1901     assert!(props.revisions.is_empty(), "revisions not relevant here");
1902
1903     let out_dir = output_base_name(config, testpaths);
1904     let _ = fs::remove_dir_all(&out_dir);
1905     ensure_dir(&out_dir);
1906
1907     let proc_res = document(config, props, testpaths, &out_dir);
1908     if !proc_res.status.success() {
1909         fatal_proc_rec(None, "rustdoc failed!", &proc_res);
1910     }
1911     let root = find_rust_src_root(config).unwrap();
1912
1913     let res = cmd2procres(config,
1914                           testpaths,
1915                           Command::new(&config.python)
1916                                   .arg(root.join("src/etc/htmldocck.py"))
1917                                   .arg(out_dir)
1918                                   .arg(&testpaths.file));
1919     if !res.status.success() {
1920         fatal_proc_rec(None, "htmldocck failed!", &res);
1921     }
1922 }
1923
1924 fn run_codegen_units_test(config: &Config, props: &TestProps, testpaths: &TestPaths) {
1925     assert!(props.revisions.is_empty(), "revisions not relevant here");
1926
1927     let proc_res = compile_test(config, props, testpaths);
1928
1929     if !proc_res.status.success() {
1930         fatal_proc_rec(None, "compilation failed!", &proc_res);
1931     }
1932
1933     check_no_compiler_crash(None, &proc_res);
1934
1935     let prefix = "TRANS_ITEM ";
1936
1937     let actual: HashSet<String> = proc_res
1938         .stdout
1939         .lines()
1940         .filter(|line| line.starts_with(prefix))
1941         .map(|s| (&s[prefix.len()..]).to_string())
1942         .collect();
1943
1944     let expected: HashSet<String> = errors::load_errors(&testpaths.file, None)
1945         .iter()
1946         .map(|e| e.msg.trim().to_string())
1947         .collect();
1948
1949     if actual != expected {
1950         let mut missing: Vec<_> = expected.difference(&actual).collect();
1951         missing.sort();
1952
1953         let mut too_much: Vec<_> = actual.difference(&expected).collect();
1954         too_much.sort();
1955
1956         println!("Expected and actual sets of codegen-items differ.\n\
1957                   These items should have been contained but were not:\n\n\
1958                   {}\n\n\
1959                   These items were contained but should not have been:\n\n\
1960                   {}\n\n",
1961             missing.iter().fold("".to_string(), |s1, s2| s1 + "\n" + s2),
1962             too_much.iter().fold("".to_string(), |s1, s2| s1 + "\n" + s2));
1963         panic!();
1964     }
1965 }