scm_diff_editor/
testing.rs1use std::collections::{BTreeMap, BTreeSet};
3use std::io;
4use std::path::{Path, PathBuf};
5
6use scm_record::{File, FileMode};
7
8use crate::{Error, FileContents, FileInfo, Filesystem, Result};
9
10#[derive(Debug)]
12pub struct TestFilesystem {
13 files: BTreeMap<PathBuf, FileInfo>,
14 dirs: BTreeSet<PathBuf>,
15}
16
17impl TestFilesystem {
18 pub fn new(files: BTreeMap<PathBuf, FileInfo>) -> Self {
20 let dirs = files
21 .keys()
22 .flat_map(|path| path.ancestors().skip(1))
23 .map(|path| path.to_owned())
24 .collect();
25 Self { files, dirs }
26 }
27
28 fn assert_parent_dir_exists(&self, path: &Path) {
29 if let Some(parent_dir) = path.parent() {
30 assert!(
31 self.dirs.contains(parent_dir),
32 "parent dir for {path:?} does not exist"
33 );
34 }
35 }
36}
37
38impl Filesystem for TestFilesystem {
39 fn read_dir_diff_paths(&self, left: &Path, right: &Path) -> Result<BTreeSet<PathBuf>> {
40 let left_files = self
41 .files
42 .keys()
43 .filter_map(|path| path.strip_prefix(left).ok());
44 let right_files = self
45 .files
46 .keys()
47 .filter_map(|path| path.strip_prefix(right).ok());
48 Ok(left_files
49 .chain(right_files)
50 .map(|path| path.to_path_buf())
51 .collect())
52 }
53
54 fn read_file_info(&self, path: &Path) -> Result<FileInfo> {
55 match self.files.get(path) {
56 Some(file_info) => Ok(file_info.clone()),
57 None => match self.dirs.get(path) {
58 Some(_path) => Err(Error::ReadFile {
59 path: path.to_owned(),
60 source: io::Error::new(io::ErrorKind::Other, "is a directory"),
61 }),
62 None => Ok(FileInfo {
63 file_mode: FileMode::Absent,
64 contents: FileContents::Absent,
65 }),
66 },
67 }
68 }
69
70 fn write_file(&mut self, path: &Path, contents: &str) -> Result<()> {
71 self.assert_parent_dir_exists(path);
72 self.files.insert(path.to_owned(), file_info(contents));
73 Ok(())
74 }
75
76 fn copy_file(&mut self, old_path: &Path, new_path: &Path) -> Result<()> {
77 self.assert_parent_dir_exists(new_path);
78 let file_info = self.read_file_info(old_path)?;
79 self.files.insert(new_path.to_owned(), file_info);
80 Ok(())
81 }
82
83 fn remove_file(&mut self, path: &Path) -> Result<()> {
84 self.files.remove(path);
85 Ok(())
86 }
87
88 fn create_dir_all(&mut self, path: &Path) -> Result<()> {
89 self.dirs.insert(path.to_owned());
90 Ok(())
91 }
92}
93
94pub fn file_info(contents: impl Into<String>) -> FileInfo {
97 let contents = contents.into();
98 let num_bytes = contents.len().try_into().unwrap();
99 FileInfo {
100 file_mode: FileMode::Unix(0o100644),
101 contents: FileContents::Text {
102 contents,
103 hash: "abc123".to_string(),
104 num_bytes,
105 },
106 }
107}
108
109pub fn select_all(files: &mut [File]) {
111 for file in files {
112 file.set_checked(true);
113 }
114}