bolero-engine 0.13.4

fuzz and property testing framework
Documentation
use std::path::PathBuf;

#[doc(hidden)]
#[macro_export]
macro_rules! __item_path__ {
    () => {{
        fn __bolero_item_path__() {}
        fn __resolve_item_path__<T>(_: T) -> &'static str {
            ::core::any::type_name::<T>()
        }
        __resolve_item_path__(__bolero_item_path__)
    }};
}

#[cfg(all(not(kani), test))]
mod tests;

#[doc(hidden)]
/// Information about the location of a test target
#[derive(Clone, Debug)]
pub struct TargetLocation {
    /// Path to the integration test binary
    pub package_name: &'static str,

    /// Absolute path to the directory of the test target Cargo.toml manifest
    pub manifest_dir: &'static str,

    /// Full module name of the test target
    pub module_path: &'static str,

    /// Absolute path to the test target
    pub file: &'static str,

    /// The line number at which the test target is defined
    pub line: u32,

    /// The path to the current test
    pub item_path: &'static str,

    /// The name of the test
    pub test_name: Option<String>,
}

#[cfg(kani)]
impl TargetLocation {
    pub fn should_run(&self) -> bool {
        true
    }

    pub fn abs_path(&self) -> Option<PathBuf> {
        None
    }

    pub fn work_dir(&self) -> Option<PathBuf> {
        None
    }

    pub fn is_harnessed(&self) -> bool {
        false
    }
}

#[cfg(not(kani))]
impl TargetLocation {
    pub fn should_run(&self) -> bool {
        // cargo-bolero needs to resolve information about the target
        if let Ok(mode) = ::std::env::var("CARGO_BOLERO_SELECT") {
            match mode.as_str() {
                "all" => self.print(),
                "one" if self.is_exact_match() => self.print(),
                _ => {}
            }
            return false;
        }
        true
    }

    fn is_exact_match(&self) -> bool {
        let test_name = self.item_path();
        std::env::args().take(2).any(|path| path == test_name)
    }

    fn print(&self) {
        println!(
            r#"
{{"__bolero_target":"v0.5.0","exe":{:?},"work_dir":{:?},"package_name":{:?},"is_harnessed":{:?},"test_name":{:?}}}"#,
            ::std::env::current_exe()
                .expect("valid current_exe")
                .display(),
            self.work_dir().expect("valid work_dir").display(),
            &self.package_name,
            self.is_harnessed(),
            self.item_path(),
        );
    }

    pub fn abs_path(&self) -> Option<PathBuf> {
        let file = std::path::Path::new(self.file);

        #[cfg(not(miri))] // miri does not currently support this call
        {
            if let Ok(file) = file.canonicalize() {
                return Some(file);
            }
        }

        std::path::Path::new(self.manifest_dir)
            .ancestors()
            .find_map(|ancestor| {
                let path = ancestor.join(file);
                if path.exists() {
                    Some(path)
                } else {
                    None
                }
            })
    }

    pub fn work_dir(&self) -> Option<PathBuf> {
        let mut work_dir = self.abs_path()?;
        work_dir.pop();

        if !self.is_harnessed() {
            return Some(work_dir);
        }

        work_dir.push("__fuzz__");
        if let Some(test_name) = self.test_name.as_ref() {
            work_dir.push(test_name);
        } else {
            work_dir.push(self.fuzz_dir());
        }

        Some(work_dir)
    }

    pub fn is_harnessed(&self) -> bool {
        // only harnessed tests spawn threads
        if std::thread::current()
            .name()
            .filter(|name| name != &"main")
            .is_some()
        {
            return true;
        }

        let mut parts: Vec<_> = self.item_path.split("::").collect();

        // remove parts up to the path probe
        while parts.pop().expect("empty path") != "__bolero_item_path__" {}

        // fuzz targets defined in main are not harnessed
        !matches!(
            parts.last().cloned(),
            Some("main") if parts.len() == 2
        )
    }

    fn fuzz_dir(&self) -> String {
        let test_name = self.item_path();
        let mut components: Vec<_> = test_name.split("::").collect();

        let last = components.len() - 1;
        let name = &mut components[last];

        if name.starts_with("test_") || name.starts_with("fuzz_") {
            *name = &name[5..];
        }

        if name.ends_with("_test") || name.ends_with("_fuzz") {
            let len = name.len();
            *name = &name[..(len - 5)];
        }

        components.join("__")
    }

    pub fn item_path(&self) -> String {
        Self::format_symbol_name(self.item_path)
    }

    fn format_symbol_name(name: &str) -> String {
        let mut parts: Vec<_> = name.split("::").collect();

        // remove parts up to the path probe
        while parts.pop().expect("empty path") != "__bolero_item_path__" {}

        match parts.last().cloned() {
            Some("main") if parts.len() == 2 => {
                parts.pop().expect("main symbol");
            }
            Some("{{closure}}") => {
                parts.pop().expect("unused symbol");
            }
            _ => {}
        }

        if parts.len() == 1 {
            parts.pop().unwrap().to_string()
        } else {
            parts[1..].join("::")
        }
    }
}