Implement test that pretty-printed code converges. Issue #789

This commit is contained in:
Brian Anderson 2011-07-31 15:33:40 -07:00
parent 4828d8f73f
commit 1653f3f1a9
2 changed files with 101 additions and 10 deletions

View File

@ -26,9 +26,12 @@ type reqchan = chan[request];
type handle = {task: option::t[task], chan: reqchan};
tag request { exec(str, str, str[], chan[response]); stop; }
tag request {
exec(str, str, str[], chan[response]);
stop;
}
type response = {pid: int, outfd: int, errfd: int};
type response = {pid: int, infd: int, outfd: int, errfd: int};
fn mk() -> handle {
let setupport = port();
@ -50,7 +53,8 @@ fn close(handle: &handle) {
task::join(option::get(handle.task));
}
fn run(handle: &handle, lib_path: &str, prog: &str, args: &vec[str]) ->
fn run(handle: &handle, lib_path: &str,
prog: &str, args: &vec[str], input: &option::t[str]) ->
{status: int, out: str, err: str} {
let p = port[response]();
let ch = chan(p);
@ -59,12 +63,24 @@ fn run(handle: &handle, lib_path: &str, prog: &str, args: &vec[str]) ->
clone_ivecstr(ivec::from_vec(args)),
task::clone_chan(ch)));
let resp = task::recv(p);
writeclose(resp.infd, input);
let output = readclose(resp.outfd);
let errput = readclose(resp.errfd);
let status = os::waitpid(resp.pid);
ret {status: status, out: output, err: errput};
}
fn writeclose(fd: int, s: &option::t[str]) {
if option::is_some(s) {
let writer = io::new_writer(
io::fd_buf_writer(fd, option::none));
writer.write_str(option::get(s));
}
os::libc::close(fd);
}
fn readclose(fd: int) -> str {
// Copied from run::program_output
let file = os::fd_FILE(fd);
@ -128,17 +144,20 @@ fn worker(p: port[request]) {
pipe_out.out,
pipe_err.out);
let pid = with_lib_path(execparms.lib_path, spawnproc);
os::libc::close(pipe_in.in);
os::libc::close(pipe_in.out);
os::libc::close(pipe_out.out);
os::libc::close(pipe_err.out);
if pid == -1 {
os::libc::close(pipe_in.out);
os::libc::close(pipe_out.in);
os::libc::close(pipe_err.in);
fail;
}
task::send(execparms.respchan,
{pid: pid,
infd: pipe_in.out,
outfd: pipe_out.in,
errfd: pipe_err.in});
}

View File

@ -75,6 +75,74 @@ fn run_rpass_test(cx: &cx, props: &test_props, testfile: &str) {
}
fn run_pretty_test(cx: &cx, props: &test_props, testfile: &str) {
const rounds: int = 2;
let srcs = ~[str::unsafe_from_bytes(
io::file_reader(testfile).read_whole_stream())];
let round = 0;
while round < rounds {
logv(cx.config, #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);
}
srcs += ~[procres.stdout];
round += 1;
}
let expected = srcs.(ivec::len(srcs) - 2u);
let actual = srcs.(ivec::len(srcs) - 1u);
compare_source(expected, actual);
// Finally, let's make sure it actually appears to remain valid code
let procres = typecheck_source(cx, actual);
if procres.status != 0 {
fatal_procres("pretty-printed source does not typecheck",
procres);
}
ret;
fn print_source(cx: &cx, testfile: &str, src: &str) -> 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 = config.rustc_path;
let args = ["-", "--pretty", "normal"];
ret {prog: prog, args: args};
}
fn compare_source(expected: &str, actual: &str) {
if expected != actual {
error("pretty-printed source does not converge");
let msg = #fmt("\n\
expected:\n\
------------------------------------------\n\
%s\n\
------------------------------------------\n\
actual:\n\
------------------------------------------\n\
%s\n\
------------------------------------------\n\
\n",
expected, actual);
io::stdout().write_str(msg);
fail;
}
}
fn typecheck_source(cx: &cx, src: &str) -> procres {
// FIXME
ret {status: 0, stdout: src, stderr: "", cmdline: ""};
}
}
fn check_error_patterns(props: &test_props, testfile: &str,
@ -117,19 +185,22 @@ type procres = {status: int, stdout: str, stderr: str, cmdline: str};
fn compile_test(cx: &cx, props: &test_props, testfile: &str) -> procres {
compose_and_run(cx, testfile, bind make_compile_args(_, props, _),
cx.config.compile_lib_path)
cx.config.compile_lib_path, option::none)
}
fn exec_compiled_test(cx: &cx, testfile: &str) -> procres {
compose_and_run(cx, testfile, make_run_args, cx.config.run_lib_path)
compose_and_run(cx, testfile, make_run_args,
cx.config.run_lib_path, option::none)
}
fn compose_and_run(cx: &cx, testfile: &str,
make_args: fn(&config, &str) -> procargs ,
lib_path: &str) -> procres {
lib_path: &str,
input: option::t[str]) -> procres {
let procargs = make_args(cx.config, testfile);
ret program_output(cx, testfile, lib_path,
procargs.prog, procargs.args);
procargs.prog, procargs.args,
input);
}
fn make_compile_args(config: &config,
@ -182,14 +253,15 @@ fn split_maybe_args(argstr: &option::t[str]) -> vec[str] {
}
fn program_output(cx: &cx, testfile: &str, lib_path: &str, prog: &str,
args: &vec[str]) -> procres {
args: &vec[str], input: option::t[str]) -> procres {
let cmdline =
{
let cmdline = make_cmdline(lib_path, prog, args);
logv(cx.config, #fmt("executing %s", cmdline));
cmdline
};
let res = procsrv::run(cx.procsrv, lib_path, prog, args);
let res = procsrv::run(cx.procsrv, lib_path,
prog, args, input);
dump_output(cx.config, testfile, res.out, res.err);
ret {status: res.status, stdout: res.out,
stderr: res.err, cmdline: cmdline};