predicates/path/
fs.rs

1// Copyright (c) 2018 The predicates-rs Project Developers.
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use std::fmt;
10use std::fs;
11use std::io::{self, Read};
12use std::path;
13
14use crate::reflection;
15use crate::utils;
16use crate::Predicate;
17
18fn read_file(path: &path::Path) -> io::Result<Vec<u8>> {
19    let mut buffer = Vec::new();
20    fs::File::open(path)?.read_to_end(&mut buffer)?;
21    Ok(buffer)
22}
23
24/// Predicate that compares file matches
25#[derive(Debug, Clone, PartialEq, Eq)]
26pub struct BinaryFilePredicate {
27    path: path::PathBuf,
28    content: utils::DebugAdapter<Vec<u8>>,
29}
30
31impl BinaryFilePredicate {
32    fn eval(&self, path: &path::Path) -> io::Result<bool> {
33        let content = read_file(path)?;
34        Ok(self.content.debug == content)
35    }
36
37    /// Creates a new `Predicate` that ensures complete equality
38    ///
39    /// # Examples
40    ///
41    /// ```
42    /// use std::path::Path;
43    /// use predicates::prelude::*;
44    ///
45    /// let predicate_file = predicate::path::eq_file(Path::new("Cargo.toml")).utf8().unwrap();
46    /// assert_eq!(true, predicate_file.eval(Path::new("Cargo.toml")));
47    /// assert_eq!(false, predicate_file.eval(Path::new("Cargo.lock")));
48    /// assert_eq!(false, predicate_file.eval(Path::new("src")));
49    ///
50    /// assert_eq!(false, predicate_file.eval("Not a real Cargo.toml file content"));
51    /// ```
52    pub fn utf8(self) -> Option<StrFilePredicate> {
53        let path = self.path;
54        let content = String::from_utf8(self.content.debug).ok()?;
55        Some(StrFilePredicate { path, content })
56    }
57}
58
59impl Predicate<path::Path> for BinaryFilePredicate {
60    fn eval(&self, path: &path::Path) -> bool {
61        self.eval(path).unwrap_or(false)
62    }
63
64    fn find_case<'a>(
65        &'a self,
66        expected: bool,
67        variable: &path::Path,
68    ) -> Option<reflection::Case<'a>> {
69        utils::default_find_case(self, expected, variable)
70    }
71}
72
73impl Predicate<[u8]> for BinaryFilePredicate {
74    fn eval(&self, actual: &[u8]) -> bool {
75        self.content.debug == actual
76    }
77
78    fn find_case<'a>(&'a self, expected: bool, variable: &[u8]) -> Option<reflection::Case<'a>> {
79        utils::default_find_case(self, expected, variable)
80    }
81}
82
83impl reflection::PredicateReflection for BinaryFilePredicate {
84    fn parameters<'a>(&'a self) -> Box<dyn Iterator<Item = reflection::Parameter<'a>> + 'a> {
85        let params = vec![reflection::Parameter::new("content", &self.content)];
86        Box::new(params.into_iter())
87    }
88}
89
90impl fmt::Display for BinaryFilePredicate {
91    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92        write!(f, "var is {}", self.path.display())
93    }
94}
95
96/// Creates a new `Predicate` that ensures complete equality
97///
98/// # Examples
99///
100/// ```
101/// use std::path::Path;
102/// use predicates::prelude::*;
103///
104/// let predicate_file = predicate::path::eq_file(Path::new("Cargo.toml"));
105/// assert_eq!(true, predicate_file.eval(Path::new("Cargo.toml")));
106/// assert_eq!(false, predicate_file.eval(Path::new("src")));
107/// assert_eq!(false, predicate_file.eval(Path::new("src")));
108/// ```
109pub fn eq_file<P: Into<path::PathBuf>>(path: P) -> BinaryFilePredicate {
110    let path = path.into();
111    let content = utils::DebugAdapter::new(read_file(&path).unwrap());
112    BinaryFilePredicate { path, content }
113}
114
115/// Predicate that compares string content of files
116#[derive(Debug, Clone, PartialEq, Eq)]
117pub struct StrFilePredicate {
118    path: path::PathBuf,
119    content: String,
120}
121
122impl StrFilePredicate {
123    fn eval(&self, path: &path::Path) -> Option<bool> {
124        let content = read_file(path).ok()?;
125        let content = String::from_utf8(content).ok()?;
126        Some(self.content == content)
127    }
128}
129
130impl Predicate<path::Path> for StrFilePredicate {
131    fn eval(&self, path: &path::Path) -> bool {
132        self.eval(path).unwrap_or(false)
133    }
134
135    fn find_case<'a>(
136        &'a self,
137        expected: bool,
138        variable: &path::Path,
139    ) -> Option<reflection::Case<'a>> {
140        utils::default_find_case(self, expected, variable)
141    }
142}
143
144impl Predicate<str> for StrFilePredicate {
145    fn eval(&self, actual: &str) -> bool {
146        self.content == actual
147    }
148
149    fn find_case<'a>(&'a self, expected: bool, variable: &str) -> Option<reflection::Case<'a>> {
150        utils::default_find_case(self, expected, variable)
151    }
152}
153
154impl reflection::PredicateReflection for StrFilePredicate {
155    fn parameters<'a>(&'a self) -> Box<dyn Iterator<Item = reflection::Parameter<'a>> + 'a> {
156        let params = vec![reflection::Parameter::new("content", &self.content)];
157        Box::new(params.into_iter())
158    }
159}
160
161impl fmt::Display for StrFilePredicate {
162    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
163        write!(f, "var is {}", self.path.display())
164    }
165}