alpm_types/version/requirement.rs
1//! Version requirement declarations and comparisons based on them.
2
3use std::{
4 cmp::Ordering,
5 fmt::{Display, Formatter},
6 str::FromStr,
7};
8
9use alpm_parsers::iter_str_context;
10use serde::{Deserialize, Serialize};
11use strum::VariantNames;
12use winnow::{
13 ModalResult,
14 Parser,
15 combinator::{alt, eof, fail, seq},
16 error::{StrContext, StrContextValue},
17 token::take_while,
18};
19
20use crate::{Error, Version};
21
22/// A version requirement, e.g. for a dependency package.
23///
24/// It consists of a target version and a comparison function. A version requirement of `>=1.5` has
25/// a target version of `1.5` and a comparison function of [`VersionComparison::GreaterOrEqual`].
26/// See [alpm-comparison] for details on the format.
27///
28/// ## Examples
29///
30/// ```
31/// use std::str::FromStr;
32///
33/// use alpm_types::{Version, VersionComparison, VersionRequirement};
34///
35/// # fn main() -> Result<(), alpm_types::Error> {
36/// let requirement = VersionRequirement::from_str(">=1.5")?;
37///
38/// assert_eq!(requirement.comparison, VersionComparison::GreaterOrEqual);
39/// assert_eq!(requirement.version, Version::from_str("1.5")?);
40/// # Ok(())
41/// # }
42/// ```
43///
44/// [alpm-comparison]: https://alpm.archlinux.page/specifications/alpm-comparison.7.html
45#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
46pub struct VersionRequirement {
47 /// Version comparison function
48 pub comparison: VersionComparison,
49 /// Target version
50 pub version: Version,
51}
52
53impl VersionRequirement {
54 /// Create a new `VersionRequirement`
55 pub fn new(comparison: VersionComparison, version: Version) -> Self {
56 VersionRequirement {
57 comparison,
58 version,
59 }
60 }
61
62 /// Returns `true` if the requirement is satisfied by the given package version.
63 ///
64 /// ## Examples
65 ///
66 /// ```
67 /// use std::str::FromStr;
68 ///
69 /// use alpm_types::{Version, VersionRequirement};
70 ///
71 /// # fn main() -> Result<(), alpm_types::Error> {
72 /// let requirement = VersionRequirement::from_str(">=1.5-3")?;
73 ///
74 /// assert!(!requirement.is_satisfied_by(&Version::from_str("1.5")?));
75 /// assert!(requirement.is_satisfied_by(&Version::from_str("1.5-3")?));
76 /// assert!(requirement.is_satisfied_by(&Version::from_str("1.6")?));
77 /// assert!(requirement.is_satisfied_by(&Version::from_str("2:1.0")?));
78 /// assert!(!requirement.is_satisfied_by(&Version::from_str("1.0")?));
79 ///
80 /// // If pkgrel is not specified in the requirement, it is ignored in the comparison.
81 /// let requirement = VersionRequirement::from_str("=1.5")?;
82 /// assert!(requirement.is_satisfied_by(&Version::from_str("1.5-3")?));
83 /// # Ok(())
84 /// # }
85 /// ```
86 pub fn is_satisfied_by(&self, ver: &Version) -> bool {
87 // If the requirement does not specify a pkgrel, we ignore it in the comparison.
88 // so that `foo=1` can be satisfied by `foo=1-1`.
89 let other_version = if self.version.pkgrel.is_none() {
90 &Version {
91 pkgrel: None,
92 ..ver.clone()
93 }
94 } else {
95 ver
96 };
97 self.comparison
98 .is_compatible_with(other_version.cmp(&self.version))
99 }
100
101 /// Recognizes a [`VersionRequirement`] in a string slice.
102 ///
103 /// Consumes all of its input.
104 ///
105 /// # Errors
106 ///
107 /// Returns an error if `input` is not a valid _alpm-comparison_.
108 pub fn parser(input: &mut &str) -> ModalResult<Self> {
109 seq!(Self {
110 comparison: take_while(1.., ('<', '>', '='))
111 // add context here because otherwise take_while can fail and provide no information
112 .context(StrContext::Expected(StrContextValue::Description(
113 "version comparison operator"
114 )))
115 .and_then(VersionComparison::parser),
116 version: Version::parser,
117 })
118 .parse_next(input)
119 }
120
121 /// Checks whether another [`VersionRequirement`] forms an intersection with this one.
122 ///
123 /// The intersection operation `∩` on versions simply checks if there is _any_ possible set of
124 /// versions that can exist while upholding the constraints (e.g. `>`/`<=`) on both versions.
125 ///
126 /// # Examples
127 ///
128 /// - The expression `<3 ∩ <1` forms the intersection of all versions `<1`
129 /// - The expression `<2 ∩ >1` forms the intersection `X` of all versions `1<X<2`
130 /// - The expression `=2 ∩ <3` forms the intersection of the exact version `2`
131 ///
132 /// ```
133 /// use std::str::FromStr;
134 ///
135 /// use alpm_types::VersionRequirement;
136 ///
137 /// # fn main() -> testresult::TestResult {
138 /// let requirement: VersionRequirement = "<1".parse()?;
139 /// assert!(requirement.is_intersection(&"<0.1".parse()?));
140 ///
141 /// let requirement: VersionRequirement = "<2".parse()?;
142 /// assert!(requirement.is_intersection(&">1".parse()?));
143 ///
144 /// let requirement: VersionRequirement = "=2".parse()?;
145 /// assert!(!requirement.is_intersection(&"<3".parse()?));
146 /// # Ok(())
147 /// # }
148 /// ```
149 pub fn is_intersection(&self, other: &VersionRequirement) -> bool {
150 // This documentation uses the `∩` set intersection operator to better visualize examples.
151 //
152 // In the following, we need to consider the ordering relationship between the actual
153 // versions of the two `VersionRequirement`s.
154 // If we have `self = ">1.0.1"` and `other = "<2"`, this handles the part of
155 // `"1.0.1".cmp("2")`.
156 let version_comparison = self.version.cmp(&other.version);
157
158 match self.comparison {
159 // Consider the case where we have a `Less`, e.g. `<1`.
160 VersionComparison::Less => {
161 match version_comparison {
162 // The other version is greater, so its comparison must be "Less" or
163 // "LessOrEqual" to form an intersection.
164 //
165 // Example:
166 // - `<1.0.1 ∩ <2` forms the intersection of all versions `<1.0.1`
167 Ordering::Less => matches!(
168 other.comparison,
169 VersionComparison::Less | VersionComparison::LessOrEqual
170 ),
171 // Both versions are matching. The comparison for other must be "Less" or
172 // "LessOrEqual"
173 //
174 // Example:
175 // - `<=2 ∩ <2` forms the intersection of all versions `<2`
176 // - `<2 ∩ <=2` forms the intersection of all versions `<2`
177 Ordering::Equal => matches!(
178 other.comparison,
179 VersionComparison::Less | VersionComparison::LessOrEqual
180 ),
181
182 // The other version is smaller.
183 // Since `self` enforces the `Less` constraint, there will always be at least
184 // **some** intersection.
185 //
186 // Example: Even if `other` also has a "Less" constraint, the expression
187 // `<3 ∩ <1` forms the intersection of all versions `<1`
188 Ordering::Greater => true,
189 }
190 }
191 // Consider the case where we have a `LessOrEqual`, e.g. `<=1`.
192 VersionComparison::LessOrEqual => {
193 match version_comparison {
194 // The other version is greater, so its comparison must be "Less" or
195 // "LessOrEqual" to form an intersection.
196 //
197 // Example:
198 // - `>=1.0.1 ∩ <2` forms the intersection of all versions `1.0.1<=X<2`
199 // - `>= 1.0.1 <= 1.2` forms the intersection of all versions `1.0.1<=X<=1.2`
200 Ordering::Less => matches!(
201 other.comparison,
202 VersionComparison::Less | VersionComparison::LessOrEqual
203 ),
204 // Both versions are matching, the comparison for other must be either "Less"
205 // or one of "Equal", "LessOrEqual", or "GreaterOrEqual".
206 // Any `other` "*Equal" constraint will directly match the `self`
207 // "Less**Equal**" constraint.
208 //
209 // Examples:
210 // - `<=1 ∩ >=1` forms the intersection of the version `1`
211 // - `<=1 ∩ <1` forms the intersection of all version `<1`
212 // - `<=1 ∩ <=1` forms the intersection of all version `<=1`
213 Ordering::Equal => matches!(
214 other.comparison,
215 VersionComparison::Less
216 | VersionComparison::LessOrEqual
217 | VersionComparison::Equal
218 | VersionComparison::GreaterOrEqual
219 ),
220 // The other version is smaller.
221 // Since `self` enforces the `Less` constraint, there will always be at least
222 // **some** intersection.
223 //
224 // Example: Even if `other` also has a "Less" constraint, the expression
225 // `=<3 ∩ <1` forms the intersection of all versions `<1`
226 Ordering::Greater => true,
227 }
228 }
229 // Consider the case where we have a `Equal`, e.g. `=1`.
230 VersionComparison::Equal => match version_comparison {
231 // Both versions are matching, the comparison for `other` must be
232 // "LessOrEqual", "Equal", or "GreaterOrEqual" to match the "Equal" constraint on
233 // `self`
234 //
235 // Examples:
236 // - `=1 ∩ >=1` forms the intersection of the version `1`
237 // - `=1 ∩ <=1` forms the intersection of the version `1`
238 // - `=2 ∩ =2` forms the intersection of the version `2`
239 Ordering::Equal => matches!(
240 other.comparison,
241 VersionComparison::LessOrEqual
242 | VersionComparison::Equal
243 | VersionComparison::GreaterOrEqual
244 ),
245 // The other version must be greater or smaller, so it can be inherently not be
246 // equal.
247 Ordering::Less | Ordering::Greater => false,
248 },
249 // Consider the case where we have a `GreaterOrEqual`, e.g. `>=1`.
250 VersionComparison::GreaterOrEqual => match version_comparison {
251 // The other version is greater.
252 // Since `self` enforces a `Greater` constraint, so there will always be at least
253 // **some** intersection.
254 //
255 // Example: Even if `other` also has a "Less" constraint, the expression
256 // `>=1 ∩ <3` forms the intersection of all versions `1<=X<3`
257 Ordering::Less => true,
258 // Both versions are matching, the comparison for other must be either "Greater"
259 // or one of "Equal", "LessOrEqual", or "GreaterOrEqual".
260 // Any `other` "*Equal" constraint will directly match `self`'s
261 // "LesserOr**Equal**" constraint.
262 //
263 // Examples:
264 // - `>=1 ∩ <=1` forms the intersection of the version `1`
265 // - `>=1 ∩ >1` forms the intersection of all version `>1`
266 // - `>=1 ∩ >=1` forms the intersection of all version `>=1`
267 Ordering::Equal => matches!(
268 other.comparison,
269 VersionComparison::LessOrEqual
270 | VersionComparison::Equal
271 | VersionComparison::GreaterOrEqual
272 | VersionComparison::Greater
273 ),
274 // The other version is smaller, so its comparison must be at least "Greater" or
275 // "GreaterOrEqual" to form an intersection.
276 //
277 // Example:
278 // - `>=2 ∩ >1.1` forms the intersection of all versions `>=2`
279 Ordering::Greater => matches!(
280 other.comparison,
281 VersionComparison::GreaterOrEqual | VersionComparison::Greater
282 ),
283 },
284 // Consider the case where we have a `Greater`, e.g. `>1`.
285 VersionComparison::Greater => {
286 match version_comparison {
287 // The other version is greater.
288 // Since `self` enforces a `Greater` constraint, so there will always be at
289 // least **some** intersection.
290 //
291 // Example: Even if `other` also has a "Less" constraint, the expression
292 // `>1 ∩ <3` forms the intersection of all versions `1<X<3`
293 Ordering::Less => true,
294 // Both versions are matching. The comparison for other must be "Greater" or
295 // "GreaterOrEqual"
296 //
297 // Example:
298 // - `>2 ∩ >2` forms the intersection of all versions `>2`
299 // - `>2 ∩ >=2` forms the intersection of all versions `>2`
300 Ordering::Equal => matches!(
301 other.comparison,
302 VersionComparison::GreaterOrEqual | VersionComparison::Greater
303 ),
304 // The other version is smaller, so its comparison must be at least "Greater" or
305 // "GreaterOrEqual" to form an intersection.
306 //
307 // Example:
308 // - `>2 ∩ >=1.1` forms the intersection of all versions `>=2`
309 Ordering::Greater => matches!(
310 other.comparison,
311 VersionComparison::GreaterOrEqual | VersionComparison::Greater
312 ),
313 }
314 }
315 }
316 }
317}
318
319impl Display for VersionRequirement {
320 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
321 write!(f, "{}{}", self.comparison, self.version)
322 }
323}
324
325impl FromStr for VersionRequirement {
326 type Err = Error;
327
328 /// Creates a new [`VersionRequirement`] from a string slice.
329 ///
330 /// Delegates to [`VersionRequirement::parser`].
331 ///
332 /// # Errors
333 ///
334 /// Returns an error if [`VersionRequirement::parser`] fails.
335 fn from_str(s: &str) -> Result<Self, Self::Err> {
336 Ok(Self::parser.parse(s)?)
337 }
338}
339
340/// Specifies the comparison function for a [`VersionRequirement`].
341///
342/// The package version can be required to be:
343/// - less than (`<`)
344/// - less than or equal to (`<=`)
345/// - equal to (`=`)
346/// - greater than or equal to (`>=`)
347/// - greater than (`>`)
348///
349/// the specified version.
350///
351/// See [alpm-comparison] for details on the format.
352///
353/// ## Note
354///
355/// The variants of this enum are sorted in a way, that prefers the two-letter comparators over
356/// the one-letter ones.
357/// This is because when splitting a string on the string representation of [`VersionComparison`]
358/// variant and relying on the ordering of [`strum::EnumIter`], the two-letter comparators must be
359/// checked before checking the one-letter ones to yield robust results.
360///
361/// [alpm-comparison]: https://alpm.archlinux.page/specifications/alpm-comparison.7.html
362#[derive(
363 strum::AsRefStr,
364 Clone,
365 Copy,
366 Debug,
367 strum::Display,
368 strum::EnumIter,
369 PartialEq,
370 Eq,
371 strum::VariantNames,
372 Serialize,
373 Deserialize,
374)]
375pub enum VersionComparison {
376 /// Less than or equal to
377 #[strum(to_string = "<=")]
378 LessOrEqual,
379
380 /// Greater than or equal to
381 #[strum(to_string = ">=")]
382 GreaterOrEqual,
383
384 /// Equal to
385 #[strum(to_string = "=")]
386 Equal,
387
388 /// Less than
389 #[strum(to_string = "<")]
390 Less,
391
392 /// Greater than
393 #[strum(to_string = ">")]
394 Greater,
395}
396
397impl VersionComparison {
398 /// Returns `true` if the result of a comparison between the actual and required package
399 /// versions satisfies the comparison function.
400 fn is_compatible_with(self, ord: Ordering) -> bool {
401 match (self, ord) {
402 (VersionComparison::Less, Ordering::Less)
403 | (VersionComparison::LessOrEqual, Ordering::Less | Ordering::Equal)
404 | (VersionComparison::Equal, Ordering::Equal)
405 | (VersionComparison::GreaterOrEqual, Ordering::Greater | Ordering::Equal)
406 | (VersionComparison::Greater, Ordering::Greater) => true,
407
408 (VersionComparison::Less, Ordering::Equal | Ordering::Greater)
409 | (VersionComparison::LessOrEqual, Ordering::Greater)
410 | (VersionComparison::Equal, Ordering::Less | Ordering::Greater)
411 | (VersionComparison::GreaterOrEqual, Ordering::Less)
412 | (VersionComparison::Greater, Ordering::Less | Ordering::Equal) => false,
413 }
414 }
415
416 /// Recognizes a [`VersionComparison`] in a string slice.
417 ///
418 /// Consumes all of its input.
419 ///
420 /// # Errors
421 ///
422 /// Returns an error if `input` is not a valid _alpm-comparison_.
423 pub fn parser(input: &mut &str) -> ModalResult<Self> {
424 alt((
425 // insert eofs here (instead of after alt call) so correct error message is thrown
426 ("<=", eof).value(Self::LessOrEqual),
427 (">=", eof).value(Self::GreaterOrEqual),
428 ("=", eof).value(Self::Equal),
429 ("<", eof).value(Self::Less),
430 (">", eof).value(Self::Greater),
431 fail.context(StrContext::Label("comparison operator"))
432 .context_with(iter_str_context!([VersionComparison::VARIANTS])),
433 ))
434 .parse_next(input)
435 }
436}
437
438impl FromStr for VersionComparison {
439 type Err = Error;
440
441 /// Creates a new [`VersionComparison`] from a string slice.
442 ///
443 /// Delegates to [`VersionComparison::parser`].
444 ///
445 /// # Errors
446 ///
447 /// Returns an error if [`VersionComparison::parser`] fails.
448 fn from_str(s: &str) -> Result<Self, Self::Err> {
449 Ok(Self::parser.parse(s)?)
450 }
451}
452
453#[cfg(test)]
454mod tests {
455 use insta::assert_snapshot;
456 use rstest::rstest;
457 use testresult::TestResult;
458
459 use super::*;
460 use crate::configure_insta;
461
462 /// Ensure that valid version comparison strings can be parsed.
463 #[rstest]
464 #[case("<", VersionComparison::Less)]
465 #[case("<=", VersionComparison::LessOrEqual)]
466 #[case("=", VersionComparison::Equal)]
467 #[case(">=", VersionComparison::GreaterOrEqual)]
468 #[case(">", VersionComparison::Greater)]
469 fn valid_version_comparison(#[case] comparison: &str, #[case] expected: VersionComparison) {
470 assert_eq!(comparison.parse(), Ok(expected));
471 }
472
473 /// Ensure that invalid version comparisons will throw an error.
474 #[rstest]
475 #[case("")]
476 #[case("<<")]
477 #[case("==")]
478 #[case("!=")]
479 #[case(" =")]
480 #[case("= ")]
481 #[case("<1")]
482 fn invalid_version_comparison(#[case] comparison: &str) {
483 let Err(Error::ParseError(_)) = VersionComparison::from_str(comparison) else {
484 panic!("'{comparison}' did not fail as expected")
485 };
486 }
487
488 /// Test successful parsing for version requirement strings.
489 #[rstest]
490 #[case("=1", VersionRequirement {
491 comparison: VersionComparison::Equal,
492 version: Version::from_str("1").unwrap(),
493 })]
494 #[case("<=42:abcd-2.4", VersionRequirement {
495 comparison: VersionComparison::LessOrEqual,
496 version: Version::from_str("42:abcd-2.4").unwrap(),
497 })]
498 #[case(">3.1", VersionRequirement {
499 comparison: VersionComparison::Greater,
500 version: Version::from_str("3.1").unwrap(),
501 })]
502 fn valid_version_requirement(#[case] requirement: &str, #[case] expected: VersionRequirement) {
503 assert_eq!(
504 requirement.parse(),
505 Ok(expected),
506 "Expected successful parse for version requirement '{requirement}'"
507 );
508 }
509
510 #[rstest]
511 #[case::bad_operator("<>3.1")]
512 #[case::no_operator("3.1")]
513 #[case::arrow_operator("=>3.1")]
514 #[case::no_version("<=")]
515 #[case::invalid_pkgver("<3.1>3.2")]
516 fn invalid_version_requirement(#[case] requirement: &str) {
517 let Err(Error::ParseError(err_msg)) = VersionRequirement::from_str(requirement) else {
518 panic!("'{requirement}' erroneously parsed as VersionRequirement")
519 };
520
521 let (test_name, _guard) = configure_insta();
522 assert_snapshot!(test_name, err_msg.to_string());
523 }
524
525 /// Check whether a version requirement (>= 1.0) is fulfilled by a given version string.
526 #[rstest]
527 #[case("=1", "1", true)]
528 #[case("=1", "1.0", false)]
529 #[case("=1", "1-1", true)]
530 #[case("=1", "1:1", false)]
531 #[case("=1", "0.9", false)]
532 #[case("<42", "41", true)]
533 #[case("<42", "42", false)]
534 #[case("<42", "43", false)]
535 #[case("<=42", "41", true)]
536 #[case("<=42", "42", true)]
537 #[case("<=42", "43", false)]
538 #[case(">42", "41", false)]
539 #[case(">42", "42", false)]
540 #[case(">42", "43", true)]
541 #[case(">=42", "41", false)]
542 #[case(">=42", "42", true)]
543 #[case(">=42", "43", true)]
544 fn version_requirement_satisfied(
545 #[case] requirement: &str,
546 #[case] version: &str,
547 #[case] result: bool,
548 ) {
549 let requirement = VersionRequirement::from_str(requirement).unwrap();
550 let version = Version::from_str(version).unwrap();
551 assert_eq!(requirement.is_satisfied_by(&version), result);
552 }
553
554 #[rstest]
555 #[case::self_less_matching_other_less("<1", "<1")]
556 #[case::self_less_matching_other_less_or_equal("<1", "<=1")]
557 #[case::self_less_bigger_other_less("<1", "<2")]
558 #[case::self_less_bigger_other_less_or_equal("<1", "<=2")]
559 #[case::self_less_smaller_other_less("<1", "<0.1")]
560 #[case::self_less_smaller_other_less_or_equal("<1", "<=0.1")]
561 #[case::self_less_smaller_other_equal("<1", "=0.1")]
562 #[case::self_less_smaller_other_greater_or_equal("<1", ">=0.1")]
563 #[case::self_less_smaller_other_greater("<1", ">0.1")]
564 #[case::self_less_smaller_other_equal("<1", "=0.1")]
565 #[case::self_less_or_equal_matching_other_less("<=1", "<1")]
566 #[case::self_less_or_equal_matching_other_less_or_equal("<=1", "<=1")]
567 #[case::self_less_or_equal_matching_other_equal("<=1", "=1")]
568 #[case::self_less_or_equal_matching_other_greater_or_equal("<=1", ">=1")]
569 #[case::self_less_or_equal_bigger_other_less("<=1", "<2")]
570 #[case::self_less_or_equal_bigger_other_less_or_equal("<=1", "<=2")]
571 #[case::self_less_or_equal_smaller_other_greater_or_equal("<=1", ">=0.1")]
572 #[case::self_less_or_equal_smaller_other_greater("<=1", ">0.1")]
573 #[case::self_equal_matching_other_less_or_equal("=1", "<=1")]
574 #[case::self_equal_matching_other_equal("=1", "=1")]
575 #[case::self_equal_matching_other_greater_or_equal("=1", ">=1")]
576 #[case::self_greater_or_equal_matching_other_less_or_equal(">=1", "<=1")]
577 #[case::self_greater_or_equal_matching_other_equal(">=1", "=1")]
578 #[case::self_greater_or_equal_matching_other_greater_or_equal(">=1", ">=1")]
579 #[case::self_greater_or_equal_matching_other_greater(">=1", ">1")]
580 #[case::self_greater_or_equal_bigger_other_less(">=1", "<2")]
581 #[case::self_greater_or_equal_bigger_other_less_or_equal(">=1", "<=2")]
582 #[case::self_greater_or_equal_bigger_other_equal(">=1", "=2")]
583 #[case::self_greater_or_equal_bigger_other_greater_or_equal(">=1", ">=2")]
584 #[case::self_greater_or_equal_bigger_other_greater(">=1", ">2")]
585 #[case::self_greater_or_equal_smaller_other_greater_or_equal(">=1", ">=0.1")]
586 #[case::self_greater_or_equal_smaller_other_greater(">=1", ">0.1")]
587 #[case::self_greater_matching_other_greater_or_equal(">1", ">=1")]
588 #[case::self_greater_matching_other_greater(">1", ">1")]
589 #[case::self_greater_bigger_other_less(">1", "<2")]
590 #[case::self_greater_bigger_other_less_or_equal(">1", "<=2")]
591 #[case::self_greater_bigger_other_equal(">1", "=2")]
592 #[case::self_greater_bigger_other_greater_or_equal(">1", ">=2")]
593 #[case::self_greater_bigger_other_greater(">1", ">2")]
594 #[case::self_greater_smaller_other_greater_or_equal(">1", ">=0.1")]
595 #[case::self_greater_smaller_other_greater(">1", ">0.1")]
596 fn version_requirements_form_intersection(
597 #[case] self_requirement: &str,
598 #[case] other_requirement: &str,
599 ) -> TestResult {
600 let self_requirement: VersionRequirement = self_requirement.parse()?;
601 let other_requirement: VersionRequirement = other_requirement.parse()?;
602
603 assert!(self_requirement.is_intersection(&other_requirement));
604
605 Ok(())
606 }
607
608 #[rstest]
609 #[case::self_less_matching_other_equal("<1", "=1")]
610 #[case::self_less_matching_other_greater_or_equal("<1", ">=1")]
611 #[case::self_less_matching_other_greater("<1", ">1")]
612 #[case::self_less_or_equal_matching_other_greater("<=1", ">1")]
613 #[case::self_equal_matching_other_less("=1", "<1")]
614 #[case::self_equal_matching_other_greater("=1", ">1")]
615 #[case::self_equal_bigger_other_less("=1", "<2")]
616 #[case::self_equal_bigger_other_greater("=1", ">2")]
617 #[case::self_equal_smaller_other_less("=1", "<0.1")]
618 #[case::self_equal_smaller_other_greater("=1", ">0.1")]
619 #[case::self_greater_or_equal_matching_other_less(">=1", "<1")]
620 #[case::self_greater_matching_other_less(">1", "<1")]
621 #[case::self_greater_matching_other_less_or_equal(">1", "<=1")]
622 #[case::self_greater_matching_other_equal(">1", "=1")]
623 fn version_requirements_do_not_form_intersection(
624 #[case] self_requirement: &str,
625 #[case] other_requirement: &str,
626 ) -> TestResult {
627 let self_requirement: VersionRequirement = self_requirement.parse()?;
628 let other_requirement: VersionRequirement = other_requirement.parse()?;
629
630 assert!(!self_requirement.is_intersection(&other_requirement));
631 Ok(())
632 }
633}