Skip to content

Commit

Permalink
Improve logger, merging serial & parallel logger
Browse files Browse the repository at this point in the history
  • Loading branch information
regexident committed Aug 31, 2017
1 parent 9b9bbbf commit 7d44ee0
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 94 deletions.
102 changes: 98 additions & 4 deletions src/logger/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,103 @@
//! ```
mod serial;
mod parallel;

pub use logger::serial::*;
pub use logger::parallel::*;
use std::io;

pub use logger::parallel::ParallelLogger as Logger;
use header::{SuiteHeader, ContextHeader, ExampleHeader};
use report::{BlockReport, SuiteReport, ContextReport, ExampleReport};
use runner::{Runner, RunnerObserver};
use logger::serial::SerialLogger;

/// Preferred logger for test suite execution.
pub struct Logger<T: io::Write> {
serial: SerialLogger<T>,
}

impl<T: io::Write> Logger<T>
where
T: Send + Sync,
{
pub fn new(buffer: T) -> Logger<T> {
Logger { serial: SerialLogger::new(buffer) }
}

fn replay_suite(&self, runner: &Runner, suite: &SuiteHeader, report: &SuiteReport) {
self.serial.enter_suite(runner, suite);
self.replay_context(runner, None, report.get_context());
self.serial.exit_suite(runner, suite, report);
}

fn replay_block(&self, runner: &Runner, report: &BlockReport) {
match report {
&BlockReport::Context(ref header, ref report) => {
self.replay_context(runner, header.as_ref(), report);
}
&BlockReport::Example(ref header, ref report) => {
self.replay_example(runner, header, report);
}
}
}

fn replay_context(&self, runner: &Runner, context: Option<&ContextHeader>, report: &ContextReport) {
if let Some(header) = context {
self.serial.enter_context(runner, header);
}
for report in report.get_blocks() {
self.replay_block(runner, report);
}
if let Some(header) = context {
self.serial.exit_context(runner, header, report);
}
}

fn replay_example(&self, runner: &Runner, example: &ExampleHeader, report: &ExampleReport) {
self.serial.enter_example(runner, example);
self.serial.exit_example(runner, example, report);
}
}

impl<T: io::Write> RunnerObserver for Logger<T>
where
T: Send + Sync,
{
fn enter_suite(&self, runner: &Runner, header: &SuiteHeader) {
if !runner.configuration.parallel {
self.serial.enter_suite(runner, header);
}
}

fn exit_suite(&self, runner: &Runner, header: &SuiteHeader, report: &SuiteReport) {
if !runner.configuration.parallel {
self.serial.exit_suite(runner, header, report);
} else {
// If the suite is being evaluated in parallel and we have reached the end of it,
// then it is time to forward a replay of the events to the inner serial logger:
self.replay_suite(runner, header, report);
}
}

fn enter_context(&self, runner: &Runner, header: &ContextHeader) {
if !runner.configuration.parallel {
self.serial.enter_context(runner, header);
}
}

fn exit_context(&self, runner: &Runner, header: &ContextHeader, report: &ContextReport) {
if !runner.configuration.parallel {
self.serial.exit_context(runner, header, report);
}
}

fn enter_example(&self, runner: &Runner, header: &ExampleHeader) {
if !runner.configuration.parallel {
self.serial.enter_example(runner, header);
}
}

fn exit_example(&self, runner: &Runner, header: &ExampleHeader, report: &ExampleReport) {
if !runner.configuration.parallel {
self.serial.exit_example(runner, header, report);
}
}
}
64 changes: 0 additions & 64 deletions src/logger/parallel.rs

This file was deleted.

14 changes: 7 additions & 7 deletions src/logger/serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use colored::*;

use header::{SuiteHeader, ContextHeader, ExampleHeader};
use report::{Report, BlockReport, SuiteReport, ContextReport, ExampleReport};
use runner::RunnerObserver;
use runner::{Runner, RunnerObserver};

#[derive(new)]
struct SerialLoggerState<T: io::Write = io::Stdout> {
Expand Down Expand Up @@ -166,7 +166,7 @@ impl<T: io::Write> RunnerObserver for SerialLogger<T>
where
T: Send + Sync,
{
fn enter_suite(&self, header: &SuiteHeader) {
fn enter_suite(&self, _runner: &Runner, header: &SuiteHeader) {
self.access_state(|state| {
state.level += 1;
self.write_suite_prefix(&mut state.buffer)?;
Expand All @@ -181,7 +181,7 @@ where
});
}

fn exit_suite(&self, _header: &SuiteHeader, report: &SuiteReport) {
fn exit_suite(&self, _runner: &Runner, _header: &SuiteHeader, report: &SuiteReport) {
self.access_state(|state| {
self.write_suite_failures(&mut state.buffer, 0, report)?;
self.write_suite_suffix(&mut state.buffer, report)?;
Expand All @@ -192,7 +192,7 @@ where
});
}

fn enter_context(&self, header: &ContextHeader) {
fn enter_context(&self, _runner: &Runner, header: &ContextHeader) {
self.access_state(|state| {
state.level += 1;
writeln!(
Expand All @@ -206,15 +206,15 @@ where
});
}

fn exit_context(&self, _header: &ContextHeader, _report: &ContextReport) {
fn exit_context(&self, _runner: &Runner, _header: &ContextHeader, _report: &ContextReport) {
self.access_state(|state| {
state.level -= 1;

Ok(())
});
}

fn enter_example(&self, header: &ExampleHeader) {
fn enter_example(&self, _runner: &Runner, header: &ExampleHeader) {
self.access_state(|state| {
state.level += 1;
write!(
Expand All @@ -228,7 +228,7 @@ where
});
}

fn exit_example(&self, _header: &ExampleHeader, report: &ExampleReport) {
fn exit_example(&self, _runner: &Runner, _header: &ExampleHeader, report: &ExampleReport) {
self.access_state(|state| {
writeln!(state.buffer, "{}", self.report_flag(report))?;
state.level -= 1;
Expand Down
24 changes: 11 additions & 13 deletions src/runner/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use visitor::TestSuiteVisitor;

/// Runner for executing a test suite's examples.
pub struct Runner {
configuration: configuration::Configuration,
pub configuration: configuration::Configuration,
observers: Vec<Arc<RunnerObserver>>,
should_exit: Mutex<Cell<bool>>,
}
Expand Down Expand Up @@ -184,12 +184,12 @@ where
type Output = SuiteReport;

fn visit(&self, suite: &Suite<T>, environment: &mut Self::Environment) -> Self::Output {
self.broadcast(|handler| handler.enter_suite(&suite.header));
self.broadcast(|handler| handler.enter_suite(self, &suite.header));
let report = SuiteReport::new(
suite.header.clone(),
self.visit(&suite.context, environment),
);
self.broadcast(|handler| handler.exit_suite(&suite.header, &report));
self.broadcast(|handler| handler.exit_suite(self, &suite.header, &report));
report
}
}
Expand Down Expand Up @@ -226,7 +226,7 @@ where

fn visit(&self, context: &Context<T>, environment: &mut Self::Environment) -> Self::Output {
if let Some(ref header) = context.header {
self.broadcast(|handler| handler.enter_context(&header));
self.broadcast(|handler| handler.enter_context(self, &header));
}
let reports: Vec<_> =
self.wrap_all(context, environment, |environment| if self.configuration
Expand All @@ -238,7 +238,7 @@ where
});
let report = ContextReport::new(reports);
if let Some(ref header) = context.header {
self.broadcast(|handler| handler.exit_context(&header, &report));
self.broadcast(|handler| handler.exit_context(self, &header, &report));
}
report
}
Expand All @@ -252,10 +252,10 @@ where
type Output = ExampleReport;

fn visit(&self, example: &Example<T>, environment: &mut Self::Environment) -> Self::Output {
self.broadcast(|handler| handler.enter_example(&example.header));
self.broadcast(|handler| handler.enter_example(self, &example.header));
let function = &example.function;
let report = function(environment);
self.broadcast(|handler| handler.exit_example(&example.header, &report));
self.broadcast(|handler| handler.exit_example(self, &example.header, &report));
report
}
}
Expand Down Expand Up @@ -320,7 +320,7 @@ mod tests {

// XXX stub implem
impl RunnerObserver for ObserverStub {
fn enter_suite(&self, header: &SuiteHeader) {
fn enter_suite(&self, _runner: &Runner, header: &SuiteHeader) {
let mut vec = self.events.lock().unwrap();
(*vec).push(("enter_suite", header.clone()));
}
Expand All @@ -333,7 +333,7 @@ mod tests {
let expected = SuiteHeader::new(SuiteLabel::Describe, "hello");
let runner = Runner::new(Configuration::default(), vec![spy1.clone()]);
// act
runner.broadcast(|observer| observer.enter_suite(&expected.clone()));
runner.broadcast(|observer| observer.enter_suite(&runner, &expected.clone()));
// assert
let lock = spy1.events.lock().expect("no dangling threads");
let res = (*lock).get(0).expect("to have been called once");
Expand Down Expand Up @@ -608,11 +608,11 @@ mod tests {
exit_example: Arc<AtomicBool>,
}
impl RunnerObserver for SpyObserver {
fn enter_example(&self, _header: &ExampleHeader) {
fn enter_example(&self, _runner: &Runner, _header: &ExampleHeader) {
self.enter_example.store(true, Ordering::SeqCst)
}

fn exit_example(&self, _header: &ExampleHeader, _report: &ExampleReport) {
fn exit_example(&self, _runner: &Runner, _header: &ExampleHeader, _report: &ExampleReport) {
self.exit_example.store(true, Ordering::SeqCst)
}
}
Expand Down Expand Up @@ -659,8 +659,6 @@ mod tests {
mod impl_visitor_block_for_runner {
use super::*;

use header::*;

#[test]
fn it_can_be_called() {
// arrange
Expand Down
13 changes: 7 additions & 6 deletions src/runner/observer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@
use header::{SuiteHeader, ContextHeader, ExampleHeader};
use report::{SuiteReport, ContextReport, ExampleReport};
use runner::Runner;

/// `RunnerObserver`s can be attached to a [`Runner`](../runner/struct.Runner.html) to observe a
#[allow(unused_variables)]
pub trait RunnerObserver: Send + Sync {
fn enter_suite(&self, header: &SuiteHeader) {}
fn exit_suite(&self, header: &SuiteHeader, report: &SuiteReport) {}
fn enter_context(&self, header: &ContextHeader) {}
fn exit_context(&self, header: &ContextHeader, report: &ContextReport) {}
fn enter_example(&self, header: &ExampleHeader) {}
fn exit_example(&self, header: &ExampleHeader, report: &ExampleReport) {}
fn enter_suite(&self, runner: &Runner, header: &SuiteHeader) {}
fn exit_suite(&self, runner: &Runner, header: &SuiteHeader, report: &SuiteReport) {}
fn enter_context(&self, runner: &Runner, header: &ContextHeader) {}
fn exit_context(&self, runner: &Runner, header: &ContextHeader, report: &ContextReport) {}
fn enter_example(&self, runner: &Runner, header: &ExampleHeader) {}
fn exit_example(&self, runner: &Runner, header: &ExampleHeader, report: &ExampleReport) {}
}

#[cfg(test)]
Expand Down

0 comments on commit 7d44ee0

Please sign in to comment.