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
use arbitrary::*;
use crate::Check;
pub(crate) const SATISFY_ATTEMPTS: usize = 3;
pub trait Bounds: std::fmt::Debug + PartialEq + Arbitrary<'static> + Clone {}
impl<T> Bounds for T where T: std::fmt::Debug + PartialEq + Arbitrary<'static> + Clone {}
pub type BoxFact<'a, T> = Box<dyn 'a + Fact<T>>;
pub type Facts<'a, T> = Vec<BoxFact<'a, T>>;
pub trait Fact<T>
where
T: Bounds,
{
fn check(&self, obj: &T) -> Check;
fn mutate(&self, obj: &mut T, u: &mut Unstructured<'static>);
fn advance(&mut self, obj: &T);
fn satisfy(&mut self, obj: &mut T, u: &mut Unstructured<'static>) {
let mut last_failure: Vec<String> = vec![];
for _i in 0..SATISFY_ATTEMPTS {
self.mutate(obj, u);
if let Err(errs) = self.check(obj).result() {
last_failure = errs;
} else {
return;
}
}
panic!(format!(
"Could not satisfy a constraint even after {} iterations. Last check failure: {:?}",
SATISFY_ATTEMPTS, last_failure
));
}
fn build(&mut self, u: &mut Unstructured<'static>) -> T {
let mut obj = T::arbitrary(u).unwrap();
self.satisfy(&mut obj, u);
obj
}
}
impl<T, F> Fact<T> for Box<F>
where
T: Bounds,
F: Fact<T> + ?Sized,
{
#[tracing::instrument(skip(self))]
fn check(&self, obj: &T) -> Check {
tracing::trace!("check");
(*self).as_ref().check(obj)
}
#[tracing::instrument(skip(self, u))]
fn mutate(&self, obj: &mut T, u: &mut Unstructured<'static>) {
(*self).as_ref().mutate(obj, u);
}
#[tracing::instrument(skip(self))]
fn advance(&mut self, obj: &T) {
(*self).as_mut().advance(obj)
}
}
impl<T, F> Fact<T> for &mut [F]
where
T: Bounds,
F: Fact<T>,
{
#[tracing::instrument(skip(self))]
fn check(&self, obj: &T) -> Check {
self.iter()
.flat_map(|f| f.check(obj))
.collect::<Vec<_>>()
.into()
}
#[tracing::instrument(skip(self, u))]
fn mutate(&self, obj: &mut T, u: &mut Unstructured<'static>) {
for f in self.iter() {
f.mutate(obj, u)
}
}
#[tracing::instrument(skip(self))]
fn advance(&mut self, obj: &T) {
for f in self.iter_mut() {
f.advance(obj)
}
}
}
impl<T, F> Fact<T> for Vec<F>
where
T: Bounds,
F: Fact<T>,
{
#[tracing::instrument(skip(self))]
fn check(&self, obj: &T) -> Check {
self.iter()
.flat_map(|f| f.check(obj))
.collect::<Vec<_>>()
.into()
}
#[tracing::instrument(skip(self, u))]
fn mutate(&self, obj: &mut T, u: &mut Unstructured<'static>) {
for f in self.iter() {
f.mutate(obj, u)
}
}
#[tracing::instrument(skip(self))]
fn advance(&mut self, obj: &T) {
for f in self.iter_mut() {
f.advance(obj)
}
}
}