use time::precise_time_ns;
use collections::TreeMap;
-use std::clone::Clone;
use std::cmp;
use std::io;
-use std::io::File;
-use std::io::Writer;
+use std::io::{File, PortReader, ChanWriter};
use std::io::stdio::StdWriter;
+use std::str;
use std::task;
use std::to_str::ToStr;
use std::f64;
ignored: uint,
measured: uint,
metrics: MetricMap,
- failures: ~[TestDesc],
+ failures: ~[(TestDesc, ~[u8])],
max_name_len: uint, // number of columns to fill when aligning names
}
pub fn write_failures(&mut self) -> io::IoResult<()> {
if_ok!(self.write_plain("\nfailures:\n"));
let mut failures = ~[];
- for f in self.failures.iter() {
+ let mut fail_out = ~"";
+ for &(ref f, ref stdout) in self.failures.iter() {
failures.push(f.name.to_str());
+ if stdout.len() > 0 {
+ fail_out.push_str(format!("---- {} stdout ----\n\t",
+ f.name.to_str()));
+ let output = str::from_utf8_lossy(*stdout);
+ fail_out.push_str(output.as_slice().replace("\n", "\n\t"));
+ fail_out.push_str("\n");
+ }
+ }
+ if fail_out.len() > 0 {
+ if_ok!(self.write_plain("\n"));
+ if_ok!(self.write_plain(fail_out));
}
+
+ if_ok!(self.write_plain("\nfailures:\n"));
failures.sort();
for name in failures.iter() {
if_ok!(self.write_plain(format!(" {}\n", name.to_str())));
match (*event).clone() {
TeFiltered(ref filtered_tests) => st.write_run_start(filtered_tests.len()),
TeWait(ref test, padding) => st.write_test_start(test, padding),
- TeResult(test, result) => {
+ TeResult(test, result, stdout) => {
if_ok!(st.write_log(&test, &result));
if_ok!(st.write_result(&result));
match result {
}
TrFailed => {
st.failed += 1;
- st.failures.push(test);
+ st.failures.push((test, stdout));
}
}
Ok(())
measured: 0u,
max_name_len: 10u,
metrics: MetricMap::new(),
- failures: ~[test_b, test_a]
+ failures: ~[(test_b, ~[]), (test_a, ~[])]
};
st.write_failures().unwrap();
let s = match st.out {
- Raw(ref m) => str::from_utf8(m.get_ref()).unwrap(),
+ Raw(ref m) => str::from_utf8_lossy(m.get_ref()),
Pretty(_) => unreachable!()
};
- let apos = s.find_str("a").unwrap();
- let bpos = s.find_str("b").unwrap();
+ let apos = s.as_slice().find_str("a").unwrap();
+ let bpos = s.as_slice().find_str("b").unwrap();
assert!(apos < bpos);
}
enum TestEvent {
TeFiltered(~[TestDesc]),
TeWait(TestDesc, NamePadding),
- TeResult(TestDesc, TestResult),
+ TeResult(TestDesc, TestResult, ~[u8] /* stdout */),
}
-/// The message sent to the test monitor from the individual runners.
-pub type MonitorMsg = (TestDesc, TestResult);
+pub type MonitorMsg = (TestDesc, TestResult, ~[u8] /* stdout */);
fn run_tests(opts: &TestOpts,
tests: ~[TestDescAndFn],
pending += 1;
}
- let (desc, result) = p.recv();
+ let (desc, result, stdout) = p.recv();
if concurrency != 1 {
if_ok!(callback(TeWait(desc.clone(), PadNone)));
}
- if_ok!(callback(TeResult(desc, result)));
+ if_ok!(callback(TeResult(desc, result, stdout)));
pending -= 1;
}
for b in filtered_benchs_and_metrics.move_iter() {
if_ok!(callback(TeWait(b.desc.clone(), b.testfn.padding())));
run_test(!opts.run_benchmarks, b, ch.clone());
- let (test, result) = p.recv();
- if_ok!(callback(TeResult(test, result)));
+ let (test, result, stdout) = p.recv();
+ if_ok!(callback(TeResult(test, result, stdout)));
}
Ok(())
}
let TestDescAndFn {desc, testfn} = test;
if force_ignore || desc.ignore {
- monitor_ch.send((desc, TrIgnored));
+ monitor_ch.send((desc, TrIgnored, ~[]));
return;
}
testfn: proc()) {
spawn(proc() {
let mut task = task::task();
- task.name(match desc.name {
- DynTestName(ref name) => name.to_owned().into_maybe_owned(),
- StaticTestName(name) => name.into_maybe_owned()
- });
+ let (p, c) = Chan::new();
+ let mut reader = PortReader::new(p);
+ let stdout = ChanWriter::new(c.clone());
+ let stderr = ChanWriter::new(c);
+ match desc.name {
+ DynTestName(ref name) => task.name(name.clone()),
+ StaticTestName(name) => task.name(name),
+ }
+ task.opts.stdout = Some(~stdout as ~Writer);
+ task.opts.stderr = Some(~stderr as ~Writer);
let result_future = task.future_result();
task.spawn(testfn);
+ let stdout = reader.read_to_end().unwrap();
let task_result = result_future.recv();
let test_result = calc_result(&desc, task_result.is_ok());
- monitor_ch.send((desc.clone(), test_result));
- });
+ monitor_ch.send((desc.clone(), test_result, stdout));
+ })
}
match testfn {
DynBenchFn(bencher) => {
let bs = ::test::bench::benchmark(|harness| bencher.run(harness));
- monitor_ch.send((desc, TrBench(bs)));
+ monitor_ch.send((desc, TrBench(bs), ~[]));
return;
}
StaticBenchFn(benchfn) => {
let bs = ::test::bench::benchmark(|harness| benchfn(harness));
- monitor_ch.send((desc, TrBench(bs)));
+ monitor_ch.send((desc, TrBench(bs), ~[]));
return;
}
DynMetricFn(f) => {
let mut mm = MetricMap::new();
f(&mut mm);
- monitor_ch.send((desc, TrMetrics(mm)));
+ monitor_ch.send((desc, TrMetrics(mm), ~[]));
return;
}
StaticMetricFn(f) => {
let mut mm = MetricMap::new();
f(&mut mm);
- monitor_ch.send((desc, TrMetrics(mm)));
+ monitor_ch.send((desc, TrMetrics(mm), ~[]));
return;
}
DynTestFn(f) => run_test_inner(desc, monitor_ch, f),
};
let (p, ch) = Chan::new();
run_test(false, desc, ch);
- let (_, res) = p.recv();
+ let (_, res, _) = p.recv();
assert!(res != TrOk);
}
};
let (p, ch) = Chan::new();
run_test(false, desc, ch);
- let (_, res) = p.recv();
+ let (_, res, _) = p.recv();
assert_eq!(res, TrIgnored);
}
};
let (p, ch) = Chan::new();
run_test(false, desc, ch);
- let (_, res) = p.recv();
+ let (_, res, _) = p.recv();
assert_eq!(res, TrOk);
}
};
let (p, ch) = Chan::new();
run_test(false, desc, ch);
- let (_, res) = p.recv();
+ let (_, res, _) = p.recv();
assert_eq!(res, TrFailed);
}