1use crate::Error;
2
3use clap::{Parser, ValueEnum};
4use clap_verbosity::Verbosity;
5use disksize::DiskSize;
6use output::SetupTestOutputBuilder;
7use tame_index::{KrateName, index::FileLock};
8
9mod disksize;
10mod output;
11
12#[derive(Debug, Parser, Default, ValueEnum, Clone)]
13enum SelectVersion {
14 #[default]
15 Latest,
16 Highest,
17 HighestNormal,
18 Earliest,
19 None,
20}
21
22#[derive(Parser, Debug, Default)]
23#[clap(author, version, about, long_about = None)]
24pub struct Setup {
25 #[clap(flatten)]
26 logging: Verbosity,
27 #[clap(default_value = "false", short = 'r', long)]
29 no_replace: bool,
30 #[clap(
31 short,
32 long,
33 help = "Add dependencies based on specific version\n",
34 default_value = "latest"
35 )]
36 dependencies: SelectVersion,
37 #[clap(short, long, default_value = "tests/local_registry")]
39 location: String,
40 crate_: String,
42}
43
44impl Setup {
45 pub fn run(&self) -> Result<String, Error> {
46 log::info!(
47 "Setting up local registry and adding crate: {}",
48 self.crate_
49 );
50 let lock = FileLock::unlocked();
51
52 let combo_index = crate::get_remote_combo_index()?;
53 let crate_name = KrateName::crates_io(&self.crate_)?;
54
55 let index_crate = combo_index.krate(crate_name, true, &lock)?;
56
57 let Some(index_crate) = index_crate else {
58 return Err(Error::CrateNotFoundOnIndex);
59 };
60
61 let registry = if self.location.is_empty() {
62 "tests/local_registry"
63 } else {
64 &self.location
65 };
66 log::debug!("Creating registry at {registry}");
67 let mut output = SetupTestOutputBuilder::new(index_crate.clone(), registry);
68
69 output.initialise_local_registry(self.no_replace)?;
70
71 output.insert_crate(&index_crate)?;
72
73 match self.dependencies {
74 SelectVersion::Latest => {
75 log::debug!("Adding dependencies for most recent version");
76 output.add_dependency_crates(
77 index_crate.most_recent_version().dependencies(),
78 &combo_index,
79 )?;
80 }
81 SelectVersion::Earliest => {
82 log::debug!("Adding dependencies for earliest version");
83 output.add_dependency_crates(
84 index_crate.earliest_version().dependencies(),
85 &combo_index,
86 )?;
87 }
88 SelectVersion::Highest => {
89 log::debug!("Adding dependencies for highest version");
90 output.add_dependency_crates(
91 index_crate.highest_version().dependencies(),
92 &combo_index,
93 )?;
94 }
95 SelectVersion::HighestNormal => {
96 log::debug!("Attempting to add dependencies for highest normal version");
97 let opt_index_version = index_crate.highest_normal_version();
98 if let Some(index_version) = opt_index_version {
99 output.add_dependency_crates(index_version.dependencies(), &combo_index)?;
100 } else {
101 log::warn!("No normal version found for crate: {}", self.crate_);
102 };
103 }
104 SelectVersion::None => (),
105 };
106 log::debug!("Finalizing registry");
107 let final_output = output.finalize()?;
108 log::debug!("Registry setup complete");
109 Ok(final_output.to_string())
110 }
111}
112
113#[cfg(test)]
114mod tests {
115 use std::path::Path;
116
117 use super::*;
118 const TEST_CRATE_NAME: &str = "forestry";
119 const TEST_NON_EXISTENT_CRATE_NAME: &str = "nonexistent_crate_12345";
121
122 #[test]
123 fn test_setup_run_default_directory() {
124 let _log = simple_logger::init_with_level(log::Level::Debug);
125
126 let setup = Setup {
127 crate_: String::from(TEST_CRATE_NAME),
128 dependencies: SelectVersion::Latest,
129 ..Default::default()
130 };
131 let result = setup.run();
132 log::debug!("Result: {result:?}");
133 assert!(result.is_ok());
134 assert!(Path::new("tests/local_registry").exists());
135 }
136
137 #[test]
138 fn test_setup_run_with_latest_dependencies() {
139 let _log = simple_logger::init_with_level(log::Level::Debug);
140 let temp_dir = tempfile::tempdir().unwrap();
141 let location = temp_dir.path().to_str().unwrap();
142
143 let setup = Setup {
144 crate_: String::from(TEST_CRATE_NAME),
145 dependencies: SelectVersion::Latest,
146 location: location.to_string(),
147 ..Default::default()
148 };
149 let result = setup.run();
150 log::debug!("Result: {result:?}");
151 assert!(result.is_ok());
152 assert!(Path::new(location).exists());
153 }
154
155 #[test]
156 fn test_setup_run_with_earliest_dependencies() {
157 let _log = simple_logger::init_with_level(log::Level::Debug);
158 let temp_dir = tempfile::tempdir().unwrap();
159 let location = temp_dir.path().to_str().unwrap();
160 let setup = Setup {
161 crate_: String::from(TEST_CRATE_NAME),
162 dependencies: SelectVersion::Earliest,
163 location: location.to_string(),
164 ..Default::default()
165 };
166 let result = setup.run();
167 log::debug!("Result: {result:?}");
168 assert!(result.is_ok());
169 }
170
171 #[test]
172 fn test_setup_run_with_highest_normal_dependencies() {
173 let _log = simple_logger::init_with_level(log::Level::Debug);
174 let temp_dir = tempfile::tempdir().unwrap();
175 let location = temp_dir.path().to_str().unwrap();
176 let setup = Setup {
177 crate_: String::from(TEST_CRATE_NAME),
178 dependencies: SelectVersion::HighestNormal,
179 location: location.to_string(),
180 ..Default::default()
181 };
182 let result = setup.run();
183 log::debug!("Result: {result:?}");
184 assert!(result.is_ok());
185 }
186
187 #[test]
188 fn test_setup_run_with_highest_dependencies() {
189 let _log = simple_logger::init_with_level(log::Level::Debug);
190 let temp_dir = tempfile::tempdir().unwrap();
191 let location = temp_dir.path().to_str().unwrap();
192 let setup = Setup {
193 crate_: String::from(TEST_CRATE_NAME),
194 dependencies: SelectVersion::Highest,
195 location: location.to_string(),
196 ..Default::default()
197 };
198 let result = setup.run();
199 log::debug!("Result: {result:?}");
200 assert!(result.is_ok());
201 }
202
203 #[test]
204 fn test_setup_run_with_no_dependencies() {
205 let _log = simple_logger::init_with_level(log::Level::Debug);
206 let temp_dir = tempfile::tempdir().unwrap();
207 let location = temp_dir.path().to_str().unwrap();
208 let setup = Setup {
209 crate_: String::from(TEST_CRATE_NAME),
210 dependencies: SelectVersion::None,
211 location: location.to_string(),
212 ..Default::default()
213 };
214 let result = setup.run();
215 log::debug!("Result: {result:?}");
216 assert!(result.is_ok());
217 }
218
219 #[test]
220 fn test_setup_run_nonexistent_crate() {
221 let _log = simple_logger::init_with_level(log::Level::Debug);
222 let temp_dir = tempfile::tempdir().unwrap();
223 let location = temp_dir.path().to_str().unwrap();
224 let setup = Setup {
225 crate_: String::from(TEST_NON_EXISTENT_CRATE_NAME),
226 dependencies: SelectVersion::Latest,
227 location: location.to_string(),
228 ..Default::default()
229 };
230 let result = setup.run();
231 log::debug!("Result: {result:?}");
232 assert!(matches!(result, Err(Error::CrateNotFoundOnIndex)));
233 }
234
235 #[test]
236 fn test_setup_run_with_no_replace_flag_not_set() {
237 let _log = simple_logger::init_with_level(log::Level::Debug);
238 let temp_dir = tempfile::tempdir().unwrap();
239 let location = temp_dir.path().to_str().unwrap();
240 let setup = Setup {
241 crate_: String::from(TEST_CRATE_NAME),
242 dependencies: SelectVersion::Latest,
243 no_replace: false,
244 location: location.to_string(),
245 ..Default::default()
246 };
247
248 let result1 = setup.run();
250 log::debug!("Result1: {result1:?}");
251 assert!(result1.is_ok());
252
253 let result2 = setup.run();
255 log::debug!("Result2: {result2:?}");
256 assert!(result2.is_ok());
257 }
258
259 #[test]
260 fn test_setup_run_with_no_replace_flag_set() {
261 let _log = simple_logger::init_with_level(log::Level::Debug);
262 let temp_dir = tempfile::tempdir().unwrap();
263 let location = temp_dir.path().to_str().unwrap();
264 let setup = Setup {
265 crate_: String::from(TEST_CRATE_NAME),
266 dependencies: SelectVersion::Latest,
267 no_replace: true,
268 location: location.to_string(),
269 ..Default::default()
270 };
271
272 let result1 = setup.run();
274 log::debug!("Result1: {result1:?}");
275 assert!(result1.is_ok());
276
277 let result2 = setup.run();
279 log::debug!("Result2: {result2:?}");
280 assert!(result2.is_err());
281 }
282}