#[allow(missing_doc)];
-use std::io;
+use std::io::{Decorator, Writer};
#[cfg(not(target_os = "win32"))] use std::os;
#[cfg(not(target_os = "win32"))] use terminfo::*;
}
#[cfg(not(target_os = "win32"))]
-pub struct Terminal {
+pub struct Terminal<T> {
priv num_colors: u16,
- priv out: @mut io::Writer,
+ priv out: T,
priv ti: ~TermInfo
}
#[cfg(target_os = "win32")]
-pub struct Terminal {
+pub struct Terminal<T> {
priv num_colors: u16,
- priv out: @mut io::Writer,
+ priv out: T,
}
#[cfg(not(target_os = "win32"))]
-impl Terminal {
- pub fn new(out: @mut io::Writer) -> Result<Terminal, ~str> {
+impl<T: Writer> Terminal<T> {
+ pub fn new(out: T) -> Result<Terminal<T>, ~str> {
let term = os::getenv("TERM");
if term.is_none() {
return Err(~"TERM environment variable undefined");
/// the corresponding normal color will be used instead.
///
/// Returns true if the color was set, false otherwise.
- pub fn fg(&self, color: color::Color) -> bool {
+ pub fn fg(&mut self, color: color::Color) -> bool {
let color = self.dim_if_necessary(color);
if self.num_colors > color {
let s = expand(*self.ti.strings.find_equiv(&("setaf")).unwrap(),
/// the corresponding normal color will be used instead.
///
/// Returns true if the color was set, false otherwise.
- pub fn bg(&self, color: color::Color) -> bool {
+ pub fn bg(&mut self, color: color::Color) -> bool {
let color = self.dim_if_necessary(color);
if self.num_colors > color {
let s = expand(*self.ti.strings.find_equiv(&("setab")).unwrap(),
/// Sets the given terminal attribute, if supported.
/// Returns true if the attribute was supported, false otherwise.
- pub fn attr(&self, attr: attr::Attr) -> bool {
+ pub fn attr(&mut self, attr: attr::Attr) -> bool {
match attr {
attr::ForegroundColor(c) => self.fg(c),
attr::BackgroundColor(c) => self.bg(c),
}
/// Resets all terminal attributes and color to the default.
- pub fn reset(&self) {
+ pub fn reset(&mut self) {
let mut cap = self.ti.strings.find_equiv(&("sgr0"));
if cap.is_none() {
// are there any terminals that have color/attrs and not sgr0?
}
#[cfg(target_os = "win32")]
-impl Terminal {
- pub fn new(out: @mut io::Writer) -> Result<Terminal, ~str> {
+impl<T: Writer> Terminal<T> {
+ pub fn new(out: T) -> Result<Terminal<T>, ~str> {
return Ok(Terminal {out: out, num_colors: 0});
}
- pub fn fg(&self, _color: color::Color) -> bool {
+ pub fn fg(&mut self, _color: color::Color) -> bool {
false
}
- pub fn bg(&self, _color: color::Color) -> bool {
+ pub fn bg(&mut self, _color: color::Color) -> bool {
false
}
- pub fn attr(&self, _attr: attr::Attr) -> bool {
+ pub fn attr(&mut self, _attr: attr::Attr) -> bool {
false
}
pub fn reset(&self) {
}
}
+
+impl<T: Writer> Decorator<T> for Terminal<T> {
+ fn inner(self) -> T {
+ self.out
+ }
+
+ fn inner_ref<'a>(&'a self) -> &'a T {
+ &self.out
+ }
+
+ fn inner_mut_ref<'a>(&'a mut self) -> &'a mut T {
+ &mut self.out
+ }
+}
+
+impl<T: Writer> Writer for Terminal<T> {
+ fn write(&mut self, buf: &[u8]) {
+ self.out.write(buf);
+ }
+
+ fn flush(&mut self) {
+ self.out.flush();
+ }
+}
use std::comm::{stream, SharedChan, GenericPort, GenericChan};
use std::io;
use std::io::File;
+use std::io::Writer;
+use std::io::stdio::StdWriter;
use std::task;
use std::to_str::ToStr;
use std::f64;
TrBench(BenchSamples),
}
-struct ConsoleTestState {
- out: @mut io::Writer,
- log_out: Option<@mut io::Writer>,
- term: Option<term::Terminal>,
+struct ConsoleTestState<T> {
+ log_out: Option<File>,
+ out: Either<term::Terminal<T>, T>,
use_color: bool,
total: uint,
passed: uint,
max_name_len: uint, // number of columns to fill when aligning names
}
-impl ConsoleTestState {
- pub fn new(opts: &TestOpts) -> ConsoleTestState {
+impl<T: Writer> ConsoleTestState<T> {
+ pub fn new(opts: &TestOpts, _: Option<T>) -> ConsoleTestState<StdWriter> {
let log_out = match opts.logfile {
- Some(ref path) => Some(@mut File::create(path) as @mut io::Writer),
+ Some(ref path) => File::create(path),
None => None
};
- let out = @mut io::stdio::stdout() as @mut io::Writer;
- let term = match term::Terminal::new(out) {
- Err(_) => None,
- Ok(t) => Some(t)
+ let out = match term::Terminal::new(io::stdout()) {
+ Err(_) => Right(io::stdout()),
+ Ok(t) => Left(t)
};
ConsoleTestState {
out: out,
log_out: log_out,
use_color: use_color(),
- term: term,
total: 0u,
passed: 0u,
failed: 0u,
}
}
- pub fn write_ok(&self) {
+ pub fn write_ok(&mut self) {
self.write_pretty("ok", term::color::GREEN);
}
- pub fn write_failed(&self) {
+ pub fn write_failed(&mut self) {
self.write_pretty("FAILED", term::color::RED);
}
- pub fn write_ignored(&self) {
+ pub fn write_ignored(&mut self) {
self.write_pretty("ignored", term::color::YELLOW);
}
- pub fn write_metric(&self) {
+ pub fn write_metric(&mut self) {
self.write_pretty("metric", term::color::CYAN);
}
- pub fn write_bench(&self) {
+ pub fn write_bench(&mut self) {
self.write_pretty("bench", term::color::CYAN);
}
- pub fn write_added(&self) {
+ pub fn write_added(&mut self) {
self.write_pretty("added", term::color::GREEN);
}
- pub fn write_improved(&self) {
+ pub fn write_improved(&mut self) {
self.write_pretty("improved", term::color::GREEN);
}
- pub fn write_removed(&self) {
+ pub fn write_removed(&mut self) {
self.write_pretty("removed", term::color::YELLOW);
}
- pub fn write_regressed(&self) {
+ pub fn write_regressed(&mut self) {
self.write_pretty("regressed", term::color::RED);
}
- pub fn write_pretty(&self,
+ pub fn write_pretty(&mut self,
word: &str,
color: term::color::Color) {
- match self.term {
- None => self.out.write(word.as_bytes()),
- Some(ref t) => {
+ match self.out {
+ Left(ref mut term) => {
if self.use_color {
- t.fg(color);
+ term.fg(color);
}
- self.out.write(word.as_bytes());
+ term.write(word.as_bytes());
if self.use_color {
- t.reset();
+ term.reset();
}
}
+ Right(ref mut stdout) => stdout.write(word.as_bytes())
+ }
+ }
+
+ pub fn write_plain(&mut self, s: &str) {
+ match self.out {
+ Left(ref mut term) => term.write(s.as_bytes()),
+ Right(ref mut stdout) => stdout.write(s.as_bytes())
}
}
pub fn write_run_start(&mut self, len: uint) {
self.total = len;
let noun = if len != 1 { &"tests" } else { &"test" };
- write!(self.out, "\nrunning {} {}\n", len, noun);
+ self.write_plain(format!("\nrunning {} {}\n", len, noun));
}
- pub fn write_test_start(&self, test: &TestDesc, align: NamePadding) {
+ pub fn write_test_start(&mut self, test: &TestDesc, align: NamePadding) {
let name = test.padded_name(self.max_name_len, align);
- write!(self.out, "test {} ... ", name);
+ self.write_plain(format!("test {} ... ", name));
}
- pub fn write_result(&self, result: &TestResult) {
+ pub fn write_result(&mut self, result: &TestResult) {
match *result {
TrOk => self.write_ok(),
TrFailed => self.write_failed(),
TrIgnored => self.write_ignored(),
TrMetrics(ref mm) => {
self.write_metric();
- write!(self.out, ": {}", fmt_metrics(mm));
+ self.write_plain(format!(": {}", fmt_metrics(mm)));
}
TrBench(ref bs) => {
self.write_bench();
- write!(self.out, ": {}", fmt_bench_samples(bs));
+ self.write_plain(format!(": {}", fmt_bench_samples(bs)));
}
}
- write!(self.out, "\n");
+ self.write_plain("\n");
}
- pub fn write_log(&self, test: &TestDesc, result: &TestResult) {
+ pub fn write_log(&mut self, test: &TestDesc, result: &TestResult) {
match self.log_out {
None => (),
- Some(out) => {
- write!(out, "{} {}",match *result {
- TrOk => ~"ok",
- TrFailed => ~"failed",
- TrIgnored => ~"ignored",
- TrMetrics(ref mm) => fmt_metrics(mm),
- TrBench(ref bs) => fmt_bench_samples(bs)
- }, test.name.to_str());
+ Some(ref mut o) => {
+ let s = format!("{} {}", match *result {
+ TrOk => ~"ok",
+ TrFailed => ~"failed",
+ TrIgnored => ~"ignored",
+ TrMetrics(ref mm) => fmt_metrics(mm),
+ TrBench(ref bs) => fmt_bench_samples(bs)
+ }, test.name.to_str());
+ o.write(s.as_bytes());
}
}
}
- pub fn write_failures(&self) {
- write!(self.out, "\nfailures:\n");
+ pub fn write_failures(&mut self) {
+ self.write_plain("\nfailures:\n");
let mut failures = ~[];
for f in self.failures.iter() {
failures.push(f.name.to_str());
}
sort::tim_sort(failures);
for name in failures.iter() {
- writeln!(self.out, " {}", name.to_str());
+ self.write_plain(format!(" {}\n", name.to_str()));
}
}
- pub fn write_metric_diff(&self, diff: &MetricDiff) {
+ pub fn write_metric_diff(&mut self, diff: &MetricDiff) {
let mut noise = 0;
let mut improved = 0;
let mut regressed = 0;
MetricAdded => {
added += 1;
self.write_added();
- writeln!(self.out, ": {}", *k);
+ self.write_plain(format!(": {}\n", *k));
}
MetricRemoved => {
removed += 1;
self.write_removed();
- writeln!(self.out, ": {}", *k);
+ self.write_plain(format!(": {}\n", *k));
}
Improvement(pct) => {
improved += 1;
- write!(self.out, "{}: ", *k);
+ self.write_plain(format!(": {}", *k));
self.write_improved();
- writeln!(self.out, " by {:.2f}%", pct as f64);
+ self.write_plain(format!(" by {:.2f}%\n", pct as f64));
}
Regression(pct) => {
regressed += 1;
- write!(self.out, "{}: ", *k);
+ self.write_plain(format!(": {}", *k));
self.write_regressed();
- writeln!(self.out, " by {:.2f}%", pct as f64);
+ self.write_plain(format!(" by {:.2f}%\n", pct as f64));
}
}
}
- writeln!(self.out, "result of ratchet: {} matrics added, {} removed, \
- {} improved, {} regressed, {} noise",
- added, removed, improved, regressed, noise);
+ self.write_plain(format!("result of ratchet: {} matrics added, {} removed, \
+ {} improved, {} regressed, {} noise\n",
+ added, removed, improved, regressed, noise));
if regressed == 0 {
- writeln!(self.out, "updated ratchet file");
+ self.write_plain("updated ratchet file\n");
} else {
- writeln!(self.out, "left ratchet file untouched");
+ self.write_plain("left ratchet file untouched\n");
}
}
- pub fn write_run_finish(&self,
+ pub fn write_run_finish(&mut self,
ratchet_metrics: &Option<Path>,
ratchet_pct: Option<f64>) -> bool {
assert!(self.passed + self.failed + self.ignored + self.measured == self.total);
let ratchet_success = match *ratchet_metrics {
None => true,
Some(ref pth) => {
- write!(self.out, "\nusing metrics ratcher: {}\n", pth.display());
+ self.write_plain(format!("\nusing metrics ratcher: {}\n", pth.display()));
match ratchet_pct {
None => (),
Some(pct) =>
- writeln!(self.out, "with noise-tolerance forced to: {}%",
- pct)
+ self.write_plain(format!("with noise-tolerance forced to: {}%\n",
+ pct))
}
let (diff, ok) = self.metrics.ratchet(pth, ratchet_pct);
self.write_metric_diff(&diff);
let success = ratchet_success && test_success;
- write!(self.out, "\ntest result: ");
+ self.write_plain("\ntest result: ");
if success {
// There's no parallelism at this point so it's safe to use color
self.write_ok();
} else {
self.write_failed();
}
- write!(self.out, ". {} passed; {} failed; {} ignored; {} measured\n\n",
- self.passed, self.failed, self.ignored, self.measured);
+ let s = format!(". {} passed; {} failed; {} ignored; {} measured\n\n",
+ self.passed, self.failed, self.ignored, self.measured);
+ self.write_plain(s);
return success;
}
}
// A simple console test runner
pub fn run_tests_console(opts: &TestOpts,
tests: ~[TestDescAndFn]) -> bool {
- fn callback(event: &TestEvent, st: &mut ConsoleTestState) {
+ fn callback<T: Writer>(event: &TestEvent, st: &mut ConsoleTestState<T>) {
debug!("callback(event={:?})", event);
match (*event).clone() {
TeFiltered(ref filtered_tests) => st.write_run_start(filtered_tests.len()),
}
}
}
- let st = @mut ConsoleTestState::new(opts);
+ let mut st = ConsoleTestState::new(opts, None::<StdWriter>);
fn len_if_padded(t: &TestDescAndFn) -> uint {
match t.testfn.padding() {
PadNone => 0u,
},
None => {}
}
- run_tests(opts, tests, |x| callback(&x, st));
+ run_tests(opts, tests, |x| callback(&x, &mut st));
match opts.save_metrics {
None => (),
Some(ref pth) => {
st.metrics.save(pth);
- write!(st.out, "\nmetrics saved to: {}", pth.display());
+ st.write_plain(format!("\nmetrics saved to: {}", pth.display()));
}
}
return st.write_run_finish(&opts.ratchet_metrics, opts.ratchet_noise_percent);
#[test]
fn should_sort_failures_before_printing_them() {
- use std::io;
use std::io::Decorator;
use std::io::mem::MemWriter;
use std::str;
fn dummy() {}
- let m = @mut MemWriter::new();
let test_a = TestDesc {
name: StaticTestName("a"),
ignore: false,
should_fail: false
};
- let st = @ConsoleTestState {
- out: m as @mut io::Writer,
+ let mut st = ConsoleTestState {
log_out: None,
- term: None,
+ out: Right(MemWriter::new()),
use_color: false,
total: 0u,
passed: 0u,
};
st.write_failures();
- let s = str::from_utf8(*m.inner_ref());
+ let s = match st.out {
+ Right(ref m) => str::from_utf8(*m.inner_ref()),
+ Left(_) => unreachable!()
+ };
let apos = s.find_str("a").unwrap();
let bpos = s.find_str("b").unwrap();