predicates/str/
difference.rs
1use std::borrow;
10use std::fmt;
11
12use crate::reflection;
13use crate::Predicate;
14
15#[derive(Clone, Copy, Debug, PartialEq, Eq)]
16enum DistanceOp {
17 Similar,
18 Different,
19}
20
21impl DistanceOp {
22 fn eval(self, limit: i32, distance: i32) -> bool {
23 match self {
24 DistanceOp::Similar => distance <= limit,
25 DistanceOp::Different => limit < distance,
26 }
27 }
28}
29
30#[derive(Debug, Clone, PartialEq, Eq)]
34pub struct DifferencePredicate {
35 orig: borrow::Cow<'static, str>,
36 split: borrow::Cow<'static, str>,
37 distance: i32,
38 op: DistanceOp,
39}
40
41impl DifferencePredicate {
42 pub fn split<S>(mut self, split: S) -> Self
60 where
61 S: Into<borrow::Cow<'static, str>>,
62 {
63 self.split = split.into();
64 self
65 }
66
67 pub fn distance(mut self, distance: i32) -> Self {
82 self.distance = distance;
83 self
84 }
85}
86
87impl Predicate<str> for DifferencePredicate {
88 fn eval(&self, edit: &str) -> bool {
89 let change = difference::Changeset::new(&self.orig, edit, &self.split);
90 self.op.eval(self.distance, change.distance)
91 }
92
93 fn find_case<'a>(&'a self, expected: bool, variable: &str) -> Option<reflection::Case<'a>> {
94 let change = difference::Changeset::new(&self.orig, variable, &self.split);
95 let result = self.op.eval(self.distance, change.distance);
96 if result == expected {
97 Some(
98 reflection::Case::new(Some(self), result)
99 .add_product(reflection::Product::new("actual distance", change.distance))
100 .add_product(reflection::Product::new("diff", change)),
101 )
102 } else {
103 None
104 }
105 }
106}
107
108impl reflection::PredicateReflection for DifferencePredicate {
109 fn parameters<'a>(&'a self) -> Box<dyn Iterator<Item = reflection::Parameter<'a>> + 'a> {
110 let params = vec![reflection::Parameter::new("original", &self.orig)];
111 Box::new(params.into_iter())
112 }
113}
114
115impl fmt::Display for DifferencePredicate {
116 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117 match self.op {
118 DistanceOp::Similar => write!(f, "var - original <= {}", self.distance),
119 DistanceOp::Different => write!(f, "{} < var - original", self.distance),
120 }
121 }
122}
123
124pub fn diff<S>(orig: S) -> DifferencePredicate
136where
137 S: Into<borrow::Cow<'static, str>>,
138{
139 DifferencePredicate {
140 orig: orig.into(),
141 split: "\n".into(),
142 distance: 0,
143 op: DistanceOp::Different,
144 }
145}
146
147pub fn similar<S>(orig: S) -> DifferencePredicate
159where
160 S: Into<borrow::Cow<'static, str>>,
161{
162 DifferencePredicate {
163 orig: orig.into(),
164 split: "\n".into(),
165 distance: 0,
166 op: DistanceOp::Similar,
167 }
168}