Skip to main content

nodejs_semver/
range.rs

1use std::cmp::{Ord, Ordering, PartialOrd};
2use std::convert::TryFrom;
3use std::fmt;
4use std::ops::Deref;
5
6use winnow::ascii::{space0, space1};
7use winnow::combinator::{
8    alt, delimited, eof, opt, peek, preceded, repeat_till, separated, terminated,
9};
10use winnow::token::{any, literal};
11use winnow::{ModalResult, Parser};
12
13#[cfg(feature = "serde")]
14use serde::{Deserialize, Serialize, de::Deserializer, ser::Serializer};
15use smallvec::SmallVec;
16use thiserror::Error;
17
18use crate::{
19    Identifier, MAX_SAFE_INTEGER, SemverError, SemverErrorKind, SemverParseError, Version, extras,
20    number, semver_error_from_parse,
21};
22
23mod fast;
24
25#[cold]
26#[inline(never)]
27fn no_valid_ranges_error(input: &str) -> SemverError {
28    SemverError {
29        input: input.into(),
30        span: (input.len(), 0).into(),
31        kind: SemverErrorKind::NoValidRanges,
32    }
33}
34
35fn should_skip_range_fallback(input: &str) -> bool {
36    let input = input.trim();
37    if starts_with_range_token(input) {
38        return false;
39    }
40
41    is_single_unparseable_token(input)
42}
43
44fn starts_with_range_token(input: &str) -> bool {
45    input
46        .as_bytes()
47        .first()
48        .is_some_and(|ch| is_possible_range_token(*ch))
49}
50
51fn is_possible_range_token(ch: u8) -> bool {
52    matches!(
53        ch,
54        b'0'..=b'9' | b'v' | b'V' | b'x' | b'X' | b'*' | b'>' | b'<' | b'=' | b'^' | b'~'
55    )
56}
57
58fn is_single_unparseable_token(input: &str) -> bool {
59    let mut has_colon = false;
60    let mut has_possible_range_token = false;
61    let mut previous_was_pipe = false;
62
63    for ch in input.bytes() {
64        if is_range_token_separator(ch) {
65            return false;
66        }
67
68        if ch == b':' {
69            has_colon = true;
70        }
71
72        if is_possible_range_token(ch) {
73            has_possible_range_token = true;
74        }
75
76        if ch == b'|' {
77            if previous_was_pipe {
78                return false;
79            }
80            previous_was_pipe = true;
81        } else {
82            previous_was_pipe = false;
83        }
84    }
85
86    has_colon || !has_possible_range_token
87}
88
89fn is_range_token_separator(ch: u8) -> bool {
90    matches!(ch, b' ' | b'\t' | b'\n' | b'\r' | 0x0B | 0x0C)
91}
92
93#[derive(Clone, Debug, Eq, PartialEq, Hash)]
94struct BoundSet {
95    bounds: Box<BoundPair>,
96}
97
98#[derive(Clone, Debug, Eq, PartialEq, Hash)]
99struct BoundPair {
100    upper: Bound,
101    lower: Bound,
102}
103
104impl Deref for BoundSet {
105    type Target = BoundPair;
106
107    fn deref(&self) -> &Self::Target {
108        self.bounds.as_ref()
109    }
110}
111
112impl BoundSet {
113    fn new(lower: Bound, upper: Bound) -> Option<Self> {
114        use Bound::*;
115        use Predicate::*;
116
117        match (lower, upper) {
118            (Lower(Excluding(v1)), Upper(Including(v2)))
119            | (Lower(Including(v1)), Upper(Excluding(v2)))
120                if v1 == v2 =>
121            {
122                None
123            }
124            (Lower(Including(v1)), Upper(Including(v2))) if v1 == v2 => Some(Self {
125                bounds: Box::new(BoundPair {
126                    lower: Lower(Including(v1)),
127                    upper: Upper(Including(v2)),
128                }),
129            }),
130            (lower, upper) if lower < upper => Some(Self {
131                bounds: Box::new(BoundPair { lower, upper }),
132            }),
133            _ => None,
134        }
135    }
136
137    fn at_least(p: Predicate) -> Option<Self> {
138        BoundSet::new(Bound::Lower(p), Bound::upper())
139    }
140
141    fn at_most(p: Predicate) -> Option<Self> {
142        BoundSet::new(Bound::lower(), Bound::Upper(p))
143    }
144
145    fn exact(version: Version) -> Option<Self> {
146        BoundSet::new(
147            Bound::Lower(Predicate::Including(version.clone())),
148            Bound::Upper(Predicate::Including(version)),
149        )
150    }
151
152    fn satisfies(&self, version: &Version, include_prerelease: bool) -> bool {
153        use Bound::*;
154        use Predicate::*;
155
156        let lower_bound = match &self.lower {
157            Lower(Including(lower)) => lower <= version,
158            Lower(Excluding(lower)) => lower < version,
159            Lower(Unbounded) => true,
160            _ => unreachable!(
161                "There should not have been an upper bound: {:#?}",
162                self.lower
163            ),
164        };
165
166        let upper_bound = match &self.upper {
167            Upper(Including(upper)) => version <= upper,
168            Upper(Excluding(upper)) => version < upper,
169            Upper(Unbounded) => true,
170            _ => unreachable!(
171                "There should not have been an lower bound: {:#?}",
172                self.lower
173            ),
174        };
175
176        if !lower_bound || !upper_bound {
177            return false;
178        }
179
180        if version.is_prerelease() && !include_prerelease {
181            let lower_version = match &self.lower {
182                Lower(Including(v)) => Some(v),
183                Lower(Excluding(v)) => Some(v),
184                _ => None,
185            };
186            if let Some(lower_version) = lower_version {
187                if lower_version.is_prerelease()
188                    && version.major == lower_version.major
189                    && version.minor == lower_version.minor
190                    && version.patch == lower_version.patch
191                {
192                    return true;
193                }
194            }
195
196            let upper_version = match &self.upper {
197                Upper(Including(v)) => Some(v),
198                Upper(Excluding(v)) => Some(v),
199                _ => None,
200            };
201            if let Some(upper_version) = upper_version {
202                if upper_version.is_prerelease()
203                    && version.major == upper_version.major
204                    && version.minor == upper_version.minor
205                    && version.patch == upper_version.patch
206                {
207                    return true;
208                }
209            }
210
211            return false;
212        }
213
214        true
215    }
216
217    fn allows_all(&self, other: &BoundSet) -> bool {
218        self.lower <= other.lower && other.upper <= self.upper
219    }
220
221    fn allows_any(&self, other: &BoundSet) -> bool {
222        if other.upper < self.lower {
223            return false;
224        }
225
226        if self.upper < other.lower {
227            return false;
228        }
229
230        true
231    }
232
233    fn intersect(&self, other: &Self) -> Option<Self> {
234        let lower: &Bound = std::cmp::max(&self.lower, &other.lower);
235        let upper: &Bound = std::cmp::min(&self.upper, &other.upper);
236
237        BoundSet::new(lower.clone(), upper.clone())
238    }
239
240    fn difference(&self, other: &Self) -> Option<Vec<Self>> {
241        use Bound::*;
242
243        if let Some(overlap) = self.intersect(other) {
244            if &overlap == self {
245                return None;
246            }
247
248            if self.lower < overlap.lower && overlap.upper < self.upper {
249                return Some(vec![
250                    BoundSet::new(
251                        self.lower.clone(),
252                        Upper(overlap.lower.clone().predicate().flip()),
253                    )
254                    .unwrap(),
255                    BoundSet::new(
256                        Lower(overlap.upper.clone().predicate().flip()),
257                        self.upper.clone(),
258                    )
259                    .unwrap(),
260                ]);
261            }
262
263            if self.lower < overlap.lower {
264                return BoundSet::new(
265                    self.lower.clone(),
266                    Upper(overlap.lower.clone().predicate().flip()),
267                )
268                .map(|f| vec![f]);
269            }
270
271            BoundSet::new(
272                Lower(overlap.upper.clone().predicate().flip()),
273                self.upper.clone(),
274            )
275            .map(|f| vec![f])
276        } else {
277            Some(vec![self.clone()])
278        }
279    }
280
281    fn comparators(&self) -> impl Iterator<Item = Comparator> + '_ {
282        ComparatorIter::new(self)
283    }
284}
285
286impl fmt::Display for BoundSet {
287    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
288        use Bound::*;
289        use Predicate::*;
290        match (&self.lower, &self.upper) {
291            (Lower(Unbounded), Upper(Unbounded)) => write!(f, "*"),
292            (Lower(Unbounded), Upper(Including(v))) => write!(f, "<={}", v),
293            (Lower(Unbounded), Upper(Excluding(v))) => write!(f, "<{}", v),
294            (Lower(Including(v)), Upper(Unbounded)) => write!(f, ">={}", v),
295            (Lower(Excluding(v)), Upper(Unbounded)) => write!(f, ">{}", v),
296            (Lower(Including(v)), Upper(Including(v2))) if v == v2 => write!(f, "{}", v),
297            (Lower(Including(v)), Upper(Including(v2))) => write!(f, ">={} <={}", v, v2),
298            (Lower(Including(v)), Upper(Excluding(v2))) => write!(f, ">={} <{}", v, v2),
299            (Lower(Excluding(v)), Upper(Including(v2))) => write!(f, ">{} <={}", v, v2),
300            (Lower(Excluding(v)), Upper(Excluding(v2))) => write!(f, ">{} <{}", v, v2),
301            _ => unreachable!("does not make sense"),
302        }
303    }
304}
305
306#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
307enum Operation {
308    Exact,
309    GreaterThan,
310    GreaterThanEquals,
311    LessThan,
312    LessThanEquals,
313}
314
315#[derive(Debug, Clone, Eq, PartialEq, Hash)]
316enum Predicate {
317    Excluding(Version), // < and >
318    Including(Version), // <= and >=
319    Unbounded,          // *
320}
321
322impl Predicate {
323    fn flip(self) -> Self {
324        use Predicate::*;
325        match self {
326            Excluding(v) => Including(v),
327            Including(v) => Excluding(v),
328            Unbounded => Unbounded,
329        }
330    }
331}
332
333#[derive(Debug, Clone, Eq, PartialEq, Hash)]
334enum Bound {
335    Lower(Predicate),
336    Upper(Predicate),
337}
338
339impl Bound {
340    fn upper() -> Self {
341        Bound::Upper(Predicate::Unbounded)
342    }
343
344    fn lower() -> Self {
345        Bound::Lower(Predicate::Unbounded)
346    }
347
348    fn predicate(self) -> Predicate {
349        use Bound::*;
350
351        match self {
352            Lower(p) => p,
353            Upper(p) => p,
354        }
355    }
356
357    fn rank(&self) -> (&Version, i8) {
358        use Bound::*;
359        use Predicate::*;
360
361        match self {
362            Upper(Excluding(v)) => (v, 0),
363            Lower(Including(v)) => (v, 1),
364            Upper(Including(v)) => (v, 2),
365            Lower(Excluding(v)) => (v, 3),
366            Lower(Unbounded) | Upper(Unbounded) => {
367                unreachable!("cannot rank unbounded bounds")
368            }
369        }
370    }
371}
372
373impl Ord for Bound {
374    fn cmp(&self, other: &Self) -> Ordering {
375        use Bound::*;
376        use Predicate::*;
377
378        match (self, other) {
379            (Lower(Unbounded), Lower(Unbounded)) | (Upper(Unbounded), Upper(Unbounded)) => {
380                Ordering::Equal
381            }
382            (Lower(Unbounded), _) => Ordering::Less,
383            (_, Lower(Unbounded)) => Ordering::Greater,
384            (Upper(Unbounded), _) => Ordering::Greater,
385            (_, Upper(Unbounded)) => Ordering::Less,
386            _ => {
387                let (self_version, self_rank) = self.rank();
388                let (other_version, other_rank) = other.rank();
389
390                match self_version.cmp(other_version) {
391                    Ordering::Equal => self_rank.cmp(&other_rank),
392                    ord => ord,
393                }
394            }
395        }
396    }
397}
398
399impl PartialOrd for Bound {
400    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
401        Some(self.cmp(other))
402    }
403}
404
405#[derive(Clone, Debug)]
406struct Comparator {
407    op: Operation,
408    version: Version,
409}
410
411struct ComparatorIter {
412    state: ComparatorIterState,
413}
414
415enum ComparatorIterState {
416    Exact(Option<Comparator>),
417    Pair {
418        items: [Option<Comparator>; 2],
419        index: usize,
420    },
421    Fallback(Option<Comparator>),
422    Done,
423}
424
425impl ComparatorIter {
426    fn new(bound_set: &BoundSet) -> Self {
427        match (&bound_set.lower, &bound_set.upper) {
428            (Bound::Lower(Predicate::Including(low)), Bound::Upper(Predicate::Including(high)))
429                if low == high =>
430            {
431                return Self {
432                    state: ComparatorIterState::Exact(Some(Comparator {
433                        op: Operation::Exact,
434                        version: low.clone(),
435                    })),
436                };
437            }
438            _ => {}
439        }
440
441        let upper = Comparator::from_bound(&bound_set.upper);
442        let lower = Comparator::from_bound(&bound_set.lower);
443
444        if upper.is_none() && lower.is_none() {
445            return Self {
446                state: ComparatorIterState::Fallback(Some(Comparator {
447                    op: Operation::GreaterThanEquals,
448                    version: Version::from((0, 0, 0)),
449                })),
450            };
451        }
452
453        Self {
454            state: ComparatorIterState::Pair {
455                items: [upper, lower],
456                index: 0,
457            },
458        }
459    }
460}
461
462impl Iterator for ComparatorIter {
463    type Item = Comparator;
464
465    fn next(&mut self) -> Option<Self::Item> {
466        use ComparatorIterState::*;
467
468        match &mut self.state {
469            Exact(opt) => {
470                let next = opt.take();
471                if next.is_none() {
472                    self.state = Done;
473                }
474                next
475            }
476            Pair { items, index } => {
477                while *index < items.len() {
478                    let candidate = items[*index].take();
479                    *index += 1;
480                    if candidate.is_some() {
481                        return candidate;
482                    }
483                }
484                self.state = Done;
485                None
486            }
487            Fallback(opt) => {
488                let next = opt.take();
489                if next.is_none() {
490                    self.state = Done;
491                }
492                next
493            }
494            Done => None,
495        }
496    }
497}
498
499impl Comparator {
500    fn from_bound(bound: &Bound) -> Option<Self> {
501        match bound {
502            Bound::Lower(Predicate::Including(v)) => Some(Self {
503                op: Operation::GreaterThanEquals,
504                version: v.clone(),
505            }),
506            Bound::Lower(Predicate::Excluding(v)) => Some(Self {
507                op: Operation::GreaterThan,
508                version: v.clone(),
509            }),
510            Bound::Upper(Predicate::Including(v)) => Some(Self {
511                op: Operation::LessThanEquals,
512                version: v.clone(),
513            }),
514            Bound::Upper(Predicate::Excluding(v)) => Some(Self {
515                op: Operation::LessThan,
516                version: v.clone(),
517            }),
518            Bound::Lower(Predicate::Unbounded) | Bound::Upper(Predicate::Unbounded) => None,
519        }
520    }
521}
522
523/// Direction in which to check whether a [Version] lies outside a [Range].
524#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
525pub enum OutsideDirection {
526    /// Check whether the version is greater than the range.
527    Higher,
528    /// Check whether the version is lower than the range.
529    Lower,
530}
531
532impl TryFrom<char> for OutsideDirection {
533    type Error = RangeError;
534
535    fn try_from(value: char) -> Result<Self, Self::Error> {
536        match value {
537            '>' => Ok(Self::Higher),
538            '<' => Ok(Self::Lower),
539            other => Err(RangeError::InvalidOutsideDirection(other)),
540        }
541    }
542}
543
544/// Errors that can occur when evaluating range relationships outside of parsing.
545#[derive(Debug, Clone, Copy, Error, Eq, PartialEq)]
546pub enum RangeError {
547    #[error(
548        "outside() only supports checking whether a version is above or below a range, found `{0}`"
549    )]
550    InvalidOutsideDirection(char),
551    #[error("outside() could not determine comparator bounds for this range")]
552    MissingComparatorBounds,
553}
554
555/**
556Node-style semver range.
557
558These ranges map mostly 1:1 to semver's except for some internal representation
559details that allow some more interesting set-level operations.
560
561For details on supported syntax, see <https://github.com/npm/node-semver#advanced-range-syntax>
562*/
563#[derive(Clone, Debug, Eq, PartialEq, Hash)]
564pub struct Range(SmallVec<[BoundSet; 1]>);
565
566impl fmt::Display for OutsideDirection {
567    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
568        match self {
569            OutsideDirection::Higher => write!(f, ">"),
570            OutsideDirection::Lower => write!(f, "<"),
571        }
572    }
573}
574
575impl fmt::Display for Operation {
576    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
577        use Operation::*;
578        match self {
579            Exact => write!(f, ""),
580            GreaterThan => write!(f, ">"),
581            GreaterThanEquals => write!(f, ">="),
582            LessThan => write!(f, "<"),
583            LessThanEquals => write!(f, "<="),
584        }
585    }
586}
587
588#[cfg(feature = "serde")]
589impl Serialize for Range {
590    fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
591        s.collect_str(self)
592    }
593}
594
595#[cfg(feature = "serde")]
596impl<'de> Deserialize<'de> for Range {
597    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
598        let s = String::deserialize(d)?;
599        s.parse().map_err(serde::de::Error::custom)
600    }
601}
602
603impl Range {
604    fn from_bound_set(bound_set: BoundSet) -> Self {
605        let mut bound_sets = SmallVec::new();
606        bound_sets.push(bound_set);
607        Self(bound_sets)
608    }
609
610    fn from_bound_sets(bound_sets: Vec<BoundSet>) -> Option<Self> {
611        (!bound_sets.is_empty()).then(|| Self(SmallVec::from_vec(bound_sets)))
612    }
613
614    fn append_bound_sets_to(self, bound_sets: &mut Vec<BoundSet>) {
615        bound_sets.extend(self.0);
616    }
617
618    fn iter(&self) -> std::slice::Iter<'_, BoundSet> {
619        self.0.iter()
620    }
621
622    /**
623    Parse a range from a string.
624    */
625    pub fn parse<S: AsRef<str>>(input: S) -> Result<Self, SemverError> {
626        let mut input = input.as_ref();
627
628        if input.trim().is_empty() {
629            return Ok(Self::any());
630        }
631
632        if input.split("||").all(|part| part.trim().is_empty()) {
633            return Ok(Self::any());
634        }
635
636        if let Some(range) = fast::parse(input) {
637            return Ok(range);
638        }
639
640        if should_skip_range_fallback(input) {
641            return Err(no_valid_ranges_error(input));
642        }
643
644        if let Some(range) = fast::parse_garbage(input) {
645            return Ok(range);
646        }
647
648        match range_set.parse_next(&mut input) {
649            Ok(range) => Ok(range),
650            Err(err) => Err(semver_error_from_parse(input, err)),
651        }
652    }
653
654    /**
655    Creates a new range that matches any version.
656    */
657    pub fn any() -> Self {
658        Self::from_bound_set(BoundSet::new(Bound::lower(), Bound::upper()).unwrap())
659    }
660
661    /**
662    Returns true if `version` is satisfied by this range.
663    */
664    pub fn satisfies(&self, version: &Version) -> bool {
665        self.satisfies_with_prerelease(version, false)
666    }
667
668    /**
669    Returns true if `version` is satisfied by this range.
670
671    This behaves like [Range::satisfies], but will also consider pre-release
672    versions even if the range itself does not specify a matching pre-release.
673    */
674    pub fn satisfies_with_prerelease(&self, version: &Version, include_prerelease: bool) -> bool {
675        self.0
676            .iter()
677            .any(|range| range.satisfies(version, include_prerelease))
678    }
679
680    /**
681    Returns true if `other` is a strict superset of this range.
682    */
683    pub fn allows_all(&self, other: &Range) -> bool {
684        for this in self.iter() {
685            for that in other.iter() {
686                if this.allows_all(that) {
687                    return true;
688                }
689            }
690        }
691
692        false
693    }
694
695    /**
696    Returns true if `other` has overlap with this range.
697    */
698    pub fn allows_any(&self, other: &Range) -> bool {
699        for this in self.iter() {
700            for that in other.iter() {
701                if this.allows_any(that) {
702                    return true;
703                }
704            }
705        }
706
707        false
708    }
709
710    /**
711    Returns a new range that is the set-intersection between this range and `other`.
712    */
713    pub fn intersect(&self, other: &Self) -> Option<Self> {
714        let mut sets = Vec::new();
715
716        for lefty in self.iter() {
717            for righty in other.iter() {
718                if let Some(set) = lefty.intersect(righty) {
719                    sets.push(set)
720                }
721            }
722        }
723
724        Self::from_bound_sets(sets)
725    }
726
727    /**
728    Returns a new range that is the set-difference between this range and `other`.
729    */
730    pub fn difference(&self, other: &Self) -> Option<Self> {
731        let mut predicates = Vec::new();
732
733        for lefty in self.iter() {
734            for righty in other.iter() {
735                if let Some(mut range) = lefty.difference(righty) {
736                    predicates.append(&mut range)
737                }
738            }
739        }
740
741        Self::from_bound_sets(predicates)
742    }
743
744    /// Return the highest [Version] in the list that satisfies the range,
745    /// or `None` if none of them do.
746    ///
747    /// ```rust
748    #[doc = include_str!("../examples/max_satisfying.rs")]
749    ///
750    pub fn max_satisfying<'v>(&self, versions: &'v [Version]) -> Option<&'v Version> {
751        versions.iter().filter(|v| self.satisfies(v)).max()
752    }
753
754    /// Return the lowest [Version] in the list that satisfies the range,
755    /// or `None` if none of them do.
756    ///
757    /// ```rust
758    #[doc = include_str!("../examples/min_satisfying.rs")]
759    ///
760    pub fn min_satisfying<'v>(&self, versions: &'v [Version]) -> Option<&'v Version> {
761        versions.iter().filter(|v| self.satisfies(v)).min()
762    }
763
764    /**
765    Return the lowest [Version] that can possibly match the given range.
766    */
767    pub fn min_version(&self) -> Option<Version> {
768        if let Some(min_bound) = self.iter().map(|range| &range.lower).min() {
769            match min_bound {
770                Bound::Lower(pred) => match pred {
771                    Predicate::Including(v) => Some(v.clone()),
772                    Predicate::Excluding(v) => {
773                        let mut v = v.clone();
774                        if v.is_prerelease() {
775                            v.push_pre_release(Identifier::Numeric(0))
776                        } else {
777                            v.patch += 1;
778                        }
779                        Some(v)
780                    }
781                    Predicate::Unbounded => {
782                        let mut zero = Version::from((0, 0, 0));
783                        if self.satisfies(&zero) {
784                            return Some(zero);
785                        }
786
787                        zero.push_pre_release(Identifier::Numeric(0));
788                        if self.satisfies(&zero) {
789                            return Some(zero);
790                        }
791                        None
792                    }
793                },
794                Bound::Upper(_) => None,
795            }
796        } else {
797            None
798        }
799    }
800
801    #[inline]
802    fn outside_higher(
803        &self,
804        version: &Version,
805        include_prerelease: bool,
806    ) -> Result<bool, RangeError> {
807        if self.satisfies_with_prerelease(version, include_prerelease) {
808            return Ok(false);
809        }
810
811        for range in self.iter() {
812            let mut high: Option<Comparator> = None;
813            let mut low: Option<Comparator> = None;
814
815            for comparator in range.comparators() {
816                if high.as_ref().is_none_or(|h| comparator.version > h.version) {
817                    high = Some(comparator.clone());
818                }
819
820                if low.as_ref().is_none_or(|l| comparator.version < l.version) {
821                    low = Some(comparator);
822                }
823            }
824
825            let (Some(high), Some(low)) = (high.as_ref(), low.as_ref()) else {
826                return Err(RangeError::MissingComparatorBounds);
827            };
828
829            if matches!(
830                high.op,
831                Operation::GreaterThan | Operation::GreaterThanEquals
832            ) {
833                return Ok(false);
834            }
835
836            let low_is_empty = matches!(low.op, Operation::Exact);
837
838            if ((low_is_empty || matches!(low.op, Operation::GreaterThan))
839                && version <= &low.version)
840                || (matches!(low.op, Operation::GreaterThanEquals) && version < &low.version)
841            {
842                return Ok(false);
843            }
844        }
845
846        Ok(true)
847    }
848
849    #[inline]
850    fn outside_lower(
851        &self,
852        version: &Version,
853        include_prerelease: bool,
854    ) -> Result<bool, RangeError> {
855        if self.satisfies_with_prerelease(version, include_prerelease) {
856            return Ok(false);
857        }
858
859        for range in self.iter() {
860            let mut high: Option<Comparator> = None;
861            let mut low: Option<Comparator> = None;
862
863            for comparator in range.comparators() {
864                if high.as_ref().is_none_or(|h| comparator.version < h.version) {
865                    high = Some(comparator.clone());
866                }
867
868                if low.as_ref().is_none_or(|l| comparator.version > l.version) {
869                    low = Some(comparator);
870                }
871            }
872
873            let (Some(high), Some(low)) = (high.as_ref(), low.as_ref()) else {
874                return Err(RangeError::MissingComparatorBounds);
875            };
876
877            if matches!(high.op, Operation::LessThan | Operation::LessThanEquals) {
878                return Ok(false);
879            }
880
881            let low_is_empty = matches!(low.op, Operation::Exact);
882
883            if ((low_is_empty || matches!(low.op, Operation::LessThan)) && version >= &low.version)
884                || (matches!(low.op, Operation::LessThanEquals) && version > &low.version)
885            {
886                return Ok(false);
887            }
888        }
889
890        Ok(true)
891    }
892
893    /// Return `Ok(true)` if the [Version] sits entirely outside this range in
894    /// the specified direction.
895    ///
896    /// `direction` mirrors the JavaScript implementation's "hi/lo" flag:
897    /// [`OutsideDirection::Higher`] checks whether the version is greater than
898    /// the range, while [`OutsideDirection::Lower`] checks whether it is lower.
899    /// Set `include_prerelease` to `true` to treat prerelease versions as
900    /// satisfiable even when the range does not explicitly mention them.
901    ///
902    /// # Errors
903    /// Returns [`RangeError::MissingComparatorBounds`] if the range does not
904    /// expose enough comparator information to perform the comparison.
905    pub fn outside(
906        &self,
907        version: &Version,
908        direction: OutsideDirection,
909        include_prerelease: bool,
910    ) -> Result<bool, RangeError> {
911        match direction {
912            OutsideDirection::Higher => self.outside_higher(version, include_prerelease),
913            OutsideDirection::Lower => self.outside_lower(version, include_prerelease),
914        }
915    }
916}
917
918impl fmt::Display for Range {
919    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
920        for (i, range) in self.iter().enumerate() {
921            if i > 0 {
922                write!(f, "||")?;
923            }
924            write!(f, "{}", range)?;
925        }
926        Ok(())
927    }
928}
929
930impl std::str::FromStr for Range {
931    type Err = SemverError;
932    fn from_str(s: &str) -> Result<Self, Self::Err> {
933        Range::parse(s)
934    }
935}
936
937// ---- Parser ----
938
939/*
940Grammar from https://github.com/npm/node-semver#range-grammar
941
942range-set  ::= range ( logical-or range ) *
943logical-or ::= ( ' ' ) * '||' ( ' ' ) *
944range      ::= hyphen | simple ( ' ' simple ) * | ''
945hyphen     ::= partial ' - ' partial
946simple     ::= primitive | partial | tilde | caret
947primitive  ::= ( '<' | '>' | '>=' | '<=' | '=' ) partial
948partial    ::= xr ( '.' xr ( '.' xr qualifier ? )? )?
949xr         ::= 'x' | 'X' | '*' | nr
950nr         ::= '0' | ['1'-'9'] ( ['0'-'9'] ) *
951tilde      ::= '~' partial
952caret      ::= '^' partial
953qualifier  ::= ( '-' pre )? ( '+' build )?
954pre        ::= parts
955build      ::= parts
956parts      ::= part ( '.' part ) *
957part       ::= nr | [-0-9A-Za-z]+
958
959
960Loose mode (all LHS are invalid in strict mode):
961* 01.02.03 -> 1.2.3
962* 1.2.3alpha -> 1.2.3-alpha
963* v 1.2.3 -> 1.2.3 (v1.2.3 is actually a valid "plain" version)
964* =1.2.3 -> 1.2.3 (already a valid range)
965* - 10 -> >=10.0.0 <11.0.0
966* 1.2.3 foo 4.5.6 -> 1.2.3 4.5.6
967* 1.2.3.4 -> invalid range
968* foo -> invalid range
969* 1.2beta4 -> invalid range
970
971TODO: add tests for all these
972*/
973
974// range-set ::= range ( logical-or range ) *
975fn range_set<'s>(input: &mut &'s str) -> ModalResult<Range, SemverParseError<&'s str>> {
976    Parser::try_map(bound_sets, |sets| {
977        if sets.is_empty() {
978            Err(SemverParseError {
979                input,
980                kind: Some(SemverErrorKind::NoValidRanges),
981                context: None,
982            })
983        } else {
984            Ok(Range::from_bound_sets(sets).expect("non-empty bound sets"))
985        }
986    })
987    .parse_next(input)
988}
989
990// logical-or ::= ( ' ' ) * '||' ( ' ' ) *
991fn bound_sets<'s>(input: &mut &'s str) -> ModalResult<Vec<BoundSet>, SemverParseError<&'s str>> {
992    Parser::map(
993        separated(0.., range, logical_or),
994        |sets: Vec<Vec<BoundSet>>| sets.into_iter().flatten().collect(),
995    )
996    .parse_next(input)
997}
998fn logical_or<'s>(input: &mut &'s str) -> ModalResult<(), SemverParseError<&'s str>> {
999    Parser::map(delimited(space0, literal("||"), space0), |_| ()).parse_next(input)
1000}
1001
1002fn range<'s>(input: &mut &'s str) -> ModalResult<Vec<BoundSet>, SemverParseError<&'s str>> {
1003    // TODO: loose parsing means that `1.2.3 foo` translates to `1.2.3`, so we
1004    // need to do some stuff here to filter out unwanted BoundSets.
1005    Parser::map(
1006        separated(0.., simple, space1),
1007        |bs: Vec<Option<BoundSet>>| {
1008            bs.into_iter()
1009                .flatten()
1010                .fold(Vec::new(), |mut acc: Vec<BoundSet>, bs| {
1011                    if let Some(last) = acc.pop() {
1012                        if let Some(bound) = last.intersect(&bs) {
1013                            acc.push(bound);
1014                        } else {
1015                            acc.push(last);
1016                            acc.push(bs);
1017                        }
1018                    } else {
1019                        acc.push(bs)
1020                    }
1021                    acc
1022                })
1023        },
1024    )
1025    .parse_next(input)
1026}
1027
1028// simple ::= primitive | partial | tilde | caret | garbage
1029fn simple<'s>(input: &mut &'s str) -> ModalResult<Option<BoundSet>, SemverParseError<&'s str>> {
1030    alt((
1031        terminated(hyphen, peek(alt((space1, literal("||"), eof)))),
1032        terminated(primitive, peek(alt((space1, literal("||"), eof)))),
1033        terminated(partial, peek(alt((space1, literal("||"), eof)))),
1034        terminated(tilde, peek(alt((space1, literal("||"), eof)))),
1035        terminated(caret, peek(alt((space1, literal("||"), eof)))),
1036        garbage,
1037    ))
1038    .parse_next(input)
1039}
1040
1041fn garbage<'s>(input: &mut &'s str) -> ModalResult<Option<BoundSet>, SemverParseError<&'s str>> {
1042    Parser::map(
1043        repeat_till(0.., any, alt((peek(space1), peek(literal("||")), eof))),
1044        |_: ((), &str)| None,
1045    )
1046    .parse_next(input)
1047}
1048
1049// primitive  ::= ( '<' | '>' | '>=' | '<=' | '=' ) partial
1050fn primitive<'s>(input: &mut &'s str) -> ModalResult<Option<BoundSet>, SemverParseError<&'s str>> {
1051    use Operation::*;
1052
1053    Parser::map(
1054        (operation, preceded(space0, partial_version)),
1055        |parsed| match parsed {
1056            (GreaterThanEquals, partial) => {
1057                BoundSet::at_least(Predicate::Including(partial.into()))
1058            }
1059            (
1060                GreaterThan,
1061                Partial {
1062                    major: Some(major),
1063                    minor: Some(minor),
1064                    patch: None,
1065                    ..
1066                },
1067            ) => BoundSet::at_least(Predicate::Including((major, minor + 1, 0).into())),
1068            (
1069                GreaterThan,
1070                Partial {
1071                    major: Some(major),
1072                    minor: None,
1073                    patch: None,
1074                    ..
1075                },
1076            ) => BoundSet::at_least(Predicate::Including((major + 1, 0, 0).into())),
1077            (GreaterThan, partial) => BoundSet::at_least(Predicate::Excluding(partial.into())),
1078            (
1079                LessThan,
1080                Partial {
1081                    major: Some(major),
1082                    minor: Some(minor),
1083                    patch: None,
1084                    ..
1085                },
1086            ) => BoundSet::at_most(Predicate::Excluding((major, minor, 0, 0).into())),
1087            (
1088                LessThan,
1089                Partial {
1090                    major,
1091                    minor,
1092                    patch,
1093                    pre_release,
1094                    build,
1095                    ..
1096                },
1097            ) => BoundSet::at_most(Predicate::Excluding(Version::new(
1098                major.unwrap_or(0),
1099                minor.unwrap_or(0),
1100                patch.unwrap_or(0),
1101                pre_release,
1102                build,
1103            ))),
1104            (
1105                LessThanEquals,
1106                Partial {
1107                    major,
1108                    minor: None,
1109                    patch: None,
1110                    ..
1111                },
1112            ) => BoundSet::at_most(Predicate::Including(
1113                (major.unwrap_or(0), MAX_SAFE_INTEGER, MAX_SAFE_INTEGER).into(),
1114            )),
1115            (
1116                LessThanEquals,
1117                Partial {
1118                    major,
1119                    minor,
1120                    patch: None,
1121                    ..
1122                },
1123            ) => BoundSet::at_most(Predicate::Including(
1124                (major.unwrap_or(0), minor.unwrap_or(0), MAX_SAFE_INTEGER).into(),
1125            )),
1126            (LessThanEquals, partial) => BoundSet::at_most(Predicate::Including(partial.into())),
1127            (
1128                Exact,
1129                Partial {
1130                    major: Some(major),
1131                    minor: Some(minor),
1132                    patch: Some(patch),
1133                    pre_release,
1134                    ..
1135                },
1136            ) => BoundSet::exact(Version::new(major, minor, patch, pre_release, vec![])),
1137            (
1138                Exact,
1139                Partial {
1140                    major: Some(major),
1141                    minor: Some(minor),
1142                    ..
1143                },
1144            ) => BoundSet::new(
1145                Bound::Lower(Predicate::Including((major, minor, 0).into())),
1146                Bound::Upper(Predicate::Excluding((major, minor + 1, 0, 0).into())),
1147            ),
1148            (
1149                Exact,
1150                Partial {
1151                    major: Some(major), ..
1152                },
1153            ) => BoundSet::new(
1154                Bound::Lower(Predicate::Including((major, 0, 0).into())),
1155                Bound::Upper(Predicate::Excluding((major + 1, 0, 0, 0).into())),
1156            ),
1157            _ => None,
1158        },
1159    )
1160    .context("operation range (ex: >= 1.2.3)")
1161    .parse_next(input)
1162}
1163
1164fn operation<'s>(input: &mut &'s str) -> ModalResult<Operation, SemverParseError<&'s str>> {
1165    use Operation::*;
1166    alt((
1167        Parser::map(literal(">="), |_| GreaterThanEquals),
1168        Parser::map(literal(">"), |_| GreaterThan),
1169        Parser::map(literal("="), |_| Exact),
1170        Parser::map(literal("<="), |_| LessThanEquals),
1171        Parser::map(literal("<"), |_| LessThan),
1172    ))
1173    .parse_next(input)
1174}
1175
1176fn partial<'s>(input: &mut &'s str) -> ModalResult<Option<BoundSet>, SemverParseError<&'s str>> {
1177    Parser::map(partial_version, |partial| match partial {
1178        Partial { major: None, .. } => BoundSet::at_least(Predicate::Including((0, 0, 0).into())),
1179        Partial {
1180            major: Some(major),
1181            minor: None,
1182            ..
1183        } => BoundSet::new(
1184            Bound::Lower(Predicate::Including((major, 0, 0).into())),
1185            Bound::Upper(Predicate::Excluding((major + 1, 0, 0, 0).into())),
1186        ),
1187        Partial {
1188            major: Some(major),
1189            minor: Some(minor),
1190            patch: None,
1191            ..
1192        } => BoundSet::new(
1193            Bound::Lower(Predicate::Including((major, minor, 0).into())),
1194            Bound::Upper(Predicate::Excluding((major, minor + 1, 0, 0).into())),
1195        ),
1196        partial => BoundSet::exact(partial.into()),
1197    })
1198    .context("plain version range (ex: 1.2)")
1199    .parse_next(input)
1200}
1201
1202#[derive(Debug, Clone)]
1203struct Partial {
1204    major: Option<u64>,
1205    minor: Option<u64>,
1206    patch: Option<u64>,
1207    pre_release: Vec<Identifier>,
1208    build: Vec<Identifier>,
1209}
1210
1211impl From<Partial> for Version {
1212    fn from(partial: Partial) -> Self {
1213        Version::new(
1214            partial.major.unwrap_or(0),
1215            partial.minor.unwrap_or(0),
1216            partial.patch.unwrap_or(0),
1217            partial.pre_release,
1218            partial.build,
1219        )
1220    }
1221}
1222
1223// partial ::= xr ( '.' xr ( '.' xr qualifier ? )? )?
1224// xr      ::= 'x' | 'X' | '*' | nr
1225// nr      ::= '0' | ['1'-'9'] ( ['0'-'9'] ) *
1226// NOTE: Loose mode means nr is actually just `['0'-'9']`.
1227fn partial_version<'s>(input: &mut &'s str) -> ModalResult<Partial, SemverParseError<&'s str>> {
1228    let _ = opt(literal("v")).parse_next(input)?;
1229    let _ = space0(input)?;
1230    let major = component(input)?;
1231    let minor = opt(preceded(literal("."), component)).parse_next(input)?;
1232    let patch = opt(preceded(literal("."), component)).parse_next(input)?;
1233    let (pre, build) = if patch.is_some() {
1234        extras(input)?
1235    } else {
1236        (vec![], vec![])
1237    };
1238    Ok(Partial {
1239        major,
1240        minor: minor.flatten(),
1241        patch: patch.flatten(),
1242        pre_release: pre,
1243        build,
1244    })
1245}
1246
1247fn component<'s>(input: &mut &'s str) -> ModalResult<Option<u64>, SemverParseError<&'s str>> {
1248    alt((
1249        Parser::map(x_or_asterisk, |_| None),
1250        Parser::map(number, Some),
1251    ))
1252    .parse_next(input)
1253}
1254
1255fn x_or_asterisk<'s>(input: &mut &'s str) -> ModalResult<(), SemverParseError<&'s str>> {
1256    Parser::map(alt((literal("x"), literal("X"), literal("*"))), |_| ()).parse_next(input)
1257}
1258
1259fn tilde_gt<'s>(input: &mut &'s str) -> ModalResult<Option<&'s str>, SemverParseError<&'s str>> {
1260    Parser::map(
1261        (literal("~"), space0, opt(literal(">")), space0),
1262        |(_, _, gt, _)| gt,
1263    )
1264    .parse_next(input)
1265}
1266
1267fn tilde<'s>(input: &mut &'s str) -> ModalResult<Option<BoundSet>, SemverParseError<&'s str>> {
1268    Parser::map((tilde_gt, partial_version), |parsed| match parsed {
1269        (
1270            Some(_gt),
1271            Partial {
1272                major: Some(major),
1273                minor: None,
1274                patch: None,
1275                ..
1276            },
1277        ) => BoundSet::new(
1278            Bound::Lower(Predicate::Including((major, 0, 0).into())),
1279            Bound::Upper(Predicate::Excluding((major + 1, 0, 0, 0).into())),
1280        ),
1281        (
1282            Some(_gt),
1283            Partial {
1284                major: Some(major),
1285                minor: Some(minor),
1286                patch,
1287                pre_release,
1288                ..
1289            },
1290        ) => BoundSet::new(
1291            Bound::Lower(Predicate::Including(Version::new(
1292                major,
1293                minor,
1294                patch.unwrap_or(0),
1295                pre_release,
1296                vec![],
1297            ))),
1298            Bound::Upper(Predicate::Excluding((major, minor + 1, 0, 0).into())),
1299        ),
1300        (
1301            None,
1302            Partial {
1303                major: Some(major),
1304                minor: Some(minor),
1305                patch: Some(patch),
1306                pre_release,
1307                ..
1308            },
1309        ) => BoundSet::new(
1310            Bound::Lower(Predicate::Including(Version::new(
1311                major,
1312                minor,
1313                patch,
1314                pre_release,
1315                vec![],
1316            ))),
1317            Bound::Upper(Predicate::Excluding((major, minor + 1, 0, 0).into())),
1318        ),
1319        (
1320            None,
1321            Partial {
1322                major: Some(major),
1323                minor: Some(minor),
1324                patch: None,
1325                ..
1326            },
1327        ) => BoundSet::new(
1328            Bound::Lower(Predicate::Including((major, minor, 0).into())),
1329            Bound::Upper(Predicate::Excluding((major, minor + 1, 0, 0).into())),
1330        ),
1331        (
1332            None,
1333            Partial {
1334                major: Some(major),
1335                minor: None,
1336                patch: None,
1337                ..
1338            },
1339        ) => BoundSet::new(
1340            Bound::Lower(Predicate::Including((major, 0, 0).into())),
1341            Bound::Upper(Predicate::Excluding((major + 1, 0, 0, 0).into())),
1342        ),
1343        _ => None,
1344    })
1345    .context("tilde version range (ex: ~1.2.3)")
1346    .parse_next(input)
1347}
1348
1349fn caret<'s>(input: &mut &'s str) -> ModalResult<Option<BoundSet>, SemverParseError<&'s str>> {
1350    Parser::map(
1351        preceded((literal("^"), space0), partial_version),
1352        |parsed| match parsed {
1353            Partial {
1354                major: Some(0),
1355                minor: None,
1356                patch: None,
1357                ..
1358            } => BoundSet::at_most(Predicate::Excluding((1, 0, 0, 0).into())),
1359            Partial {
1360                major: Some(0),
1361                minor: Some(minor),
1362                patch: None,
1363                ..
1364            } => BoundSet::new(
1365                Bound::Lower(Predicate::Including((0, minor, 0).into())),
1366                Bound::Upper(Predicate::Excluding((0, minor + 1, 0, 0).into())),
1367            ),
1368            // TODO: can be compressed?
1369            Partial {
1370                major: Some(major),
1371                minor: None,
1372                patch: None,
1373                ..
1374            } => BoundSet::new(
1375                Bound::Lower(Predicate::Including((major, 0, 0).into())),
1376                Bound::Upper(Predicate::Excluding((major + 1, 0, 0, 0).into())),
1377            ),
1378            Partial {
1379                major: Some(major),
1380                minor: Some(minor),
1381                patch: None,
1382                ..
1383            } => BoundSet::new(
1384                Bound::Lower(Predicate::Including((major, minor, 0).into())),
1385                Bound::Upper(Predicate::Excluding((major + 1, 0, 0, 0).into())),
1386            ),
1387            Partial {
1388                major: Some(major),
1389                minor: Some(minor),
1390                patch: Some(patch),
1391                pre_release,
1392                ..
1393            } => BoundSet::new(
1394                Bound::Lower(Predicate::Including(Version::new(
1395                    major,
1396                    minor,
1397                    patch,
1398                    pre_release,
1399                    vec![],
1400                ))),
1401                Bound::Upper(Predicate::Excluding(match (major, minor, patch) {
1402                    (0, 0, n) => Version::from((0, 0, n + 1, 0)),
1403                    (0, n, _) => Version::from((0, n + 1, 0, 0)),
1404                    (n, _, _) => Version::from((n + 1, 0, 0, 0)),
1405                })),
1406            ),
1407            _ => None,
1408        },
1409    )
1410    .context("caret version range (ex: ^1.2.3)")
1411    .parse_next(input)
1412}
1413
1414// hyphen ::= ' - ' partial /* loose */ | partial ' - ' partial
1415fn hyphen<'s>(input: &mut &'s str) -> ModalResult<Option<BoundSet>, SemverParseError<&'s str>> {
1416    fn parser<'s>(input: &mut &'s str) -> ModalResult<Option<BoundSet>, SemverParseError<&'s str>> {
1417        let lower = opt(partial_version).parse_next(input)?;
1418        let _ = space1(input)?;
1419        let _ = literal("-").parse_next(input)?;
1420        let _ = space1(input)?;
1421        let upper = partial_version(input)?;
1422        let upper = match upper {
1423            Partial {
1424                major: None,
1425                minor: None,
1426                patch: None,
1427                ..
1428            } => Predicate::Excluding((0, 0, 0, 0).into()),
1429            Partial {
1430                major: Some(major),
1431                minor: None,
1432                patch: None,
1433                ..
1434            } => Predicate::Excluding((major + 1, 0, 0, 0).into()),
1435            Partial {
1436                major: Some(major),
1437                minor: Some(minor),
1438                patch: None,
1439                ..
1440            } => Predicate::Excluding((major, minor + 1, 0, 0).into()),
1441            partial => Predicate::Including(partial.into()),
1442        };
1443        let bounds = if let Some(lower) = lower {
1444            BoundSet::new(
1445                Bound::Lower(Predicate::Including(lower.into())),
1446                Bound::Upper(upper),
1447            )
1448        } else {
1449            BoundSet::at_most(upper)
1450        };
1451        Ok(bounds)
1452    }
1453
1454    parser
1455        .context("hyphenated version range (ex: 1.2 - 2)")
1456        .parse_next(input)
1457}
1458
1459macro_rules! create_tests_for {
1460    ($func:ident $($name:ident => $version_range:expr , { $x:ident => $allows:expr, $y:ident => $denies:expr$(,)? }),+ ,$(,)?) => {
1461
1462        #[cfg(test)]
1463        mod $func {
1464        use super::*;
1465
1466            $(
1467                #[test]
1468                fn $name() {
1469                    let version_range = Range::parse($version_range).unwrap();
1470
1471                    let allows: Vec<Range> = $allows.iter().map(|v| Range::parse(v).unwrap()).collect();
1472                    for version in &allows {
1473                        assert!(version_range.$func(version), "should have allowed: {}", version);
1474                    }
1475
1476                    let ranges: Vec<Range> = $denies.iter().map(|v| Range::parse(v).unwrap()).collect();
1477                    for version in &ranges {
1478                        assert!(!version_range.$func(version), "should have denied: {}", version);
1479                    }
1480                }
1481            )+
1482        }
1483    }
1484}
1485
1486create_tests_for! {
1487    // The function we are testing:
1488    allows_all
1489
1490    greater_than_eq_123   => ">=1.2.3", {
1491        allows => [">=2.0.0", ">2", "2.0.0", "0.1 || 1.4", "1.2.3", "2 - 7", ">2.0.0"],
1492        denies => ["1.0.0", "<1.2", ">=1.2.2", "1 - 3", "0.1 || <1.2.0", ">1.0.0"],
1493    },
1494
1495    greater_than_123      => ">1.2.3", {
1496        allows => [">=2.0.0", ">2", "2.0.0", "0.1 || 1.4", ">2.0.0"],
1497        denies => ["1.0.0", "<1.2", ">=1.2.3", "1 - 3", "0.1 || <1.2.0", "<=3"],
1498    },
1499
1500    eq_123  => "1.2.3", {
1501        allows => ["1.2.3"],
1502        denies => ["1.0.0", "<1.2", "1.x", ">=1.2.2", "1 - 3", "0.1 || <1.2.0"],
1503    },
1504
1505    lt_123  => "<1.2.3", {
1506        allows => ["<=1.2.0", "<1", "1.0.0", "0.1 || 1.4"],
1507        denies => ["1 - 3", ">1", "2.0.0", "2.0 || >9", ">1.0.0"],
1508    },
1509
1510    lt_eq_123 => "<=1.2.3", {
1511        allows => ["<=1.2.0", "<1", "1.0.0", "0.1 || 1.4", "1.2.3"],
1512        denies => ["1 - 3", ">1.0.0", ">=1.0.0"],
1513    },
1514
1515    eq_123_or_gt_400  => "1.2.3 || >4", {
1516        allows => [ "1.2.3", ">4", "5.x", "5.2.x", ">=8.2.1", "2.0 || 5.6.7"],
1517        denies => ["<2", "1 - 7", "1.9.4 || 2 - 3"],
1518    },
1519
1520    between_two_and_eight => "2 - 8", {
1521        allows => [ "2.2.3", "4 - 5"],
1522        denies => ["1 - 4", "5 - 9", ">3", "<=5"],
1523    },
1524}
1525
1526create_tests_for! {
1527    // The function we are testing:
1528    allows_any
1529
1530    greater_than_eq_123   => ">=1.2.3", {
1531        allows => ["<=1.2.4", "3.0.0", "<2", ">=3", ">3.0.0"],
1532        denies => ["<=1.2.0", "1.0.0", "<1"],
1533    },
1534
1535    greater_than_123   => ">1.2.3", {
1536        allows => ["<=1.2.4", "3.0.0", "<2", ">=3", ">3.0.0"],
1537        denies => ["<=1.2.3", "1.0.0", "<1"],
1538    },
1539
1540    eq_123   => "1.2.3", {
1541        allows => ["1.2.3", "1 - 2"],
1542        denies => ["<1.2.3", "1.0.0", ">4.5.6", ">5"],
1543    },
1544
1545    lt_eq_123  => "<=1.2.3", {
1546        allows => ["<=1.2.0", "<1.0.0", "1.0.0", ">1.0.0", ">=1.2.0"],
1547        denies => ["4.5.6", ">2.0.0", ">=2.0.0"],
1548    },
1549
1550    lt_123  => "<1.2.3", {
1551        allows => ["<=2.2.0", "<2.0.0", "1.0.0", ">1.0.0", ">=1.2.0"],
1552        denies => ["2.0.0", ">1.8.0", ">=1.8.0"],
1553    },
1554
1555    between_two_and_eight => "2 - 8", {
1556        allows => ["2.2.3", "4 - 10", ">4", ">4.0.0", "<=4.0.0", "<9.1.2"],
1557        denies => [">10", "10 - 11", "0 - 1"],
1558    },
1559
1560    eq_123_or_gt_400  => "1.2.3 || >4", {
1561        allows => [ "1.2.3", ">3", "5.x", "5.2.x", ">=8.2.1", "2 - 7", "2.0 || 5.6.7"],
1562        denies => [ "1.9.4 || 2 - 3"],
1563    },
1564}
1565
1566#[cfg(test)]
1567mod intersection {
1568    use super::*;
1569
1570    fn v(range: &'static str) -> Range {
1571        range.parse().unwrap()
1572    }
1573
1574    #[test]
1575    fn gt_eq_123() {
1576        let base_range = v(">=1.2.3");
1577
1578        let samples = vec![
1579            ("<=2.0.0", Some(">=1.2.3 <=2.0.0")),
1580            ("<2.0.0", Some(">=1.2.3 <2.0.0")),
1581            (">=2.0.0", Some(">=2.0.0")),
1582            (">2.0.0", Some(">2.0.0")),
1583            (">1.0.0", Some(">=1.2.3")),
1584            (">1.2.3", Some(">1.2.3")),
1585            ("<=1.2.3", Some("1.2.3")),
1586            ("2.0.0", Some("2.0.0")),
1587            ("1.1.1", None),
1588            ("<1.0.0", None),
1589        ];
1590
1591        assert_ranges_match(base_range, samples);
1592    }
1593
1594    #[test]
1595    fn gt_123() {
1596        let base_range = v(">1.2.3");
1597
1598        let samples = vec![
1599            ("<=2.0.0", Some(">1.2.3 <=2.0.0")),
1600            ("<2.0.0", Some(">1.2.3 <2.0.0")),
1601            (">=2.0.0", Some(">=2.0.0")),
1602            (">2.0.0", Some(">2.0.0")),
1603            ("2.0.0", Some("2.0.0")),
1604            (">1.2.3", Some(">1.2.3")),
1605            ("<=1.2.3", None),
1606            ("1.1.1", None),
1607            ("<1.0.0", None),
1608        ];
1609
1610        assert_ranges_match(base_range, samples);
1611    }
1612
1613    #[test]
1614    fn eq_123() {
1615        let base_range = v("1.2.3");
1616
1617        let samples = vec![
1618            ("<=2.0.0", Some("1.2.3")),
1619            ("<2.0.0", Some("1.2.3")),
1620            (">=2.0.0", None),
1621            (">2.0.0", None),
1622            ("2.0.0", None),
1623            ("1.2.3", Some("1.2.3")),
1624            (">1.2.3", None),
1625            ("<=1.2.3", Some("1.2.3")),
1626            ("1.1.1", None),
1627            ("<1.0.0", None),
1628        ];
1629
1630        assert_ranges_match(base_range, samples);
1631    }
1632
1633    #[test]
1634    fn lt_123() {
1635        let base_range = v("<1.2.3");
1636
1637        let samples = vec![
1638            ("<=2.0.0", Some("<1.2.3")),
1639            ("<2.0.0", Some("<1.2.3")),
1640            (">=2.0.0", None),
1641            (">=1.0.0", Some(">=1.0.0 <1.2.3")),
1642            (">2.0.0", None),
1643            ("2.0.0", None),
1644            ("1.2.3", None),
1645            (">1.2.3", None),
1646            ("<=1.2.3", Some("<1.2.3")),
1647            ("1.1.1", Some("1.1.1")),
1648            ("<1.0.0", Some("<1.0.0")),
1649        ];
1650
1651        assert_ranges_match(base_range, samples);
1652    }
1653
1654    #[test]
1655    fn lt_eq_123() {
1656        let base_range = v("<=1.2.3");
1657
1658        let samples = vec![
1659            ("<=2.0.0", Some("<=1.2.3")),
1660            ("<2.0.0", Some("<=1.2.3")),
1661            (">=2.0.0", None),
1662            (">=1.0.0", Some(">=1.0.0 <=1.2.3")),
1663            (">2.0.0", None),
1664            ("2.0.0", None),
1665            ("1.2.3", Some("1.2.3")),
1666            (">1.2.3", None),
1667            ("<=1.2.3", Some("<=1.2.3")),
1668            ("1.1.1", Some("1.1.1")),
1669            ("<1.0.0", Some("<1.0.0")),
1670        ];
1671
1672        assert_ranges_match(base_range, samples);
1673    }
1674
1675    #[test]
1676    fn multiple() {
1677        let base_range = v("<1 || 3 - 4");
1678
1679        let samples = vec![("0.5 - 3.5.0", Some(">=0.5.0 <1.0.0||>=3.0.0 <=3.5.0"))];
1680
1681        assert_ranges_match(base_range, samples);
1682    }
1683
1684    fn assert_ranges_match(base: Range, samples: Vec<(&'static str, Option<&'static str>)>) {
1685        for (other, expected) in samples {
1686            let other = v(other);
1687            let resulting_range = base.intersect(&other).map(|v| v.to_string());
1688            assert_eq!(
1689                resulting_range.clone(),
1690                expected.map(|e| e.to_string()),
1691                "{} ∩ {} := {}",
1692                base,
1693                other,
1694                resulting_range.unwrap_or_else(|| "⊗".into())
1695            );
1696        }
1697    }
1698}
1699
1700#[cfg(test)]
1701mod difference {
1702    use super::*;
1703
1704    fn v(range: &'static str) -> Range {
1705        range.parse().unwrap()
1706    }
1707
1708    #[test]
1709    fn gt_eq_123() {
1710        let base_range = v(">=1.2.3");
1711
1712        let samples = vec![
1713            ("<=2.0.0", Some(">2.0.0")),
1714            ("<2.0.0", Some(">=2.0.0")),
1715            (">=2.0.0", Some(">=1.2.3 <2.0.0")),
1716            (">2.0.0", Some(">=1.2.3 <=2.0.0")),
1717            (">1.0.0", None),
1718            (">1.2.3", Some("1.2.3")),
1719            ("<=1.2.3", Some(">1.2.3")),
1720            ("1.1.1", Some(">=1.2.3")),
1721            ("<1.0.0", Some(">=1.2.3")),
1722            ("2.0.0", Some(">=1.2.3 <2.0.0||>2.0.0")),
1723        ];
1724
1725        assert_ranges_match(base_range, samples);
1726    }
1727
1728    #[test]
1729    fn gt_123() {
1730        let base_range = v(">1.2.3");
1731
1732        let samples = vec![
1733            ("<=2.0.0", Some(">2.0.0")),
1734            ("<2.0.0", Some(">=2.0.0")),
1735            (">=2.0.0", Some(">1.2.3 <2.0.0")),
1736            (">2.0.0", Some(">1.2.3 <=2.0.0")),
1737            (">1.0.0", None),
1738            (">1.2.3", None),
1739            ("<=1.2.3", Some(">1.2.3")),
1740            ("1.1.1", Some(">1.2.3")),
1741            ("<1.0.0", Some(">1.2.3")),
1742            ("2.0.0", Some(">1.2.3 <2.0.0||>2.0.0")),
1743        ];
1744
1745        assert_ranges_match(base_range, samples);
1746    }
1747
1748    #[test]
1749    fn eq_123() {
1750        let base_range = v("1.2.3");
1751
1752        let samples = vec![
1753            ("<=2.0.0", None),
1754            ("<2.0.0", None),
1755            (">=2.0.0", Some("1.2.3")),
1756            (">2.0.0", Some("1.2.3")),
1757            (">1.0.0", None),
1758            (">1.2.3", Some("1.2.3")),
1759            ("1.2.3", None),
1760            ("<=1.2.3", None),
1761            ("1.1.1", Some("1.2.3")),
1762            ("<1.0.0", Some("1.2.3")),
1763            ("2.0.0", Some("1.2.3")),
1764        ];
1765
1766        assert_ranges_match(base_range, samples);
1767    }
1768
1769    #[test]
1770    fn lt_123() {
1771        let base_range = v("<1.2.3");
1772
1773        let samples = vec![
1774            ("<=2.0.0", None),
1775            ("<2.0.0", None),
1776            (">=2.0.0", Some("<1.2.3")),
1777            (">2.0.0", Some("<1.2.3")),
1778            (">1.0.0", Some("<=1.0.0")),
1779            (">1.2.3", Some("<1.2.3")),
1780            ("<=1.2.3", None),
1781            ("1.1.1", Some("<1.1.1||>1.1.1 <1.2.3")),
1782            ("<1.0.0", Some(">=1.0.0 <1.2.3")),
1783            ("2.0.0", Some("<1.2.3")),
1784        ];
1785
1786        assert_ranges_match(base_range, samples);
1787    }
1788
1789    #[test]
1790    fn lt_eq_123() {
1791        let base_range = v("<=1.2.3");
1792
1793        let samples = vec![
1794            ("<=2.0.0", None),
1795            ("<2.0.0", None),
1796            (">=2.0.0", Some("<=1.2.3")),
1797            (">2.0.0", Some("<=1.2.3")),
1798            (">1.0.0", Some("<=1.0.0")),
1799            (">1.2.3", Some("<=1.2.3")),
1800            ("<=1.2.3", None),
1801            ("1.1.1", Some("<1.1.1||>1.1.1 <=1.2.3")),
1802            ("<1.0.0", Some(">=1.0.0 <=1.2.3")),
1803            ("2.0.0", Some("<=1.2.3")),
1804        ];
1805
1806        assert_ranges_match(base_range, samples);
1807    }
1808
1809    #[test]
1810    fn multiple() {
1811        let base_range = v("<1 || 3 - 4");
1812
1813        let samples = vec![("0.5 - 3.5.0", Some("<0.5.0||>3.5.0 <5.0.0-0"))];
1814
1815        assert_ranges_match(base_range, samples);
1816    }
1817
1818    fn assert_ranges_match(base: Range, samples: Vec<(&'static str, Option<&'static str>)>) {
1819        for (other, expected) in samples {
1820            let other = v(other);
1821            let resulting_range = base.difference(&other).map(|v| v.to_string());
1822            assert_eq!(
1823                resulting_range.clone(),
1824                expected.map(|e| e.to_string()),
1825                "{} \\ {} := {}",
1826                base,
1827                other,
1828                resulting_range.unwrap_or_else(|| "⊗".into())
1829            );
1830        }
1831    }
1832}
1833
1834#[cfg(test)]
1835mod outside {
1836    use super::*;
1837    use std::convert::TryFrom;
1838
1839    const VERSION_GT_RANGE: &[(&str, &str, bool)] = &[
1840        ("~1.2.2", "1.3.0", false),
1841        ("~0.6.1-1", "0.7.1-1", false),
1842        ("1.0.0 - 2.0.0", "2.0.1", false),
1843        ("1.0.0", "1.0.1-beta1", false),
1844        ("1.0.0", "2.0.0", false),
1845        ("<=2.0.0", "2.1.1", false),
1846        ("<=2.0.0", "3.2.9", false),
1847        ("<2.0.0", "2.0.0", false),
1848        ("0.1.20 || 1.2.4", "1.2.5", false),
1849        ("2.x.x", "3.0.0", false),
1850        ("1.2.x", "1.3.0", false),
1851        ("1.2.x || 2.x", "3.0.0", false),
1852        ("2.*.*", "5.0.1", false),
1853        ("1.2.*", "1.3.3", false),
1854        ("1.2.* || 2.*", "4.0.0", false),
1855        ("2", "3.0.0", false),
1856        ("2.3", "2.4.2", false),
1857        ("~2.4", "2.5.0", false),
1858        ("~2.4", "2.5.5", false),
1859        ("~>3.2.1", "3.3.0", false),
1860        ("~1", "2.2.3", false),
1861        ("~>1", "2.2.4", false),
1862        ("~> 1", "3.2.3", false),
1863        ("~1.0", "1.1.2", false),
1864        ("~ 1.0", "1.1.0", false),
1865        ("<1.2", "1.2.0", false),
1866        ("< 1.2", "1.2.1", false),
1867        ("1", "2.0.0beta", false),
1868        ("~v0.5.4-pre", "0.6.0", false),
1869        ("~v0.5.4-pre", "0.6.1-pre", false),
1870        ("=0.7.x", "0.8.0", false),
1871        ("=0.7.x", "0.8.0-asdf", false),
1872        ("<0.7.x", "0.7.0", false),
1873        ("1.0.0 - 2.0.0", "2.2.3", false),
1874        ("1.0.0", "1.0.1", false),
1875        ("<=2.0.0", "3.0.0", false),
1876        ("<=2.0.0", "2.9999.9999", false),
1877        ("<=2.0.0", "2.2.9", false),
1878        ("<2.0.0", "2.9999.9999", false),
1879        ("<2.0.0", "2.2.9", false),
1880        ("2.x.x", "3.1.3", false),
1881        ("1.2.x", "1.3.3", false),
1882        ("1.2.x || 2.x", "3.1.3", false),
1883        ("2.*.*", "3.1.3", false),
1884        ("1.2.* || 2.*", "3.1.3", false),
1885        ("2", "3.1.2", false),
1886        ("2.3", "2.4.1", false),
1887        ("~>3.2.1", "3.3.2", false),
1888        ("~>1", "2.2.3", false),
1889        ("~1.0", "1.1.0", false),
1890        ("<1", "1.0.0", false),
1891        ("<1", "1.0.0beta", false),
1892        ("< 1", "1.0.0beta", false),
1893        ("=0.7.x", "0.8.2", false),
1894        ("<0.7.x", "0.7.2", false),
1895        ("0.7.x", "0.7.2-beta", false),
1896    ];
1897
1898    const VERSION_NOT_GT_RANGE: &[(&str, &str, bool)] = &[
1899        ("~0.6.1-1", "0.6.1-1", false),
1900        ("1.0.0 - 2.0.0", "1.2.3", false),
1901        ("1.0.0 - 2.0.0", "0.9.9", false),
1902        ("1.0.0", "1.0.0", false),
1903        (">=*", "0.2.4", false),
1904        ("", "1.0.0", false),
1905        ("*", "1.2.3", false),
1906        ("*", "v1.2.3-foo", false),
1907        (">=1.0.0", "1.0.0", false),
1908        (">=1.0.0", "1.0.1", false),
1909        (">=1.0.0", "1.1.0", false),
1910        (">1.0.0", "1.0.1", false),
1911        (">1.0.0", "1.1.0", false),
1912        ("<=2.0.0", "2.0.0", false),
1913        ("<=2.0.0", "1.9999.9999", false),
1914        ("<=2.0.0", "0.2.9", false),
1915        ("<2.0.0", "1.9999.9999", false),
1916        ("<2.0.0", "0.2.9", false),
1917        (">= 1.0.0", "1.0.0", false),
1918        (">=  1.0.0", "1.0.1", false),
1919        (">=   1.0.0", "1.1.0", false),
1920        ("> 1.0.0", "1.0.1", false),
1921        (">  1.0.0", "1.1.0", false),
1922        ("<=   2.0.0", "2.0.0", false),
1923        ("<= 2.0.0", "1.9999.9999", false),
1924        ("<=  2.0.0", "0.2.9", false),
1925        ("<    2.0.0", "1.9999.9999", false),
1926        ("<\t2.0.0", "0.2.9", false),
1927        (">=0.1.97", "v0.1.97", false),
1928        (">=0.1.97", "0.1.97", false),
1929        ("0.1.20 || 1.2.4", "1.2.4", false),
1930        ("0.1.20 || >1.2.4", "1.2.4", false),
1931        ("0.1.20 || 1.2.4", "1.2.3", false),
1932        ("0.1.20 || 1.2.4", "0.1.20", false),
1933        (">=0.2.3 || <0.0.1", "0.0.0", false),
1934        (">=0.2.3 || <0.0.1", "0.2.3", false),
1935        (">=0.2.3 || <0.0.1", "0.2.4", false),
1936        ("||", "1.3.4", false),
1937        ("2.x.x", "2.1.3", false),
1938        ("1.2.x", "1.2.3", false),
1939        ("1.2.x || 2.x", "2.1.3", false),
1940        ("1.2.x || 2.x", "1.2.3", false),
1941        ("x", "1.2.3", false),
1942        ("2.*.*", "2.1.3", false),
1943        ("1.2.*", "1.2.3", false),
1944        ("1.2.* || 2.*", "2.1.3", false),
1945        ("1.2.* || 2.*", "1.2.3", false),
1946        ("2", "2.1.2", false),
1947        ("2.3", "2.3.1", false),
1948        ("~2.4", "2.4.0", false),
1949        ("~2.4", "2.4.5", false),
1950        ("~>3.2.1", "3.2.2", false),
1951        ("~1", "1.2.3", false),
1952        ("~>1", "1.2.3", false),
1953        ("~> 1", "1.2.3", false),
1954        ("~1.0", "1.0.2", false),
1955        ("~ 1.0", "1.0.2", false),
1956        (">=1", "1.0.0", false),
1957        (">= 1", "1.0.0", false),
1958        ("<1.2", "1.1.1", false),
1959        ("< 1.2", "1.1.1", false),
1960        ("1", "1.0.0beta", false),
1961        ("~v0.5.4-pre", "0.5.5", false),
1962        ("~v0.5.4-pre", "0.5.4", false),
1963        ("=0.7.x", "0.7.2", false),
1964        (">=0.7.x", "0.7.2", false),
1965        ("=0.7.x", "0.7.0-asdf", false),
1966        (">=0.7.x", "0.7.0-asdf", false),
1967        ("<=0.7.x", "0.6.2", false),
1968        (">0.2.3 >0.2.4 <=0.2.5", "0.2.5", false),
1969        (">=0.2.3 <=0.2.4", "0.2.4", false),
1970        ("1.0.0 - 2.0.0", "2.0.0", false),
1971        ("^1", "0.0.0-0", false),
1972        ("^3.0.0", "2.0.0", false),
1973        ("^1.0.0 || ~2.0.1", "2.0.0", false),
1974        ("^0.1.0 || ~3.0.1 || 5.0.0", "3.2.0", false),
1975        ("^0.1.0 || ~3.0.1 || 5.0.0", "1.0.0beta", false),
1976        ("^0.1.0 || ~3.0.1 || 5.0.0", "5.0.0-0", false),
1977        ("^0.1.0 || ~3.0.1 || >4 <=5.0.0", "3.5.0", false),
1978        ("0.7.x", "0.7.2-beta", true),
1979    ];
1980
1981    const VERSION_LT_RANGE: &[(&str, &str, bool)] = &[
1982        ("~1.2.2", "1.2.1", false),
1983        ("~0.6.1-1", "0.6.1-0", false),
1984        ("1.0.0 - 2.0.0", "0.0.1", false),
1985        ("1.0.0-beta.2", "1.0.0-beta.1", false),
1986        ("1.0.0", "0.0.0", false),
1987        (">=2.0.0", "1.1.1", false),
1988        (">=2.0.0", "1.2.9", false),
1989        (">2.0.0", "2.0.0", false),
1990        ("0.1.20 || 1.2.4", "0.1.5", false),
1991        ("2.x.x", "1.0.0", false),
1992        ("1.2.x", "1.1.0", false),
1993        ("1.2.x || 2.x", "1.0.0", false),
1994        ("2.*.*", "1.0.1", false),
1995        ("1.2.*", "1.1.3", false),
1996        ("1.2.* || 2.*", "1.1.9999", false),
1997        ("2", "1.0.0", false),
1998        ("2.3", "2.2.2", false),
1999        ("~2.4", "2.3.0", false),
2000        ("~2.4", "2.3.5", false),
2001        ("~>3.2.1", "3.2.0", false),
2002        ("~1", "0.2.3", false),
2003        ("~>1", "0.2.4", false),
2004        ("~> 1", "0.2.3", false),
2005        ("~1.0", "0.1.2", false),
2006        ("~ 1.0", "0.1.0", false),
2007        (">1.2", "1.2.0", false),
2008        ("> 1.2", "1.2.1", false),
2009        ("1", "0.0.0beta", false),
2010        ("~v0.5.4-pre", "0.5.4-alpha", false),
2011        ("=0.7.x", "0.6.0", false),
2012        ("=0.7.x", "0.6.0-asdf", false),
2013        (">=0.7.x", "0.6.0", false),
2014        ("1.0.0 - 2.0.0", "0.2.3", false),
2015        ("1.0.0", "0.0.1", false),
2016        (">=2.0.0", "1.0.0", false),
2017        (">=2.0.0", "1.9999.9999", false),
2018        (">2.0.0", "1.2.9", false),
2019        ("2.x.x", "1.1.3", false),
2020        ("1.2.x", "1.1.3", false),
2021        ("1.2.x || 2.x", "1.1.3", false),
2022        ("2.*.*", "1.1.3", false),
2023        ("1.2.* || 2.*", "1.1.3", false),
2024        ("2", "1.9999.9999", false),
2025        ("2.3", "2.2.1", false),
2026        ("~>3.2.1", "2.3.2", false),
2027        ("~>1", "0.2.3", false),
2028        ("~1.0", "0.0.0", false),
2029        (">1", "1.0.0", false),
2030        ("2", "1.0.0beta", false),
2031        (">1", "1.0.0beta", false),
2032        ("> 1", "1.0.0beta", false),
2033        ("=0.7.x", "0.6.2", false),
2034        ("=0.7.x", "0.7.0-asdf", false),
2035        ("^1", "1.0.0-0", false),
2036        (">=0.7.x", "0.7.0-asdf", false),
2037        ("1", "1.0.0beta", false),
2038        (">=0.7.x", "0.6.2", false),
2039        (">1.2.3", "1.3.0-alpha", false),
2040    ];
2041
2042    const VERSION_NOT_LT_RANGE: &[(&str, &str, bool)] = &[
2043        ("~ 1.0", "1.1.0", false),
2044        ("~0.6.1-1", "0.6.1-1", false),
2045        ("1.0.0 - 2.0.0", "1.2.3", false),
2046        ("1.0.0 - 2.0.0", "2.9.9", false),
2047        ("1.0.0", "1.0.0", false),
2048        (">=*", "0.2.4", false),
2049        ("", "1.0.0", false),
2050        ("*", "1.2.3", false),
2051        (">=1.0.0", "1.0.0", false),
2052        (">=1.0.0", "1.0.1", false),
2053        (">=1.0.0", "1.1.0", false),
2054        (">1.0.0", "1.0.1", false),
2055        (">1.0.0", "1.1.0", false),
2056        ("<=2.0.0", "2.0.0", false),
2057        ("<=2.0.0", "1.9999.9999", false),
2058        ("<=2.0.0", "0.2.9", false),
2059        ("<2.0.0", "1.9999.9999", false),
2060        ("<2.0.0", "0.2.9", false),
2061        (">= 1.0.0", "1.0.0", false),
2062        (">=  1.0.0", "1.0.1", false),
2063        (">=   1.0.0", "1.1.0", false),
2064        ("> 1.0.0", "1.0.1", false),
2065        (">  1.0.0", "1.1.0", false),
2066        ("<=   2.0.0", "2.0.0", false),
2067        ("<= 2.0.0", "1.9999.9999", false),
2068        ("<=  2.0.0", "0.2.9", false),
2069        ("<    2.0.0", "1.9999.9999", false),
2070        ("<\t2.0.0", "0.2.9", false),
2071        (">=0.1.97", "v0.1.97", false),
2072        (">=0.1.97", "0.1.97", false),
2073        ("0.1.20 || 1.2.4", "1.2.4", false),
2074        ("0.1.20 || >1.2.4", "1.2.4", false),
2075        ("0.1.20 || 1.2.4", "1.2.3", false),
2076        ("0.1.20 || 1.2.4", "0.1.20", false),
2077        (">=0.2.3 || <0.0.1", "0.0.0", false),
2078        (">=0.2.3 || <0.0.1", "0.2.3", false),
2079        (">=0.2.3 || <0.0.1", "0.2.4", false),
2080        ("||", "1.3.4", false),
2081        ("2.x.x", "2.1.3", false),
2082        ("1.2.x", "1.2.3", false),
2083        ("1.2.x || 2.x", "2.1.3", false),
2084        ("1.2.x || 2.x", "1.2.3", false),
2085        ("x", "1.2.3", false),
2086        ("2.*.*", "2.1.3", false),
2087        ("1.2.*", "1.2.3", false),
2088        ("1.2.* || 2.*", "2.1.3", false),
2089        ("1.2.* || 2.*", "1.2.3", false),
2090        ("2", "2.1.2", false),
2091        ("2.3", "2.3.1", false),
2092        ("~2.4", "2.4.0", false),
2093        ("~2.4", "2.4.5", false),
2094        ("~>3.2.1", "3.2.2", false),
2095        ("~1", "1.2.3", false),
2096        ("~>1", "1.2.3", false),
2097        ("~> 1", "1.2.3", false),
2098        ("~1.0", "1.0.2", false),
2099        ("~ 1.0", "1.0.2", false),
2100        (">=1", "1.0.0", false),
2101        (">= 1", "1.0.0", false),
2102        ("<1.2", "1.1.1", false),
2103        ("< 1.2", "1.1.1", false),
2104        ("~v0.5.4-pre", "0.5.5", false),
2105        ("~v0.5.4-pre", "0.5.4", false),
2106        ("=0.7.x", "0.7.2", false),
2107        (">=0.7.x", "0.7.2", false),
2108        ("<=0.7.x", "0.6.2", false),
2109        (">0.2.3 >0.2.4 <=0.2.5", "0.2.5", false),
2110        (">=0.2.3 <=0.2.4", "0.2.4", false),
2111        ("1.0.0 - 2.0.0", "2.0.0", false),
2112        ("^3.0.0", "4.0.0", false),
2113        ("^1.0.0 || ~2.0.1", "2.0.0", false),
2114        ("^0.1.0 || ~3.0.1 || 5.0.0", "3.2.0", false),
2115        ("^0.1.0 || ~3.0.1 || 5.0.0", "1.0.0beta", false),
2116        ("^0.1.0 || ~3.0.1 || 5.0.0", "5.0.0-0", false),
2117        ("^0.1.0 || ~3.0.1 || >4 <=5.0.0", "3.5.0", false),
2118        ("^1.0.0alpha", "1.0.0beta", false),
2119        ("~1.0.0alpha", "1.0.0beta", false),
2120        ("^1.0.0-alpha", "1.0.0beta", false),
2121        ("~1.0.0-alpha", "1.0.0beta", false),
2122        ("^1.0.0-alpha", "1.0.0-beta", false),
2123        ("~1.0.0-alpha", "1.0.0-beta", false),
2124        ("=0.1.0", "1.0.0", false),
2125        (">1.2.3", "1.3.0-alpha", true),
2126    ];
2127
2128    fn assert_outside(
2129        cases: &[(&str, &str, bool)],
2130        direction: OutsideDirection,
2131        include_prerelease: bool,
2132        expected: bool,
2133    ) {
2134        for (range, version, explicit_include) in cases {
2135            let include_prerelease = include_prerelease || *explicit_include;
2136            let range = Range::parse(range).unwrap();
2137            let version = Version::parse(version).unwrap();
2138
2139            let result = range
2140                .outside(&version, direction, include_prerelease)
2141                .expect("outside should always have comparator bounds");
2142            let message = format!(
2143                "{}outside({}, {}, {}, include_prerelease={})",
2144                if expected { "" } else { "!" },
2145                version,
2146                range,
2147                direction,
2148                include_prerelease
2149            );
2150
2151            if expected {
2152                assert!(result, "{}", message);
2153            } else {
2154                assert!(!result, "{}", message);
2155            }
2156        }
2157    }
2158
2159    #[test]
2160    fn greater_than_range() {
2161        assert_outside(VERSION_GT_RANGE, OutsideDirection::Higher, false, true);
2162    }
2163
2164    #[test]
2165    fn less_than_range() {
2166        assert_outside(VERSION_LT_RANGE, OutsideDirection::Lower, false, true);
2167    }
2168
2169    #[test]
2170    fn not_greater_than_range() {
2171        assert_outside(VERSION_NOT_GT_RANGE, OutsideDirection::Higher, false, false);
2172    }
2173
2174    #[test]
2175    fn not_less_than_range() {
2176        assert_outside(VERSION_NOT_LT_RANGE, OutsideDirection::Lower, false, false);
2177    }
2178
2179    #[test]
2180    fn outside_with_bad_direction_returns_error() {
2181        let range = Range::parse(">1.5.0").unwrap();
2182        let version = Version::parse("1.2.3").unwrap();
2183
2184        let result = OutsideDirection::try_from('x')
2185            .and_then(|direction| range.outside(&version, direction, false));
2186
2187        assert!(matches!(
2188            result,
2189            Err(RangeError::InvalidOutsideDirection('x'))
2190        ));
2191    }
2192}
2193
2194#[cfg(test)]
2195mod satisfies_ranges_tests {
2196    use super::*;
2197
2198    macro_rules! refute {
2199        ($e:expr) => {
2200            assert!(!$e)
2201        };
2202        ($e:expr, $msg:expr) => {
2203            assert!(!$e, $msg)
2204        };
2205    }
2206
2207    #[test]
2208    fn greater_than_equals() {
2209        let parsed = Range::parse(">=1.2.3").expect("unable to parse");
2210
2211        refute!(parsed.satisfies(&(0, 2, 3).into()), "major too low");
2212        refute!(parsed.satisfies(&(1, 1, 3).into()), "minor too low");
2213        refute!(parsed.satisfies(&(1, 2, 2).into()), "patch too low");
2214        assert!(parsed.satisfies(&(1, 2, 3).into()), "exact");
2215        assert!(parsed.satisfies(&(2, 2, 3).into()), "above");
2216    }
2217
2218    #[test]
2219    fn greater_than() {
2220        let parsed = Range::parse(">1.2.3").expect("unable to parse");
2221
2222        refute!(parsed.satisfies(&(0, 2, 3).into()), "major too low");
2223        refute!(parsed.satisfies(&(1, 1, 3).into()), "minor too low");
2224        refute!(parsed.satisfies(&(1, 2, 2).into()), "patch too low");
2225        refute!(parsed.satisfies(&(1, 2, 3).into()), "exact");
2226        assert!(parsed.satisfies(&(1, 2, 4).into()), "above");
2227    }
2228
2229    #[test]
2230    fn exact() {
2231        let parsed = Range::parse("=1.2.3").expect("unable to parse");
2232
2233        refute!(parsed.satisfies(&(1, 2, 2).into()), "patch too low");
2234        assert!(parsed.satisfies(&(1, 2, 3).into()), "exact");
2235        refute!(parsed.satisfies(&(1, 2, 4).into()), "above");
2236    }
2237
2238    #[test]
2239    fn less_than() {
2240        let parsed = Range::parse("<1.2.3").expect("unable to parse");
2241
2242        assert!(parsed.satisfies(&(0, 2, 3).into()), "major below");
2243        assert!(parsed.satisfies(&(1, 1, 3).into()), "minor below");
2244        assert!(parsed.satisfies(&(1, 2, 2).into()), "patch below");
2245        refute!(parsed.satisfies(&(1, 2, 3).into()), "exact");
2246        refute!(parsed.satisfies(&(1, 2, 4).into()), "above");
2247    }
2248
2249    #[test]
2250    fn less_than_equals() {
2251        let parsed = Range::parse("<=1.2.3").expect("unable to parse");
2252
2253        assert!(parsed.satisfies(&(0, 2, 3).into()), "major below");
2254        assert!(parsed.satisfies(&(1, 1, 3).into()), "minor below");
2255        assert!(parsed.satisfies(&(1, 2, 2).into()), "patch below");
2256        assert!(parsed.satisfies(&(1, 2, 3).into()), "exact");
2257        refute!(parsed.satisfies(&(1, 2, 4).into()), "above");
2258    }
2259
2260    #[test]
2261    fn less_than_equals_major() {
2262        let parsed = Range::parse("<=1").expect("unable to parse");
2263
2264        assert!(parsed.satisfies(&(0, 2, 3).into()), "major below");
2265        assert!(parsed.satisfies(&(1, 1, 3).into()), "minor below");
2266        assert!(parsed.satisfies(&(1, 2, 2).into()), "minor below");
2267        assert!(parsed.satisfies(&(1, 2, 3).into()), "minor below");
2268        assert!(parsed.satisfies(&(1, 2, 4).into()), "minor below");
2269        refute!(parsed.satisfies(&(2, 0, 0).into()), "above");
2270    }
2271
2272    #[test]
2273    fn less_than_equals_minor() {
2274        let parsed = Range::parse("<=1.2").expect("unable to parse");
2275
2276        assert!(parsed.satisfies(&(0, 2, 3).into()), "major below");
2277        assert!(parsed.satisfies(&(1, 1, 3).into()), "minor below");
2278        assert!(parsed.satisfies(&(1, 2, 1).into()), "patch below");
2279        assert!(parsed.satisfies(&(1, 2, 5).into()), "patch below");
2280        refute!(parsed.satisfies(&(1, 3, 0).into()), "above");
2281    }
2282
2283    #[test]
2284    fn only_major() {
2285        let parsed = Range::parse("1").expect("unable to parse");
2286
2287        refute!(parsed.satisfies(&(0, 2, 3).into()), "major below");
2288        assert!(parsed.satisfies(&(1, 0, 0).into()), "exact bottom of range");
2289        assert!(parsed.satisfies(&(1, 2, 2).into()), "middle");
2290        refute!(parsed.satisfies(&(2, 0, 0).into()), "exact top of range");
2291        refute!(parsed.satisfies(&(2, 7, 3).into()), "above");
2292    }
2293
2294    #[test]
2295    fn pre_release_version() {
2296        let range = Range::parse("^2").unwrap();
2297
2298        refute!(
2299            range.satisfies(&Version::parse("2.0.0-alpha.0").unwrap()),
2300            "below"
2301        );
2302        refute!(
2303            range.satisfies(&Version::parse("2.1.0-alpha.0").unwrap()),
2304            "above but pre-release"
2305        );
2306    }
2307
2308    #[test]
2309    fn pre_release_range() {
2310        let range = Range::parse("^1.2.3-rc.4").unwrap();
2311
2312        refute!(range.satisfies(&Version::parse("1.2.2").unwrap()), "below");
2313        assert!(
2314            range.satisfies(&Version::parse("1.2.3").unwrap()),
2315            "equal non-prerelease"
2316        );
2317        assert!(range.satisfies(&Version::parse("1.2.4").unwrap()), "above");
2318    }
2319
2320    #[test]
2321    fn pre_release_version_and_range() {
2322        let range = Range::parse("^1.2.3-rc.4").unwrap();
2323
2324        refute!(
2325            range.satisfies(&Version::parse("1.2.3-rc.3").unwrap()),
2326            "below"
2327        );
2328        assert!(
2329            range.satisfies(&Version::parse("1.2.3-rc.4").unwrap()),
2330            "equal"
2331        );
2332        assert!(
2333            range.satisfies(&Version::parse("1.2.3-rc.5").unwrap()),
2334            "above"
2335        );
2336        refute!(
2337            range.satisfies(&Version::parse("1.2.4-rc.6").unwrap()),
2338            "above patch but pre-release"
2339        );
2340    }
2341
2342    #[test]
2343    fn npm_compatibility_cases() {
2344        let cases = [
2345            ("3.4.5", ">=3.3.0-beta.1 <3.4.0-beta.3", false),
2346            ("1.0.0", "1.0.x", true),
2347            ("1.2.3", "1.x.x", true),
2348            ("1.2.3", "x.x.x", true),
2349            ("1.0.1", "1.0.0 - 1.0.x", true),
2350            ("2.0.0", "1.0.0 - 1.x", false),
2351            ("1.2.3", "^1 || ^2", true),
2352            ("2.0.0-beta.1", "^1 || ^2", false),
2353        ];
2354
2355        for (version, range, expected) in cases {
2356            let version = Version::parse(version).unwrap();
2357            let range = Range::parse(range).unwrap();
2358
2359            assert_eq!(
2360                range.satisfies(&version),
2361                expected,
2362                "expected satisfies({}, {}) to be {}",
2363                version,
2364                range,
2365                expected
2366            );
2367        }
2368    }
2369}
2370
2371/// https://github.com/npm/node-semver/blob/master/test/fixtures/range-parse.js
2372#[cfg(test)]
2373mod tests {
2374    use super::*;
2375
2376    use pretty_assertions::assert_eq;
2377
2378    macro_rules! range_parse_tests {
2379        ($($name:ident => $vals:expr),+ ,$(,)?) => {
2380            $(
2381                #[test]
2382                fn $name() {
2383                    let [input, expected] = $vals;
2384
2385                    let parsed = Range::parse(input).expect("unable to parse");
2386
2387                    assert_eq!(expected, parsed.to_string());
2388                }
2389            )+
2390        }
2391
2392    }
2393
2394    range_parse_tests![
2395        //       [input,   parsed and then `to_string`ed]
2396        exact => ["1.0.0", "1.0.0"],
2397        major_minor_patch_range => ["1.0.0 - 2.0.0", ">=1.0.0 <=2.0.0"],
2398        only_major_versions =>  ["1 - 2", ">=1.0.0 <3.0.0-0"],
2399        only_major_and_minor => ["1.0 - 2.0", ">=1.0.0 <2.1.0-0"],
2400        mixed_major_minor => ["1.2 - 3.4.5", ">=1.2.0 <=3.4.5"],
2401        mixed_major_minor_2 => ["1.2.3 - 3.4", ">=1.2.3 <3.5.0-0"],
2402        minor_minor_range => ["1.2 - 3.4", ">=1.2.0 <3.5.0-0"],
2403        single_sided_only_major => ["1", ">=1.0.0 <2.0.0-0"],
2404        single_sided_lower_equals_bound =>  [">=1.0.0", ">=1.0.0"],
2405        single_sided_lower_equals_bound_2 => [">=0.1.97", ">=0.1.97"],
2406        single_sided_lower_bound => [">1.0.0", ">1.0.0"],
2407        single_sided_upper_equals_bound => ["<=2.0.0", "<=2.0.0"],
2408        single_sided_upper_equals_bound_with_minor => ["<=2.0", "<=2.0.900719925474099"],
2409        single_sided_upper_bound => ["<2.0.0", "<2.0.0"],
2410        major_and_minor => ["2.3", ">=2.3.0 <2.4.0-0"],
2411        major_dot_x => ["2.x", ">=2.0.0 <3.0.0-0"],
2412        x_and_asterisk_version => ["2.x.x", ">=2.0.0 <3.0.0-0"],
2413        patch_x => ["1.2.x", ">=1.2.0 <1.3.0-0"],
2414        minor_asterisk_patch_asterisk => ["2.*.*", ">=2.0.0 <3.0.0-0"],
2415        patch_asterisk => ["1.2.*", ">=1.2.0 <1.3.0-0"],
2416        caret_zero => ["^0", "<1.0.0-0"],
2417        caret_zero_minor => ["^0.1", ">=0.1.0 <0.2.0-0"],
2418        caret_one => ["^1.0", ">=1.0.0 <2.0.0-0"],
2419        caret_minor => ["^1.2", ">=1.2.0 <2.0.0-0"],
2420        caret_patch => ["^0.0.1", ">=0.0.1 <0.0.2-0"],
2421        caret_with_patch =>   ["^0.1.2", ">=0.1.2 <0.2.0-0"],
2422        caret_with_patch_2 => ["^1.2.3", ">=1.2.3 <2.0.0-0"],
2423        tilde_one => ["~1", ">=1.0.0 <2.0.0-0"],
2424        tilde_minor => ["~1.0", ">=1.0.0 <1.1.0-0"],
2425        tilde_minor_2 => ["~2.4", ">=2.4.0 <2.5.0-0"],
2426        tilde_with_greater_than_patch => ["~>3.2.1", ">=3.2.1 <3.3.0-0"],
2427        tilde_major_minor_zero => ["~1.1.0", ">=1.1.0 <1.2.0-0"],
2428        grater_than_equals_one => [">=1", ">=1.0.0"],
2429        greater_than_one => [">1", ">=2.0.0"],
2430        less_than_one_dot_two => ["<1.2", "<1.2.0-0"],
2431        greater_than_one_dot_two => [">1.2", ">=1.3.0"],
2432        greater_than_with_prerelease => [">1.1.0-beta-10", ">1.1.0-beta-10"],
2433        either_one_version_or_the_other => ["0.1.20 || 1.2.4", "0.1.20||1.2.4"],
2434        either_one_version_range_or_another => [">=0.2.3 || <0.0.1", ">=0.2.3||<0.0.1"],
2435        either_x_version_works => ["1.2.x || 2.x", ">=1.2.0 <1.3.0-0||>=2.0.0 <3.0.0-0"],
2436        either_asterisk_version_works => ["1.2.* || 2.*", ">=1.2.0 <1.3.0-0||>=2.0.0 <3.0.0-0"],
2437        one_two_three_or_greater_than_four => ["1.2.3 || >4", "1.2.3||>=5.0.0"],
2438        any_version_asterisk => ["*", ">=0.0.0"],
2439        any_version_x => ["x", ">=0.0.0"],
2440        any_version_upper_x => ["X", ">=0.0.0"],
2441        greater_than_equals_x => [">=x", ">=0.0.0"],
2442        whitespace_1 => [">= 1.0.0", ">=1.0.0"],
2443        whitespace_2 => [">=  1.0.0", ">=1.0.0"],
2444        whitespace_3 => [">=   1.0.0", ">=1.0.0"],
2445        whitespace_4 => ["> 1.0.0", ">1.0.0"],
2446        whitespace_5 => [">  1.0.0", ">1.0.0"],
2447        whitespace_6 => ["<=   2.0.0", "<=2.0.0"],
2448        whitespace_7 => ["<= 2.0.0", "<=2.0.0"],
2449        whitespace_8 => ["<=  2.0.0", "<=2.0.0"],
2450        whitespace_9 => ["<    2.0.0", "<2.0.0"],
2451        whitespace_10 => ["<\t2.0.0", "<2.0.0"],
2452        whitespace_11 => ["^ 1", ">=1.0.0 <2.0.0-0"],
2453        whitespace_12 => ["~> 1", ">=1.0.0 <2.0.0-0"],
2454        whitespace_13 => ["~ 1.0", ">=1.0.0 <1.1.0-0"],
2455        beta          => ["^0.0.1-beta", ">=0.0.1-beta <0.0.2-0"],
2456        beta_tilde => ["~1.2.3-beta", ">=1.2.3-beta <1.3.0-0"],
2457        beta_4        => ["^1.2.3-beta.4", ">=1.2.3-beta.4 <2.0.0-0"],
2458        pre_release_on_both => ["1.0.0-alpha - 2.0.0-beta", ">=1.0.0-alpha <=2.0.0-beta"],
2459        single_sided_lower_bound_with_pre_release => [">1.0.0-alpha", ">1.0.0-alpha"],
2460        space_separated1 => [">=1.2.3 <4.5.6", ">=1.2.3 <4.5.6"],
2461        garbage1 => ["1.2.3 foo", "1.2.3"],
2462        garbage2 => ["foo 1.2.3", "1.2.3"],
2463        garbage3 => ["~1.y 1.2.3", "1.2.3"],
2464        garbage4 => ["1.2.3 ~1.y", "1.2.3"],
2465        loose1 => [">01.02.03", ">1.2.3"],
2466        loose2 => ["~1.2.3beta", ">=1.2.3-beta <1.3.0-0"],
2467        caret_weird => ["^ 1.2 ^ 1", ">=1.2.0 <2.0.0-0"],
2468        loose_eq1 => ["=0.7", ">=0.7.0 <0.8.0-0"],
2469        loose_eq2 => ["=1", ">=1.0.0 <2.0.0-0"],
2470        consistent => ["^1.0.1", ">=1.0.1 <2.0.0-0"],
2471        consistent2 => [">=1.0.1 <2.0.0-0", ">=1.0.1 <2.0.0-0"],
2472    ];
2473
2474    #[test]
2475    fn rejects_single_token_garbage_and_protocols() {
2476        for input in [
2477            "foo",
2478            "workspace:*",
2479            "npm:react-dom@19.3.0-canary-b1786c31-20260618",
2480        ] {
2481            assert_eq!(
2482                Range::parse(input).unwrap_err().kind(),
2483                &SemverErrorKind::NoValidRanges
2484            );
2485        }
2486
2487        assert_eq!(Range::parse("foo 1.2.3").unwrap().to_string(), "1.2.3");
2488    }
2489
2490    /*
2491    // And these weirdos that I don't know what to do with.
2492    [">X", "<0.0.0-0"],
2493    ["<X", "<0.0.0-0"],
2494    ["<x <* || >* 2.x", "<0.0.0-0"],
2495    */
2496}
2497
2498#[cfg(test)]
2499mod ranges {
2500    use super::*;
2501
2502    #[test]
2503    fn one() {
2504        let r = BoundSet::new(
2505            Bound::Lower(Predicate::Including((1, 2, 0).into())),
2506            Bound::Upper(Predicate::Excluding((3, 3, 4).into())),
2507        )
2508        .unwrap();
2509
2510        assert_eq!(r.to_string(), ">=1.2.0 <3.3.4")
2511    }
2512}
2513
2514#[cfg(test)]
2515mod max_satisfying {
2516    use super::*;
2517
2518    fn assert_max_satisfying(versions: Vec<&str>, range: &str, expected: &str) {
2519        let versions: Vec<_> = versions
2520            .into_iter()
2521            .map(|s| Version::parse(s).unwrap())
2522            .collect();
2523        let range = Range::parse(range).unwrap();
2524        let result = range.max_satisfying(&versions);
2525
2526        assert_eq!(
2527            result,
2528            Some(&Version::parse(expected).unwrap()),
2529            "expected: {}, got: {:?}",
2530            expected,
2531            result
2532        );
2533    }
2534
2535    #[test]
2536    fn test_max_satisfying() {
2537        let cases = vec![
2538            (vec!["1.2.3", "1.2.4"], "1.2", "1.2.4"),
2539            (vec!["1.2.4", "1.2.3"], "1.2", "1.2.4"),
2540            (vec!["1.2.3", "1.2.4", "1.2.5", "1.2.6"], "~1.2.3", "1.2.6"),
2541            (
2542                vec!["1.1.0", "1.2.0", "1.2.1", "1.3.0", "2.0.0", "2.1.0"],
2543                "~2.0.0",
2544                "2.0.0",
2545            ),
2546        ];
2547
2548        for case in cases {
2549            assert_max_satisfying(case.0, case.1, case.2);
2550        }
2551    }
2552
2553    #[test]
2554    fn test_max_satisfying_empty() {
2555        let range = Range::parse("~1.2.3").unwrap();
2556        let versions = vec![];
2557        let result = range.max_satisfying(&versions);
2558
2559        assert_eq!(result, None);
2560    }
2561
2562    #[test]
2563    fn test_max_satisfying_none() {
2564        let range = Range::parse(">=1.0.0 <2.0.0").unwrap();
2565        let versions: Vec<_> = vec!["2.0.0", "0.1.0"]
2566            .iter()
2567            .map(|s| Version::parse(s).unwrap())
2568            .collect();
2569        let result = range.max_satisfying(&versions);
2570
2571        assert_eq!(result, None);
2572    }
2573}
2574
2575#[cfg(test)]
2576mod min_satisfying {
2577    use super::*;
2578
2579    fn assert_min_satisfying(versions: Vec<&str>, range: &str, expected: &str) {
2580        let versions: Vec<_> = versions
2581            .into_iter()
2582            .map(|s| Version::parse(s).unwrap())
2583            .collect();
2584        let range = Range::parse(range).unwrap();
2585        let result = range.min_satisfying(&versions);
2586
2587        assert_eq!(
2588            result,
2589            Some(&Version::parse(expected).unwrap()),
2590            "expected: {}, got: {:?}",
2591            expected,
2592            result
2593        );
2594    }
2595
2596    #[test]
2597    fn test_min_satisfying() {
2598        let cases = vec![
2599            (vec!["1.2.3", "1.2.4"], "1.2", "1.2.3"),
2600            (vec!["1.2.4", "1.2.3"], "1.2", "1.2.3"),
2601            (vec!["1.2.3", "1.2.4", "1.2.5", "1.2.6"], "~1.2.3", "1.2.3"),
2602            (
2603                vec!["1.1.0", "1.2.0", "1.2.1", "1.3.0", "2.0.0", "2.1.0"],
2604                "~2.0.0",
2605                "2.0.0",
2606            ),
2607        ];
2608
2609        for case in cases {
2610            assert_min_satisfying(case.0, case.1, case.2);
2611        }
2612    }
2613
2614    #[test]
2615    fn test_min_satisfying_empty() {
2616        let range = Range::parse("~1.2.3").unwrap();
2617        let versions = vec![];
2618        let result = range.min_satisfying(&versions);
2619
2620        assert_eq!(result, None);
2621    }
2622
2623    #[test]
2624    fn test_min_satisfying_none() {
2625        let range = Range::parse(">=1.0.0 <2.0.0").unwrap();
2626        let versions: Vec<_> = vec!["2.0.0", "0.1.0"]
2627            .iter()
2628            .map(|s| Version::parse(s).unwrap())
2629            .collect();
2630        let result = range.min_satisfying(&versions);
2631
2632        assert_eq!(result, None);
2633    }
2634}
2635
2636#[cfg(test)]
2637mod min_version {
2638    use super::*;
2639
2640    #[test]
2641    fn min_version_test() {
2642        // [range, minimum]
2643        let tests = vec![
2644            // Stars
2645            ("*", Some("0.0.0")),
2646            ("* || >=2", Some("0.0.0")),
2647            (">=2 || *", Some("0.0.0")),
2648            (">2 || *", Some("0.0.0")),
2649            // equal
2650            ("1.0.0", Some("1.0.0")),
2651            ("1.0", Some("1.0.0")),
2652            ("1.0.x", Some("1.0.0")),
2653            ("1.0.*", Some("1.0.0")),
2654            ("1", Some("1.0.0")),
2655            ("1.x.x", Some("1.0.0")),
2656            ("1.x.x", Some("1.0.0")),
2657            ("1.*.x", Some("1.0.0")),
2658            ("1.x.*", Some("1.0.0")),
2659            ("1.x", Some("1.0.0")),
2660            ("1.*", Some("1.0.0")),
2661            ("=1.0.0", Some("1.0.0")),
2662            // Tilde
2663            ("~1.1.1", Some("1.1.1")),
2664            ("~1.1.1-beta", Some("1.1.1-beta")),
2665            ("~1.1.1 || >=2", Some("1.1.1")),
2666            // Carot
2667            ("^1.1.1", Some("1.1.1")),
2668            ("^1.1.1-beta", Some("1.1.1-beta")),
2669            ("^1.1.1 || >=2", Some("1.1.1")),
2670            ("^2.16.2 ^2.16", Some("2.16.2")),
2671            // "-" operator
2672            ("1.1.1 - 1.8.0", Some("1.1.1")),
2673            ("1.1 - 1.8.0", Some("1.1.0")),
2674            // Less / less or equal
2675            ("<2", Some("0.0.0")),
2676            ("<0.0.0-beta", Some("0.0.0-0")),
2677            ("<0.0.1-beta", Some("0.0.0")),
2678            ("<2 || >4", Some("0.0.0")),
2679            (">4 || <2", Some("0.0.0")),
2680            ("<=2 || >=4", Some("0.0.0")),
2681            (">=4 || <=2", Some("0.0.0")),
2682            ("<0.0.0-beta >0.0.0-alpha", Some("0.0.0-alpha.0")),
2683            (">0.0.0-alpha <0.0.0-beta", Some("0.0.0-alpha.0")),
2684            // Greater than or equal
2685            (">=1.1.1 <2 || >=2.2.2 <3", Some("1.1.1")),
2686            (">=2.2.2 <3 || >=1.1.1 <2", Some("1.1.1")),
2687            // Greater than but not equal
2688            (">1.0.0", Some("1.0.1")),
2689            (">1.0.0-0", Some("1.0.0-0.0")),
2690            (">1.0.0-beta", Some("1.0.0-beta.0")),
2691            (">2 || >1.0.0", Some("1.0.1")),
2692            (">2 || >1.0.0-0", Some("1.0.0-0.0")),
2693            (">2 || >1.0.0-beta", Some("1.0.0-beta.0")),
2694        ];
2695
2696        for (range, version) in tests {
2697            let parsed_range = Range::parse(range).unwrap();
2698            let parsed_version = version.map(|v| Version::parse(v).unwrap());
2699            assert_eq!(
2700                parsed_range.min_version(),
2701                parsed_version,
2702                "expected min_version of {:?} to be {:?}",
2703                range,
2704                version
2705            );
2706        }
2707    }
2708}
2709
2710#[cfg(feature = "serde")]
2711#[cfg(test)]
2712mod serde_tests {
2713    use super::*;
2714
2715    #[test]
2716    fn test_serialize() {
2717        let range = Range::parse("~1.2.3").unwrap();
2718        let serialized = serde_json::to_string(&range).unwrap();
2719        let deserialized: Range = serde_json::from_str(&serialized).unwrap();
2720
2721        assert_eq!(range, deserialized);
2722    }
2723}