1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
//! # Fluid
//! 
//! ## Summary
//! 
//! `fluid` is an human readable test library.
//! 
//! The current goals of this crate are:
//! 
//! - Easily readable tests: they should be read like english sentences.
//! - Nice and understandable error messages.
//! - Provide the most possible useful assertions for common cases:
//!   numbers, `Iterator`s, `Option`s, `Result`s, etc.
//! 
//! ## How to use it
//! 
//! Add the crate in your `Cargo.toml`:
//! 
//! ```toml
//! # Do not use in crate build, only in test
//! [dev-dependencies]
//! fluid = "0.1"
//! ```
//! 
//! and in you main file:
//! 
//! ```rust
//! #[macro_use] extern crate fluid;
//! 
//! use fluid::*;
//! ```
//! 
//! ## Examples
//! 
//! ### Simple equality
//! 
//! ```rust
//! use fluid::*;
//! 
//! theory!(1 + 1).should().be_equal_to(2);
//! ```
//! 
//! ### Negation
//! 
//! ```rust
//! use fluid::*;
//! 
//! theory!(1 + 1).should().not().be_equal_to(10);
//! ```
//! 
//! ### Explanation
//! 
//! ```rust
//! use fluid::*;
//! 
//! theory!(1 + 1).should().be_equal_to(2)
//!     .because("this is basic arithmetic");
//! ```
//! 
//! ### Nice error message
//! 
//! ```rust,should_panic
//! use fluid::*;
//! 
//! let my_result: Result<i32, ()> = Err(()); //Oops
//! theory!(my_result).should().not().be_an_error()
//!     .and().should().contain(42)
//!     .because("I must have the answer");
//! ```
//! 
//! Displays:
//! 
//! ```none
//! The test failed at src/tests.rs:76:
//!     'my_result' should not have been an error
//!     But it is: 'Err(())'
//! 
//!     'my_result' should have contain '42'
//!     But it does not.
//! This test should have pass because I must have the answer
//! ```
//! 
//! ### Floats precision
//! 
//! ```rust
//! use fluid::*;
//! 
//! theory!(1.).should().be_equal_to(1.01).with_precision(0.1);
//! ```
//! 
//! ### `Result::Err`
//! 
//! ```rust
//! use fluid::*;
//! 
//! let parse_error = match "?".parse::<i32>() {
//!     Ok(_) => unimplemented!(),
//!     Err(e) => e,
//! };
//! let result = "two".parse::<i32>();
//! theory!(result).should().be_an_error()
//!     .and().should().be_this_error(parse_error);
//! ```
//! 
//! ### `Iterator`s
//! 
//! ```rust
//! use fluid::*;
//! 
//! fn error(e: bool) -> Result<i32, i32> {
//!     match e {
//!         true => Result::Err(0),
//!         false => Result::Ok(0),
//!     }
//! }
//! 
//! theory!(error(false)).should().contain(0);
//! theory!(error(true)).should().not().contain(0);
//! theory!(&[1, 2, 3]).should().not().contain(&0);
//! ```

//TODO: limit the size of displayed data (configurable)
//TODO: simplify this kind of messages:
//       | 	'zero' should not have been equal to '2'
//       |	But it is equal to '2'

#![deny(missing_docs)]
#![deny(unused)]

extern crate colored;
extern crate num_traits;

#[macro_export]
macro_rules! theory {
    ($e:expr) => {
        LeftElement::new($e, stringify!($e), concat!(file!(), ":", line!()))
    };
}

mod assertions;
mod infos;
mod theory;
#[cfg(test)]
mod tests;

pub use std::ops::Not;
pub use theory::{LeftElement, Theory};

fn not_str(truthness: bool) -> &'static str {
    match truthness {
        true => "",
        false => " not",
    }
}