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
use anyhow::{bail, ensure, Context, Result};
use assert_cmd::Command;
use cargo_metadata::{Artifact, ArtifactProfile, Message};
use if_chain::if_chain;
use lazy_static::lazy_static;
use log::debug;
use std::{io::BufReader, path::Path};
use subprocess::{Exec, Redirection};
lazy_static! {
static ref MANIFEST_PATH: String = Path::new(env!("CARGO_MANIFEST_DIR"))
.join("..")
.join("examples")
.join("Cargo.toml")
.to_string_lossy()
.to_string();
}
pub fn test(krate: &str, test: &str) -> Result<Command> {
let serde_format_feature = "test-fuzz/".to_owned() + crate::serde_format().as_feature();
let mut args = vec![
"test",
"--manifest-path",
&*MANIFEST_PATH,
"--test",
krate,
"--no-default-features",
"--features",
&serde_format_feature,
];
if crate::auto_concretize_enabled() {
args.extend_from_slice(&["--features", "__auto_concretize"]);
}
args.extend_from_slice(&["--no-run", "--message-format=json"]);
let exec = Exec::cmd("cargo").args(&args).stdout(Redirection::Pipe);
debug!("{:?}", exec);
let mut popen = exec.clone().popen()?;
let messages = popen
.stdout
.take()
.map_or(Ok(vec![]), |stream| -> Result<_> {
let reader = BufReader::new(stream);
let messages: Vec<Message> = Message::parse_stream(reader)
.collect::<std::result::Result<_, std::io::Error>>()
.with_context(|| format!("`parse_stream` failed for `{:?}`", exec))?;
Ok(messages)
})?;
let status = popen
.wait()
.with_context(|| format!("`wait` failed for `{:?}`", popen))?;
ensure!(status.success(), "Command failed: {:?}", exec);
let executables = messages
.into_iter()
.filter_map(|message| {
if_chain! {
if let Message::CompilerArtifact(Artifact {
profile: ArtifactProfile { test: true, .. },
executable: Some(executable),
..
}) = message;
if let Some(file_name) = executable.file_name();
if file_name.starts_with(&(krate.to_owned() + "-"));
then {
Some(executable)
} else {
None
}
}
})
.collect::<Vec<_>>();
ensure!(
executables.len() <= 1,
"Found multiple executables starting with `{}`",
krate
);
if let Some(executable) = executables.into_iter().next() {
let mut cmd = Command::new(executable);
cmd.args(&["--exact", test]);
Ok(cmd)
} else {
bail!("Found no executables starting with `{}`", krate)
}
}
pub fn test_fuzz(krate: &str, target: &str) -> Result<Command> {
let serde_format_feature = "test-fuzz/".to_owned() + crate::serde_format().as_feature();
let mut args = vec![
"test-fuzz",
"--manifest-path",
&*MANIFEST_PATH,
"--test",
krate,
"--no-default-features",
"--features",
&serde_format_feature,
];
if crate::auto_concretize_enabled() {
args.extend_from_slice(&["--features", "__auto_concretize"]);
}
args.extend_from_slice(&["--exact", "--target", target]);
let mut cmd = Command::cargo_bin("cargo-test-fuzz")?;
cmd.args(&args);
Ok(cmd)
}