1use std::collections::BTreeSet;
2use std::process::{Command, Stdio};
3
4pub type Feature = &'static str;
5
6pub struct TestArgs {
7    pub features: BTreeSet<Feature>,
8    pub default_features: bool,
9    pub lib_only: bool,
10}
11
12impl Default for TestArgs {
13    fn default() -> Self {
14        TestArgs {
15            features: BTreeSet::new(),
16            default_features: true,
17            lib_only: false,
18        }
19    }
20}
21
22impl TestArgs {
23    fn features_string(&self) -> Option<String> {
24        if self.features.is_empty() {
25            return None;
26        }
27
28        let s = self.features.iter().fold(String::new(), |mut s, f| {
29            if !s.is_empty() {
30                s.push(' ');
31            }
32            s.push_str(f);
33
34            s
35        });
36
37        Some(s)
38    }
39}
40
41pub fn test(args: TestArgs) -> bool {
42    let features = args.features_string();
43
44    let mut command = Command::new("cargo");
45
46    command
47        .stdout(Stdio::inherit())
48        .stderr(Stdio::inherit())
49        .arg("test")
50        .arg("--verbose");
51
52    if !args.default_features {
53        command.arg("--no-default-features");
54    }
55
56    if args.lib_only {
57        command.arg("--lib");
58    }
59
60    if let Some(features) = &features {
61        command.args(&["--features", features]);
62    }
63
64    println!("running {:?}", command);
65
66    let status = command.status().expect("Failed to execute command");
67
68    if !status.success() {
69        eprintln!(
70            "test execution failed for features: {}",
71            features.as_ref().map(AsRef::as_ref).unwrap_or("")
72        );
73        false
74    } else {
75        true
76    }
77}
78