test_fuzz_internal/
dirs.rs

1use cargo_metadata::MetadataCommand;
2use std::{
3    any::type_name,
4    env,
5    path::PathBuf,
6    sync::atomic::{AtomicBool, Ordering},
7};
8
9pub static IN_TEST: AtomicBool = AtomicBool::new(false);
10
11#[must_use]
12pub fn impl_generic_args_directory_from_args_type<T>() -> PathBuf {
13    impl_generic_args_directory().join(path_from_args_type::<T>())
14}
15
16#[must_use]
17pub fn impl_generic_args_directory_from_target(krate: &str, target: &str) -> PathBuf {
18    impl_generic_args_directory().join(path_from_target(krate, target))
19}
20
21#[must_use]
22pub fn generic_args_directory_from_args_type<T>() -> PathBuf {
23    generic_args_directory().join(path_from_args_type::<T>())
24}
25
26#[must_use]
27pub fn generic_args_directory_from_target(krate: &str, target: &str) -> PathBuf {
28    generic_args_directory().join(path_from_target(krate, target))
29}
30
31#[must_use]
32pub fn corpus_directory_from_args_type<T>() -> PathBuf {
33    corpus_directory().join(path_from_args_type::<T>())
34}
35
36#[must_use]
37pub fn corpus_directory_from_target(krate: &str, target: &str) -> PathBuf {
38    corpus_directory().join(path_from_target(krate, target))
39}
40
41#[must_use]
42pub fn crashes_directory_from_target(krate: &str, target: &str) -> PathBuf {
43    output_directory_from_target(krate, target).join("default/crashes")
44}
45
46#[must_use]
47pub fn hangs_directory_from_target(krate: &str, target: &str) -> PathBuf {
48    output_directory_from_target(krate, target).join("default/hangs")
49}
50
51#[must_use]
52pub fn queue_directory_from_target(krate: &str, target: &str) -> PathBuf {
53    output_directory_from_target(krate, target).join("default/queue")
54}
55
56#[must_use]
57pub fn output_directory_from_target(krate: &str, target: &str) -> PathBuf {
58    output_directory().join(path_from_target(krate, target))
59}
60
61#[must_use]
62fn impl_generic_args_directory() -> PathBuf {
63    target_directory(false).join(path_segment("impl_generic_args"))
64}
65
66#[must_use]
67fn generic_args_directory() -> PathBuf {
68    target_directory(false).join(path_segment("generic_args"))
69}
70
71#[must_use]
72fn corpus_directory() -> PathBuf {
73    target_directory(false).join(path_segment("corpus"))
74}
75
76#[must_use]
77fn output_directory() -> PathBuf {
78    target_directory(true).join(path_segment("output"))
79}
80
81#[must_use]
82pub fn path_segment(s: &str) -> String {
83    let maybe_id = maybe_id();
84    format!(
85        "{s}{}{}",
86        if maybe_id.is_some() { "_" } else { "" },
87        maybe_id.unwrap_or_default()
88    )
89}
90
91fn maybe_id() -> Option<String> {
92    env::var("TEST_FUZZ_ID").ok().or_else(|| {
93        if IN_TEST.load(Ordering::SeqCst) {
94            Some(thread_id())
95        } else {
96            None
97        }
98    })
99}
100
101fn thread_id() -> String {
102    format!("{:?}", std::thread::current().id()).replace(['(', ')'], "_")
103}
104
105#[must_use]
106pub fn target_directory(instrumented: bool) -> PathBuf {
107    let mut command = MetadataCommand::new();
108    if let Ok(path) = env::var("TEST_FUZZ_MANIFEST_PATH") {
109        command.manifest_path(path);
110    }
111    let mut target_dir = command.no_deps().exec().unwrap().target_directory;
112    if instrumented {
113        target_dir = target_dir.join("afl");
114    }
115    target_dir.into()
116}
117
118#[must_use]
119fn path_from_args_type<T>() -> String {
120    let type_name = type_name::<T>();
121    let n = type_name
122        .find("_fuzz__")
123        .unwrap_or_else(|| panic!("unexpected type name: `{type_name}`"));
124    type_name[..n].to_owned()
125}
126
127#[must_use]
128fn path_from_target(krate: &str, target: &str) -> String {
129    krate.replace('-', "_") + "::" + target
130}