Convert compiletest to istrs. Issue #855

This commit is contained in:
Brian Anderson 2011-08-30 15:40:25 -07:00 committed by Brian Anderson
parent eb70267e5e
commit 4007006574
5 changed files with 249 additions and 214 deletions

View file

@ -23,14 +23,13 @@ import common::mode;
import util::logv;
fn main(args: [str]) {
let args = istr::from_estrs(args);
let config = parse_config(args);
log_config(config);
run_tests(config);
}
fn parse_config(args: &[str]) -> config {
let args = istr::from_estrs(args);
fn parse_config(args: &[istr]) -> config {
let opts =
[getopts::reqopt(~"compile-lib-path"),
getopts::reqopt(~"run-lib-path"),
@ -60,7 +59,7 @@ fn parse_config(args: &[str]) -> config {
src_base: getopts::opt_str(match, ~"src-base"),
build_base: getopts::opt_str(match, ~"build-base"),
stage_id: getopts::opt_str(match, ~"stage-id"),
mode: str_mode(istr::to_estr(getopts::opt_str(match, ~"mode"))),
mode: str_mode(getopts::opt_str(match, ~"mode")),
run_ignored: getopts::opt_present(match, ~"ignored"),
filter:
if vec::len(match.free) > 0u {
@ -73,27 +72,40 @@ fn parse_config(args: &[str]) -> config {
fn log_config(config: &config) {
let c = config;
logv(c, #fmt["configuration:"]);
logv(c, #fmt["compile_lib_path: %s",
istr::to_estr(config.compile_lib_path)]);
logv(c, #fmt["run_lib_path: %s", istr::to_estr(config.run_lib_path)]);
logv(c, #fmt["rustc_path: %s", istr::to_estr(config.rustc_path)]);
logv(c, #fmt["src_base: %s", istr::to_estr(config.src_base)]);
logv(c, #fmt["build_base: %s", istr::to_estr(config.build_base)]);
logv(c, #fmt["stage_id: %s", istr::to_estr(config.stage_id)]);
logv(c, #fmt["mode: %s", mode_str(config.mode)]);
logv(c, #fmt["run_ignored: %b", config.run_ignored]);
logv(c, #fmt["filter: %s", opt_str(config.filter)]);
logv(c, #fmt["runtool: %s", opt_str(config.runtool)]);
logv(c, #fmt["rustcflags: %s", opt_str(config.rustcflags)]);
logv(c, #fmt["verbose: %b", config.verbose]);
logv(c, #fmt["\n"]);
logv(c, istr::from_estr(
#fmt["configuration:"]));
logv(c, istr::from_estr(
#fmt["compile_lib_path: %s",
istr::to_estr(config.compile_lib_path)]));
logv(c, istr::from_estr(
#fmt["run_lib_path: %s", istr::to_estr(config.run_lib_path)]));
logv(c, istr::from_estr(
#fmt["rustc_path: %s", istr::to_estr(config.rustc_path)]));
logv(c, istr::from_estr(
#fmt["src_base: %s", istr::to_estr(config.src_base)]));
logv(c, istr::from_estr(
#fmt["build_base: %s", istr::to_estr(config.build_base)]));
logv(c, istr::from_estr(
#fmt["stage_id: %s", istr::to_estr(config.stage_id)]));
logv(c, istr::from_estr(
#fmt["mode: %s", istr::to_estr(mode_str(config.mode))]));
logv(c, istr::from_estr(
#fmt["run_ignored: %b", config.run_ignored]));
logv(c, istr::from_estr(
#fmt["filter: %s", istr::to_estr(opt_str(config.filter))]));
logv(c, istr::from_estr(
#fmt["runtool: %s", istr::to_estr(opt_str(config.runtool))]));
logv(c, istr::from_estr(
#fmt["rustcflags: %s", istr::to_estr(opt_str(config.rustcflags))]));
logv(c, istr::from_estr(
#fmt["verbose: %b", config.verbose]));
logv(c, istr::from_estr(#fmt["\n"]));
}
fn opt_str(maybestr: option::t<istr>) -> str {
fn opt_str(maybestr: option::t<istr>) -> istr {
alt maybestr {
option::some(s) { istr::to_estr(s) }
option::none. { "(none)" }
option::some(s) { s }
option::none. { ~"(none)" }
}
}
@ -101,8 +113,8 @@ fn str_opt(maybestr: &istr) -> option::t<istr> {
if maybestr != ~"(none)" { option::some(maybestr) } else { option::none }
}
fn str_mode(s: str) -> mode {
alt s {
fn str_mode(s: &istr) -> mode {
alt istr::to_estr(s) {
"compile-fail" { mode_compile_fail }
"run-fail" { mode_run_fail }
"run-pass" { mode_run_pass }
@ -111,12 +123,12 @@ fn str_mode(s: str) -> mode {
}
}
fn mode_str(mode: mode) -> str {
fn mode_str(mode: mode) -> istr {
alt mode {
mode_compile_fail. { "compile-fail" }
mode_run_fail. { "run-fail" }
mode_run_pass. { "run-pass" }
mode_pretty. { "pretty" }
mode_compile_fail. { ~"compile-fail" }
mode_run_fail. { ~"run-fail" }
mode_run_pass. { ~"run-pass" }
mode_pretty. { ~"pretty" }
}
}
@ -146,8 +158,7 @@ fn make_tests(cx: &cx) -> tests_and_conv_fn {
let configport = port::<[u8]>();
let tests = [];
for file: istr in fs::list_dir(cx.config.src_base) {
let file = istr::to_estr(file);
log #fmt["inspecting file %s", file];
log #fmt["inspecting file %s", istr::to_estr(file)];
if is_test(cx.config, file) {
tests += [make_test(cx, file, configport)];
}
@ -155,14 +166,14 @@ fn make_tests(cx: &cx) -> tests_and_conv_fn {
ret {tests: tests, to_task: bind closure_to_task(cx, configport, _)};
}
fn is_test(config: &config, testfile: &str) -> bool {
fn is_test(config: &config, testfile: &istr) -> bool {
// Pretty-printer does not work with .rc files yet
let valid_extensions = alt config.mode {
mode_pretty. { [~".rs"] }
_ { [~".rc", ~".rs"] }
};
let invalid_prefixes = [~".", ~"#", ~"~"];
let name = fs::basename(istr::from_estr(testfile));
let name = fs::basename(testfile);
let valid = false;
@ -177,15 +188,17 @@ fn is_test(config: &config, testfile: &str) -> bool {
ret valid;
}
fn make_test(cx: &cx, testfile: &str, configport: &port<[u8]>) ->
fn make_test(cx: &cx, testfile: &istr, configport: &port<[u8]>) ->
test::test_desc {
{name: make_test_name(cx.config, testfile),
fn: make_test_closure(testfile, chan(configport)),
ignore: header::is_test_ignored(cx.config, testfile)}
}
fn make_test_name(config: &config, testfile: &str) -> str {
#fmt["[%s] %s", mode_str(config.mode), testfile]
fn make_test_name(config: &config, testfile: &istr) -> str {
#fmt["[%s] %s",
istr::to_estr(mode_str(config.mode)),
istr::to_estr(testfile)]
}
/*
@ -207,13 +220,13 @@ up. Then we'll spawn that data into another task and return the task.
Really convoluted. Need to think up of a better definition for tests.
*/
fn make_test_closure(testfile: &str, configchan: chan<[u8]>) ->
fn make_test_closure(testfile: &istr, configchan: chan<[u8]>) ->
test::test_fn {
bind send_config(testfile, configchan)
}
fn send_config(testfile: str, configchan: chan<[u8]>) {
send(configchan, str::bytes(testfile));
fn send_config(testfile: istr, configchan: chan<[u8]>) {
send(configchan, istr::bytes(testfile));
}
/*
@ -237,11 +250,11 @@ fn closure_to_task(cx: cx, configport: port<[u8]>, testfn: &fn()) ->
let src_base = cx.config.src_base;
let build_base = cx.config.build_base;
let stage_id = cx.config.stage_id;
let mode = istr::from_estr(mode_str(cx.config.mode));
let mode = mode_str(cx.config.mode);
let run_ignored = cx.config.run_ignored;
let filter = istr::from_estr(opt_str(cx.config.filter));
let runtool = istr::from_estr(opt_str(cx.config.runtool));
let rustcflags = istr::from_estr(opt_str(cx.config.rustcflags));
let filter = opt_str(cx.config.filter);
let runtool = opt_str(cx.config.runtool);
let rustcflags = opt_str(cx.config.rustcflags);
let verbose = cx.config.verbose;
let chan = cx.procsrv.chan;
@ -277,7 +290,7 @@ fn run_test_task(compile_lib_path: -istr, run_lib_path: -istr,
src_base: src_base,
build_base: build_base,
stage_id: stage_id,
mode: str_mode(istr::to_estr(mode)),
mode: str_mode(mode),
run_ignored: run_ignored,
filter: str_opt(opt_filter),
runtool: str_opt(opt_runtool),

View file

@ -12,24 +12,24 @@ export is_test_ignored;
type test_props = {
// Lines that should be expected, in order, on standard out
error_patterns: [str],
error_patterns: [istr],
// Extra flags to pass to the compiler
compile_flags: option::t<str>,
compile_flags: option::t<istr>,
// If present, the name of a file that this test should match when
// pretty-printed
pp_exact: option::t<str>,
pp_exact: option::t<istr>,
// FIXME: no-valgrind is a temporary directive until all of run-fail
// is valgrind-clean
no_valgrind: bool
};
// Load any test directives embedded in the file
fn load_props(testfile: &str) -> test_props {
fn load_props(testfile: &istr) -> test_props {
let error_patterns = [];
let compile_flags = option::none;
let pp_exact = option::none;
let no_valgrind = false;
for each ln: str in iter_header(testfile) {
for each ln: istr in iter_header(testfile) {
alt parse_error_pattern(ln) {
option::some(ep) { error_patterns += [ep]; }
option::none. { }
@ -44,7 +44,7 @@ fn load_props(testfile: &str) -> test_props {
}
if no_valgrind == false {
no_valgrind = parse_name_directive(ln, "no-valgrind");
no_valgrind = parse_name_directive(ln, ~"no-valgrind");
}
}
ret {
@ -55,50 +55,50 @@ fn load_props(testfile: &str) -> test_props {
};
}
fn is_test_ignored(config: &config, testfile: &str) -> bool {
fn is_test_ignored(config: &config, testfile: &istr) -> bool {
let found = false;
for each ln: str in iter_header(testfile) {
for each ln: istr in iter_header(testfile) {
// FIXME: Can't return or break from iterator
found = found
|| parse_name_directive(ln, "xfail-"
+ istr::to_estr(config.stage_id));
|| parse_name_directive(ln, ~"xfail-"
+ config.stage_id);
if (config.mode == common::mode_pretty) {
found = found
|| parse_name_directive(ln, "xfail-pretty");
|| parse_name_directive(ln, ~"xfail-pretty");
}
}
ret found;
}
iter iter_header(testfile: &str) -> str {
let rdr = io::file_reader(istr::from_estr(testfile));
iter iter_header(testfile: &istr) -> istr {
let rdr = io::file_reader(testfile);
while !rdr.eof() {
let ln = istr::to_estr(rdr.read_line());
let ln = rdr.read_line();
// Assume that any directives will be found before the first
// module or function. This doesn't seem to be an optimization
// with a warm page cache. Maybe with a cold one.
if str::starts_with(ln, "fn") || str::starts_with(ln, "mod") {
if istr::starts_with(ln, ~"fn")
|| istr::starts_with(ln, ~"mod") {
break;
} else { put ln; }
}
}
fn parse_error_pattern(line: &str) -> option::t<str> {
parse_name_value_directive(line, "error-pattern")
fn parse_error_pattern(line: &istr) -> option::t<istr> {
parse_name_value_directive(line, ~"error-pattern")
}
fn parse_compile_flags(line: &str) -> option::t<str> {
parse_name_value_directive(line, "compile-flags")
fn parse_compile_flags(line: &istr) -> option::t<istr> {
parse_name_value_directive(line, ~"compile-flags")
}
fn parse_pp_exact(line: &str, testfile: &str) -> option::t<str> {
alt parse_name_value_directive(line, "pp-exact") {
fn parse_pp_exact(line: &istr, testfile: &istr) -> option::t<istr> {
alt parse_name_value_directive(line, ~"pp-exact") {
option::some(s) { option::some(s) }
option::none. {
if parse_name_directive(line, "pp-exact") {
option::some(istr::to_estr(
fs::basename(istr::from_estr(testfile))))
if parse_name_directive(line, ~"pp-exact") {
option::some(fs::basename(testfile))
} else {
option::none
}
@ -106,19 +106,21 @@ fn parse_pp_exact(line: &str, testfile: &str) -> option::t<str> {
}
}
fn parse_name_directive(line: &str, directive: &str) -> bool {
str::find(line, directive) >= 0
fn parse_name_directive(line: &istr, directive: &istr) -> bool {
istr::find(line, directive) >= 0
}
fn parse_name_value_directive(line: &str,
directive: &str) -> option::t<str> {
let keycolon = directive + ":";
if str::find(line, keycolon) >= 0 {
let colon = str::find(line, keycolon) as uint;
fn parse_name_value_directive(line: &istr,
directive: &istr) -> option::t<istr> {
let keycolon = directive + ~":";
if istr::find(line, keycolon) >= 0 {
let colon = istr::find(line, keycolon) as uint;
let value =
str::slice(line, colon + str::byte_len(keycolon),
str::byte_len(line));
log #fmt("%s: %s", directive, value);
istr::slice(line, colon + istr::byte_len(keycolon),
istr::byte_len(line));
log #fmt("%s: %s",
istr::to_estr(directive),
istr::to_estr(value));
option::some(value)
} else { option::none }
}

View file

@ -54,12 +54,12 @@ fn close(handle: &handle) {
task::join(option::get(handle.task));
}
fn run(handle: &handle, lib_path: &str, prog: &str, args: &[str],
input: &option::t<str>) -> {status: int, out: str, err: str} {
fn run(handle: &handle, lib_path: &istr, prog: &istr, args: &[istr],
input: &option::t<istr>) -> {status: int, out: istr, err: istr} {
let p = port();
let ch = chan(p);
send(handle.chan,
exec(str::bytes(lib_path), str::bytes(prog), clone_vecstr(args),
exec(istr::bytes(lib_path), istr::bytes(prog), clone_vecstr(args),
ch));
let resp = recv(p);
@ -70,23 +70,23 @@ fn run(handle: &handle, lib_path: &str, prog: &str, args: &[str],
ret {status: status, out: output, err: errput};
}
fn writeclose(fd: int, s: &option::t<str>) {
fn writeclose(fd: int, s: &option::t<istr>) {
if option::is_some(s) {
let writer = io::new_writer(io::fd_buf_writer(fd, option::none));
writer.write_str(istr::from_estr(option::get(s)));
writer.write_str(option::get(s));
}
os::libc::close(fd);
}
fn readclose(fd: int) -> str {
fn readclose(fd: int) -> istr {
// Copied from run::program_output
let file = os::fd_FILE(fd);
let reader = io::new_reader(io::FILE_buf_reader(file, option::none));
let buf = "";
let buf = ~"";
while !reader.eof() {
let bytes = reader.read_bytes(4096u);
buf += str::unsafe_from_bytes(bytes);
buf += istr::unsafe_from_bytes(bytes);
}
os::libc::fclose(file);
ret buf;
@ -115,8 +115,8 @@ fn worker(p: port<request>) {
// the alt discriminant are wrong.
alt recv(p) {
exec(lib_path, prog, args, respchan) {
{lib_path: str::unsafe_from_bytes(lib_path),
prog: str::unsafe_from_bytes(prog),
{lib_path: istr::unsafe_from_bytes(lib_path),
prog: istr::unsafe_from_bytes(prog),
args: clone_vecu8str(args),
respchan: respchan}
}
@ -129,8 +129,8 @@ fn worker(p: port<request>) {
let pipe_out = os::pipe();
let pipe_err = os::pipe();
let spawnproc =
bind run::spawn_process(istr::from_estr(execparms.prog),
istr::from_estrs(execparms.args),
bind run::spawn_process(execparms.prog,
execparms.args,
pipe_in.in, pipe_out.out, pipe_err.out);
let pid = with_lib_path(execparms.lib_path, spawnproc);
@ -152,35 +152,37 @@ fn worker(p: port<request>) {
}
}
fn with_lib_path<@T>(path: &str, f: fn() -> T) -> T {
let maybe_oldpath = getenv(istr::from_estr(util::lib_path_env_var()));
fn with_lib_path<@T>(path: &istr, f: fn() -> T) -> T {
let maybe_oldpath = getenv(util::lib_path_env_var());
append_lib_path(path);
let res = f();
if option::is_some(maybe_oldpath) {
export_lib_path(istr::to_estr(option::get(maybe_oldpath)));
export_lib_path(option::get(maybe_oldpath));
} else {
// FIXME: This should really be unset but we don't have that yet
export_lib_path("");
export_lib_path(~"");
}
ret res;
}
fn append_lib_path(path: &str) { export_lib_path(util::make_new_path(path)); }
fn export_lib_path(path: &str) {
setenv(istr::from_estr(util::lib_path_env_var()), istr::from_estr(path));
fn append_lib_path(path: &istr) {
export_lib_path(util::make_new_path(path));
}
fn clone_vecstr(v: &[str]) -> [[u8]] {
fn export_lib_path(path: &istr) {
setenv(util::lib_path_env_var(), path);
}
fn clone_vecstr(v: &[istr]) -> [[u8]] {
let r = [];
for t: str in vec::slice(v, 0u, vec::len(v)) { r += [str::bytes(t)]; }
for t: istr in vec::slice(v, 0u, vec::len(v)) { r += [istr::bytes(t)]; }
ret r;
}
fn clone_vecu8str(v: &[[u8]]) -> [str] {
fn clone_vecu8str(v: &[[u8]]) -> [istr] {
let r = [];
for t in vec::slice(v, 0u, vec::len(v)) {
r += [str::unsafe_from_bytes(t)];
r += [istr::unsafe_from_bytes(t)];
}
ret r;
}

View file

@ -20,12 +20,12 @@ import util::logv;
export run;
fn run(cx: &cx, _testfile: -[u8]) {
let testfile = str::unsafe_from_bytes(_testfile);
let testfile = istr::unsafe_from_bytes(_testfile);
if cx.config.verbose {
// We're going to be dumping a lot of info. Start on a new line.
io::stdout().write_str(~"\n\n");
}
log #fmt["running %s", testfile];
log #fmt["running %s", istr::to_estr(testfile)];
let props = load_props(testfile);
alt cx.config.mode {
mode_compile_fail. { run_cfail_test(cx, props, testfile); }
@ -35,25 +35,25 @@ fn run(cx: &cx, _testfile: -[u8]) {
}
}
fn run_cfail_test(cx: &cx, props: &test_props, testfile: &str) {
fn run_cfail_test(cx: &cx, props: &test_props, testfile: &istr) {
let procres = compile_test(cx, props, testfile);
if procres.status == 0 {
fatal_procres("compile-fail test compiled successfully!", procres);
fatal_procres(~"compile-fail test compiled successfully!", procres);
}
check_error_patterns(props, testfile, procres);
}
fn run_rfail_test(cx: &cx, props: &test_props, testfile: &str) {
fn run_rfail_test(cx: &cx, props: &test_props, testfile: &istr) {
let procres = compile_test(cx, props, testfile);
if procres.status != 0 { fatal_procres("compilation failed!", procres); }
if procres.status != 0 { fatal_procres(~"compilation failed!", procres); }
procres = exec_compiled_test(cx, props, testfile);
if procres.status == 0 {
fatal_procres("run-fail test didn't produce an error!", procres);
fatal_procres(~"run-fail test didn't produce an error!", procres);
}
// This is the value valgrind returns on failure
@ -62,42 +62,44 @@ fn run_rfail_test(cx: &cx, props: &test_props, testfile: &str) {
// exit code on the command-line (137)?
const valgrind_err: int = 9;
if procres.status == valgrind_err {
fatal_procres("run-fail test isn't valgrind-clean!", procres);
fatal_procres(~"run-fail test isn't valgrind-clean!", procres);
}
check_error_patterns(props, testfile, procres);
}
fn run_rpass_test(cx: &cx, props: &test_props, testfile: &str) {
fn run_rpass_test(cx: &cx, props: &test_props, testfile: &istr) {
let procres = compile_test(cx, props, testfile);
if procres.status != 0 { fatal_procres("compilation failed!", procres); }
if procres.status != 0 { fatal_procres(~"compilation failed!", procres); }
procres = exec_compiled_test(cx, props, testfile);
if procres.status != 0 { fatal_procres("test run failed!", procres); }
if procres.status != 0 { fatal_procres(~"test run failed!", procres); }
}
fn run_pretty_test(cx: &cx, props: &test_props, testfile: &str) {
fn run_pretty_test(cx: &cx, props: &test_props, testfile: &istr) {
if option::is_some(props.pp_exact) {
logv(cx.config, "testing for exact pretty-printing");
} else { logv(cx.config, "testing for converging pretty-printing"); }
logv(cx.config, ~"testing for exact pretty-printing");
} else { logv(cx.config, ~"testing for converging pretty-printing"); }
let rounds =
alt props.pp_exact { option::some(_) { 1 } option::none. { 2 } };
let srcs = [istr::to_estr(io::read_whole_file_str(
istr::from_estr(testfile)))];
let srcs = [io::read_whole_file_str(testfile)];
let round = 0;
while round < rounds {
logv(cx.config, #fmt["pretty-printing round %d", round]);
logv(cx.config,
istr::from_estr(#fmt["pretty-printing round %d", round]));
let procres = print_source(cx, testfile, srcs[round]);
if procres.status != 0 {
fatal_procres(#fmt["pretty-printing failed in round %d", round],
procres);
fatal_procres(
istr::from_estr(#fmt["pretty-printing failed in round %d",
round]),
procres);
}
srcs += [procres.stdout];
@ -107,9 +109,8 @@ fn run_pretty_test(cx: &cx, props: &test_props, testfile: &str) {
let expected =
alt props.pp_exact {
option::some(file) {
let filepath = fs::connect(fs::dirname(
istr::from_estr(testfile)), istr::from_estr(file));
istr::to_estr(io::read_whole_file_str(filepath))
let filepath = fs::connect(fs::dirname(testfile), file);
io::read_whole_file_str(filepath)
}
option::none. { srcs[vec::len(srcs) - 2u] }
};
@ -117,10 +118,10 @@ fn run_pretty_test(cx: &cx, props: &test_props, testfile: &str) {
if option::is_some(props.pp_exact) {
// Now we have to care about line endings
let cr = "\r";
check (str::is_not_empty(cr));
actual = str::replace(actual, cr, "");
expected = str::replace(expected, cr, "");
let cr = ~"\r";
check (istr::is_not_empty(cr));
actual = istr::replace(actual, cr, ~"");
expected = istr::replace(expected, cr, ~"");
}
compare_source(expected, actual);
@ -129,25 +130,25 @@ fn run_pretty_test(cx: &cx, props: &test_props, testfile: &str) {
let procres = typecheck_source(cx, testfile, actual);
if procres.status != 0 {
fatal_procres("pretty-printed source does not typecheck", procres);
fatal_procres(~"pretty-printed source does not typecheck", procres);
}
ret;
fn print_source(cx: &cx, testfile: &str, src: &str) -> procres {
fn print_source(cx: &cx, testfile: &istr, src: &istr) -> procres {
compose_and_run(cx, testfile, make_pp_args,
cx.config.compile_lib_path, option::some(src))
}
fn make_pp_args(config: &config, _testfile: &str) -> procargs {
let prog = istr::to_estr(config.rustc_path);
let args = ["-", "--pretty", "normal"];
fn make_pp_args(config: &config, _testfile: &istr) -> procargs {
let prog = config.rustc_path;
let args = [~"-", ~"--pretty", ~"normal"];
ret {prog: prog, args: args};
}
fn compare_source(expected: &str, actual: &str) {
fn compare_source(expected: &istr, actual: &istr) {
if expected != actual {
error("pretty-printed source does match expected source");
error(~"pretty-printed source does match expected source");
let msg =
#fmt["\n\
expected:\n\
@ -159,39 +160,39 @@ actual:\n\
%s\n\
------------------------------------------\n\
\n",
expected, actual];
istr::to_estr(expected), istr::to_estr(actual)];
io::stdout().write_str(istr::from_estr(msg));
fail;
}
}
fn typecheck_source(cx: &cx, testfile: &str, src: &str) -> procres {
fn typecheck_source(cx: &cx, testfile: &istr, src: &istr) -> procres {
compose_and_run(cx, testfile, make_typecheck_args,
cx.config.compile_lib_path, option::some(src))
}
fn make_typecheck_args(config: &config, _testfile: &str) -> procargs {
let prog = istr::to_estr(config.rustc_path);
let args = ["-", "--no-trans", "--lib"];
fn make_typecheck_args(config: &config, _testfile: &istr) -> procargs {
let prog = config.rustc_path;
let args = [~"-", ~"--no-trans", ~"--lib"];
ret {prog: prog, args: args};
}
}
fn check_error_patterns(props: &test_props, testfile: &str,
fn check_error_patterns(props: &test_props, testfile: &istr,
procres: &procres) {
if vec::is_empty(props.error_patterns) {
fatal("no error pattern specified in " + testfile);
fatal(~"no error pattern specified in " + testfile);
}
if procres.status == 0 {
fatal("process did not return an error status");
fatal(~"process did not return an error status");
}
let next_err_idx = 0u;
let next_err_pat = props.error_patterns[next_err_idx];
for line: str in str::split(procres.stdout, '\n' as u8) {
if str::find(line, next_err_pat) > 0 {
log #fmt["found error pattern %s", next_err_pat];
for line: istr in istr::split(procres.stdout, '\n' as u8) {
if istr::find(line, next_err_pat) > 0 {
log #fmt["found error pattern %s", istr::to_estr(next_err_pat)];
next_err_idx += 1u;
if next_err_idx == vec::len(props.error_patterns) {
log "found all error patterns";
@ -205,45 +206,49 @@ fn check_error_patterns(props: &test_props, testfile: &str,
vec::slice(props.error_patterns, next_err_idx,
vec::len(props.error_patterns));
if vec::len(missing_patterns) == 1u {
fatal_procres(#fmt["error pattern '%s' not found!",
missing_patterns[0]], procres);
fatal_procres(istr::from_estr(
#fmt["error pattern '%s' not found!",
istr::to_estr(missing_patterns[0])]), procres);
} else {
for pattern: str in missing_patterns {
error(#fmt["error pattern '%s' not found!", pattern]);
for pattern: istr in missing_patterns {
error(istr::from_estr(
#fmt["error pattern '%s' not found!",
istr::to_estr(pattern)]));
}
fatal_procres("multiple error patterns not found", procres);
fatal_procres(~"multiple error patterns not found", procres);
}
}
type procargs = {prog: str, args: [str]};
type procargs = {prog: istr, args: [istr]};
type procres = {status: int, stdout: str, stderr: str, cmdline: str};
type procres = {status: int, stdout: istr, stderr: istr, cmdline: istr};
fn compile_test(cx: &cx, props: &test_props, testfile: &str) -> procres {
fn compile_test(cx: &cx, props: &test_props, testfile: &istr) -> procres {
compose_and_run(cx, testfile, bind make_compile_args(_, props, _),
cx.config.compile_lib_path, option::none)
}
fn exec_compiled_test(cx: &cx, props: &test_props, testfile: &str) ->
fn exec_compiled_test(cx: &cx, props: &test_props, testfile: &istr) ->
procres {
compose_and_run(cx, testfile, bind make_run_args(_, props, _),
cx.config.run_lib_path, option::none)
}
fn compose_and_run(cx: &cx, testfile: &str,
make_args: fn(&config, &str) -> procargs, lib_path: &istr,
input: option::t<str>) -> procres {
fn compose_and_run(cx: &cx, testfile: &istr,
make_args: fn(&config, &istr) -> procargs,
lib_path: &istr,
input: option::t<istr>) -> procres {
let procargs = make_args(cx.config, testfile);
ret program_output(cx, testfile, lib_path, procargs.prog, procargs.args,
input);
}
fn make_compile_args(config: &config, props: &test_props, testfile: &str) ->
fn make_compile_args(config: &config, props: &test_props, testfile: &istr) ->
procargs {
let prog = istr::to_estr(config.rustc_path);
let args = [testfile, "-o", make_exe_name(config, testfile)];
let prog = config.rustc_path;
let args = [testfile, ~"-o", make_exe_name(config, testfile)];
let rustcflags = alt config.rustcflags {
option::some(s) { option::some(istr::to_estr(s)) }
option::some(s) { option::some(s) }
option::none. { option::none }
};
args += split_maybe_args(rustcflags);
@ -251,17 +256,17 @@ fn make_compile_args(config: &config, props: &test_props, testfile: &str) ->
ret {prog: prog, args: args};
}
fn make_exe_name(config: &config, testfile: &str) -> str {
output_base_name(config, testfile) + istr::to_estr(os::exec_suffix())
fn make_exe_name(config: &config, testfile: &istr) -> istr {
output_base_name(config, testfile) + os::exec_suffix()
}
fn make_run_args(config: &config, props: &test_props, testfile: &str) ->
fn make_run_args(config: &config, props: &test_props, testfile: &istr) ->
procargs {
let toolargs = if !props.no_valgrind {
// If we've got another tool to run under (valgrind),
// then split apart its command
let runtool = alt config.runtool {
option::some(s) { option::some(istr::to_estr(s)) }
option::some(s) { option::some(s) }
option::none. { option::none }
};
split_maybe_args(runtool)
@ -271,14 +276,14 @@ fn make_run_args(config: &config, props: &test_props, testfile: &str) ->
ret {prog: args[0], args: vec::slice(args, 1u, vec::len(args))};
}
fn split_maybe_args(argstr: &option::t<str>) -> [str] {
fn rm_whitespace(v: &[str]) -> [str] {
fn flt(s: &str) -> option::t<str> {
fn split_maybe_args(argstr: &option::t<istr>) -> [istr] {
fn rm_whitespace(v: &[istr]) -> [istr] {
fn flt(s: &istr) -> option::t<istr> {
if !is_whitespace(s) { option::some(s) } else { option::none }
}
// FIXME: This should be in std
fn is_whitespace(s: str) -> bool {
fn is_whitespace(s: &istr) -> bool {
for c: u8 in s { if c != ' ' as u8 { ret false; } }
ret true;
}
@ -286,18 +291,19 @@ fn split_maybe_args(argstr: &option::t<str>) -> [str] {
}
alt argstr {
option::some(s) { rm_whitespace(str::split(s, ' ' as u8)) }
option::some(s) { rm_whitespace(istr::split(s, ' ' as u8)) }
option::none. { [] }
}
}
fn program_output(cx: &cx, testfile: &str, lib_path: &istr, prog: &str,
args: &[str], input: option::t<str>) -> procres {
let lib_path = istr::to_estr(lib_path);
fn program_output(cx: &cx, testfile: &istr, lib_path: &istr, prog: &istr,
args: &[istr], input: option::t<istr>) -> procres {
let cmdline =
{
let cmdline = make_cmdline(lib_path, prog, args);
logv(cx.config, #fmt["executing %s", cmdline]);
logv(cx.config,
istr::from_estr(#fmt["executing %s",
istr::to_estr(cmdline)]));
cmdline
};
let res = procsrv::run(cx.procsrv, lib_path, prog, args, input);
@ -308,76 +314,83 @@ fn program_output(cx: &cx, testfile: &str, lib_path: &istr, prog: &str,
cmdline: cmdline};
}
fn make_cmdline(libpath: &str, prog: &str, args: &[str]) -> str {
#fmt["%s %s %s", lib_path_cmd_prefix(libpath), prog,
str::connect(args, " ")]
fn make_cmdline(libpath: &istr, prog: &istr, args: &[istr]) -> istr {
istr::from_estr(#fmt["%s %s %s",
istr::to_estr(lib_path_cmd_prefix(libpath)),
istr::to_estr(prog),
istr::to_estr(istr::connect(args, ~" "))])
}
// Build the LD_LIBRARY_PATH variable as it would be seen on the command line
// for diagnostic purposes
fn lib_path_cmd_prefix(path: &str) -> str {
#fmt["%s=\"%s\"", util::lib_path_env_var(), util::make_new_path(path)]
fn lib_path_cmd_prefix(path: &istr) -> istr {
istr::from_estr(#fmt["%s=\"%s\"",
istr::to_estr(util::lib_path_env_var()),
istr::to_estr(util::make_new_path(path))])
}
fn dump_output(config: &config, testfile: &str, out: &str, err: &str) {
dump_output_file(config, testfile, out, "out");
dump_output_file(config, testfile, err, "err");
fn dump_output(config: &config, testfile: &istr, out: &istr, err: &istr) {
dump_output_file(config, testfile, out, ~"out");
dump_output_file(config, testfile, err, ~"err");
maybe_dump_to_stdout(config, out, err);
}
#[cfg(target_os = "win32")]
#[cfg(target_os = "linux")]
fn dump_output_file(config: &config, testfile: &str, out: &str,
extension: &str) {
fn dump_output_file(config: &config, testfile: &istr, out: &istr,
extension: &istr) {
let outfile = make_out_name(config, testfile, extension);
let writer = io::file_writer(istr::from_estr(outfile),
let writer = io::file_writer(outfile,
[io::create, io::truncate]);
writer.write_str(istr::from_estr(out));
writer.write_str(out);
}
// FIXME (726): Can't use file_writer on mac
#[cfg(target_os = "macos")]
fn dump_output_file(config: &config, testfile: &str, out: &str,
extension: &str) {
fn dump_output_file(config: &config, testfile: &istr, out: &istr,
extension: &istr) {
}
fn make_out_name(config: &config, testfile: &str, extension: &str) -> str {
output_base_name(config, testfile) + "." + extension
fn make_out_name(config: &config, testfile: &istr,
extension: &istr) -> istr {
output_base_name(config, testfile) + ~"." + extension
}
fn output_base_name(config: &config, testfile: &str) -> str {
let base = istr::to_estr(config.build_base);
fn output_base_name(config: &config, testfile: &istr) -> istr {
let base = config.build_base;
let filename =
{
let parts = istr::split(fs::basename(istr::from_estr(testfile)),
let parts = istr::split(fs::basename(testfile),
'.' as u8);
parts = vec::slice(parts, 0u, vec::len(parts) - 1u);
istr::connect(parts, ~".")
};
#fmt["%s%s.%s", base, istr::to_estr(filename),
istr::to_estr(config.stage_id)]
istr::from_estr(#fmt["%s%s.%s", istr::to_estr(base),
istr::to_estr(filename),
istr::to_estr(config.stage_id)])
}
fn maybe_dump_to_stdout(config: &config, out: &str, err: &str) {
fn maybe_dump_to_stdout(config: &config, out: &istr, err: &istr) {
if config.verbose {
let sep1 = #fmt["------%s------------------------------", "stdout"];
let sep2 = #fmt["------%s------------------------------", "stderr"];
let sep3 = "------------------------------------------";
let sep3 = ~"------------------------------------------";
io::stdout().write_line(istr::from_estr(sep1));
io::stdout().write_line(istr::from_estr(out));
io::stdout().write_line(out);
io::stdout().write_line(istr::from_estr(sep2));
io::stdout().write_line(istr::from_estr(err));
io::stdout().write_line(istr::from_estr(sep3));
io::stdout().write_line(err);
io::stdout().write_line(sep3);
}
}
fn error(err: &str) {
io::stdout().write_line(istr::from_estr(#fmt["\nerror: %s", err]));
fn error(err: &istr) {
io::stdout().write_line(istr::from_estr(#fmt["\nerror: %s",
istr::to_estr(err)]));
}
fn fatal(err: &str) -> ! { error(err); fail; }
fn fatal(err: &istr) -> ! { error(err); fail; }
fn fatal_procres(err: &str, procres: procres) -> ! {
fn fatal_procres(err: &istr, procres: procres) -> ! {
let msg =
istr::from_estr(#fmt["\n\
error: %s\n\
@ -391,7 +404,10 @@ stderr:\n\
%s\n\
------------------------------------------\n\
\n",
err, procres.cmdline, procres.stdout, procres.stderr]);
istr::to_estr(err),
istr::to_estr(procres.cmdline),
istr::to_estr(procres.stdout),
istr::to_estr(procres.stderr)]);
io::stdout().write_str(msg);
fail;
}

View file

@ -5,28 +5,30 @@ import std::istr;
import common::config;
fn make_new_path(path: &str) -> str {
fn make_new_path(path: &istr) -> istr {
// Windows just uses PATH as the library search path, so we have to
// maintain the current value while adding our own
alt getenv(istr::from_estr(lib_path_env_var())) {
option::some(curr) { #fmt["%s:%s", path, istr::to_estr(curr)] }
alt getenv(lib_path_env_var()) {
option::some(curr) {
istr::from_estr(#fmt["%s:%s",
istr::to_estr(path), istr::to_estr(curr)]) }
option::none. { path }
}
}
#[cfg(target_os = "linux")]
fn lib_path_env_var() -> str { "LD_LIBRARY_PATH" }
fn lib_path_env_var() -> istr { ~"LD_LIBRARY_PATH" }
#[cfg(target_os = "macos")]
fn lib_path_env_var() -> str { "DYLD_LIBRARY_PATH" }
fn lib_path_env_var() -> istr { ~"DYLD_LIBRARY_PATH" }
#[cfg(target_os = "win32")]
fn lib_path_env_var() -> str { "PATH" }
fn lib_path_env_var() -> istr { "PATH" }
fn logv(config: &config, s: &str) {
fn logv(config: &config, s: &istr) {
log s;
if config.verbose {
io::stdout().write_line(std::istr::from_estr(s));
io::stdout().write_line(s);
}
}