version_sync/
helpers.rs

1use std::fs::File;
2use std::io::{self, Read};
3
4/// The common result type, our errors will be simple strings.
5pub type Result<T> = std::result::Result<T, String>;
6
7#[cfg(any(feature = "html_root_url_updated", feature = "markdown_deps_updated"))]
8fn join<T>(iter: T, sep: &str) -> String
9where
10    T: IntoIterator,
11    T::Item: std::fmt::Display,
12{
13    let mut buf = String::new();
14    let mut iter = iter.into_iter();
15    if let Some(item) = iter.next() {
16        let item = item.to_string();
17        buf.push_str(&item);
18    } else {
19        return buf;
20    }
21    for item in iter {
22        buf.push_str(sep);
23        let item = item.to_string();
24        buf.push_str(&item);
25    }
26    buf
27}
28
29/// Return all data from `path`. Line boundaries are normalized from
30/// "\r\n" to "\n" to make sure "^" and "$" will match them. See
31/// https://github.com/rust-lang/regex/issues/244 for details.
32pub fn read_file(path: &str) -> io::Result<String> {
33    let mut file = File::open(path)?;
34    let mut buf = String::new();
35    file.read_to_string(&mut buf)?;
36    Ok(buf.replace("\r\n", "\n"))
37}
38
39/// Indent every line in text by four spaces.
40#[cfg(any(feature = "html_root_url_updated", feature = "markdown_deps_updated"))]
41pub fn indent(text: &str) -> String {
42    join(text.lines().map(|line| String::from("    ") + line), "\n")
43}
44
45/// Verify that the version range request matches the given version.
46#[cfg(any(
47    feature = "html_root_url_updated",
48    feature = "markdown_deps_updated",
49    feature = "contains_regex"
50))]
51pub fn version_matches_request(
52    version: &semver::Version,
53    request: &semver::VersionReq,
54) -> Result<()> {
55    use semver::Op;
56
57    for comparator in &request.comparators {
58        match comparator.op {
59            Op::Tilde | Op::Caret | Op::Exact | Op::Greater | Op::GreaterEq | Op::Wildcard => {
60                if comparator.major != version.major {
61                    return Err(format!(
62                        "expected major version {}, found {}",
63                        version.major, comparator.major,
64                    ));
65                }
66                if let Some(minor) = comparator.minor {
67                    if minor != version.minor {
68                        return Err(format!(
69                            "expected minor version {}, found {}",
70                            version.minor, minor
71                        ));
72                    }
73                }
74                if let Some(patch) = comparator.patch {
75                    if patch != version.patch {
76                        return Err(format!(
77                            "expected patch version {}, found {}",
78                            version.patch, patch
79                        ));
80                    }
81                }
82                if comparator.pre != version.pre {
83                    return Err(format!(
84                        "expected pre-release \"{}\", found \"{}\"",
85                        version.pre, comparator.pre
86                    ));
87                }
88            }
89            _ => {} // We cannot check other operators.
90        }
91    }
92
93    Ok(())
94}
95
96#[cfg(test)]
97mod tests {
98    #[cfg(any(feature = "html_root_url_updated", feature = "markdown_deps_updated"))]
99    use semver::{Version, VersionReq};
100
101    #[cfg(any(feature = "html_root_url_updated", feature = "markdown_deps_updated"))]
102    use super::*;
103
104    #[cfg(any(feature = "html_root_url_updated", feature = "markdown_deps_updated"))]
105    mod test_version_matches_request {
106        use super::*;
107
108        #[test]
109        fn implicit_compatible() {
110            let version = Version::parse("1.2.3").unwrap();
111            let request = VersionReq::parse("1.2.3").unwrap();
112            assert_eq!(version_matches_request(&version, &request), Ok(()));
113
114            let request = VersionReq::parse("1.2.0").unwrap();
115            assert!(version_matches_request(&version, &request).is_err());
116        }
117
118        #[test]
119        fn compatible() {
120            let version = Version::parse("1.2.3").unwrap();
121            let request = VersionReq::parse("^1.2.3").unwrap();
122            assert_eq!(version_matches_request(&version, &request), Ok(()));
123
124            let request = VersionReq::parse("^1.2.0").unwrap();
125            assert!(version_matches_request(&version, &request).is_err());
126        }
127
128        #[test]
129        fn tilde() {
130            let version = Version::parse("1.2.3").unwrap();
131            let request = VersionReq::parse("~1.2.3").unwrap();
132            assert_eq!(version_matches_request(&version, &request), Ok(()));
133
134            let request = VersionReq::parse("~1.2.0").unwrap();
135            assert!(version_matches_request(&version, &request).is_err());
136        }
137
138        #[test]
139        fn exact() {
140            let version = Version::parse("1.2.3").unwrap();
141            let request = VersionReq::parse("=1.2.3").unwrap();
142            assert_eq!(version_matches_request(&version, &request), Ok(()));
143
144            let request = VersionReq::parse("=1.2.0").unwrap();
145            assert!(version_matches_request(&version, &request).is_err());
146        }
147
148        #[test]
149        fn greater_or_equal() {
150            let version = Version::parse("1.2.3").unwrap();
151            let request = VersionReq::parse(">=1.2.3").unwrap();
152            assert_eq!(version_matches_request(&version, &request), Ok(()));
153
154            let request = VersionReq::parse(">=1.2.0").unwrap();
155            assert!(version_matches_request(&version, &request).is_err());
156        }
157
158        #[test]
159        fn wildcard() {
160            let version = Version::parse("1.2.3").unwrap();
161            let request = VersionReq::parse("1.2.*").unwrap();
162            assert_eq!(version_matches_request(&version, &request), Ok(()));
163
164            let request = VersionReq::parse("1.3.*").unwrap();
165            assert!(version_matches_request(&version, &request).is_err());
166        }
167
168        #[test]
169        fn greater() {
170            let version = Version::parse("1.2.3").unwrap();
171            let request = VersionReq::parse(">1.2.3").unwrap();
172            assert_eq!(version_matches_request(&version, &request), Ok(()));
173
174            let request = VersionReq::parse(">1.2.0").unwrap();
175            assert!(version_matches_request(&version, &request).is_err());
176        }
177
178        #[test]
179        fn no_patch() {
180            let version = Version::parse("1.2.3").unwrap();
181            let request = VersionReq::parse("1.2").unwrap();
182            assert_eq!(version_matches_request(&version, &request), Ok(()));
183        }
184
185        #[test]
186        fn no_minor() {
187            let version = Version::parse("1.2.3").unwrap();
188            let request = VersionReq::parse("1").unwrap();
189            assert_eq!(version_matches_request(&version, &request), Ok(()));
190        }
191
192        #[test]
193        fn multiple_comparators() {
194            let version = Version::parse("1.2.3").unwrap();
195            let request = VersionReq::parse(">= 1.2.3, < 2.0").unwrap();
196            assert_eq!(version_matches_request(&version, &request), Ok(()));
197
198            let request = VersionReq::parse(">= 1.2.0, < 2.0").unwrap();
199            assert!(version_matches_request(&version, &request).is_err());
200        }
201
202        #[test]
203        fn unhandled_operator() {
204            let version = Version::parse("1.2.3").unwrap();
205            let request = VersionReq::parse("< 2.0").unwrap();
206            assert_eq!(version_matches_request(&version, &request), Ok(()));
207        }
208
209        #[test]
210        fn bad_major() {
211            let version = Version::parse("2.0.0").unwrap();
212            let request = VersionReq::parse("1.2.3").unwrap();
213            assert_eq!(
214                version_matches_request(&version, &request),
215                Err(String::from("expected major version 2, found 1"))
216            );
217        }
218
219        #[test]
220        fn bad_minor() {
221            let version = Version::parse("1.3.0").unwrap();
222            let request = VersionReq::parse("1.2.3").unwrap();
223            assert_eq!(
224                version_matches_request(&version, &request),
225                Err(String::from("expected minor version 3, found 2"))
226            );
227        }
228
229        #[test]
230        fn bad_patch() {
231            let version = Version::parse("1.2.4").unwrap();
232            let request = VersionReq::parse("1.2.3").unwrap();
233            assert_eq!(
234                version_matches_request(&version, &request),
235                Err(String::from("expected patch version 4, found 3"))
236            );
237        }
238
239        #[test]
240        fn bad_pre_release() {
241            let version = Version::parse("1.2.3-rc2").unwrap();
242            let request = VersionReq::parse("1.2.3-rc1").unwrap();
243            assert_eq!(
244                version_matches_request(&version, &request),
245                Err(String::from("expected pre-release \"rc2\", found \"rc1\""))
246            );
247        }
248    }
249}