nodejs_semver/
range.rs

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