test_fuzz_internal/
dirs.rs1use 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 #[allow(clippy::disallowed_methods)]
64 target_directory(false, false).join(path_segment("impl_generic_args"))
65}
66
67#[must_use]
68fn generic_args_directory() -> PathBuf {
69 #[allow(clippy::disallowed_methods)]
70 target_directory(false, false).join(path_segment("generic_args"))
71}
72
73#[must_use]
74fn corpus_directory() -> PathBuf {
75 #[allow(clippy::disallowed_methods)]
76 target_directory(false, false).join(path_segment("corpus"))
77}
78
79#[must_use]
80fn output_directory() -> PathBuf {
81 #[allow(clippy::disallowed_methods)]
82 target_directory(false, true).join(path_segment("output"))
83}
84
85#[must_use]
86pub fn path_segment(s: &str) -> String {
87 let maybe_id = maybe_id();
88 format!(
89 "{s}{}{}",
90 if maybe_id.is_some() { "_" } else { "" },
91 maybe_id.unwrap_or_default()
92 )
93}
94
95fn maybe_id() -> Option<String> {
96 env::var("TEST_FUZZ_ID").ok().or_else(|| {
97 if IN_TEST.load(Ordering::SeqCst) {
98 Some(thread_id())
99 } else {
100 None
101 }
102 })
103}
104
105fn thread_id() -> String {
106 format!("{:?}", std::thread::current().id()).replace(['(', ')'], "_")
107}
108
109#[must_use]
110pub fn target_directory(coverage: bool, fuzzing: bool) -> PathBuf {
111 assert!(!(coverage && fuzzing));
112 let mut command = MetadataCommand::new();
113 if let Ok(path) = env::var("TEST_FUZZ_MANIFEST_PATH") {
114 command.manifest_path(path);
115 }
116 let mut target_dir = command.no_deps().exec().unwrap().target_directory;
117 if coverage {
118 target_dir = target_dir.join("coverage");
119 }
120 if fuzzing {
121 target_dir = target_dir.join("afl");
122 }
123 target_dir.into()
124}
125
126#[must_use]
127fn path_from_args_type<T>() -> String {
128 let type_name = type_name::<T>();
129 let n = type_name
130 .find("_fuzz__")
131 .unwrap_or_else(|| panic!("unexpected type name: `{type_name}`"));
132 type_name[..n].to_owned()
133}
134
135#[must_use]
136fn path_from_target(krate: &str, target: &str) -> String {
137 krate.replace('-', "_") + "::" + target
138}