use std::env; use std::fs::{self, File}; use std::io::Read; use std::path::{Path, PathBuf}; use std::process::Command; use tempfile::TempDir; use git2::build::CheckoutBuilder; use git2::Repository; use git2::Signature; pub struct BatTester { /// Temporary working directory temp_dir: TempDir, /// Path to the *bat* executable exe: PathBuf, } impl BatTester { pub fn test_snapshot(&self, name: &str, style: &str) { let output = Command::new(&self.exe) .current_dir(self.temp_dir.path()) .args(&[ "sample.rs", "--no-config", "--paging=never", "--color=never", "--decorations=always", "--terminal-width=80", &format!("--style={}", style), ]) .output() .expect("bat failed"); // have to do the replace because the filename in the header changes based on the current working directory let actual = String::from_utf8_lossy(&output.stdout) .as_ref() .replace("tests/snapshots/", ""); let mut expected = String::new(); let mut file = File::open(format!("tests/snapshots/output/{}.snapshot.txt", name)) .expect("snapshot file missing"); file.read_to_string(&mut expected) .expect("could not read snapshot file"); assert_eq!(expected, actual); } } impl Default for BatTester { fn default() -> Self { let temp_dir = create_sample_directory().expect("sample directory"); let root = env::current_exe() .expect("tests executable") .parent() .expect("tests executable directory") .parent() .expect("bat executable directory") .to_path_buf(); let exe_name = if cfg!(windows) { "bat.exe" } else { "bat" }; let exe = root.join(exe_name); BatTester { temp_dir, exe } } } fn create_sample_directory() -> Result { // Create temp directory and initialize repository let temp_dir = TempDir::new().expect("Temp directory"); let repo = Repository::init(&temp_dir)?; // Copy over `sample.rs` let sample_path = temp_dir.path().join("sample.rs"); println!("{:?}", &sample_path); fs::copy("tests/snapshots/sample.rs", &sample_path).expect("successful copy"); // Commit let mut index = repo.index()?; index.add_path(Path::new("sample.rs"))?; let oid = index.write_tree()?; let signature = Signature::now("bat test runner", "bat@test.runner")?; let tree = repo.find_tree(oid)?; let _ = repo.commit( Some("HEAD"), // point HEAD to our new commit &signature, // author &signature, // committer "initial commit", &tree, &[], ); let mut opts = CheckoutBuilder::new(); repo.checkout_head(Some(opts.force()))?; fs::copy("tests/snapshots/sample.modified.rs", &sample_path).expect("successful copy"); Ok(temp_dir) }