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
use crypto::{digest::Digest, sha1::Sha1};
use dirs::corpus_directory_from_args_type;
use serde::{de::DeserializeOwned, Serialize};
use std::{
any::type_name,
env,
fmt::{self, Debug, Formatter},
fs::{create_dir_all, write},
io::{self, Read},
marker::PhantomData,
path::Path,
};
struct DebugUnimplemented<T>(PhantomData<T>);
impl<T> Debug for DebugUnimplemented<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
const PAT: &str = "TryDebug<";
let type_name = type_name::<T>();
let pos = type_name.find(PAT).unwrap() + PAT.len();
write!(
f,
"<unknown of type {}>",
type_name[pos..].strip_suffix(">").unwrap()
)
}
}
pub trait TryDebugFallback {
fn apply<U>(&self, f: &mut dyn FnMut(&dyn Debug) -> U) -> U;
}
impl<T> TryDebugFallback for T {
fn apply<U>(&self, f: &mut dyn FnMut(&dyn Debug) -> U) -> U {
f(&DebugUnimplemented::<Self>(PhantomData))
}
}
pub struct TryDebug<'a, T>(pub &'a T);
impl<'a, T: Debug> TryDebug<'a, T> {
pub fn apply<U>(&self, f: &mut dyn FnMut(&dyn Debug) -> U) -> U {
f(self.0)
}
}
pub trait TryDefaultFallback<U> {
fn default() -> Option<U>;
}
impl<T, U> TryDefaultFallback<U> for T {
#[must_use]
fn default() -> Option<U> {
None
}
}
pub struct TryDefault<'a, T>(pub &'a T);
impl<'a, T: Default> TryDefault<'a, T> {
#[must_use]
pub fn default() -> Option<T> {
Some(T::default())
}
}
#[must_use]
pub fn test_fuzz_enabled() -> bool {
enabled("")
}
#[must_use]
pub fn display_enabled() -> bool {
enabled("DISPLAY")
}
#[must_use]
pub fn pretty_print_enabled() -> bool {
enabled("PRETTY_PRINT")
}
#[must_use]
pub fn replay_enabled() -> bool {
enabled("REPLAY")
}
#[must_use]
pub fn write_enabled() -> bool {
enabled("WRITE")
}
#[must_use]
fn enabled(opt: &str) -> bool {
let key = "TEST_FUZZ".to_owned() + if opt.is_empty() { "" } else { "_" } + opt;
env::var(key).map_or(false, |value| value != "0")
}
pub fn write_args<T: Serialize>(args: &T) {
let corpus = corpus_directory_from_args_type::<T>();
let data = serde_cbor::to_vec(args).unwrap();
write_data(&corpus, &data).unwrap();
}
pub fn write_data(corpus: &Path, data: &[u8]) -> io::Result<()> {
create_dir_all(&corpus).unwrap_or_default();
let hex = {
let mut hasher = Sha1::new();
hasher.input(data);
hasher.result_str()
};
let path = corpus.join(hex);
write(path, &data)
}
pub fn read_args<T: DeserializeOwned, R: Read>(reader: R) -> Option<T> {
serde_cbor::from_reader(reader).ok()
}