use super::manifest::CargoToml;
use super::manifest_models::{DiscoveredTarget, TestRole};
use std::fs;
use std::path::Path;
impl CargoToml {
pub fn discover_test_targets(&self, pkg_dir: &Path) -> Vec<DiscoveredTarget> {
let mut targets = Vec::new();
let pkg_name = self.package.as_ref().map(|p| p.name.as_str()).unwrap_or("");
let edition = self.package.as_ref().and_then(|p| p.edition.clone());
let default_lib = pkg_dir.join("src").join("lib.rs");
let lib_src = if let Some(ref lib) = self.lib {
lib.path
.as_ref()
.map(|p| pkg_dir.join(p))
.unwrap_or(default_lib)
} else {
default_lib
};
let lib_has_test = self.lib.as_ref().and_then(|l| l.test).unwrap_or(true);
let lib_has_harness = self.lib.as_ref().and_then(|l| l.harness).unwrap_or(true);
if lib_src.is_file() {
targets.push(DiscoveredTarget {
name: format!("{}_unit_test", pkg_name.replace('-', "_")),
kind: "test".to_string(),
src_path: lib_src,
edition: edition.clone(),
crate_types: vec!["bin".to_string()],
required_features: None,
harness: lib_has_harness,
test_role: Some(TestRole::LibUnit),
explicit_only: !lib_has_test,
});
}
let bin_targets: Vec<DiscoveredTarget> = self
.discover_targets(pkg_dir)
.into_iter()
.filter(|t| t.kind == "bin")
.collect();
for b in bin_targets {
let bin_has_test = self
.bin
.iter()
.find(|bin| bin.name == b.name)
.and_then(|bin| bin.test)
.unwrap_or(true);
targets.push(DiscoveredTarget {
name: format!("{}_bin_test", b.name.replace('-', "_")),
kind: "test".to_string(),
src_path: b.src_path,
edition: b.edition,
crate_types: vec!["bin".to_string()],
required_features: b.required_features,
harness: b.harness,
test_role: Some(TestRole::BinUnit(b.name.clone())),
explicit_only: !bin_has_test,
});
}
let mut explicit_test_paths = std::collections::HashSet::new();
for t in &self.test {
let test_enabled = t.test.unwrap_or(true);
let src = match t.path {
Some(ref p) => pkg_dir.join(p),
None => pkg_dir.join("tests").join(format!("{}.rs", t.name)),
};
if src.is_file() {
explicit_test_paths.insert(src.clone());
targets.push(DiscoveredTarget {
name: t.name.clone(),
kind: "test".to_string(),
src_path: src,
edition: edition.clone(),
crate_types: vec!["bin".to_string()],
required_features: t.required_features.clone(),
harness: t.harness.unwrap_or(true),
test_role: Some(TestRole::Integration),
explicit_only: !test_enabled,
});
}
}
let autotests = self
.package
.as_ref()
.and_then(|p| p.autotests)
.unwrap_or(true);
if autotests {
let tests_dir = pkg_dir.join("tests");
if let Ok(entries) = fs::read_dir(&tests_dir) {
let mut auto_targets = Vec::new();
for entry in entries.flatten() {
let p = entry.path();
if p.is_file()
&& p.extension().and_then(|e| e.to_str()) == Some("rs")
&& !explicit_test_paths.contains(&p)
{
if let Some(stem) = p.file_stem().and_then(|s| s.to_str()) {
if !stem.starts_with('.') {
auto_targets.push((stem.to_string(), p));
}
}
} else if p.is_dir() {
let main_rs = p.join("main.rs");
if main_rs.is_file() && !explicit_test_paths.contains(&main_rs) {
if let Some(dir_name) = p.file_name().and_then(|s| s.to_str()) {
if !dir_name.starts_with('.') {
auto_targets.push((dir_name.to_string(), main_rs));
}
}
}
}
}
auto_targets.sort_by(|a, b| a.0.cmp(&b.0));
for (name, path) in auto_targets {
if !targets
.iter()
.any(|t| t.name == name && t.test_role == Some(TestRole::Integration))
{
targets.push(DiscoveredTarget {
name,
kind: "test".to_string(),
src_path: path,
edition: edition.clone(),
crate_types: vec!["bin".to_string()],
required_features: None,
harness: true,
test_role: Some(TestRole::Integration),
explicit_only: false,
});
}
}
}
}
targets
}
pub fn discover_doctest_target(&self, pkg_dir: &Path) -> Option<DiscoveredTarget> {
let pkg_name = self.package.as_ref().map(|p| p.name.as_str()).unwrap_or("");
let edition = self.package.as_ref().and_then(|p| p.edition.clone());
let default_lib = pkg_dir.join("src").join("lib.rs");
let lib_src = if let Some(ref lib) = self.lib {
lib.path
.as_ref()
.map(|p| pkg_dir.join(p))
.unwrap_or(default_lib)
} else {
default_lib
};
let doctest_enabled = self.lib.as_ref().and_then(|l| l.doctest).unwrap_or(true);
let doc_enabled = self.lib.as_ref().and_then(|l| l.doc).unwrap_or(true);
if lib_src.is_file() && doctest_enabled && doc_enabled {
Some(DiscoveredTarget {
name: pkg_name.replace('-', "_"),
kind: "doctest".to_string(),
src_path: lib_src,
edition,
crate_types: vec!["lib".to_string()],
required_features: None,
harness: true,
test_role: None,
explicit_only: false,
})
} else {
None
}
}
}