use std::borrow;
use std::fmt;
use difference;
use reflection;
use Predicate;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum DistanceOp {
Similar,
Different,
}
impl DistanceOp {
fn eval(self, limit: i32, distance: i32) -> bool {
match self {
DistanceOp::Similar => distance <= limit,
DistanceOp::Different => limit < distance,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DifferencePredicate {
orig: borrow::Cow<'static, str>,
split: borrow::Cow<'static, str>,
distance: i32,
op: DistanceOp,
}
impl DifferencePredicate {
pub fn split<S>(mut self, split: S) -> Self
where
S: Into<borrow::Cow<'static, str>>,
{
self.split = split.into();
self
}
pub fn distance(mut self, distance: i32) -> Self {
self.distance = distance;
self
}
}
impl Predicate<str> for DifferencePredicate {
fn eval(&self, edit: &str) -> bool {
let change = difference::Changeset::new(&self.orig, edit, &self.split);
self.op.eval(self.distance, change.distance)
}
fn find_case<'a>(&'a self, expected: bool, variable: &str) -> Option<reflection::Case<'a>> {
let change = difference::Changeset::new(&self.orig, variable, &self.split);
let result = self.op.eval(self.distance, change.distance);
if result == expected {
Some(
reflection::Case::new(Some(self), result)
.add_product(reflection::Product::new("actual distance", change.distance))
.add_product(reflection::Product::new("diff", change)),
)
} else {
None
}
}
}
impl reflection::PredicateReflection for DifferencePredicate {
fn parameters<'a>(&'a self) -> Box<Iterator<Item = reflection::Parameter<'a>> + 'a> {
let params = vec![reflection::Parameter::new("original", &self.orig)];
Box::new(params.into_iter())
}
}
impl fmt::Display for DifferencePredicate {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.op {
DistanceOp::Similar => write!(f, "var - original <= {}", self.distance),
DistanceOp::Different => write!(f, "{} < var - original", self.distance),
}
}
}
pub fn diff<S>(orig: S) -> DifferencePredicate
where
S: Into<borrow::Cow<'static, str>>,
{
DifferencePredicate {
orig: orig.into(),
split: "\n".into(),
distance: 0,
op: DistanceOp::Different,
}
}
pub fn similar<S>(orig: S) -> DifferencePredicate
where
S: Into<borrow::Cow<'static, str>>,
{
DifferencePredicate {
orig: orig.into(),
split: "\n".into(),
distance: 0,
op: DistanceOp::Similar,
}
}