1 // Copyright 2012-2013 The Rust Project Developers. See the
2 // COPYRIGHT file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
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.
11 use common::mode_run_pass;
12 use common::mode_run_fail;
13 use common::mode_compile_fail;
14 use common::mode_pretty;
17 use header::load_props;
18 use header::TestProps;
28 use extra::test::MetricMap;
30 pub fn run(config: config, testfile: ~str) {
31 let mut _mm = MetricMap::new();
32 run_metrics(config, testfile, &mut _mm);
35 pub fn run_metrics(config: config, testfile: ~str, mm: &mut MetricMap) {
37 // We're going to be dumping a lot of info. Start on a new line.
38 io::stdout().write_str("\n\n");
40 let testfile = Path(testfile);
41 debug!("running %s", testfile.to_str());
42 let props = load_props(&testfile);
43 debug!("loaded props");
45 mode_compile_fail => run_cfail_test(&config, &props, &testfile),
46 mode_run_fail => run_rfail_test(&config, &props, &testfile),
47 mode_run_pass => run_rpass_test(&config, &props, &testfile),
48 mode_pretty => run_pretty_test(&config, &props, &testfile),
49 mode_debug_info => run_debuginfo_test(&config, &props, &testfile),
50 mode_codegen => run_codegen_test(&config, &props, &testfile, mm)
54 fn run_cfail_test(config: &config, props: &TestProps, testfile: &Path) {
55 let ProcRes = compile_test(config, props, testfile);
57 if ProcRes.status == 0 {
58 fatal_ProcRes(~"compile-fail test compiled successfully!", &ProcRes);
61 check_correct_failure_status(&ProcRes);
63 let expected_errors = errors::load_errors(testfile);
64 if !expected_errors.is_empty() {
65 if !props.error_patterns.is_empty() {
66 fatal(~"both error pattern and expected errors specified");
68 check_expected_errors(expected_errors, testfile, &ProcRes);
70 check_error_patterns(props, testfile, &ProcRes);
74 fn run_rfail_test(config: &config, props: &TestProps, testfile: &Path) {
75 let ProcRes = if !config.jit {
76 let ProcRes = compile_test(config, props, testfile);
78 if ProcRes.status != 0 {
79 fatal_ProcRes(~"compilation failed!", &ProcRes);
82 exec_compiled_test(config, props, testfile)
84 jit_test(config, props, testfile)
87 // The value our Makefile configures valgrind to return on failure
88 static VALGRIND_ERR: int = 100;
89 if ProcRes.status == VALGRIND_ERR {
90 fatal_ProcRes(~"run-fail test isn't valgrind-clean!", &ProcRes);
95 ~"arm-linux-androideabi" => {
96 if (config.adb_device_status) {
97 check_correct_failure_status(&ProcRes);
98 check_error_patterns(props, testfile, &ProcRes);
103 check_correct_failure_status(&ProcRes);
104 check_error_patterns(props, testfile, &ProcRes);
109 fn check_correct_failure_status(ProcRes: &ProcRes) {
110 // The value the rust runtime returns on failure
111 static RUST_ERR: int = 101;
112 if ProcRes.status != RUST_ERR {
114 fmt!("failure produced the wrong error code: %d",
120 fn run_rpass_test(config: &config, props: &TestProps, testfile: &Path) {
122 let mut ProcRes = compile_test(config, props, testfile);
124 if ProcRes.status != 0 {
125 fatal_ProcRes(~"compilation failed!", &ProcRes);
128 ProcRes = exec_compiled_test(config, props, testfile);
130 if ProcRes.status != 0 {
131 fatal_ProcRes(~"test run failed!", &ProcRes);
134 let ProcRes = jit_test(config, props, testfile);
136 if ProcRes.status != 0 { fatal_ProcRes(~"jit failed!", &ProcRes); }
140 fn run_pretty_test(config: &config, props: &TestProps, testfile: &Path) {
141 if props.pp_exact.is_some() {
142 logv(config, ~"testing for exact pretty-printing");
143 } else { logv(config, ~"testing for converging pretty-printing"); }
146 match props.pp_exact { Some(_) => 1, None => 2 };
148 let mut srcs = ~[io::read_whole_file_str(testfile).unwrap()];
151 while round < rounds {
152 logv(config, fmt!("pretty-printing round %d", round));
153 let ProcRes = print_source(config, testfile, srcs[round].clone());
155 if ProcRes.status != 0 {
156 fatal_ProcRes(fmt!("pretty-printing failed in round %d", round),
160 let ProcRes{ stdout, _ } = ProcRes;
165 let mut expected = match props.pp_exact {
167 let filepath = testfile.dir_path().push_rel(file);
168 io::read_whole_file_str(&filepath).unwrap()
170 None => { srcs[srcs.len() - 2u].clone() }
172 let mut actual = srcs[srcs.len() - 1u].clone();
174 if props.pp_exact.is_some() {
175 // Now we have to care about line endings
177 actual = actual.replace(cr, "");
178 expected = expected.replace(cr, "");
181 compare_source(expected, actual);
183 // Finally, let's make sure it actually appears to remain valid code
184 let ProcRes = typecheck_source(config, props, testfile, actual);
186 if ProcRes.status != 0 {
187 fatal_ProcRes(~"pretty-printed source does not typecheck", &ProcRes);
192 fn print_source(config: &config, testfile: &Path, src: ~str) -> ProcRes {
193 compose_and_run(config, testfile, make_pp_args(config, testfile),
194 ~[], config.compile_lib_path, Some(src))
197 fn make_pp_args(config: &config, _testfile: &Path) -> ProcArgs {
198 let args = ~[~"-", ~"--pretty", ~"normal"];
199 return ProcArgs {prog: config.rustc_path.to_str(), args: args};
202 fn compare_source(expected: &str, actual: &str) {
203 if expected != actual {
204 error(~"pretty-printed source does not match expected source");
208 ------------------------------------------\n\
210 ------------------------------------------\n\
212 ------------------------------------------\n\
214 ------------------------------------------\n\
217 io::stdout().write_str(msg);
222 fn typecheck_source(config: &config, props: &TestProps,
223 testfile: &Path, src: ~str) -> ProcRes {
224 let args = make_typecheck_args(config, props, testfile);
225 compose_and_run_compiler(config, props, testfile, args, Some(src))
228 fn make_typecheck_args(config: &config, props: &TestProps, testfile: &Path) -> ProcArgs {
229 let mut args = ~[~"-",
230 ~"--no-trans", ~"--lib",
231 ~"-L", config.build_base.to_str(),
233 aux_output_dir_name(config, testfile).to_str()];
234 args.push_all_move(split_maybe_args(&config.rustcflags));
235 args.push_all_move(split_maybe_args(&props.compile_flags));
236 return ProcArgs {prog: config.rustc_path.to_str(), args: args};
240 fn run_debuginfo_test(config: &config, props: &TestProps, testfile: &Path) {
241 // do not optimize debuginfo tests
242 let mut config = match config.rustcflags {
243 Some(ref flags) => config {
244 rustcflags: Some(flags.replace("-O", "")),
247 None => (*config).clone()
249 let config = &mut config;
250 let cmds = props.debugger_cmds.connect("\n");
251 let check_lines = props.check_lines.clone();
253 // compile test file (it shoud have 'compile-flags:-g' in the header)
254 let mut ProcRes = compile_test(config, props, testfile);
255 if ProcRes.status != 0 {
256 fatal_ProcRes(~"compilation failed!", &ProcRes);
259 // write debugger script
260 let script_str = cmds.append("\nquit\n");
261 debug!("script_str = %s", script_str);
262 dump_output_file(config, testfile, script_str, "debugger.script");
264 // run debugger script with gdb
266 fn debugger() -> ~str { ~"gdb.exe" }
268 fn debugger() -> ~str { ~"gdb" }
269 let debugger_script = make_out_name(config, testfile, "debugger.script");
270 let debugger_opts = ~[~"-quiet", ~"-batch", ~"-nx",
271 ~"-command=" + debugger_script.to_str(),
272 make_exe_name(config, testfile).to_str()];
273 let ProcArgs = ProcArgs {prog: debugger(), args: debugger_opts};
274 ProcRes = compose_and_run(config, testfile, ProcArgs, ~[], "", None);
275 if ProcRes.status != 0 {
276 fatal(~"gdb failed to execute");
279 let num_check_lines = check_lines.len();
280 if num_check_lines > 0 {
281 // check if each line in props.check_lines appears in the
284 for line in ProcRes.stdout.line_iter() {
285 if check_lines[i].trim() == line.trim() {
288 if i == num_check_lines {
293 if i != num_check_lines {
294 fatal_ProcRes(fmt!("line not found in debugger output: %s",
295 check_lines[i]), &ProcRes);
300 fn check_error_patterns(props: &TestProps,
303 if props.error_patterns.is_empty() {
304 fatal(~"no error pattern specified in " + testfile.to_str());
307 if ProcRes.status == 0 {
308 fatal(~"process did not return an error status");
311 let mut next_err_idx = 0u;
312 let mut next_err_pat = &props.error_patterns[next_err_idx];
313 let mut done = false;
314 for line in ProcRes.stderr.line_iter() {
315 if line.contains(*next_err_pat) {
316 debug!("found error pattern %s", *next_err_pat);
318 if next_err_idx == props.error_patterns.len() {
319 debug!("found all error patterns");
323 next_err_pat = &props.error_patterns[next_err_idx];
328 let missing_patterns =
329 props.error_patterns.slice(next_err_idx, props.error_patterns.len());
330 if missing_patterns.len() == 1u {
331 fatal_ProcRes(fmt!("error pattern '%s' not found!",
332 missing_patterns[0]), ProcRes);
334 for pattern in missing_patterns.iter() {
335 error(fmt!("error pattern '%s' not found!", *pattern));
337 fatal_ProcRes(~"multiple error patterns not found", ProcRes);
341 fn check_expected_errors(expected_errors: ~[errors::ExpectedError],
345 // true if we found the error in question
346 let mut found_flags = vec::from_elem(
347 expected_errors.len(), false);
349 if ProcRes.status == 0 {
350 fatal(~"process did not return an error status");
353 let prefixes = expected_errors.iter().transform(|ee| {
354 fmt!("%s:%u:", testfile.to_str(), ee.line)
355 }).collect::<~[~str]>();
357 fn to_lower( s : &str ) -> ~str {
359 let c : ~[char] = i.transform( |c| {
361 c.to_ascii().to_lower().to_char()
369 #[cfg(target_os = "win32")]
370 fn prefix_matches( line : &str, prefix : &str ) -> bool {
371 to_lower(line).starts_with( to_lower(prefix) )
374 #[cfg(target_os = "linux")]
375 #[cfg(target_os = "macos")]
376 #[cfg(target_os = "freebsd")]
377 fn prefix_matches( line : &str, prefix : &str ) -> bool {
378 line.starts_with( prefix )
381 // Scan and extract our error/warning messages,
383 // filename:line1:col1: line2:col2: *error:* msg
384 // filename:line1:col1: line2:col2: *warning:* msg
385 // where line1:col1: is the starting point, line2:col2:
386 // is the ending point, and * represents ANSI color codes.
387 for line in ProcRes.stderr.line_iter() {
388 let mut was_expected = false;
389 for (i, ee) in expected_errors.iter().enumerate() {
391 debug!("prefix=%s ee.kind=%s ee.msg=%s line=%s",
392 prefixes[i], ee.kind, ee.msg, line);
393 if (prefix_matches(line, prefixes[i]) &&
394 line.contains(ee.kind) &&
395 line.contains(ee.msg)) {
396 found_flags[i] = true;
403 // ignore this msg which gets printed at the end
404 if line.contains("aborting due to") {
408 if !was_expected && is_compiler_error_or_warning(line) {
409 fatal_ProcRes(fmt!("unexpected compiler error or warning: '%s'",
415 for (i, &flag) in found_flags.iter().enumerate() {
417 let ee = &expected_errors[i];
418 fatal_ProcRes(fmt!("expected %s on line %u not found: %s",
419 ee.kind, ee.line, ee.msg), ProcRes);
424 fn is_compiler_error_or_warning(line: &str) -> bool {
427 scan_until_char(line, ':', &mut i) &&
428 scan_char(line, ':', &mut i) &&
429 scan_integer(line, &mut i) &&
430 scan_char(line, ':', &mut i) &&
431 scan_integer(line, &mut i) &&
432 scan_char(line, ':', &mut i) &&
433 scan_char(line, ' ', &mut i) &&
434 scan_integer(line, &mut i) &&
435 scan_char(line, ':', &mut i) &&
436 scan_integer(line, &mut i) &&
437 scan_char(line, ' ', &mut i) &&
438 (scan_string(line, "error", &mut i) ||
439 scan_string(line, "warning", &mut i));
442 fn scan_until_char(haystack: &str, needle: char, idx: &mut uint) -> bool {
443 if *idx >= haystack.len() {
446 let opt = haystack.slice_from(*idx).find(needle);
454 fn scan_char(haystack: &str, needle: char, idx: &mut uint) -> bool {
455 if *idx >= haystack.len() {
458 let range = haystack.char_range_at(*idx);
459 if range.ch != needle {
466 fn scan_integer(haystack: &str, idx: &mut uint) -> bool {
468 while i < haystack.len() {
469 let range = haystack.char_range_at(i);
470 if range.ch < '0' || '9' < range.ch {
482 fn scan_string(haystack: &str, needle: &str, idx: &mut uint) -> bool {
483 let mut haystack_i = *idx;
484 let mut needle_i = 0u;
485 while needle_i < needle.len() {
486 if haystack_i >= haystack.len() {
489 let range = haystack.char_range_at(haystack_i);
490 haystack_i = range.next;
491 if !scan_char(needle, range.ch, &mut needle_i) {
499 struct ProcArgs {prog: ~str, args: ~[~str]}
501 struct ProcRes {status: int, stdout: ~str, stderr: ~str, cmdline: ~str}
503 fn compile_test(config: &config, props: &TestProps,
504 testfile: &Path) -> ProcRes {
505 compile_test_(config, props, testfile, [])
508 fn jit_test(config: &config, props: &TestProps, testfile: &Path) -> ProcRes {
509 compile_test_(config, props, testfile, [~"--jit"])
512 fn compile_test_(config: &config, props: &TestProps,
513 testfile: &Path, extra_args: &[~str]) -> ProcRes {
514 let link_args = ~[~"-L", aux_output_dir_name(config, testfile).to_str()];
515 let args = make_compile_args(config, props, link_args + extra_args,
516 make_exe_name, testfile);
517 compose_and_run_compiler(config, props, testfile, args, None)
520 fn exec_compiled_test(config: &config, props: &TestProps,
521 testfile: &Path) -> ProcRes {
523 // If testing the new runtime then set the RUST_NEWRT env var
524 let env = props.exec_env.clone();
525 let env = if config.newrt { env + &[(~"RUST_NEWRT", ~"1")] } else { env };
527 match config.target {
529 ~"arm-linux-androideabi" => {
530 if (config.adb_device_status) {
531 _arm_exec_compiled_test(config, props, testfile)
533 _dummy_exec_compiled_test(config, props, testfile)
538 compose_and_run(config, testfile,
539 make_run_args(config, props, testfile),
541 config.run_lib_path, None)
546 fn compose_and_run_compiler(
551 input: Option<~str>) -> ProcRes {
553 if !props.aux_builds.is_empty() {
554 ensure_dir(&aux_output_dir_name(config, testfile));
557 let extra_link_args = ~[~"-L",
558 aux_output_dir_name(config, testfile).to_str()];
560 for rel_ab in props.aux_builds.iter() {
561 let abs_ab = config.aux_base.push_rel(&Path(*rel_ab));
563 make_compile_args(config, props, ~[~"--lib"] + extra_link_args,
564 |a,b| make_lib_name(a, b, testfile), &abs_ab);
565 let auxres = compose_and_run(config, &abs_ab, aux_args, ~[],
566 config.compile_lib_path, None);
567 if auxres.status != 0 {
569 fmt!("auxiliary build of %s failed to compile: ",
574 match config.target {
576 ~"arm-linux-androideabi" => {
577 if (config.adb_device_status) {
578 _arm_push_aux_shared_library(config, testfile);
586 compose_and_run(config, testfile, args, ~[],
587 config.compile_lib_path, input)
590 fn ensure_dir(path: &Path) {
591 if os::path_is_dir(path) { return; }
592 if !os::make_dir(path, 0x1c0i32) {
593 fail!("can't make dir %s", path.to_str());
597 fn compose_and_run(config: &config, testfile: &Path,
598 ProcArgs{ args, prog }: ProcArgs,
599 procenv: ~[(~str, ~str)],
601 input: Option<~str>) -> ProcRes {
602 return program_output(config, testfile, lib_path,
603 prog, args, procenv, input);
606 fn make_compile_args(config: &config, props: &TestProps, extras: ~[~str],
607 xform: &fn(&config, (&Path)) -> Path,
608 testfile: &Path) -> ProcArgs {
609 let mut args = ~[testfile.to_str(),
610 ~"-o", xform(config, testfile).to_str(),
611 ~"-L", config.build_base.to_str()]
613 args.push_all_move(split_maybe_args(&config.rustcflags));
614 args.push_all_move(split_maybe_args(&props.compile_flags));
615 return ProcArgs {prog: config.rustc_path.to_str(), args: args};
618 fn make_lib_name(config: &config, auxfile: &Path, testfile: &Path) -> Path {
619 // what we return here is not particularly important, as it
620 // happens; rustc ignores everything except for the directory.
621 let auxname = output_testname(auxfile);
622 aux_output_dir_name(config, testfile).push_rel(&auxname)
625 fn make_exe_name(config: &config, testfile: &Path) -> Path {
626 Path(output_base_name(config, testfile).to_str() + os::EXE_SUFFIX)
629 fn make_run_args(config: &config, _props: &TestProps, testfile: &Path) ->
631 // If we've got another tool to run under (valgrind),
632 // then split apart its command
633 let mut args = split_maybe_args(&config.runtool);
634 args.push(make_exe_name(config, testfile).to_str());
635 let prog = args.shift();
636 return ProcArgs {prog: prog, args: args};
639 fn split_maybe_args(argstr: &Option<~str>) -> ~[~str] {
643 .filter_map(|s| if s.is_whitespace() {None} else {Some(s.to_owned())})
650 fn program_output(config: &config, testfile: &Path, lib_path: &str, prog: ~str,
651 args: ~[~str], env: ~[(~str, ~str)],
652 input: Option<~str>) -> ProcRes {
655 let cmdline = make_cmdline(lib_path, prog, args);
656 logv(config, fmt!("executing %s", cmdline));
659 let procsrv::Result{ out, err, status } =
660 procsrv::run(lib_path, prog, args, env, input);
661 dump_output(config, testfile, out, err);
662 return ProcRes {status: status,
668 // Linux and mac don't require adjusting the library search path
669 #[cfg(target_os = "linux")]
670 #[cfg(target_os = "macos")]
671 #[cfg(target_os = "freebsd")]
672 fn make_cmdline(_libpath: &str, prog: &str, args: &[~str]) -> ~str {
673 fmt!("%s %s", prog, args.connect(" "))
676 #[cfg(target_os = "win32")]
677 fn make_cmdline(libpath: &str, prog: &str, args: &[~str]) -> ~str {
678 fmt!("%s %s %s", lib_path_cmd_prefix(libpath), prog,
682 // Build the LD_LIBRARY_PATH variable as it would be seen on the command line
683 // for diagnostic purposes
684 fn lib_path_cmd_prefix(path: &str) -> ~str {
685 fmt!("%s=\"%s\"", util::lib_path_env_var(), util::make_new_path(path))
688 fn dump_output(config: &config, testfile: &Path, out: &str, err: &str) {
689 dump_output_file(config, testfile, out, "out");
690 dump_output_file(config, testfile, err, "err");
691 maybe_dump_to_stdout(config, out, err);
694 fn dump_output_file(config: &config, testfile: &Path,
695 out: &str, extension: &str) {
696 let outfile = make_out_name(config, testfile, extension);
698 io::file_writer(&outfile, [io::Create, io::Truncate]).unwrap();
699 writer.write_str(out);
702 fn make_out_name(config: &config, testfile: &Path, extension: &str) -> Path {
703 output_base_name(config, testfile).with_filetype(extension)
706 fn aux_output_dir_name(config: &config, testfile: &Path) -> Path {
707 Path(output_base_name(config, testfile).to_str() + ".libaux")
710 fn output_testname(testfile: &Path) -> Path {
711 Path(testfile.filestem().unwrap())
714 fn output_base_name(config: &config, testfile: &Path) -> Path {
716 .push_rel(&output_testname(testfile))
717 .with_filetype(config.stage_id)
720 fn maybe_dump_to_stdout(config: &config, out: &str, err: &str) {
722 let sep1 = fmt!("------%s------------------------------", "stdout");
723 let sep2 = fmt!("------%s------------------------------", "stderr");
724 let sep3 = ~"------------------------------------------";
725 io::stdout().write_line(sep1);
726 io::stdout().write_line(out);
727 io::stdout().write_line(sep2);
728 io::stdout().write_line(err);
729 io::stdout().write_line(sep3);
733 fn error(err: ~str) { io::stdout().write_line(fmt!("\nerror: %s", err)); }
735 fn fatal(err: ~str) -> ! { error(err); fail!(); }
737 fn fatal_ProcRes(err: ~str, ProcRes: &ProcRes) -> ! {
743 ------------------------------------------\n\
745 ------------------------------------------\n\
747 ------------------------------------------\n\
749 ------------------------------------------\n\
751 err, ProcRes.cmdline, ProcRes.stdout, ProcRes.stderr);
752 io::stdout().write_str(msg);
756 fn _arm_exec_compiled_test(config: &config, props: &TestProps,
757 testfile: &Path) -> ProcRes {
759 let args = make_run_args(config, props, testfile);
760 let cmdline = make_cmdline("", args.prog, args.args);
762 // get bare program string
763 let mut tvec: ~[~str] = args.prog.split_iter('/').transform(|ts| ts.to_owned()).collect();
764 let prog_short = tvec.pop();
767 let copy_result = procsrv::run("", config.adb_path,
768 [~"push", args.prog.clone(), config.adb_test_dir.clone()],
769 ~[(~"",~"")], Some(~""));
772 io::stdout().write_str(fmt!("push (%s) %s %s %s",
773 config.target, args.prog,
774 copy_result.out, copy_result.err));
777 logv(config, fmt!("executing (%s) %s", config.target, cmdline));
779 let mut runargs = ~[];
781 // run test via adb_run_wrapper
782 runargs.push(~"shell");
783 runargs.push(fmt!("%s/adb_run_wrapper.sh", config.adb_test_dir));
784 runargs.push(fmt!("%s", config.adb_test_dir));
785 runargs.push(fmt!("%s", prog_short));
787 for tv in args.args.iter() {
788 runargs.push(tv.to_owned());
791 procsrv::run("", config.adb_path, runargs, ~[(~"",~"")], Some(~""));
793 // get exitcode of result
795 runargs.push(~"shell");
796 runargs.push(~"cat");
797 runargs.push(fmt!("%s/%s.exitcode", config.adb_test_dir, prog_short));
799 let procsrv::Result{ out: exitcode_out, err: _, status: _ } =
800 procsrv::run("", config.adb_path, runargs, ~[(~"",~"")],
803 let mut exitcode : int = 0;
804 for c in exitcode_out.iter() {
805 if !c.is_digit() { break; }
806 exitcode = exitcode * 10 + match c {
807 '0' .. '9' => c as int - ('0' as int),
812 // get stdout of result
814 runargs.push(~"shell");
815 runargs.push(~"cat");
816 runargs.push(fmt!("%s/%s.stdout", config.adb_test_dir, prog_short));
818 let procsrv::Result{ out: stdout_out, err: _, status: _ } =
819 procsrv::run("", config.adb_path, runargs, ~[(~"",~"")], Some(~""));
821 // get stderr of result
823 runargs.push(~"shell");
824 runargs.push(~"cat");
825 runargs.push(fmt!("%s/%s.stderr", config.adb_test_dir, prog_short));
827 let procsrv::Result{ out: stderr_out, err: _, status: _ } =
828 procsrv::run("", config.adb_path, runargs, ~[(~"",~"")], Some(~""));
830 dump_output(config, testfile, stdout_out, stderr_out);
832 ProcRes {status: exitcode, stdout: stdout_out, stderr: stderr_out, cmdline: cmdline }
835 fn _dummy_exec_compiled_test(config: &config, props: &TestProps,
836 testfile: &Path) -> ProcRes {
838 let args = make_run_args(config, props, testfile);
839 let cmdline = make_cmdline("", args.prog, args.args);
842 mode_run_fail => ProcRes {status: 101, stdout: ~"",
843 stderr: ~"", cmdline: cmdline},
844 _ => ProcRes {status: 0, stdout: ~"",
845 stderr: ~"", cmdline: cmdline}
849 fn _arm_push_aux_shared_library(config: &config, testfile: &Path) {
850 let tstr = aux_output_dir_name(config, testfile).to_str();
852 let dirs = os::list_dir_path(&Path(tstr));
853 for file in dirs.iter() {
855 if (file.filetype() == Some(~".so")) {
857 let copy_result = procsrv::run("", config.adb_path,
858 [~"push", file.to_str(), config.adb_test_dir.clone()],
859 ~[(~"",~"")], Some(~""));
862 io::stdout().write_str(fmt!("push (%s) %s %s %s",
863 config.target, file.to_str(),
864 copy_result.out, copy_result.err));
870 // codegen tests (vs. clang)
872 fn make_o_name(config: &config, testfile: &Path) -> Path {
873 output_base_name(config, testfile).with_filetype("o")
876 fn append_suffix_to_stem(p: &Path, suffix: &str) -> Path {
877 if suffix.len() == 0 {
880 let stem = p.filestem().unwrap();
881 p.with_filestem(stem + "-" + suffix)
885 fn compile_test_and_save_bitcode(config: &config, props: &TestProps,
886 testfile: &Path) -> ProcRes {
887 let link_args = ~[~"-L", aux_output_dir_name(config, testfile).to_str()];
888 let llvm_args = ~[~"-c", ~"--lib", ~"--save-temps"];
889 let args = make_compile_args(config, props,
890 link_args + llvm_args,
891 make_o_name, testfile);
892 compose_and_run_compiler(config, props, testfile, args, None)
895 fn compile_cc_with_clang_and_save_bitcode(config: &config, _props: &TestProps,
896 testfile: &Path) -> ProcRes {
897 let bitcodefile = output_base_name(config, testfile).with_filetype("bc");
898 let bitcodefile = append_suffix_to_stem(&bitcodefile, "clang");
899 let ProcArgs = ProcArgs {
900 prog: config.clang_path.get_ref().to_str(),
903 ~"-o", bitcodefile.to_str(),
904 testfile.with_filetype("cc").to_str() ]
906 compose_and_run(config, testfile, ProcArgs, ~[], "", None)
909 fn extract_function_from_bitcode(config: &config, _props: &TestProps,
910 fname: &str, testfile: &Path,
911 suffix: &str) -> ProcRes {
912 let bitcodefile = output_base_name(config, testfile).with_filetype("bc");
913 let bitcodefile = append_suffix_to_stem(&bitcodefile, suffix);
914 let extracted_bc = append_suffix_to_stem(&bitcodefile, "extract");
915 let ProcArgs = ProcArgs {
916 prog: config.llvm_bin_path.get_ref().push("llvm-extract").to_str(),
917 args: ~[~"-func=" + fname,
918 ~"-o=" + extracted_bc.to_str(),
919 bitcodefile.to_str() ]
921 compose_and_run(config, testfile, ProcArgs, ~[], "", None)
924 fn disassemble_extract(config: &config, _props: &TestProps,
925 testfile: &Path, suffix: &str) -> ProcRes {
926 let bitcodefile = output_base_name(config, testfile).with_filetype("bc");
927 let bitcodefile = append_suffix_to_stem(&bitcodefile, suffix);
928 let extracted_bc = append_suffix_to_stem(&bitcodefile, "extract");
929 let extracted_ll = extracted_bc.with_filetype("ll");
930 let ProcArgs = ProcArgs {
931 prog: config.llvm_bin_path.get_ref().push("llvm-dis").to_str(),
932 args: ~[~"-o=" + extracted_ll.to_str(),
933 extracted_bc.to_str() ]
935 compose_and_run(config, testfile, ProcArgs, ~[], "", None)
939 fn count_extracted_lines(p: &Path) -> uint {
940 let x = io::read_whole_file_str(&p.with_filetype("ll")).unwrap();
945 fn run_codegen_test(config: &config, props: &TestProps,
946 testfile: &Path, mm: &mut MetricMap) {
948 if config.llvm_bin_path.is_none() {
949 fatal(~"missing --llvm-bin-path");
952 if config.clang_path.is_none() {
953 fatal(~"missing --clang-path");
956 let mut ProcRes = compile_test_and_save_bitcode(config, props, testfile);
957 if ProcRes.status != 0 {
958 fatal_ProcRes(~"compilation failed!", &ProcRes);
961 ProcRes = extract_function_from_bitcode(config, props, "test", testfile, "");
962 if ProcRes.status != 0 {
963 fatal_ProcRes(~"extracting 'test' function failed", &ProcRes);
966 ProcRes = disassemble_extract(config, props, testfile, "");
967 if ProcRes.status != 0 {
968 fatal_ProcRes(~"disassembling extract failed", &ProcRes);
972 let mut ProcRes = compile_cc_with_clang_and_save_bitcode(config, props, testfile);
973 if ProcRes.status != 0 {
974 fatal_ProcRes(~"compilation failed!", &ProcRes);
977 ProcRes = extract_function_from_bitcode(config, props, "test", testfile, "clang");
978 if ProcRes.status != 0 {
979 fatal_ProcRes(~"extracting 'test' function failed", &ProcRes);
982 ProcRes = disassemble_extract(config, props, testfile, "clang");
983 if ProcRes.status != 0 {
984 fatal_ProcRes(~"disassembling extract failed", &ProcRes);
987 let base = output_base_name(config, testfile);
988 let base_extract = append_suffix_to_stem(&base, "extract");
990 let base_clang = append_suffix_to_stem(&base, "clang");
991 let base_clang_extract = append_suffix_to_stem(&base_clang, "extract");
993 let base_lines = count_extracted_lines(&base_extract);
994 let clang_lines = count_extracted_lines(&base_clang_extract);
996 mm.insert_metric("clang-codegen-ratio",
997 (base_lines as f64) / (clang_lines as f64),