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 | |
9 | use std::fmt; |
10 | use std::fs; |
11 | use std::io::{self, Read}; |
12 | use std::path; |
13 | |
14 | use crate::reflection; |
15 | use crate::utils; |
16 | use crate::Predicate; |
17 | |
18 | fn 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)] |
26 | pub struct BinaryFilePredicate { |
27 | path: path::PathBuf, |
28 | content: utils::DebugAdapter<Vec<u8>>, |
29 | } |
30 | |
31 | impl 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 | |
59 | impl 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 | |
73 | impl 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 | |
83 | impl 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 | |
90 | impl fmt::Display for BinaryFilePredicate { |
91 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
92 | let palette = crate::Palette::current(); |
93 | write!( |
94 | f, |
95 | "{} {} {}" , |
96 | palette.var.paint("var" ), |
97 | palette.description.paint("is" ), |
98 | palette.expected.paint(self.path.display()) |
99 | ) |
100 | } |
101 | } |
102 | |
103 | /// Creates a new `Predicate` that ensures complete equality |
104 | /// |
105 | /// # Examples |
106 | /// |
107 | /// ``` |
108 | /// use std::path::Path; |
109 | /// use predicates::prelude::*; |
110 | /// |
111 | /// let predicate_file = predicate::path::eq_file(Path::new("Cargo.toml" )); |
112 | /// assert_eq!(true, predicate_file.eval(Path::new("Cargo.toml" ))); |
113 | /// assert_eq!(false, predicate_file.eval(Path::new("src" ))); |
114 | /// assert_eq!(false, predicate_file.eval(Path::new("src" ))); |
115 | /// ``` |
116 | pub fn eq_file<P: Into<path::PathBuf>>(path: P) -> BinaryFilePredicate { |
117 | let path = path.into(); |
118 | let content = utils::DebugAdapter::new(read_file(&path).unwrap()); |
119 | BinaryFilePredicate { path, content } |
120 | } |
121 | |
122 | /// Predicate that compares string content of files |
123 | #[derive(Debug, Clone, PartialEq, Eq)] |
124 | pub struct StrFilePredicate { |
125 | path: path::PathBuf, |
126 | content: String, |
127 | } |
128 | |
129 | impl StrFilePredicate { |
130 | fn eval(&self, path: &path::Path) -> Option<bool> { |
131 | let content = read_file(path).ok()?; |
132 | let content = String::from_utf8(content).ok()?; |
133 | Some(self.content == content) |
134 | } |
135 | } |
136 | |
137 | impl Predicate<path::Path> for StrFilePredicate { |
138 | fn eval(&self, path: &path::Path) -> bool { |
139 | self.eval(path).unwrap_or(false) |
140 | } |
141 | |
142 | fn find_case<'a>( |
143 | &'a self, |
144 | expected: bool, |
145 | variable: &path::Path, |
146 | ) -> Option<reflection::Case<'a>> { |
147 | utils::default_find_case(self, expected, variable) |
148 | } |
149 | } |
150 | |
151 | impl Predicate<str> for StrFilePredicate { |
152 | fn eval(&self, actual: &str) -> bool { |
153 | self.content == actual |
154 | } |
155 | |
156 | fn find_case<'a>(&'a self, expected: bool, variable: &str) -> Option<reflection::Case<'a>> { |
157 | utils::default_find_case(self, expected, variable) |
158 | } |
159 | } |
160 | |
161 | impl reflection::PredicateReflection for StrFilePredicate { |
162 | fn parameters<'a>(&'a self) -> Box<dyn Iterator<Item = reflection::Parameter<'a>> + 'a> { |
163 | let params = vec![reflection::Parameter::new("content" , &self.content)]; |
164 | Box::new(params.into_iter()) |
165 | } |
166 | } |
167 | |
168 | impl fmt::Display for StrFilePredicate { |
169 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
170 | let palette = crate::Palette::current(); |
171 | write!( |
172 | f, |
173 | "{} {} {}" , |
174 | palette.var.paint("var" ), |
175 | palette.description.paint("is" ), |
176 | palette.expected.paint(self.path.display()) |
177 | ) |
178 | } |
179 | } |
180 | |