From dfc548dddafbf4e58a568329ebbe29f1eb36a0e8 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 13 Apr 2012 09:19:07 -0700 Subject: [PATCH] add option exec-env to set env variables during test execution --- src/compiletest/header.rs | 24 ++++++++++++++++-- src/compiletest/procsrv.rs | 18 ++++++++------ src/compiletest/runtest.rs | 47 +++++++++++++++++++---------------- src/libcore/run.rs | 8 +++--- src/test/run-pass/exec-env.rs | 6 +++++ 5 files changed, 69 insertions(+), 34 deletions(-) create mode 100644 src/test/run-pass/exec-env.rs diff --git a/src/compiletest/header.rs b/src/compiletest/header.rs index 75f4eb98050..0db9672f50d 100644 --- a/src/compiletest/header.rs +++ b/src/compiletest/header.rs @@ -17,13 +17,16 @@ type test_props = { // pretty-printed pp_exact: option, // Modules from aux directory that should be compiled - aux_builds: [str] + aux_builds: [str], + // Environment settings to use during execution + exec_env: [(str,str)] }; // Load any test directives embedded in the file fn load_props(testfile: str) -> test_props { let mut error_patterns = []; let mut aux_builds = []; + let mut exec_env = []; let mut compile_flags = option::none; let mut pp_exact = option::none; iter_header(testfile) {|ln| @@ -43,12 +46,17 @@ fn load_props(testfile: str) -> test_props { option::iter(parse_aux_build(ln)) {|ab| aux_builds += [ab]; } + + option::iter(parse_exec_env(ln)) {|ee| + exec_env += [ee]; + } }; ret { error_patterns: error_patterns, compile_flags: compile_flags, pp_exact: pp_exact, - aux_builds: aux_builds + aux_builds: aux_builds, + exec_env: exec_env }; } @@ -97,6 +105,18 @@ fn parse_compile_flags(line: str) -> option { parse_name_value_directive(line, "compile-flags") } +fn parse_exec_env(line: str) -> option<(str, str)> { + parse_name_value_directive(line, "exec-env").map {|nv| + // nv is either FOO or FOO=BAR + let strs = str::splitn_char(nv, '=', 1u); + alt strs.len() { + 1u { (strs[0], "") } + 2u { (strs[0], strs[1]) } + n { fail #fmt["Expected 1 or 2 strings, not %u", n]; } + } + } +} + fn parse_pp_exact(line: str, testfile: str) -> option { alt parse_name_value_directive(line, "pp-exact") { option::some(s) { option::some(s) } diff --git a/src/compiletest/procsrv.rs b/src/compiletest/procsrv.rs index d9a27b405de..dc7a3f384cc 100644 --- a/src/compiletest/procsrv.rs +++ b/src/compiletest/procsrv.rs @@ -5,7 +5,7 @@ import libc::{c_int, pid_t}; export run; #[cfg(target_os = "win32")] -fn target_env(lib_path: str, prog: str) -> option<[(str,str)]> { +fn target_env(lib_path: str, prog: str) -> [(str,str)] { let env = os::env(); @@ -17,25 +17,29 @@ fn target_env(lib_path: str, prog: str) -> option<[(str,str)]> { if str::ends_with(prog, "rustc.exe") { env += [("RUST_THREADS", "1")] } - ret some(env); + ret env; } #[cfg(target_os = "linux")] #[cfg(target_os = "macos")] #[cfg(target_os = "freebsd")] -fn target_env(_lib_path: str, _prog: str) -> option<[(str,str)]> { - none +fn target_env(_lib_path: str, _prog: str) -> [(str,str)] { + [] } -fn run(lib_path: str, prog: str, args: [str], +fn run(lib_path: str, + prog: str, + args: [str], + env: [(str, str)], input: option) -> {status: int, out: str, err: str} { let pipe_in = os::pipe(); let pipe_out = os::pipe(); let pipe_err = os::pipe(); - let pid = spawn_process(prog, args, target_env(lib_path, prog), none, - pipe_in.in, pipe_out.out, pipe_err.out); + let pid = spawn_process(prog, args, + some(env + target_env(lib_path, prog)), + none, pipe_in.in, pipe_out.out, pipe_err.out); os::close(pipe_in.in); os::close(pipe_out.out); diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index 390facbec3d..b86cd334c79 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -81,7 +81,6 @@ fn run_rpass_test(config: config, props: test_props, testfile: str) { procres = exec_compiled_test(config, props, testfile); - if procres.status != 0 { fatal_procres("test run failed!", procres); } } @@ -139,8 +138,8 @@ fn run_pretty_test(config: config, props: test_props, testfile: str) { ret; fn print_source(config: config, testfile: str, src: str) -> procres { - compose_and_run(config, testfile, make_pp_args, - config.compile_lib_path, option::some(src)) + compose_and_run(config, testfile, make_pp_args(config, testfile), + [], config.compile_lib_path, option::some(src)) } fn make_pp_args(config: config, _testfile: str) -> procargs { @@ -172,7 +171,9 @@ actual:\n\ fn typecheck_source(config: config, props: test_props, testfile: str, src: str) -> procres { compose_and_run_compiler( - config, props, testfile, make_typecheck_args, option::some(src)) + config, props, testfile, + make_typecheck_args(config, testfile), + option::some(src)) } fn make_typecheck_args(config: config, testfile: str) -> procargs { @@ -292,24 +293,26 @@ type procres = {status: int, stdout: str, stderr: str, cmdline: str}; fn compile_test(config: config, props: test_props, testfile: str) -> procres { let link_args = ["-L", aux_output_dir_name(config, testfile)]; - compose_and_run_compiler(config, props, testfile, - make_compile_args(_, props, link_args, - make_exe_name, _), - none) + compose_and_run_compiler( + config, props, testfile, + make_compile_args(config, props, link_args, + make_exe_name, testfile), + none) } fn exec_compiled_test(config: config, props: test_props, testfile: str) -> procres { compose_and_run(config, testfile, - bind make_run_args(_, props, _), - config.run_lib_path, option::none) + make_run_args(config, props, testfile), + props.exec_env, + config.run_lib_path, option::none) } fn compose_and_run_compiler( config: config, props: test_props, testfile: str, - mk_args: fn(config: config, _testfile: str) -> procargs, + args: procargs, input: option) -> procres { if props.aux_builds.is_not_empty() { @@ -320,10 +323,10 @@ fn compose_and_run_compiler( vec::iter(props.aux_builds) {|rel_ab| let abs_ab = path::connect(config.aux_base, rel_ab); - let mk_compile_args = - make_compile_args(_, props, ["--lib"] + extra_link_args, - bind make_lib_name(_, _, testfile), _); - let auxres = compose_and_run(config, abs_ab, mk_compile_args, + let aux_args = + make_compile_args(config, props, ["--lib"] + extra_link_args, + bind make_lib_name(_, _, testfile), abs_ab); + let auxres = compose_and_run(config, abs_ab, aux_args, [], config.compile_lib_path, option::none); if auxres.status != 0 { fatal_procres( @@ -332,7 +335,7 @@ fn compose_and_run_compiler( } } - compose_and_run(config, testfile, mk_args, + compose_and_run(config, testfile, args, [], config.compile_lib_path, input) } @@ -344,11 +347,12 @@ fn ensure_dir(path: path) { } fn compose_and_run(config: config, testfile: str, - make_args: fn(config, str) -> procargs, lib_path: str, + procargs: procargs, + procenv: [(str, str)], + lib_path: str, input: option) -> procres { - let procargs = make_args(config, testfile); ret program_output(config, testfile, lib_path, - procargs.prog, procargs.args, input); + procargs.prog, procargs.args, procenv, input); } fn make_compile_args(config: config, props: test_props, extras: [str], @@ -405,14 +409,15 @@ fn split_maybe_args(argstr: option) -> [str] { } fn program_output(config: config, testfile: str, lib_path: str, prog: str, - args: [str], input: option) -> procres { + args: [str], env: [(str, str)], + input: option) -> procres { let cmdline = { let cmdline = make_cmdline(lib_path, prog, args); logv(config, #fmt["executing %s", cmdline]); cmdline }; - let res = procsrv::run(lib_path, prog, args, input); + let res = procsrv::run(lib_path, prog, args, env, input); dump_output(config, testfile, res.out, res.err); ret {status: res.status, stdout: res.out, diff --git a/src/libcore/run.rs b/src/libcore/run.rs index 0b82d79b331..34ba16844d8 100644 --- a/src/libcore/run.rs +++ b/src/libcore/run.rs @@ -98,7 +98,7 @@ fn with_envp(env: option<[(str,str)]>, // On posixy systems we can pass a char** for envp, which is // a null-terminated array of "k=v\n" strings. alt env { - some (es) { + some(es) if !vec::is_empty(es) { let mut tmps = []; let mut ptrs = []; @@ -111,7 +111,7 @@ fn with_envp(env: option<[(str,str)]>, ptrs += [ptr::null()]; vec::as_buf(ptrs) { |p| cb(::unsafe::reinterpret_cast(p)) } } - none { + _ { cb(ptr::null()) } } @@ -124,7 +124,7 @@ fn with_envp(env: option<[(str,str)]>, // rather a concatenation of null-terminated k=v\0 sequences, with a final // \0 to terminate. alt env { - some (es) { + some(es) if !vec::is_empty(es) { let mut blk : [u8] = []; for vec::each(es) {|e| let (k,v) = e; @@ -136,7 +136,7 @@ fn with_envp(env: option<[(str,str)]>, blk += [0_u8]; vec::as_buf(blk) {|p| cb(::unsafe::reinterpret_cast(p)) } } - none { + _ { cb(ptr::null()) } } diff --git a/src/test/run-pass/exec-env.rs b/src/test/run-pass/exec-env.rs new file mode 100644 index 00000000000..cddcd4987e5 --- /dev/null +++ b/src/test/run-pass/exec-env.rs @@ -0,0 +1,6 @@ +// xfail-fast (exec-env not supported in fast mode) +// exec-env:TEST_EXEC_ENV=22 + +fn main() { + assert os::getenv("TEST_EXEC_ENV") == some("22"); +}