Skip to main content

nodejs_semver/
range.rs

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