#![allow(dead_code)] use std::collections; use std::fs; use std::path; use anyhow::Context as _; pub const EMPTY: &[&str] = &[]; pub fn renamer(editor: impl AsRef) -> anyhow::Result { let editor_path = path::Path::new("tests/editors").join(editor.as_ref()); anyhow::ensure!( editor_path.is_file(), "Editor {} not found", editor.as_ref().display() ); let mut cmd = assert_cmd::Command::cargo_bin("renamer").context("Could not find renamer binary")?; cmd.arg("--yes"); cmd.env( "EDITOR", format!( "{} {}", editor_path.canonicalize()?.to_str().unwrap(), "-n -i --wait" ), ); Ok(cmd) } pub fn run_with_env( input: &[impl AsRef], replacements: &[impl AsRef], create_inputs: bool, ) -> anyhow::Result { let input: Vec<_> = input.iter().map(AsRef::as_ref).collect(); let replacements: Vec<_> = replacements.iter().map(AsRef::as_ref).collect(); let tempdir = tempfile::tempdir().context("Could not create tempdir")?; let input_file = tempdir.path().join("input"); let output_file = tempdir.path().join("output"); if create_inputs { for file in &input { let _ = fs::File::create(tempdir.path().join(file)); } } fs::write(&output_file, replacements.join("\n")) .context("Could not write replacements to editor output file")?; let assert = renamer("env-editor.py")? .env("TEST_EDITOR_INPUT", &input_file) .env("TEST_EDITOR_OUTPUT", &output_file) .current_dir(tempdir.path()) .write_stdin(input.join("\n")) .assert(); let editor_input = if input_file.exists() { fs::read_to_string(&input_file).context("Could not read editor input file")? } else { String::new() }; assert_eq!(input.join("\n"), editor_input); Ok(assert) } pub struct TestCase { dir: tempfile::TempDir, replacements: Vec<(String, String)>, } impl TestCase { pub fn new() -> anyhow::Result { let dir = tempfile::tempdir().context("Could not create tempdir")?; Ok(TestCase { dir, replacements: Vec::new(), }) } pub fn replace( &mut self, old: impl Into, new: impl Into, ) -> anyhow::Result<()> { let old = old.into(); let new = new.into(); let old_file = self.dir.path().join(&old); fs::write(&old_file, &old).context("Could not write to test case file")?; self.replacements.push((old, new)); Ok(()) } pub fn input(&self) -> anyhow::Result> { self.replacements .iter() .map(|(s, _)| self.dir.path().join(s)) .map(|p| { p.to_str() .map(ToOwned::to_owned) .with_context(|| format!("Invalid input file name: {}", p.display())) }) .collect::, _>>() } pub fn replacements(&self) -> anyhow::Result> { self.replacements .iter() .map(|(_, s)| self.dir.path().join(s)) .map(|p| { p.to_str() .map(ToOwned::to_owned) .with_context(|| format!("Invalid output file name: {}", p.display())) }) .collect::, _>>() } pub fn run(&self) -> anyhow::Result { run_with_env(&self.input()?, &self.replacements()?, false) } pub fn assert_run(&self) -> anyhow::Result { let assert = self.run()?.success().stderr(""); // TODO: assert stdout Ok(assert) } pub fn assert_renamed(&self) -> anyhow::Result<()> { let actual_files = self.get_files()?; let expected_files: collections::HashSet<_> = self.replacements.iter().map(|(_, s)| s).collect(); assert_eq!( expected_files, actual_files .iter() .map(|s| s) .collect::>() ); for (old, new) in &self.replacements { let new_path = self.dir.path().join(&new); assert!(new_path.is_file(), "New file does not exist: {}", &new); let content = fs::read_to_string(&new_path).context("Could not read output file")?; assert_eq!(old, &content, "File {} has unexpected content", &new); } Ok(()) } fn get_files(&self) -> anyhow::Result> { let mut files = Vec::new(); for file in self .dir .path() .read_dir() .context("Could not read tempdir")? { let file = file?; let file_name = file .file_name() .to_str() .map(|s| s.to_owned()) .with_context(|| format!("Invalid file name: {:?}", file.file_name()))?; assert!(file.file_type()?.is_file(), "{} is not a file", &file_name); files.push(file_name); } Ok(files) } }