/home/runner/work/rustc-semver/rustc-semver/src/lib.rs
Line | Count | Source (jump to first uncovered line) |
1 | 1 | #![no_std]#![no_std] |
2 | | |
3 | | use core::{cmp::Ordering, fmt::Display, num::ParseIntError}; |
4 | | |
5 | | /// `Error` represents an Error during parsing of a [`RustcVersion`]. |
6 | 14 | #[derive(D0 ebug0 , Eq, PartialEq, Copy, Clone0 )] |
7 | | pub enum Error { |
8 | | /// A version was passed that has too many elements seperated by `'.'`. |
9 | | TooManyElements, |
10 | | /// A version was passed that neither is a [`SpecialVersion`], nor a |
11 | | /// normal [`RustcVersion`]. |
12 | | NotASpecialVersion, |
13 | | /// A version was passed, that was either an empty string or a part of the |
14 | | /// version was left out, e.g. `1. .3` |
15 | | EmptyVersionPart, |
16 | | /// A version was passed that has unallowed chracters. |
17 | | ParseIntError, |
18 | | } |
19 | | |
20 | | impl From<ParseIntError> for Error { |
21 | 2 | fn from(_: ParseIntError) -> Self { |
22 | 2 | Self::ParseIntError |
23 | 2 | } |
24 | | } |
25 | | |
26 | | /// Result type for this crate |
27 | | pub type Result<T> = core::result::Result<T, Error>; |
28 | | |
29 | | /// `RustcVersion` represents a version of the Rust Compiler. |
30 | | /// |
31 | | /// This struct only supports the [`NormalVersion`] format |
32 | | /// ```text |
33 | | /// major.minor.patch |
34 | | /// ``` |
35 | | /// and 3 special formats represented by the [`SpecialVersion`] enum. |
36 | | /// |
37 | | /// A version can be created with one of the functions [`RustcVersion::new`] or |
38 | | /// [`RustcVersion::parse`]. The [`RustcVersion::new`] method only supports the |
39 | | /// normal version format. |
40 | | /// |
41 | | /// You can compare two versions, just as you would expect: |
42 | | /// |
43 | | /// ```rust |
44 | | /// use rustc_semver::RustcVersion; |
45 | | /// |
46 | | /// assert!(RustcVersion::new(1, 34, 0) > RustcVersion::parse("1.10").unwrap()); |
47 | | /// assert!(RustcVersion::new(1, 34, 0) > RustcVersion::parse("0.9").unwrap()); |
48 | | /// ``` |
49 | | /// |
50 | | /// This comparison is semver conform according to the [semver definition of |
51 | | /// precedence]. However, if you want to check whether one version meets |
52 | | /// another version according to the [Caret Requirements], you should use |
53 | | /// [`RustcVersion::meets`]. |
54 | | /// |
55 | | /// [Caret Requirements]: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#caret-requirements |
56 | | /// [semver definition of precedence]: https://semver.org/#spec-item-11 |
57 | 22 | #[derive(D0 ebug0 , Eq, PartialEq, Copy, Clone0 )] Unexecuted instantiation: <rustc_semver::RustcVersion as core::cmp::PartialEq>::ne <rustc_semver::RustcVersion as core::cmp::PartialEq>::eq Line | Count | Source | 57 | 22 | #[derive(Debug, Eq, PartialEq, Copy, Clone)] |
|
58 | | pub enum RustcVersion { |
59 | | Normal(NormalVersion), |
60 | | Special(SpecialVersion), |
61 | | } |
62 | | |
63 | | /// `NormalVersion` represents a normal version used for all releases since |
64 | | /// Rust 1.0.0. |
65 | | /// |
66 | | /// This struct supports versions in the format |
67 | | /// ```test |
68 | | /// major.minor.patch |
69 | | /// ``` |
70 | 0 | #[derive(Debug, Copy, Clone)] |
71 | | pub struct NormalVersion { |
72 | | major: u32, |
73 | | minor: u32, |
74 | | patch: u32, |
75 | | omitted: OmittedParts, |
76 | | } |
77 | | |
78 | 0 | #[derive(Debug, Copy, Clone)] |
79 | | enum OmittedParts { |
80 | | None, |
81 | | Minor, |
82 | | Patch, |
83 | | } |
84 | | |
85 | | impl From<usize> for OmittedParts { |
86 | 39 | fn from(parts: usize) -> Self { |
87 | 39 | match parts { |
88 | 11 | 1 => Self::Minor, |
89 | 18 | 2 => Self::Patch, |
90 | 8 | 3 => Self::None, |
91 | 2 | _ => unreachable!( |
92 | 2 | "This function should never be called with `parts == 0` or `parts > 3`" |
93 | 2 | ), |
94 | | } |
95 | 37 | } |
96 | | } |
97 | | |
98 | | /// `SpecialVersion` represents a special version from the first releases. |
99 | | /// |
100 | | /// Before Rust 1.0.0, there were two alpha and one beta release, namely |
101 | | /// |
102 | | /// - `1.0.0-alpha` |
103 | | /// - `1.0.0-alpha.2` |
104 | | /// - `1.0.0-beta` |
105 | | /// |
106 | | /// This enum represents those releases. |
107 | 9 | #[derive(D0 ebug0 , Eq, PartialEq, Copy, Clone0 )] |
108 | | pub enum SpecialVersion { |
109 | | Alpha, |
110 | | Alpha2, |
111 | | Beta, |
112 | | } |
113 | | |
114 | | impl PartialOrd for RustcVersion { |
115 | 18 | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { |
116 | 18 | Some(self.cmp(other)) |
117 | 18 | } |
118 | | } |
119 | | |
120 | | impl Ord for RustcVersion { |
121 | | fn cmp(&self, other: &Self) -> Ordering { |
122 | 21 | match (self, other) { |
123 | 8 | (Self::Normal(ver), Self::Normal(o_ver)) => ver.cmp(o_ver), |
124 | 2 | (Self::Normal(NormalVersion { major, .. }), Self::Special(_)) => { |
125 | 2 | if *major >= 1 { |
126 | 1 | Ordering::Greater |
127 | | } else { |
128 | 1 | Ordering::Less |
129 | | } |
130 | | } |
131 | 2 | (Self::Special(_), Self::Normal(NormalVersion { major, .. })) => { |
132 | 2 | if *major >= 1 { |
133 | 1 | Ordering::Less |
134 | | } else { |
135 | 1 | Ordering::Greater |
136 | | } |
137 | | } |
138 | 9 | (Self::Special(s_ver), Self::Special(o_s_ver)) => s_ver.cmp(o_s_ver), |
139 | | } |
140 | 21 | } |
141 | | } |
142 | | |
143 | | impl PartialOrd for NormalVersion { |
144 | 34 | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { |
145 | 34 | Some(self.cmp(other)) |
146 | 34 | } |
147 | | } |
148 | | |
149 | | impl Ord for NormalVersion { |
150 | 42 | fn cmp(&self, other: &Self) -> Ordering { |
151 | 42 | match self.major.cmp(&other.major) { |
152 | 32 | Ordering::Equal => match self.minor.cmp(&other.minor) { |
153 | 19 | Ordering::Equal => self.patch.cmp(&other.patch), |
154 | 13 | ord => ord, |
155 | | }, |
156 | 10 | ord => ord, |
157 | | } |
158 | 42 | } |
159 | | } |
160 | | |
161 | | impl PartialEq for NormalVersion { |
162 | 7 | fn eq(&self, other: &Self) -> bool { |
163 | 7 | self.major == other.major && self.minor == other.minor && self.patch == other.patch |
164 | 7 | } |
165 | | } |
166 | | |
167 | | impl Eq for NormalVersion {} |
168 | | |
169 | | impl PartialOrd for SpecialVersion { |
170 | 0 | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { |
171 | 0 | Some(self.cmp(other)) |
172 | 0 | } |
173 | | } |
174 | | |
175 | | impl Ord for SpecialVersion { |
176 | | fn cmp(&self, other: &Self) -> Ordering { |
177 | 9 | match (self, other) { |
178 | | (Self::Alpha, Self::Alpha) |
179 | | | (Self::Alpha2, Self::Alpha2) |
180 | 3 | | (Self::Beta, Self::Beta) => Ordering::Equal, |
181 | 3 | (Self::Alpha, _) | (Self::Alpha2, Self::Beta) => Ordering::Less, |
182 | 3 | (Self::Beta, _) | (Self::Alpha2, Self::Alpha) => Ordering::Greater, |
183 | | } |
184 | 9 | } |
185 | | } |
186 | | |
187 | | impl Display for RustcVersion { |
188 | 4 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
189 | 4 | match self { |
190 | | Self::Normal(NormalVersion { |
191 | 1 | major, |
192 | 1 | minor, |
193 | 1 | patch, |
194 | 1 | .. |
195 | 1 | }) => write!(f, "{}.{}.{}", major, minor, patch), |
196 | 3 | Self::Special(special) => write!(f, "{}", special), |
197 | | } |
198 | 4 | } |
199 | | } |
200 | | |
201 | | impl Display for SpecialVersion { |
202 | 3 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
203 | 3 | match self { |
204 | 1 | Self::Alpha => write!(f, "1.0.0-alpha"), |
205 | 1 | Self::Alpha2 => write!(f, "1.0.0-alpha.2"), |
206 | 1 | Self::Beta => write!(f, "1.0.0-beta"), |
207 | | } |
208 | 3 | } |
209 | | } |
210 | | |
211 | | impl From<[u32; 3]> for NormalVersion { |
212 | 37 | fn from(arr: [u32; 3]) -> Self { |
213 | 37 | NormalVersion { |
214 | 37 | major: arr[0], |
215 | 37 | minor: arr[1], |
216 | 37 | patch: arr[2], |
217 | 37 | omitted: OmittedParts::None, |
218 | 37 | } |
219 | 37 | } |
220 | | } |
221 | | |
222 | | const ACCEPTED_SPECIAL_VERSIONS: [(&str, SpecialVersion); 3] = [ |
223 | | ("1.0.0-alpha", SpecialVersion::Alpha), |
224 | | ("1.0.0-alpha.2", SpecialVersion::Alpha2), |
225 | | ("1.0.0-beta", SpecialVersion::Beta), |
226 | | ]; |
227 | | |
228 | | impl RustcVersion { |
229 | | /// `RustcVersion::new` is a `const` constructor for a `RustcVersion`. |
230 | | /// |
231 | | /// This function is primarily used to construct constants, for everything |
232 | | /// else use [`RustcVersion::parse`]. |
233 | | /// |
234 | | /// This function only allows to construct normal versions. For special |
235 | | /// versions, construct them directly with the [`SpecialVersion`] enum. |
236 | | /// |
237 | | /// # Examples |
238 | | /// |
239 | | /// ```rust |
240 | | /// use rustc_semver::RustcVersion; |
241 | | /// |
242 | | /// const MY_FAVORITE_RUST: RustcVersion = RustcVersion::new(1, 48, 0); |
243 | | /// |
244 | | /// assert!(MY_FAVORITE_RUST > RustcVersion::new(1, 0, 0)) |
245 | | /// ``` |
246 | 65 | pub const fn new(major: u32, minor: u32, patch: u32) -> Self { |
247 | 65 | Self::Normal(NormalVersion { |
248 | 65 | major, |
249 | 65 | minor, |
250 | 65 | patch, |
251 | 65 | omitted: OmittedParts::None, |
252 | 65 | }) |
253 | 65 | } |
254 | | |
255 | | /// `RustcVersion::parse` parses a [`RustcVersion`]. |
256 | | /// |
257 | | /// This function can parse all normal and special versions. It is possbile |
258 | | /// to omit parts of the version, like the patch or minor version part. So |
259 | | /// `1`, `1.0`, and `1.0.0` are all valid inputs and will result in the |
260 | | /// same version. |
261 | | /// |
262 | | /// # Errors |
263 | | /// |
264 | | /// This function returns an [`Error`], if the passed string is not a valid |
265 | | /// [`RustcVersion`] |
266 | | /// |
267 | | /// # Examples |
268 | | /// |
269 | | /// ```rust |
270 | | /// use rustc_semver::{SpecialVersion, RustcVersion}; |
271 | | /// |
272 | | /// let ver = RustcVersion::new(1, 0, 0); |
273 | | /// |
274 | | /// assert_eq!(RustcVersion::parse("1").unwrap(), ver); |
275 | | /// assert_eq!(RustcVersion::parse("1.0").unwrap(), ver); |
276 | | /// assert_eq!(RustcVersion::parse("1.0.0").unwrap(), ver); |
277 | | /// assert_eq!( |
278 | | /// RustcVersion::parse("1.0.0-alpha").unwrap(), |
279 | | /// RustcVersion::Special(SpecialVersion::Alpha) |
280 | | /// ); |
281 | | /// ``` |
282 | 65 | pub fn parse(version: &str) -> Result<Self> { |
283 | 182 | let special_version = ACCEPTED_SPECIAL_VERSIONS.iter().find_map(|sv| { |
284 | 182 | if version == sv.0 { |
285 | 14 | Some(sv.1) |
286 | | } else { |
287 | 168 | None |
288 | | } |
289 | 182 | })65 ; |
290 | 65 | if let Some(special_version14 ) = special_version { |
291 | 14 | return Ok(RustcVersion::Special(special_version)); |
292 | 51 | } |
293 | 51 | |
294 | 51 | let mut rustc_version = [0_u32; 3]; |
295 | 51 | let mut parts = 0; |
296 | 101 | for (i, part) in version.split('.').enumerate()51 { |
297 | 101 | let part = part.trim(); |
298 | 101 | if part.is_empty() { |
299 | 7 | return Err(Error::EmptyVersionPart); |
300 | 94 | } |
301 | 94 | if i == 3 { |
302 | 1 | return Err(Error::TooManyElements); |
303 | 93 | } |
304 | 93 | match str::parse(part) { |
305 | 87 | Ok(part) => rustc_version[i] = part, |
306 | 6 | Err(e) => { |
307 | 6 | if i == 2 { |
308 | 4 | return Err(Error::NotASpecialVersion); |
309 | | } else { |
310 | 2 | return Err(e.into()); |
311 | | } |
312 | | } |
313 | | } |
314 | | |
315 | 87 | parts = i + 1; |
316 | | } |
317 | | |
318 | 37 | let mut ver = NormalVersion::from(rustc_version); |
319 | 37 | ver.omitted = OmittedParts::from(parts); |
320 | 37 | Ok(RustcVersion::Normal(ver)) |
321 | 65 | } |
322 | | |
323 | | /// `RustcVersion::meets` implements a semver conform version check |
324 | | /// according to the [Caret Requirements]. |
325 | | /// |
326 | | /// Note that [`SpecialVersion`]s only meet themself and no other version |
327 | | /// meets a [`SpecialVersion`]. This is because [according to semver], |
328 | | /// special versions are considered unstable and "might not satisfy the |
329 | | /// intended compatibility requirements as denoted by \[their\] associated |
330 | | /// normal version". |
331 | | /// |
332 | | /// # Examples |
333 | | /// |
334 | | /// ```rust |
335 | | /// use rustc_semver::RustcVersion; |
336 | | /// |
337 | | /// assert!(RustcVersion::new(1, 30, 0).meets(RustcVersion::parse("1.29").unwrap())); |
338 | | /// assert!(!RustcVersion::new(1, 30, 0).meets(RustcVersion::parse("1.31").unwrap())); |
339 | | /// |
340 | | /// assert!(RustcVersion::new(0, 2, 1).meets(RustcVersion::parse("0.2").unwrap())); |
341 | | /// assert!(!RustcVersion::new(0, 3, 0).meets(RustcVersion::parse("0.2").unwrap())); |
342 | | /// ``` |
343 | | /// |
344 | | /// [Caret Requirements]: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#caret-requirements |
345 | | /// [according to semver]: https://semver.org/#spec-item-9 |
346 | | pub fn meets(self, other: Self) -> bool { |
347 | 46 | match (self, other) { |
348 | 12 | (RustcVersion::Special(_), _) | (_, RustcVersion::Special(_)) => self == other, |
349 | 34 | (RustcVersion::Normal(ver), RustcVersion::Normal(o_ver)) => { |
350 | | // In any case must `self` be bigger than `other`, with the major part matching |
351 | | // the other version. |
352 | 34 | let mut meets = ver >= o_ver && ver.major == o_ver.major31 ; |
353 | | |
354 | | // In addition, the left-most non-zero digit must not be modified. |
355 | 34 | match o_ver.omitted { |
356 | | OmittedParts::None => { |
357 | | // Nothing was omitted, this means that everything must match in case of |
358 | | // leading zeros. |
359 | 14 | if o_ver.major == 0 { |
360 | | // Leading 0 in major position, check for |
361 | | // `self.minor == other.minor` |
362 | 9 | meets &= ver.minor == o_ver.minor; |
363 | 9 | |
364 | 9 | if o_ver.minor == 0 { |
365 | 5 | // Leading 0 in minor position, check for |
366 | 5 | // `self.patch == other.patch`. |
367 | 5 | meets &= ver.patch == o_ver.patch; |
368 | 5 | }4 |
369 | 5 | } |
370 | | } |
371 | | OmittedParts::Patch => { |
372 | | // The patch version was omitted, this means the patch version of `self` |
373 | | // does not have to match the patch version of `other`. |
374 | 12 | if o_ver.major == 0 { |
375 | 7 | meets &= ver.minor == o_ver.minor; |
376 | 7 | }5 |
377 | | } |
378 | 8 | OmittedParts::Minor => { |
379 | 8 | // The minor (and patch) version was omitted, this means |
380 | 8 | // the minor and patch version of `self` do not have to |
381 | 8 | // match the minor and patch version of `other` |
382 | 8 | } |
383 | | } |
384 | | |
385 | 34 | meets |
386 | | } |
387 | | } |
388 | 46 | } |
389 | | } |
390 | | |
391 | | #[cfg(test)] |
392 | | mod test { |
393 | | use super::*; |
394 | | |
395 | 1 | #[test] |
396 | 1 | fn omitted_parts() { |
397 | 1 | assert_eq!( |
398 | 1 | RustcVersion::parse("1.0.0").unwrap(), |
399 | 1 | RustcVersion::new(1, 0, 0) |
400 | 1 | ); |
401 | 1 | assert_eq!( |
402 | 1 | RustcVersion::parse("1.0").unwrap(), |
403 | 1 | RustcVersion::new(1, 0, 0) |
404 | 1 | ); |
405 | 1 | assert_eq!( |
406 | 1 | RustcVersion::parse("1").unwrap(), |
407 | 1 | RustcVersion::new(1, 0, 0) |
408 | 1 | ); |
409 | 1 | } |
410 | | |
411 | 1 | #[test] |
412 | 1 | fn special_versions() { |
413 | 1 | assert_eq!( |
414 | 1 | RustcVersion::parse("1.0.0-alpha").unwrap(), |
415 | 1 | RustcVersion::Special(SpecialVersion::Alpha) |
416 | 1 | ); |
417 | 1 | assert_eq!( |
418 | 1 | RustcVersion::parse("1.0.0-alpha.2").unwrap(), |
419 | 1 | RustcVersion::Special(SpecialVersion::Alpha2) |
420 | 1 | ); |
421 | 1 | assert_eq!( |
422 | 1 | RustcVersion::parse("1.0.0-beta").unwrap(), |
423 | 1 | RustcVersion::Special(SpecialVersion::Beta) |
424 | 1 | ); |
425 | 1 | assert_eq!( |
426 | 1 | RustcVersion::parse("1.0.0-sigma"), |
427 | 1 | Err(Error::NotASpecialVersion) |
428 | 1 | ); |
429 | 1 | assert_eq!( |
430 | 1 | RustcVersion::parse("1.0.0beta"), |
431 | 1 | Err(Error::NotASpecialVersion) |
432 | 1 | ); |
433 | 1 | assert_eq!( |
434 | 1 | RustcVersion::parse("1.1.0-beta"), |
435 | 1 | Err(Error::NotASpecialVersion) |
436 | 1 | ); |
437 | 1 | } |
438 | | |
439 | 1 | #[test] |
440 | 1 | fn less_than() { |
441 | 1 | let bigger = RustcVersion::new(1, 30, 1); |
442 | 1 | assert!(RustcVersion::parse("1.0.0").unwrap() < bigger); |
443 | 1 | assert!(RustcVersion::parse("1.0").unwrap() < bigger); |
444 | 1 | assert!(RustcVersion::parse("1").unwrap() < bigger); |
445 | 1 | assert!(RustcVersion::parse("1.30").unwrap() < bigger); |
446 | 1 | assert!(RustcVersion::parse("1.0.0-beta").unwrap() < bigger); |
447 | 1 | assert!(RustcVersion::parse("0.9").unwrap() < RustcVersion::Special(SpecialVersion::Alpha)); |
448 | 1 | assert!( |
449 | 1 | RustcVersion::parse("1.0.0-alpha").unwrap() |
450 | 1 | < RustcVersion::Special(SpecialVersion::Alpha2) |
451 | 1 | ); |
452 | 1 | assert!( |
453 | 1 | RustcVersion::parse("1.0.0-alpha").unwrap() |
454 | 1 | < RustcVersion::Special(SpecialVersion::Beta) |
455 | 1 | ); |
456 | 1 | assert!( |
457 | 1 | RustcVersion::parse("1.0.0-alpha.2").unwrap() |
458 | 1 | < RustcVersion::Special(SpecialVersion::Beta) |
459 | 1 | ); |
460 | 1 | } |
461 | | |
462 | 1 | #[test] |
463 | 1 | fn equal() { |
464 | 1 | assert_eq!( |
465 | 1 | RustcVersion::parse("1.22.0").unwrap(), |
466 | 1 | RustcVersion::new(1, 22, 0) |
467 | 1 | ); |
468 | 1 | assert_eq!( |
469 | 1 | RustcVersion::parse("1.22").unwrap(), |
470 | 1 | RustcVersion::new(1, 22, 0) |
471 | 1 | ); |
472 | 1 | assert_eq!( |
473 | 1 | RustcVersion::parse("1.48.1").unwrap(), |
474 | 1 | RustcVersion::new(1, 48, 1) |
475 | 1 | ); |
476 | 1 | assert_eq!( |
477 | 1 | RustcVersion::parse("1.0.0-alpha") |
478 | 1 | .unwrap() |
479 | 1 | .cmp(&RustcVersion::Special(SpecialVersion::Alpha)), |
480 | 1 | Ordering::Equal |
481 | 1 | ); |
482 | 1 | assert_eq!( |
483 | 1 | RustcVersion::parse("1.0.0-alpha.2") |
484 | 1 | .unwrap() |
485 | 1 | .cmp(&RustcVersion::Special(SpecialVersion::Alpha2)), |
486 | 1 | Ordering::Equal |
487 | 1 | ); |
488 | 1 | assert_eq!( |
489 | 1 | RustcVersion::parse("1.0.0-beta") |
490 | 1 | .unwrap() |
491 | 1 | .cmp(&RustcVersion::Special(SpecialVersion::Beta)), |
492 | 1 | Ordering::Equal |
493 | 1 | ); |
494 | 1 | } |
495 | | |
496 | 1 | #[test] |
497 | 1 | fn greater_than() { |
498 | 1 | let less = RustcVersion::new(1, 15, 1); |
499 | 1 | assert!(RustcVersion::parse("1.16.0").unwrap() > less); |
500 | 1 | assert!(RustcVersion::parse("1.16").unwrap() > less); |
501 | 1 | assert!(RustcVersion::parse("2").unwrap() > less); |
502 | 1 | assert!(RustcVersion::parse("1.15.2").unwrap() > less); |
503 | 1 | assert!( |
504 | 1 | RustcVersion::parse("1.0.0-beta").unwrap() |
505 | 1 | > RustcVersion::Special(SpecialVersion::Alpha2) |
506 | 1 | ); |
507 | 1 | assert!( |
508 | 1 | RustcVersion::parse("1.0.0-beta").unwrap() |
509 | 1 | > RustcVersion::Special(SpecialVersion::Alpha) |
510 | 1 | ); |
511 | 1 | assert!( |
512 | 1 | RustcVersion::parse("1.0.0-alpha.2").unwrap() |
513 | 1 | > RustcVersion::Special(SpecialVersion::Alpha) |
514 | 1 | ); |
515 | 1 | assert!(RustcVersion::parse("1.0.0-alpha.2").unwrap() > RustcVersion::new(0, 8, 0)); |
516 | 1 | assert!( |
517 | 1 | RustcVersion::parse("1.45.2").unwrap() > RustcVersion::Special(SpecialVersion::Alpha2) |
518 | 1 | ); |
519 | 1 | } |
520 | | |
521 | 1 | #[test] |
522 | 1 | fn edge_cases() { |
523 | 1 | assert_eq!(RustcVersion::parse(""), Err(Error::EmptyVersionPart)); |
524 | 1 | assert_eq!(RustcVersion::parse(" "), Err(Error::EmptyVersionPart)); |
525 | 1 | assert_eq!(RustcVersion::parse("\t"), Err(Error::EmptyVersionPart)); |
526 | 1 | assert_eq!(RustcVersion::parse("1."), Err(Error::EmptyVersionPart)); |
527 | 1 | assert_eq!(RustcVersion::parse("1. "), Err(Error::EmptyVersionPart)); |
528 | 1 | assert_eq!(RustcVersion::parse("1.\t"), Err(Error::EmptyVersionPart)); |
529 | 1 | assert_eq!(RustcVersion::parse("1. \t.3"), Err(Error::EmptyVersionPart)); |
530 | 1 | assert_eq!( |
531 | 1 | RustcVersion::parse(" 1 . \t 3.\r 5").unwrap(), |
532 | 1 | RustcVersion::new(1, 3, 5) |
533 | 1 | ); |
534 | 1 | } |
535 | | |
536 | 1 | #[test] |
537 | 1 | fn formatting() { |
538 | 1 | extern crate alloc; |
539 | 1 | use alloc::string::{String, ToString}; |
540 | 1 | assert_eq!( |
541 | 1 | RustcVersion::new(1, 42, 28).to_string(), |
542 | 1 | String::from("1.42.28") |
543 | 1 | ); |
544 | 1 | assert_eq!( |
545 | 1 | RustcVersion::Special(SpecialVersion::Alpha).to_string(), |
546 | 1 | String::from("1.0.0-alpha") |
547 | 1 | ); |
548 | 1 | assert_eq!( |
549 | 1 | RustcVersion::Special(SpecialVersion::Alpha2).to_string(), |
550 | 1 | String::from("1.0.0-alpha.2") |
551 | 1 | ); |
552 | 1 | assert_eq!( |
553 | 1 | RustcVersion::Special(SpecialVersion::Beta).to_string(), |
554 | 1 | String::from("1.0.0-beta") |
555 | 1 | ); |
556 | 1 | } |
557 | | |
558 | 1 | #[test] |
559 | 1 | fn too_many_elements() { |
560 | 1 | assert_eq!( |
561 | 1 | RustcVersion::parse("1.0.0.100"), |
562 | 1 | Err(Error::TooManyElements) |
563 | 1 | ); |
564 | 1 | } |
565 | | |
566 | 1 | #[test] |
567 | 1 | fn alpha_numeric_version() { |
568 | 1 | assert_eq!(RustcVersion::parse("a.0.1"), Err(Error::ParseIntError)); |
569 | 1 | assert_eq!(RustcVersion::parse("2.x.1"), Err(Error::ParseIntError)); |
570 | 1 | assert_eq!(RustcVersion::parse("0.2.s"), Err(Error::NotASpecialVersion)); |
571 | 1 | } |
572 | | |
573 | 1 | #[test] |
574 | 1 | fn meets_full() { |
575 | 1 | // Nothing was omitted |
576 | 1 | assert!(RustcVersion::new(1, 2, 3).meets(RustcVersion::new(1, 2, 3))); |
577 | 1 | assert!(RustcVersion::new(1, 2, 5).meets(RustcVersion::new(1, 2, 3))); |
578 | 1 | assert!(RustcVersion::new(1, 3, 0).meets(RustcVersion::new(1, 2, 3))); |
579 | 1 | assert!(!RustcVersion::new(2, 0, 0).meets(RustcVersion::new(1, 2, 3))); |
580 | 1 | assert!(!RustcVersion::new(0, 9, 0).meets(RustcVersion::new(1, 0, 0))); |
581 | | |
582 | 1 | assert!(RustcVersion::new(0, 2, 3).meets(RustcVersion::new(0, 2, 3))); |
583 | 1 | assert!(RustcVersion::new(0, 2, 5).meets(RustcVersion::new(0, 2, 3))); |
584 | 1 | assert!(!RustcVersion::new(0, 3, 0).meets(RustcVersion::new(0, 2, 3))); |
585 | 1 | assert!(!RustcVersion::new(1, 0, 0).meets(RustcVersion::new(0, 2, 3))); |
586 | | |
587 | 1 | assert!(RustcVersion::new(0, 0, 3).meets(RustcVersion::new(0, 0, 3))); |
588 | 1 | assert!(!RustcVersion::new(0, 0, 5).meets(RustcVersion::new(0, 0, 3))); |
589 | 1 | assert!(!RustcVersion::new(0, 1, 0).meets(RustcVersion::new(0, 0, 3))); |
590 | | |
591 | 1 | assert!(RustcVersion::new(0, 0, 0).meets(RustcVersion::new(0, 0, 0))); |
592 | 1 | assert!(!RustcVersion::new(0, 0, 1).meets(RustcVersion::new(0, 0, 0))); |
593 | 1 | } |
594 | | |
595 | 1 | #[test] |
596 | 1 | fn meets_no_patch() { |
597 | 1 | // Patch was omitted |
598 | 1 | assert!(RustcVersion::new(1, 2, 0).meets(RustcVersion::parse("1.2").unwrap())); |
599 | 1 | assert!(RustcVersion::new(1, 2, 5).meets(RustcVersion::parse("1.2").unwrap())); |
600 | 1 | assert!(RustcVersion::new(1, 3, 0).meets(RustcVersion::parse("1.2").unwrap())); |
601 | 1 | assert!(!RustcVersion::new(2, 0, 0).meets(RustcVersion::parse("1.2").unwrap())); |
602 | 1 | assert!(!RustcVersion::new(0, 9, 0).meets(RustcVersion::parse("1.0").unwrap())); |
603 | | |
604 | 1 | assert!(RustcVersion::new(0, 2, 0).meets(RustcVersion::parse("0.2").unwrap())); |
605 | 1 | assert!(RustcVersion::new(0, 2, 5).meets(RustcVersion::parse("0.2").unwrap())); |
606 | 1 | assert!(!RustcVersion::new(0, 3, 0).meets(RustcVersion::parse("0.2").unwrap())); |
607 | 1 | assert!(!RustcVersion::new(1, 0, 0).meets(RustcVersion::parse("0.2").unwrap())); |
608 | | |
609 | 1 | assert!(RustcVersion::new(0, 0, 0).meets(RustcVersion::parse("0.0").unwrap())); |
610 | 1 | assert!(RustcVersion::new(0, 0, 5).meets(RustcVersion::parse("0.0").unwrap())); |
611 | 1 | assert!(!RustcVersion::new(0, 1, 0).meets(RustcVersion::parse("0.0").unwrap())); |
612 | 1 | } |
613 | | |
614 | 1 | #[test] |
615 | 1 | fn meets_no_minor() { |
616 | 1 | // Minor was omitted |
617 | 1 | assert!(RustcVersion::new(1, 0, 0).meets(RustcVersion::parse("1").unwrap())); |
618 | 1 | assert!(RustcVersion::new(1, 3, 0).meets(RustcVersion::parse("1").unwrap())); |
619 | 1 | assert!(!RustcVersion::new(2, 0, 0).meets(RustcVersion::parse("1").unwrap())); |
620 | 1 | assert!(!RustcVersion::new(0, 9, 0).meets(RustcVersion::parse("1").unwrap())); |
621 | | |
622 | 1 | assert!(RustcVersion::new(0, 0, 0).meets(RustcVersion::parse("0").unwrap())); |
623 | 1 | assert!(RustcVersion::new(0, 0, 1).meets(RustcVersion::parse("0").unwrap())); |
624 | 1 | assert!(RustcVersion::new(0, 2, 5).meets(RustcVersion::parse("0").unwrap())); |
625 | 1 | assert!(!RustcVersion::new(1, 0, 0).meets(RustcVersion::parse("0").unwrap())); |
626 | 1 | } |
627 | | |
628 | 1 | #[test] |
629 | 1 | fn meets_special() { |
630 | 1 | assert!(RustcVersion::Special(SpecialVersion::Alpha) |
631 | 1 | .meets(RustcVersion::Special(SpecialVersion::Alpha))); |
632 | 1 | assert!(RustcVersion::Special(SpecialVersion::Alpha2) |
633 | 1 | .meets(RustcVersion::Special(SpecialVersion::Alpha2))); |
634 | 1 | assert!(RustcVersion::Special(SpecialVersion::Beta) |
635 | 1 | .meets(RustcVersion::Special(SpecialVersion::Beta))); |
636 | 1 | assert!(!RustcVersion::Special(SpecialVersion::Alpha) |
637 | 1 | .meets(RustcVersion::Special(SpecialVersion::Alpha2))); |
638 | 1 | assert!(!RustcVersion::Special(SpecialVersion::Alpha) |
639 | 1 | .meets(RustcVersion::Special(SpecialVersion::Beta))); |
640 | 1 | assert!(!RustcVersion::Special(SpecialVersion::Alpha2) |
641 | 1 | .meets(RustcVersion::Special(SpecialVersion::Beta))); |
642 | 1 | assert!(!RustcVersion::Special(SpecialVersion::Alpha).meets(RustcVersion::new(1, 0, 0))); |
643 | 1 | assert!(!RustcVersion::Special(SpecialVersion::Alpha2).meets(RustcVersion::new(1, 0, 0))); |
644 | 1 | assert!(!RustcVersion::Special(SpecialVersion::Beta).meets(RustcVersion::new(1, 0, 0))); |
645 | 1 | assert!(!RustcVersion::new(1, 0, 0).meets(RustcVersion::Special(SpecialVersion::Alpha))); |
646 | 1 | assert!(!RustcVersion::new(1, 0, 0).meets(RustcVersion::Special(SpecialVersion::Alpha2))); |
647 | 1 | assert!(!RustcVersion::new(1, 0, 0).meets(RustcVersion::Special(SpecialVersion::Beta))); |
648 | 1 | } |
649 | | |
650 | 1 | #[test] |
651 | | #[should_panic( |
652 | | expected = "This function should never be called with `parts == 0` or `parts > 3`" |
653 | | )] |
654 | 1 | fn omitted_parts_with_zero() { |
655 | 1 | let _ = OmittedParts::from(0); |
656 | 1 | } |
657 | | |
658 | 1 | #[test] |
659 | | #[should_panic( |
660 | | expected = "This function should never be called with `parts == 0` or `parts > 3`" |
661 | | )] |
662 | 1 | fn omitted_parts_with_four() { |
663 | 1 | let _ = OmittedParts::from(4); |
664 | 1 | } |
665 | | } |