uncloneable/
uncloneable.rs

1extern crate pseudo;
2
3use std::{fmt, io};
4use std::fmt::{Display, Formatter};
5use std::error::Error;
6use std::io::ErrorKind;
7use std::path::{Path, PathBuf};
8
9use pseudo::Mock;
10
11trait FileSystem: Clone {
12    fn copy<P: AsRef<Path>, Q: AsRef<Path>>(&self, from: P, to: Q) -> io::Result<()>;
13}
14
15fn copy_to_all<FS: FileSystem, P: AsRef<Path>>(fs: &FS, from: P, to: &[P]) -> Vec<io::Result<()>> {
16    to.iter()
17        .map(|path| fs.copy(&from, &path))
18        .collect::<Vec<io::Result<()>>>()
19}
20
21#[derive(Debug, Clone)]
22struct MockFileSystem<'a> {
23    pub copy: Mock<(PathBuf, PathBuf), Result<(), CloneableError<'a>>>,
24}
25
26impl<'a> FileSystem for MockFileSystem<'a> {
27    fn copy<P: AsRef<Path>, Q: AsRef<Path>>(&self, from: P, to: Q) -> io::Result<()> {
28        let args = (from.as_ref().to_path_buf(), to.as_ref().to_path_buf());
29        self.copy.call(args).map_err(|err| {
30            let (kind, description) = (err.kind, err.description);
31            io::Error::new(kind, description)
32        })
33    }
34}
35
36impl<'a> Default for MockFileSystem<'a> {
37    fn default() -> Self {
38        MockFileSystem {
39            copy: Mock::new(Ok(())),
40        }
41    }
42}
43
44#[derive(Debug, Clone)]
45struct CloneableError<'a> {
46    pub kind: io::ErrorKind,
47    pub description: &'a str,
48}
49
50impl<'a> Error for CloneableError<'a> {
51    fn description(&self) -> &str {
52        self.description
53    }
54}
55
56impl<'a> Display for CloneableError<'a> {
57    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
58        write!(f, "{}", self.description())
59    }
60}
61
62fn main() {
63    // Initially, the `copy` mock returns `Ok()`
64    let mock = MockFileSystem::default();
65
66    let result = copy_to_all(&mock, "from", &["to"]);
67
68    assert!(result.iter().all(|res| res.is_ok()));
69
70    assert_eq!(mock.copy.num_calls(), 1);
71    let expected_args = (
72        Path::new("from").to_path_buf(),
73        Path::new("to").to_path_buf(),
74    );
75    assert!(mock.copy.called_with(expected_args));
76
77    let err = CloneableError {
78        kind: ErrorKind::NotFound,
79        description: "test",
80    };
81    mock.copy.return_err(err);
82
83    let result = copy_to_all(&mock, "from", &["to"]);
84
85    assert!(result.iter().all(|res| res.is_err()));
86}