trycmd_indygreg_fork/
cases.rs1use std::borrow::Cow;
2
3#[derive(Debug, Default)]
5pub struct TestCases {
6 runner: std::cell::RefCell<crate::RunnerSpec>,
7 bins: std::cell::RefCell<crate::BinRegistry>,
8 substitutions: std::cell::RefCell<snapbox::Substitutions>,
9 has_run: std::cell::Cell<bool>,
10 file_loaders: std::cell::RefCell<crate::schema::TryCmdLoaders>,
11}
12
13impl TestCases {
14 pub fn new() -> Self {
15 let s = Self::default();
16 s.runner
17 .borrow_mut()
18 .include(parse_include(std::env::args_os()));
19 s
20 }
21
22 pub fn case(&self, glob: impl AsRef<std::path::Path>) -> &Self {
24 self.runner.borrow_mut().case(glob.as_ref(), None);
25 self
26 }
27
28 pub fn pass(&self, glob: impl AsRef<std::path::Path>) -> &Self {
30 self.runner
31 .borrow_mut()
32 .case(glob.as_ref(), Some(crate::schema::CommandStatus::Success));
33 self
34 }
35
36 pub fn fail(&self, glob: impl AsRef<std::path::Path>) -> &Self {
38 self.runner
39 .borrow_mut()
40 .case(glob.as_ref(), Some(crate::schema::CommandStatus::Failed));
41 self
42 }
43
44 pub fn interrupted(&self, glob: impl AsRef<std::path::Path>) -> &Self {
46 self.runner.borrow_mut().case(
47 glob.as_ref(),
48 Some(crate::schema::CommandStatus::Interrupted),
49 );
50 self
51 }
52
53 pub fn skip(&self, glob: impl AsRef<std::path::Path>) -> &Self {
55 self.runner
56 .borrow_mut()
57 .case(glob.as_ref(), Some(crate::schema::CommandStatus::Skipped));
58 self
59 }
60
61 pub fn default_bin_path(&self, path: impl AsRef<std::path::Path>) -> &Self {
63 let bin = Some(crate::schema::Bin::Path(path.as_ref().into()));
64 self.runner.borrow_mut().default_bin(bin);
65 self
66 }
67
68 pub fn default_bin_name(&self, name: impl AsRef<str>) -> &Self {
70 let bin = Some(crate::schema::Bin::Name(name.as_ref().into()));
71 self.runner.borrow_mut().default_bin(bin);
72 self
73 }
74
75 pub fn timeout(&self, time: std::time::Duration) -> &Self {
77 self.runner.borrow_mut().timeout(Some(time));
78 self
79 }
80
81 pub fn env(&self, key: impl Into<String>, value: impl Into<String>) -> &Self {
83 self.runner.borrow_mut().env(key, value);
84 self
85 }
86
87 pub fn register_bin(
89 &self,
90 name: impl Into<String>,
91 path: impl Into<crate::schema::Bin>,
92 ) -> &Self {
93 self.bins
94 .borrow_mut()
95 .register_bin(name.into(), path.into());
96 self
97 }
98
99 pub fn register_bins<N: Into<String>, B: Into<crate::schema::Bin>>(
101 &self,
102 bins: impl IntoIterator<Item = (N, B)>,
103 ) -> &Self {
104 self.bins
105 .borrow_mut()
106 .register_bins(bins.into_iter().map(|(n, b)| (n.into(), b.into())));
107 self
108 }
109
110 pub fn file_extension_loader(
119 &self,
120 extension: impl Into<std::ffi::OsString>,
121 loader: crate::schema::TryCmdLoader,
122 ) -> &Self {
123 self.file_loaders
124 .borrow_mut()
125 .insert(extension.into(), loader);
126 self
127 }
128
129 pub fn insert_var(
156 &self,
157 var: &'static str,
158 value: impl Into<Cow<'static, str>>,
159 ) -> Result<&Self, crate::Error> {
160 self.substitutions.borrow_mut().insert(var, value)?;
161 Ok(self)
162 }
163
164 pub fn extend_vars(
168 &self,
169 vars: impl IntoIterator<Item = (&'static str, impl Into<Cow<'static, str>>)>,
170 ) -> Result<&Self, crate::Error> {
171 self.substitutions.borrow_mut().extend(vars)?;
172 Ok(self)
173 }
174
175 pub fn run(&self) {
179 self.has_run.set(true);
180
181 let mode = parse_mode(std::env::var_os("TRYCMD").as_deref());
182 mode.initialize().unwrap();
183
184 let runner = self.runner.borrow_mut().prepare();
185 runner.run(
186 &self.file_loaders.borrow(),
187 &mode,
188 &self.bins.borrow(),
189 &self.substitutions.borrow(),
190 );
191 }
192}
193
194impl std::panic::RefUnwindSafe for TestCases {}
195
196#[doc(hidden)]
197impl Drop for TestCases {
198 fn drop(&mut self) {
199 if !self.has_run.get() && !std::thread::panicking() {
200 self.run();
201 }
202 }
203}
204
205#[allow(clippy::needless_collect)] fn parse_include(args: impl IntoIterator<Item = std::ffi::OsString>) -> Option<Vec<String>> {
216 let filters = args
217 .into_iter()
218 .flat_map(std::ffi::OsString::into_string)
219 .filter_map(|arg| {
220 const PREFIX: &str = "trycmd=";
221 if let Some(remainder) = arg.strip_prefix(PREFIX) {
222 if remainder.is_empty() {
223 None
224 } else {
225 Some(remainder.to_owned())
226 }
227 } else {
228 None
229 }
230 })
231 .collect::<Vec<String>>();
232
233 if filters.is_empty() {
234 None
235 } else {
236 Some(filters)
237 }
238}
239
240fn parse_mode(var: Option<&std::ffi::OsStr>) -> crate::Mode {
241 if var == Some(std::ffi::OsStr::new("overwrite")) {
242 crate::Mode::Overwrite
243 } else if var == Some(std::ffi::OsStr::new("dump")) {
244 crate::Mode::Dump("dump".into())
245 } else {
246 crate::Mode::Fail
247 }
248}