rust-rspec/rspec

Formatter: Documentation

Opened this issue · 4 comments

Tests are documentation, and the formatters should represent that. Rspec has some nice examples of a doc output, mocha.js also.

Here is an example of how it looks like: example

Not hard to do. Just some work.

Problem I see with this is that we support several different sources:

  • Result<T, E>
  • Bool
  • ()
  • panic!()
  • expectest's own Result<…>

The problem is with the last two in particular, as we can only retrieve a string from a panic, no structured data (such as "expected: …", "found: …", etc).
We would need to parse the string to extract the individual values for applying our own formatting.

From Panics string we can just put the string and let it go for now.

As goes the saying: “Two seated intellectuals goes less far that a walking dumb guy“. ;-)

I agree. :)

Rust's assert_eq! and assert_ne! however both panic. As such one couldn't do any of the above (screenshot) without some kind of parsing of the returned string.

Or we would have to provide our own macro which would return Result<(), IsEqError> and ask users to use that instead. At which point we would re-invent and over-optimize for our own matchers, turning third-party matchers into 2nd-class citizens, which I'd like to avoid is possible (being a fan of expectest myself).

Simple proof-of-concept:

struct IsEqError {
    lhs: String,
    rhs: String,
    file: &'static str,
    line: u32,
    column: u32,
}

macro_rules! is_eq {
    ($lhs:expr, $rhs:expr) => {
        if $lhs == $rhs {
            Ok(())
        } else {
            Err(IsEqError {
                lhs: $lhs.to_string(),
                rhs: $rhs.to_string(),
                file: file!(),
                line: line!(),
                column: column!(),
            })
        }
    }
}

fn test<F>(f: F) where F: Fn() -> Result<(), IsEqError> {
    match f() {
        Ok(()) => println!("ok"),
        Err(IsEqError { lhs, rhs, file, line, column }) => {
            println!("Failure/Error: ({}:{}:{})", file, line, column);
            println!("");
            println!("  Expected: {} == {}", lhs, rhs);
            println!("  Found: {} != {}", lhs, rhs);
        }
    }
}

fn main() {
    let foo = 1;
    test(|| is_eq!(foo, 2));
}

… producing this:

Failure/Error: (is_eq.rs:40:12)

  Expected: 1 == 2
  Found: 1 != 2

This being said I think in the long run we need to improve Rust's testing API instead of trying to shoehorn our far more expressive API into it. These hacks should—if at all—only be seen as temporary fixes and no more.

Especially as tight 1st-class integration with cargo test should be our #1 goal, imho. I'll create a separate issue dedicated to discussing possible roads to standardization/integration with cargo test.