use std::path;
use std::process;
use crate::error::{CargoError, CargoResult};
use crate::format;
use crate::msg::CommandMessages;
pub struct CargoTest {
bin_path: path::PathBuf,
kind: String,
name: String,
}
impl CargoTest {
pub(crate) fn with_messages(
msgs: CommandMessages,
) -> impl Iterator<Item = Result<Self, CargoError>> {
extract_binary_paths(msgs)
}
pub fn name(&self) -> &str {
self.name.as_str()
}
pub fn kind(&self) -> &str {
self.kind.as_str()
}
pub fn path(&self) -> &path::Path {
&self.bin_path
}
pub fn command(&self) -> process::Command {
let mut cmd = process::Command::new(self.path());
cmd.arg("-Z").arg("unstable-options").arg("--format=json");
cmd
}
pub fn exec(&self) -> CargoResult<CommandMessages> {
CommandMessages::with_command(self.command())
}
}
fn extract_bin(msg: &format::Message<'_>) -> Option<CargoTest> {
match msg {
format::Message::CompilerArtifact(art) => {
if art.profile.test {
let bin_path = art
.filenames
.first()
.expect("files must exist")
.to_path_buf();
let kind = art
.target
.kind
.first()
.expect("kind must exist")
.as_ref()
.to_owned();
let name = art.target.name.as_ref().to_owned();
Some(CargoTest {
bin_path,
kind,
name,
})
} else {
None
}
}
_ => None,
}
}
fn transpose<T, E>(r: Result<Option<T>, E>) -> Option<Result<T, E>> {
match r {
Ok(Some(x)) => Some(Ok(x)),
Ok(None) => None,
Err(e) => Some(Err(e)),
}
}
fn extract_binary_paths(
msgs: CommandMessages,
) -> impl Iterator<Item = Result<CargoTest, CargoError>> {
msgs.filter_map(move |m| {
let m = m.and_then(|m| {
let m = m.decode()?;
format::log_message(&m);
let p = extract_bin(&m);
Ok(p)
});
transpose(m)
})
}