Skip to main content

node_semver_with_ord/
range.rs

1use std::cmp::{Ord, Ordering, PartialOrd};
2use std::fmt;
3
4use serde::{
5    de::{self, Deserialize, Deserializer, Visitor},
6    ser::{Serialize, Serializer},
7};
8
9use nom::branch::alt;
10use nom::bytes::complete::tag;
11use nom::character::complete::{anychar, space0, space1};
12use nom::combinator::{all_consuming, eof, map, map_res, opt, peek};
13use nom::error::context;
14use nom::multi::{many_till, separated_list0};
15use nom::sequence::{delimited, preceded, terminated, tuple};
16use nom::{Err, IResult};
17
18use crate::{extras, number, Identifier, SemverError, SemverErrorKind, SemverParseError, Version};
19
20#[derive(Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)]
21struct BoundSet {
22    upper: Bound,
23    lower: Bound,
24}
25
26impl BoundSet {
27    fn new(lower: Bound, upper: Bound) -> Option<Self> {
28        use Bound::*;
29        use Predicate::*;
30
31        match (lower, upper) {
32            (Lower(Excluding(v1)), Upper(Including(v2)))
33            | (Lower(Including(v1)), Upper(Excluding(v2)))
34                if v1 == v2 =>
35            {
36                None
37            }
38            (Lower(Including(v1)), Upper(Including(v2))) if v1 == v2 => Some(Self {
39                lower: Lower(Including(v1)),
40                upper: Upper(Including(v2)),
41            }),
42            (lower, upper) if lower < upper => Some(Self { lower, upper }),
43            _ => None,
44        }
45    }
46
47    fn at_least(p: Predicate) -> Option<Self> {
48        BoundSet::new(Bound::Lower(p), Bound::upper())
49    }
50
51    fn at_most(p: Predicate) -> Option<Self> {
52        BoundSet::new(Bound::lower(), Bound::Upper(p))
53    }
54
55    fn exact(version: Version) -> Option<Self> {
56        BoundSet::new(
57            Bound::Lower(Predicate::Including(version.clone())),
58            Bound::Upper(Predicate::Including(version)),
59        )
60    }
61
62    fn satisfies(&self, version: &Version) -> bool {
63        use Bound::*;
64        use Predicate::*;
65
66        let lower_bound = match &self.lower {
67            Lower(Including(lower)) => lower <= version,
68            Lower(Excluding(lower)) => lower < version,
69            Lower(Unbounded) => true,
70            _ => unreachable!(
71                "There should not have been an upper bound: {:#?}",
72                self.lower
73            ),
74        };
75
76        let upper_bound = match &self.upper {
77            Upper(Including(upper)) => version <= upper,
78            Upper(Excluding(upper)) => version < upper,
79            Upper(Unbounded) => true,
80            _ => unreachable!(
81                "There should not have been an lower bound: {:#?}",
82                self.lower
83            ),
84        };
85
86        lower_bound && upper_bound
87    }
88
89    fn allows_all(&self, other: &BoundSet) -> bool {
90        self.lower <= other.lower && other.upper <= self.upper
91    }
92
93    fn allows_any(&self, other: &BoundSet) -> bool {
94        if other.upper < self.lower {
95            return false;
96        }
97
98        if self.upper < other.lower {
99            return false;
100        }
101
102        true
103    }
104
105    fn intersect(&self, other: &Self) -> Option<Self> {
106        let lower = std::cmp::max(&self.lower, &other.lower);
107        let upper = std::cmp::min(&self.upper, &other.upper);
108
109        BoundSet::new(lower.clone(), upper.clone())
110    }
111
112    fn difference(&self, other: &Self) -> Option<Vec<Self>> {
113        use Bound::*;
114
115        if let Some(overlap) = self.intersect(other) {
116            if &overlap == self {
117                return None;
118            }
119
120            if self.lower < overlap.lower && overlap.upper < self.upper {
121                return Some(vec![
122                    BoundSet::new(self.lower.clone(), Upper(overlap.lower.predicate().flip()))
123                        .unwrap(),
124                    BoundSet::new(Lower(overlap.upper.predicate().flip()), self.upper.clone())
125                        .unwrap(),
126                ]);
127            }
128
129            if self.lower < overlap.lower {
130                return BoundSet::new(self.lower.clone(), Upper(overlap.lower.predicate().flip()))
131                    .map(|f| vec![f]);
132            }
133
134            BoundSet::new(Lower(overlap.upper.predicate().flip()), self.upper.clone())
135                .map(|f| vec![f])
136        } else {
137            Some(vec![self.clone()])
138        }
139    }
140}
141
142impl fmt::Display for BoundSet {
143    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144        use Bound::*;
145        use Predicate::*;
146        match (&self.lower, &self.upper) {
147            (Lower(Unbounded), Upper(Unbounded)) => write!(f, "*"),
148            (Lower(Unbounded), Upper(Including(v))) => write!(f, "<={}", v),
149            (Lower(Unbounded), Upper(Excluding(v))) => write!(f, "<{}", v),
150            (Lower(Including(v)), Upper(Unbounded)) => write!(f, ">={}", v),
151            (Lower(Excluding(v)), Upper(Unbounded)) => write!(f, ">{}", v),
152            (Lower(Including(v)), Upper(Including(v2))) if v == v2 => write!(f, "{}", v),
153            (Lower(Including(v)), Upper(Including(v2))) => write!(f, ">={} <={}", v, v2),
154            (Lower(Including(v)), Upper(Excluding(v2))) => write!(f, ">={} <{}", v, v2),
155            (Lower(Excluding(v)), Upper(Including(v2))) => write!(f, ">{} <={}", v, v2),
156            (Lower(Excluding(v)), Upper(Excluding(v2))) => write!(f, ">{} <{}", v, v2),
157            _ => unreachable!("does not make sense"),
158        }
159    }
160}
161
162#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
163enum Operation {
164    Exact,
165    GreaterThan,
166    GreaterThanEquals,
167    LessThan,
168    LessThanEquals,
169}
170
171#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
172enum Predicate {
173    Excluding(Version), // < and >
174    Including(Version), // <= and >=
175    Unbounded,          // *
176}
177
178impl Predicate {
179    fn flip(&self) -> Self {
180        use Predicate::*;
181        match self {
182            Excluding(v) => Including(v.clone()),
183            Including(v) => Excluding(v.clone()),
184            Unbounded => Unbounded,
185        }
186    }
187}
188
189#[derive(Debug, Clone, Eq, PartialEq, Hash)]
190enum Bound {
191    Lower(Predicate),
192    Upper(Predicate),
193}
194
195impl Bound {
196    fn upper() -> Self {
197        Bound::Upper(Predicate::Unbounded)
198    }
199
200    fn lower() -> Self {
201        Bound::Lower(Predicate::Unbounded)
202    }
203
204    fn predicate(&self) -> Predicate {
205        use Bound::*;
206
207        match self {
208            Lower(p) => p.clone(),
209            Upper(p) => p.clone(),
210        }
211    }
212}
213
214impl Ord for Bound {
215    fn cmp(&self, other: &Self) -> Ordering {
216        use Bound::*;
217        use Predicate::*;
218
219        match (self, other) {
220            (Lower(Unbounded), Lower(Unbounded)) | (Upper(Unbounded), Upper(Unbounded)) => {
221                Ordering::Equal
222            }
223            (Upper(Unbounded), _) | (_, Lower(Unbounded)) => Ordering::Greater,
224            (Lower(Unbounded), _) | (_, Upper(Unbounded)) => Ordering::Less,
225
226            (Upper(Including(v1)), Upper(Including(v2)))
227            | (Upper(Including(v1)), Lower(Including(v2)))
228            | (Upper(Excluding(v1)), Upper(Excluding(v2)))
229            | (Upper(Excluding(v1)), Lower(Excluding(v2)))
230            | (Lower(Including(v1)), Upper(Including(v2)))
231            | (Lower(Including(v1)), Lower(Including(v2)))
232            | (Lower(Excluding(v1)), Lower(Excluding(v2))) => v1.cmp(v2),
233
234            (Lower(Excluding(v1)), Upper(Excluding(v2)))
235            | (Lower(Including(v1)), Upper(Excluding(v2))) => {
236                if v2 <= v1 {
237                    Ordering::Greater
238                } else {
239                    Ordering::Less
240                }
241            }
242            (Upper(Including(v1)), Upper(Excluding(v2)))
243            | (Upper(Including(v1)), Lower(Excluding(v2)))
244            | (Lower(Excluding(v1)), Upper(Including(v2))) => {
245                if v2 < v1 {
246                    Ordering::Greater
247                } else {
248                    Ordering::Less
249                }
250            }
251            (Lower(Excluding(v1)), Lower(Including(v2))) => {
252                if v1 < v2 {
253                    Ordering::Less
254                } else {
255                    Ordering::Greater
256                }
257            }
258            (Lower(Including(v1)), Lower(Excluding(v2)))
259            | (Upper(Excluding(v1)), Lower(Including(v2)))
260            | (Upper(Excluding(v1)), Upper(Including(v2))) => {
261                if v1 <= v2 {
262                    Ordering::Less
263                } else {
264                    Ordering::Greater
265                }
266            }
267        }
268    }
269}
270
271impl PartialOrd for Bound {
272    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
273        Some(self.cmp(other))
274    }
275}
276
277/**
278Node-style semver range.
279
280These ranges map mostly 1:1 to semver's except for some internal representation
281details that allow some more interesting set-level operations.
282
283For details on supported syntax, see https://github.com/npm/node-semver#advanced-range-syntax
284*/
285#[derive(Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)]
286pub struct Range(Vec<BoundSet>);
287
288impl fmt::Display for Operation {
289    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
290        use Operation::*;
291        match self {
292            Exact => write!(f, ""),
293            GreaterThan => write!(f, ">"),
294            GreaterThanEquals => write!(f, ">="),
295            LessThan => write!(f, "<"),
296            LessThanEquals => write!(f, "<="),
297        }
298    }
299}
300
301impl Range {
302    /**
303    Parse a range from a string.
304    */
305    pub fn parse<S: AsRef<str>>(input: S) -> Result<Self, SemverError> {
306        let input = input.as_ref();
307
308        match all_consuming(range_set)(input) {
309            Ok((_, range)) => Ok(range),
310            Err(err) => Err(match err {
311                Err::Error(e) | Err::Failure(e) => SemverError {
312                    input: input.into(),
313                    span: (e.input.as_ptr() as usize - input.as_ptr() as usize, 0).into(),
314                    kind: if let Some(kind) = e.kind {
315                        kind
316                    } else if let Some(ctx) = e.context {
317                        SemverErrorKind::Context(ctx)
318                    } else {
319                        SemverErrorKind::Other
320                    },
321                },
322                Err::Incomplete(_) => SemverError {
323                    input: input.into(),
324                    span: (input.len() - 1, 0).into(),
325                    kind: SemverErrorKind::IncompleteInput,
326                },
327            }),
328        }
329    }
330
331    /**
332    Creates a new range that matches any version.
333    */
334    pub fn any() -> Self {
335        Self(vec![BoundSet::new(Bound::lower(), Bound::upper()).unwrap()])
336    }
337
338    /**
339    Returns true if `version` is satisfied by this range.
340    */
341    pub fn satisfies(&self, version: &Version) -> bool {
342        for range in &self.0 {
343            if range.satisfies(version) {
344                return true;
345            }
346        }
347
348        false
349    }
350
351    /**
352    Returns true if `other` is a strict superset of this range.
353    */
354    pub fn allows_all(&self, other: &Range) -> bool {
355        for this in &self.0 {
356            for that in &other.0 {
357                if this.allows_all(that) {
358                    return true;
359                }
360            }
361        }
362
363        false
364    }
365
366    /**
367    Returns true if `other` has overlap with this range.
368    */
369    pub fn allows_any(&self, other: &Range) -> bool {
370        for this in &self.0 {
371            for that in &other.0 {
372                if this.allows_any(that) {
373                    return true;
374                }
375            }
376        }
377
378        false
379    }
380
381    /**
382    Returns a new range that is the set-intersection between this range and `other`.
383    */
384    pub fn intersect(&self, other: &Self) -> Option<Self> {
385        let mut sets = Vec::new();
386
387        for lefty in &self.0 {
388            for righty in &other.0 {
389                if let Some(set) = lefty.intersect(righty) {
390                    sets.push(set)
391                }
392            }
393        }
394
395        if sets.is_empty() {
396            None
397        } else {
398            Some(Self(sets))
399        }
400    }
401
402    /**
403    Returns a new range that is the set-difference between this range and `other`.
404    */
405    pub fn difference(&self, other: &Self) -> Option<Self> {
406        let mut predicates = Vec::new();
407
408        for lefty in &self.0 {
409            for righty in &other.0 {
410                if let Some(mut range) = lefty.difference(righty) {
411                    predicates.append(&mut range)
412                }
413            }
414        }
415
416        if predicates.is_empty() {
417            None
418        } else {
419            Some(Self(predicates))
420        }
421    }
422}
423
424impl fmt::Display for Range {
425    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
426        for (i, range) in self.0.iter().enumerate() {
427            if i > 0 {
428                write!(f, "||")?;
429            }
430            write!(f, "{}", range)?;
431        }
432        Ok(())
433    }
434}
435
436impl std::str::FromStr for Range {
437    type Err = SemverError;
438    fn from_str(s: &str) -> Result<Self, Self::Err> {
439        Range::parse(s)
440    }
441}
442
443impl Serialize for Range {
444    fn serialize<S>(&self, serializer: S) -> ::std::result::Result<S::Ok, S::Error>
445    where
446        S: Serializer,
447    {
448        // Serialize VersionReq as a string.
449        serializer.collect_str(self)
450    }
451}
452
453impl<'de> Deserialize<'de> for Range {
454    fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
455    where
456        D: Deserializer<'de>,
457    {
458        struct VersionReqVisitor;
459
460        /// Deserialize `VersionReq` from a string.
461        impl<'de> Visitor<'de> for VersionReqVisitor {
462            type Value = Range;
463
464            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
465                formatter.write_str("a SemVer version requirement as a string")
466            }
467
468            fn visit_str<E>(self, v: &str) -> ::std::result::Result<Self::Value, E>
469            where
470                E: de::Error,
471            {
472                Range::parse(v).map_err(de::Error::custom)
473            }
474        }
475
476        deserializer.deserialize_str(VersionReqVisitor)
477    }
478}
479
480// ---- Parser ----
481
482/*
483Grammar from https://github.com/npm/node-semver#range-grammar
484
485range-set  ::= range ( logical-or range ) *
486logical-or ::= ( ' ' ) * '||' ( ' ' ) *
487range      ::= hyphen | simple ( ' ' simple ) * | ''
488hyphen     ::= partial ' - ' partial
489simple     ::= primitive | partial | tilde | caret
490primitive  ::= ( '<' | '>' | '>=' | '<=' | '=' ) partial
491partial    ::= xr ( '.' xr ( '.' xr qualifier ? )? )?
492xr         ::= 'x' | 'X' | '*' | nr
493nr         ::= '0' | ['1'-'9'] ( ['0'-'9'] ) *
494tilde      ::= '~' partial
495caret      ::= '^' partial
496qualifier  ::= ( '-' pre )? ( '+' build )?
497pre        ::= parts
498build      ::= parts
499parts      ::= part ( '.' part ) *
500part       ::= nr | [-0-9A-Za-z]+
501
502
503Loose mode (all LHS are invalid in strict mode):
504* 01.02.03 -> 1.2.3
505* 1.2.3alpha -> 1.2.3-alpha
506* v 1.2.3 -> 1.2.3 (v1.2.3 is actually a valid "plain" version)
507* =1.2.3 -> 1.2.3 (already a valid range)
508* - 10 -> >=10.0.0 <11.0.0
509* 1.2.3 foo 4.5.6 -> 1.2.3 4.5.6
510* 1.2.3.4 -> invalid range
511* foo -> invalid range
512* 1.2beta4 -> invalid range
513
514TODO: add tests for all these
515*/
516
517// range-set ::= range ( logical-or range ) *
518fn range_set(input: &str) -> IResult<&str, Range, SemverParseError<&str>> {
519    map_res(bound_sets, |sets| {
520        if sets.is_empty() {
521            Err(SemverParseError {
522                input,
523                kind: Some(SemverErrorKind::NoValidRanges),
524                context: None,
525            })
526        } else {
527            Ok(Range(sets))
528        }
529    })(input)
530}
531
532// logical-or ::= ( ' ' ) * '||' ( ' ' ) *
533fn bound_sets(input: &str) -> IResult<&str, Vec<BoundSet>, SemverParseError<&str>> {
534    map(separated_list0(logical_or, range), |sets| {
535        sets.into_iter().flatten().collect()
536    })(input)
537}
538fn logical_or(input: &str) -> IResult<&str, (), SemverParseError<&str>> {
539    map(delimited(space0, tag("||"), space0), |_| ())(input)
540}
541
542fn range(input: &str) -> IResult<&str, Vec<BoundSet>, SemverParseError<&str>> {
543    // TODO: loose parsing means that `1.2.3 foo` translates to `1.2.3`, so we
544    // need to do some stuff here to filter out unwanted BoundSets.
545    map(separated_list0(space1, simple), |bs| {
546        bs.into_iter()
547            .flatten()
548            .fold(Vec::new(), |mut acc: Vec<BoundSet>, bs| {
549                if let Some(last) = acc.pop() {
550                    if let Some(bound) = last.intersect(&bs) {
551                        acc.push(bound);
552                    } else {
553                        acc.push(last);
554                        acc.push(bs);
555                    }
556                } else {
557                    acc.push(bs)
558                }
559                acc
560            })
561    })(input)
562}
563
564// simple ::= primitive | partial | tilde | caret | garbage
565fn simple(input: &str) -> IResult<&str, Option<BoundSet>, SemverParseError<&str>> {
566    alt((
567        terminated(hyphen, peek(alt((space1, tag("||"), eof)))),
568        terminated(primitive, peek(alt((space1, tag("||"), eof)))),
569        terminated(partial, peek(alt((space1, tag("||"), eof)))),
570        terminated(tilde, peek(alt((space1, tag("||"), eof)))),
571        terminated(caret, peek(alt((space1, tag("||"), eof)))),
572        garbage,
573    ))(input)
574}
575
576fn garbage(input: &str) -> IResult<&str, Option<BoundSet>, SemverParseError<&str>> {
577    map(
578        many_till(anychar, alt((peek(space1), peek(tag("||")), eof))),
579        |_| None,
580    )(input)
581}
582
583// primitive  ::= ( '<' | '>' | '>=' | '<=' | '=' ) partial
584fn primitive(input: &str) -> IResult<&str, Option<BoundSet>, SemverParseError<&str>> {
585    use Operation::*;
586    context(
587        "operation range (ex: >= 1.2.3)",
588        map(
589            tuple((operation, preceded(space0, partial_version))),
590            |parsed| match parsed {
591                (GreaterThanEquals, partial) => {
592                    BoundSet::at_least(Predicate::Including(partial.into()))
593                }
594                (
595                    GreaterThan,
596                    Partial {
597                        major: Some(major),
598                        minor: Some(minor),
599                        patch: None,
600                        ..
601                    },
602                ) => BoundSet::at_least(Predicate::Including((major, minor + 1, 0).into())),
603                (
604                    GreaterThan,
605                    Partial {
606                        major: Some(major),
607                        minor: None,
608                        patch: None,
609                        ..
610                    },
611                ) => BoundSet::at_least(Predicate::Including((major + 1, 0, 0).into())),
612                (GreaterThan, partial) => BoundSet::at_least(Predicate::Excluding(partial.into())),
613                (
614                    LessThan,
615                    Partial {
616                        major: Some(major),
617                        minor: Some(minor),
618                        patch: None,
619                        ..
620                    },
621                ) => BoundSet::at_most(Predicate::Excluding((major, minor, 0, 0).into())),
622                (
623                    LessThan,
624                    Partial {
625                        major,
626                        minor,
627                        patch,
628                        pre_release,
629                        build,
630                        ..
631                    },
632                ) => BoundSet::at_most(Predicate::Excluding(Version {
633                    major: major.unwrap_or(0),
634                    minor: minor.unwrap_or(0),
635                    patch: patch.unwrap_or(0),
636                    build,
637                    pre_release,
638                })),
639                (
640                    LessThanEquals,
641                    Partial {
642                        major,
643                        minor,
644                        patch: None,
645                        ..
646                    },
647                ) => BoundSet::at_most(Predicate::Including(
648                    (major.unwrap_or(0), minor.unwrap_or(0), 0, 0).into(),
649                )),
650                (LessThanEquals, partial) => {
651                    BoundSet::at_most(Predicate::Including(partial.into()))
652                }
653                (
654                    Exact,
655                    Partial {
656                        major,
657                        minor: Some(minor),
658                        patch,
659                        ..
660                    },
661                ) => BoundSet::exact((major.unwrap_or(0), minor, patch.unwrap_or(0)).into()),
662                _ => None,
663            },
664        ),
665    )(input)
666}
667
668fn operation(input: &str) -> IResult<&str, Operation, SemverParseError<&str>> {
669    use Operation::*;
670    alt((
671        map(tag(">="), |_| GreaterThanEquals),
672        map(tag(">"), |_| GreaterThan),
673        map(tag("="), |_| Exact),
674        map(tag("<="), |_| LessThanEquals),
675        map(tag("<"), |_| LessThan),
676    ))(input)
677}
678
679fn partial(input: &str) -> IResult<&str, Option<BoundSet>, SemverParseError<&str>> {
680    context(
681        "plain version range (ex: 1.2)",
682        map(partial_version, |partial| match partial {
683            Partial { major: None, .. } => {
684                BoundSet::at_least(Predicate::Including((0, 0, 0).into()))
685            }
686            Partial {
687                major: Some(major),
688                minor: None,
689                ..
690            } => BoundSet::new(
691                Bound::Lower(Predicate::Including((major, 0, 0).into())),
692                Bound::Upper(Predicate::Excluding(Version {
693                    major: major + 1,
694                    minor: 0,
695                    patch: 0,
696                    pre_release: vec![Identifier::Numeric(0)],
697                    build: vec![],
698                })),
699            ),
700            Partial {
701                major: Some(major),
702                minor: Some(minor),
703                patch: None,
704                ..
705            } => BoundSet::new(
706                Bound::Lower(Predicate::Including((major, minor, 0).into())),
707                Bound::Upper(Predicate::Excluding(Version {
708                    major,
709                    minor: minor + 1,
710                    patch: 0,
711                    pre_release: vec![Identifier::Numeric(0)],
712                    build: vec![],
713                })),
714            ),
715            partial => BoundSet::exact(partial.into()),
716        }),
717    )(input)
718}
719
720#[derive(Debug, Clone)]
721struct Partial {
722    major: Option<u64>,
723    minor: Option<u64>,
724    patch: Option<u64>,
725    pre_release: Vec<Identifier>,
726    build: Vec<Identifier>,
727}
728
729impl From<Partial> for Version {
730    fn from(partial: Partial) -> Self {
731        Version {
732            major: partial.major.unwrap_or(0),
733            minor: partial.minor.unwrap_or(0),
734            patch: partial.patch.unwrap_or(0),
735            pre_release: partial.pre_release,
736            build: partial.build,
737        }
738    }
739}
740
741// partial ::= xr ( '.' xr ( '.' xr qualifier ? )? )?
742// xr      ::= 'x' | 'X' | '*' | nr
743// nr      ::= '0' | ['1'-'9'] ( ['0'-'9'] ) *
744// NOTE: Loose mode means nr is actually just `['0'-'9']`.
745fn partial_version(input: &str) -> IResult<&str, Partial, SemverParseError<&str>> {
746    let (input, _) = opt(tag("v"))(input)?;
747    let (input, _) = space0(input)?;
748    let (input, major) = component(input)?;
749    let (input, minor) = opt(preceded(tag("."), component))(input)?;
750    let (input, patch) = opt(preceded(tag("."), component))(input)?;
751    let (input, (pre, build)) = if patch.is_some() {
752        extras(input)?
753    } else {
754        (input, (vec![], vec![]))
755    };
756    Ok((
757        input,
758        Partial {
759            major,
760            minor: minor.flatten(),
761            patch: patch.flatten(),
762            pre_release: pre,
763            build,
764        },
765    ))
766}
767
768fn component(input: &str) -> IResult<&str, Option<u64>, SemverParseError<&str>> {
769    alt((map(x_or_asterisk, |_| None), map(number, Some)))(input)
770}
771
772fn x_or_asterisk(input: &str) -> IResult<&str, (), SemverParseError<&str>> {
773    map(alt((tag("x"), tag("X"), tag("*"))), |_| ())(input)
774}
775
776fn tilde_gt(input: &str) -> IResult<&str, Option<&str>, SemverParseError<&str>> {
777    map(
778        tuple((tag("~"), space0, opt(tag(">")), space0)),
779        |(_, _, gt, _)| gt,
780    )(input)
781}
782
783fn tilde(input: &str) -> IResult<&str, Option<BoundSet>, SemverParseError<&str>> {
784    context(
785        "tilde version range (ex: ~1.2.3)",
786        map(tuple((tilde_gt, partial_version)), |parsed| match parsed {
787            (
788                Some(_gt),
789                Partial {
790                    major: Some(major),
791                    minor: None,
792                    patch: None,
793                    ..
794                },
795            ) => BoundSet::new(
796                Bound::Lower(Predicate::Including((major, 0, 0).into())),
797                Bound::Upper(Predicate::Excluding((major + 1, 0, 0, 0).into())),
798            ),
799            (
800                Some(_gt),
801                Partial {
802                    major: Some(major),
803                    minor: Some(minor),
804                    patch: Some(patch),
805                    pre_release,
806                    ..
807                },
808            ) => BoundSet::new(
809                Bound::Lower(Predicate::Including(Version {
810                    major,
811                    minor,
812                    patch,
813                    pre_release,
814                    build: vec![],
815                })),
816                Bound::Upper(Predicate::Excluding((major, minor + 1, 0, 0).into())),
817            ),
818            (
819                None,
820                Partial {
821                    major: Some(major),
822                    minor: Some(minor),
823                    patch: Some(patch),
824                    pre_release,
825                    ..
826                },
827            ) => BoundSet::new(
828                Bound::Lower(Predicate::Including(Version {
829                    major,
830                    minor,
831                    patch,
832                    pre_release,
833                    build: vec![],
834                })),
835                Bound::Upper(Predicate::Excluding((major, minor + 1, 0, 0).into())),
836            ),
837            (
838                None,
839                Partial {
840                    major: Some(major),
841                    minor: Some(minor),
842                    patch: None,
843                    ..
844                },
845            ) => BoundSet::new(
846                Bound::Lower(Predicate::Including((major, minor, 0).into())),
847                Bound::Upper(Predicate::Excluding((major, minor + 1, 0, 0).into())),
848            ),
849            (
850                None,
851                Partial {
852                    major: Some(major),
853                    minor: None,
854                    patch: None,
855                    ..
856                },
857            ) => BoundSet::new(
858                Bound::Lower(Predicate::Including((major, 0, 0).into())),
859                Bound::Upper(Predicate::Excluding((major + 1, 0, 0, 0).into())),
860            ),
861            _ => None,
862        }),
863    )(input)
864}
865
866fn caret(input: &str) -> IResult<&str, Option<BoundSet>, SemverParseError<&str>> {
867    context(
868        "caret version range (ex: ^1.2.3)",
869        map(
870            preceded(tuple((tag("^"), space0)), partial_version),
871            |parsed| match parsed {
872                Partial {
873                    major: Some(0),
874                    minor: None,
875                    patch: None,
876                    ..
877                } => BoundSet::at_most(Predicate::Excluding((1, 0, 0, 0).into())),
878                Partial {
879                    major: Some(0),
880                    minor: Some(minor),
881                    patch: None,
882                    ..
883                } => BoundSet::new(
884                    Bound::Lower(Predicate::Including((0, minor, 0).into())),
885                    Bound::Upper(Predicate::Excluding((0, minor + 1, 0, 0).into())),
886                ),
887                // TODO: can be compressed?
888                Partial {
889                    major: Some(major),
890                    minor: None,
891                    patch: None,
892                    ..
893                } => BoundSet::new(
894                    Bound::Lower(Predicate::Including((major, 0, 0).into())),
895                    Bound::Upper(Predicate::Excluding((major + 1, 0, 0, 0).into())),
896                ),
897                Partial {
898                    major: Some(major),
899                    minor: Some(minor),
900                    patch: None,
901                    ..
902                } => BoundSet::new(
903                    Bound::Lower(Predicate::Including((major, minor, 0).into())),
904                    Bound::Upper(Predicate::Excluding((major + 1, 0, 0, 0).into())),
905                ),
906                Partial {
907                    major: Some(major),
908                    minor: Some(minor),
909                    patch: Some(patch),
910                    pre_release,
911                    ..
912                } => BoundSet::new(
913                    Bound::Lower(Predicate::Including(Version {
914                        major,
915                        minor,
916                        patch,
917                        pre_release,
918                        build: vec![],
919                    })),
920                    Bound::Upper(Predicate::Excluding(match (major, minor, patch) {
921                        (0, 0, n) => Version::from((0, 0, n + 1, 0)),
922                        (0, n, _) => Version::from((0, n + 1, 0, 0)),
923                        (n, _, _) => Version::from((n + 1, 0, 0, 0)),
924                    })),
925                ),
926                _ => None,
927            },
928        ),
929    )(input)
930}
931
932// hyphen ::= ' - ' partial /* loose */ | partial ' - ' partial
933fn hyphen(input: &str) -> IResult<&str, Option<BoundSet>, SemverParseError<&str>> {
934    context("hyphenated version range (ex: 1.2 - 2)", |input| {
935        let (input, lower) = opt(partial_version)(input)?;
936        let (input, _) = space1(input)?;
937        let (input, _) = tag("-")(input)?;
938        let (input, _) = space1(input)?;
939        let (input, upper) = partial_version(input)?;
940        let upper = match upper {
941            Partial {
942                major: None,
943                minor: None,
944                patch: None,
945                ..
946            } => Predicate::Excluding(Version {
947                major: 0,
948                minor: 0,
949                patch: 0,
950                pre_release: vec![Identifier::Numeric(0)],
951                build: vec![],
952            }),
953            Partial {
954                major: Some(major),
955                minor: None,
956                patch: None,
957                ..
958            } => Predicate::Excluding(Version {
959                major: major + 1,
960                minor: 0,
961                patch: 0,
962                pre_release: vec![Identifier::Numeric(0)],
963                build: vec![],
964            }),
965            Partial {
966                major: Some(major),
967                minor: Some(minor),
968                patch: None,
969                ..
970            } => Predicate::Excluding(Version {
971                major,
972                minor: minor + 1,
973                patch: 0,
974                pre_release: vec![Identifier::Numeric(0)],
975                build: vec![],
976            }),
977            partial => Predicate::Including(partial.into()),
978        };
979        let bounds = if let Some(lower) = lower {
980            BoundSet::new(
981                Bound::Lower(Predicate::Including(lower.into())),
982                Bound::Upper(upper),
983            )
984        } else {
985            BoundSet::at_most(upper)
986        };
987        Ok((input, bounds))
988    })(input)
989}
990
991macro_rules! create_tests_for {
992    ($func:ident $($name:ident => $version_range:expr , { $x:ident => $allows:expr, $y:ident => $denies:expr$(,)? }),+ ,$(,)?) => {
993
994        #[cfg(test)]
995        mod $func {
996        use super::*;
997
998            $(
999                #[test]
1000                fn $name() {
1001                    let version_range = Range::parse($version_range).unwrap();
1002
1003                    let allows: Vec<Range> = $allows.iter().map(|v| Range::parse(v).unwrap()).collect();
1004                    for version in &allows {
1005                        assert!(version_range.$func(version), "should have allowed: {}", version);
1006                    }
1007
1008                    let ranges: Vec<Range> = $denies.iter().map(|v| Range::parse(v).unwrap()).collect();
1009                    for version in &ranges {
1010                        assert!(!version_range.$func(version), "should have denied: {}", version);
1011                    }
1012                }
1013            )+
1014        }
1015    }
1016}
1017
1018create_tests_for! {
1019    // The function we are testing:
1020    allows_all
1021
1022    greater_than_eq_123   => ">=1.2.3", {
1023        allows => [">=2.0.0", ">2", "2.0.0", "0.1 || 1.4", "1.2.3", "2 - 7", ">2.0.0"],
1024        denies => ["1.0.0", "<1.2", ">=1.2.2", "1 - 3", "0.1 || <1.2.0", ">1.0.0"],
1025    },
1026
1027    greater_than_123      => ">1.2.3", {
1028        allows => [">=2.0.0", ">2", "2.0.0", "0.1 || 1.4", ">2.0.0"],
1029        denies => ["1.0.0", "<1.2", ">=1.2.3", "1 - 3", "0.1 || <1.2.0", "<=3"],
1030    },
1031
1032    eq_123  => "1.2.3", {
1033        allows => ["1.2.3"],
1034        denies => ["1.0.0", "<1.2", "1.x", ">=1.2.2", "1 - 3", "0.1 || <1.2.0"],
1035    },
1036
1037    lt_123  => "<1.2.3", {
1038        allows => ["<=1.2.0", "<1", "1.0.0", "0.1 || 1.4"],
1039        denies => ["1 - 3", ">1", "2.0.0", "2.0 || >9", ">1.0.0"],
1040    },
1041
1042    lt_eq_123 => "<=1.2.3", {
1043        allows => ["<=1.2.0", "<1", "1.0.0", "0.1 || 1.4", "1.2.3"],
1044        denies => ["1 - 3", ">1.0.0", ">=1.0.0"],
1045    },
1046
1047    eq_123_or_gt_400  => "1.2.3 || >4", {
1048        allows => [ "1.2.3", ">4", "5.x", "5.2.x", ">=8.2.1", "2.0 || 5.6.7"],
1049        denies => ["<2", "1 - 7", "1.9.4 || 2 - 3"],
1050    },
1051
1052    between_two_and_eight => "2 - 8", {
1053        allows => [ "2.2.3", "4 - 5"],
1054        denies => ["1 - 4", "5 - 9", ">3", "<=5"],
1055    },
1056}
1057
1058create_tests_for! {
1059    // The function we are testing:
1060    allows_any
1061
1062    greater_than_eq_123   => ">=1.2.3", {
1063        allows => ["<=1.2.4", "3.0.0", "<2", ">=3", ">3.0.0"],
1064        denies => ["<=1.2.0", "1.0.0", "<1", "<=1.2"],
1065    },
1066
1067    greater_than_123   => ">1.2.3", {
1068        allows => ["<=1.2.4", "3.0.0", "<2", ">=3", ">3.0.0"],
1069        denies => ["<=1.2.3", "1.0.0", "<1", "<=1.2"],
1070    },
1071
1072    eq_123   => "1.2.3", {
1073        allows => ["1.2.3", "1 - 2"],
1074        denies => ["<1.2.3", "1.0.0", "<=1.2", ">4.5.6", ">5"],
1075    },
1076
1077    lt_eq_123  => "<=1.2.3", {
1078        allows => ["<=1.2.0", "<1.0.0", "1.0.0", ">1.0.0", ">=1.2.0"],
1079        denies => ["4.5.6", ">2.0.0", ">=2.0.0"],
1080    },
1081
1082    lt_123  => "<1.2.3", {
1083        allows => ["<=2.2.0", "<2.0.0", "1.0.0", ">1.0.0", ">=1.2.0"],
1084        denies => ["2.0.0", ">1.8.0", ">=1.8.0"],
1085    },
1086
1087    between_two_and_eight => "2 - 8", {
1088        allows => ["2.2.3", "4 - 10", ">4", ">4.0.0", "<=4.0.0", "<9.1.2"],
1089        denies => [">10", "10 - 11", "0 - 1"],
1090    },
1091
1092    eq_123_or_gt_400  => "1.2.3 || >4", {
1093        allows => [ "1.2.3", ">3", "5.x", "5.2.x", ">=8.2.1", "2 - 7", "2.0 || 5.6.7"],
1094        denies => [ "1.9.4 || 2 - 3"],
1095    },
1096}
1097
1098#[cfg(test)]
1099mod intersection {
1100    use super::*;
1101
1102    fn v(range: &'static str) -> Range {
1103        range.parse().unwrap()
1104    }
1105
1106    #[test]
1107    fn gt_eq_123() {
1108        let base_range = v(">=1.2.3");
1109
1110        let samples = vec![
1111            ("<=2.0.0", Some(">=1.2.3 <=2.0.0")),
1112            ("<2.0.0", Some(">=1.2.3 <2.0.0")),
1113            (">=2.0.0", Some(">=2.0.0")),
1114            (">2.0.0", Some(">2.0.0")),
1115            (">1.0.0", Some(">=1.2.3")),
1116            (">1.2.3", Some(">1.2.3")),
1117            ("<=1.2.3", Some("1.2.3")),
1118            ("2.0.0", Some("2.0.0")),
1119            ("1.1.1", None),
1120            ("<1.0.0", None),
1121        ];
1122
1123        assert_ranges_match(base_range, samples);
1124    }
1125
1126    #[test]
1127    fn gt_123() {
1128        let base_range = v(">1.2.3");
1129
1130        let samples = vec![
1131            ("<=2.0.0", Some(">1.2.3 <=2.0.0")),
1132            ("<2.0.0", Some(">1.2.3 <2.0.0")),
1133            (">=2.0.0", Some(">=2.0.0")),
1134            (">2.0.0", Some(">2.0.0")),
1135            ("2.0.0", Some("2.0.0")),
1136            (">1.2.3", Some(">1.2.3")),
1137            ("<=1.2.3", None),
1138            ("1.1.1", None),
1139            ("<1.0.0", None),
1140        ];
1141
1142        assert_ranges_match(base_range, samples);
1143    }
1144
1145    #[test]
1146    fn eq_123() {
1147        let base_range = v("1.2.3");
1148
1149        let samples = vec![
1150            ("<=2.0.0", Some("1.2.3")),
1151            ("<2.0.0", Some("1.2.3")),
1152            (">=2.0.0", None),
1153            (">2.0.0", None),
1154            ("2.0.0", None),
1155            ("1.2.3", Some("1.2.3")),
1156            (">1.2.3", None),
1157            ("<=1.2.3", Some("1.2.3")),
1158            ("1.1.1", None),
1159            ("<1.0.0", None),
1160        ];
1161
1162        assert_ranges_match(base_range, samples);
1163    }
1164
1165    #[test]
1166    fn lt_123() {
1167        let base_range = v("<1.2.3");
1168
1169        let samples = vec![
1170            ("<=2.0.0", Some("<1.2.3")),
1171            ("<2.0.0", Some("<1.2.3")),
1172            (">=2.0.0", None),
1173            (">=1.0.0", Some(">=1.0.0 <1.2.3")),
1174            (">2.0.0", None),
1175            ("2.0.0", None),
1176            ("1.2.3", None),
1177            (">1.2.3", None),
1178            ("<=1.2.3", Some("<1.2.3")),
1179            ("1.1.1", Some("1.1.1")),
1180            ("<1.0.0", Some("<1.0.0")),
1181        ];
1182
1183        assert_ranges_match(base_range, samples);
1184    }
1185
1186    #[test]
1187    fn lt_eq_123() {
1188        let base_range = v("<=1.2.3");
1189
1190        let samples = vec![
1191            ("<=2.0.0", Some("<=1.2.3")),
1192            ("<2.0.0", Some("<=1.2.3")),
1193            (">=2.0.0", None),
1194            (">=1.0.0", Some(">=1.0.0 <=1.2.3")),
1195            (">2.0.0", None),
1196            ("2.0.0", None),
1197            ("1.2.3", Some("1.2.3")),
1198            (">1.2.3", None),
1199            ("<=1.2.3", Some("<=1.2.3")),
1200            ("1.1.1", Some("1.1.1")),
1201            ("<1.0.0", Some("<1.0.0")),
1202        ];
1203
1204        assert_ranges_match(base_range, samples);
1205    }
1206
1207    #[test]
1208    fn multiple() {
1209        let base_range = v("<1 || 3 - 4");
1210
1211        let samples = vec![("0.5 - 3.5.0", Some(">=0.5.0 <1.0.0||>=3.0.0 <=3.5.0"))];
1212
1213        assert_ranges_match(base_range, samples);
1214    }
1215
1216    fn assert_ranges_match(base: Range, samples: Vec<(&'static str, Option<&'static str>)>) {
1217        for (other, expected) in samples {
1218            let other = v(other);
1219            let resulting_range = base.intersect(&other).map(|v| v.to_string());
1220            assert_eq!(
1221                resulting_range.clone(),
1222                expected.map(|e| e.to_string()),
1223                "{} ∩ {} := {}",
1224                base,
1225                other,
1226                resulting_range.unwrap_or_else(|| "⊗".into())
1227            );
1228        }
1229    }
1230}
1231
1232#[cfg(test)]
1233mod difference {
1234    use super::*;
1235
1236    fn v(range: &'static str) -> Range {
1237        range.parse().unwrap()
1238    }
1239
1240    #[test]
1241    fn gt_eq_123() {
1242        let base_range = v(">=1.2.3");
1243
1244        let samples = vec![
1245            ("<=2.0.0", Some(">2.0.0")),
1246            ("<2.0.0", Some(">=2.0.0")),
1247            (">=2.0.0", Some(">=1.2.3 <2.0.0")),
1248            (">2.0.0", Some(">=1.2.3 <=2.0.0")),
1249            (">1.0.0", None),
1250            (">1.2.3", Some("1.2.3")),
1251            ("<=1.2.3", Some(">1.2.3")),
1252            ("1.1.1", Some(">=1.2.3")),
1253            ("<1.0.0", Some(">=1.2.3")),
1254            ("2.0.0", Some(">=1.2.3 <2.0.0||>2.0.0")),
1255        ];
1256
1257        assert_ranges_match(base_range, samples);
1258    }
1259
1260    #[test]
1261    fn gt_123() {
1262        let base_range = v(">1.2.3");
1263
1264        let samples = vec![
1265            ("<=2.0.0", Some(">2.0.0")),
1266            ("<2.0.0", Some(">=2.0.0")),
1267            (">=2.0.0", Some(">1.2.3 <2.0.0")),
1268            (">2.0.0", Some(">1.2.3 <=2.0.0")),
1269            (">1.0.0", None),
1270            (">1.2.3", None),
1271            ("<=1.2.3", Some(">1.2.3")),
1272            ("1.1.1", Some(">1.2.3")),
1273            ("<1.0.0", Some(">1.2.3")),
1274            ("2.0.0", Some(">1.2.3 <2.0.0||>2.0.0")),
1275        ];
1276
1277        assert_ranges_match(base_range, samples);
1278    }
1279
1280    #[test]
1281    fn eq_123() {
1282        let base_range = v("1.2.3");
1283
1284        let samples = vec![
1285            ("<=2.0.0", None),
1286            ("<2.0.0", None),
1287            (">=2.0.0", Some("1.2.3")),
1288            (">2.0.0", Some("1.2.3")),
1289            (">1.0.0", None),
1290            (">1.2.3", Some("1.2.3")),
1291            ("1.2.3", None),
1292            ("<=1.2.3", None),
1293            ("1.1.1", Some("1.2.3")),
1294            ("<1.0.0", Some("1.2.3")),
1295            ("2.0.0", Some("1.2.3")),
1296        ];
1297
1298        assert_ranges_match(base_range, samples);
1299    }
1300
1301    #[test]
1302    fn lt_123() {
1303        let base_range = v("<1.2.3");
1304
1305        let samples = vec![
1306            ("<=2.0.0", None),
1307            ("<2.0.0", None),
1308            (">=2.0.0", Some("<1.2.3")),
1309            (">2.0.0", Some("<1.2.3")),
1310            (">1.0.0", Some("<=1.0.0")),
1311            (">1.2.3", Some("<1.2.3")),
1312            ("<=1.2.3", None),
1313            ("1.1.1", Some("<1.1.1||>1.1.1 <1.2.3")),
1314            ("<1.0.0", Some(">=1.0.0 <1.2.3")),
1315            ("2.0.0", Some("<1.2.3")),
1316        ];
1317
1318        assert_ranges_match(base_range, samples);
1319    }
1320
1321    #[test]
1322    fn lt_eq_123() {
1323        let base_range = v("<=1.2.3");
1324
1325        let samples = vec![
1326            ("<=2.0.0", None),
1327            ("<2.0.0", None),
1328            (">=2.0.0", Some("<=1.2.3")),
1329            (">2.0.0", Some("<=1.2.3")),
1330            (">1.0.0", Some("<=1.0.0")),
1331            (">1.2.3", Some("<=1.2.3")),
1332            ("<=1.2.3", None),
1333            ("1.1.1", Some("<1.1.1||>1.1.1 <=1.2.3")),
1334            ("<1.0.0", Some(">=1.0.0 <=1.2.3")),
1335            ("2.0.0", Some("<=1.2.3")),
1336        ];
1337
1338        assert_ranges_match(base_range, samples);
1339    }
1340
1341    #[test]
1342    fn multiple() {
1343        let base_range = v("<1 || 3 - 4");
1344
1345        let samples = vec![("0.5 - 3.5.0", Some("<0.5.0||>3.5.0 <5.0.0-0"))];
1346
1347        assert_ranges_match(base_range, samples);
1348    }
1349
1350    fn assert_ranges_match(base: Range, samples: Vec<(&'static str, Option<&'static str>)>) {
1351        for (other, expected) in samples {
1352            let other = v(other);
1353            let resulting_range = base.difference(&other).map(|v| v.to_string());
1354            assert_eq!(
1355                resulting_range.clone(),
1356                expected.map(|e| e.to_string()),
1357                "{} \\ {} := {}",
1358                base,
1359                other,
1360                resulting_range.unwrap_or_else(|| "⊗".into())
1361            );
1362        }
1363    }
1364}
1365
1366#[cfg(test)]
1367mod satisfies_ranges_tests {
1368    use super::*;
1369
1370    macro_rules! refute {
1371        ($e:expr) => {
1372            assert!(!$e)
1373        };
1374        ($e:expr, $msg:expr) => {
1375            assert!(!$e, $msg)
1376        };
1377    }
1378
1379    #[test]
1380    fn greater_than_equals() {
1381        let parsed = Range::parse(">=1.2.3").expect("unable to parse");
1382
1383        refute!(parsed.satisfies(&(0, 2, 3).into()), "major too low");
1384        refute!(parsed.satisfies(&(1, 1, 3).into()), "minor too low");
1385        refute!(parsed.satisfies(&(1, 2, 2).into()), "patch too low");
1386        assert!(parsed.satisfies(&(1, 2, 3).into()), "exact");
1387        assert!(parsed.satisfies(&(2, 2, 3).into()), "above");
1388    }
1389
1390    #[test]
1391    fn greater_than() {
1392        let parsed = Range::parse(">1.2.3").expect("unable to parse");
1393
1394        refute!(parsed.satisfies(&(0, 2, 3).into()), "major too low");
1395        refute!(parsed.satisfies(&(1, 1, 3).into()), "minor too low");
1396        refute!(parsed.satisfies(&(1, 2, 2).into()), "patch too low");
1397        refute!(parsed.satisfies(&(1, 2, 3).into()), "exact");
1398        assert!(parsed.satisfies(&(1, 2, 4).into()), "above");
1399    }
1400
1401    #[test]
1402    fn exact() {
1403        let parsed = Range::parse("=1.2.3").expect("unable to parse");
1404
1405        refute!(parsed.satisfies(&(1, 2, 2).into()), "patch too low");
1406        assert!(parsed.satisfies(&(1, 2, 3).into()), "exact");
1407        refute!(parsed.satisfies(&(1, 2, 4).into()), "above");
1408    }
1409
1410    #[test]
1411    fn less_than() {
1412        let parsed = Range::parse("<1.2.3").expect("unable to parse");
1413
1414        assert!(parsed.satisfies(&(0, 2, 3).into()), "major below");
1415        assert!(parsed.satisfies(&(1, 1, 3).into()), "minor below");
1416        assert!(parsed.satisfies(&(1, 2, 2).into()), "patch below");
1417        refute!(parsed.satisfies(&(1, 2, 3).into()), "exact");
1418        refute!(parsed.satisfies(&(1, 2, 4).into()), "above");
1419    }
1420
1421    #[test]
1422    fn less_than_equals() {
1423        let parsed = Range::parse("<=1.2.3").expect("unable to parse");
1424
1425        assert!(parsed.satisfies(&(0, 2, 3).into()), "major below");
1426        assert!(parsed.satisfies(&(1, 1, 3).into()), "minor below");
1427        assert!(parsed.satisfies(&(1, 2, 2).into()), "patch below");
1428        assert!(parsed.satisfies(&(1, 2, 3).into()), "exact");
1429        refute!(parsed.satisfies(&(1, 2, 4).into()), "above");
1430    }
1431
1432    #[test]
1433    fn only_major() {
1434        let parsed = Range::parse("1").expect("unable to parse");
1435
1436        refute!(parsed.satisfies(&(0, 2, 3).into()), "major below");
1437        assert!(parsed.satisfies(&(1, 0, 0).into()), "exact bottom of range");
1438        assert!(parsed.satisfies(&(1, 2, 2).into()), "middle");
1439        refute!(parsed.satisfies(&(2, 0, 0).into()), "exact top of range");
1440        refute!(parsed.satisfies(&(2, 7, 3).into()), "above");
1441    }
1442}
1443
1444/// https://github.com/npm/node-semver/blob/master/test/fixtures/range-parse.js
1445#[cfg(test)]
1446mod tests {
1447    use super::*;
1448    use serde_derive::{Deserialize, Serialize};
1449
1450    use pretty_assertions::assert_eq;
1451
1452    macro_rules! range_parse_tests {
1453        ($($name:ident => $vals:expr),+ ,$(,)?) => {
1454            $(
1455                #[test]
1456                fn $name() {
1457                    let [input, expected] = $vals;
1458
1459                    let parsed = Range::parse(input).expect("unable to parse");
1460
1461                    assert_eq!(expected, parsed.to_string());
1462                }
1463            )+
1464        }
1465
1466    }
1467
1468    range_parse_tests![
1469        //       [input,   parsed and then `to_string`ed]
1470        exact => ["1.0.0", "1.0.0"],
1471        major_minor_patch_range => ["1.0.0 - 2.0.0", ">=1.0.0 <=2.0.0"],
1472        only_major_versions =>  ["1 - 2", ">=1.0.0 <3.0.0-0"],
1473        only_major_and_minor => ["1.0 - 2.0", ">=1.0.0 <2.1.0-0"],
1474        mixed_major_minor => ["1.2 - 3.4.5", ">=1.2.0 <=3.4.5"],
1475        mixed_major_minor_2 => ["1.2.3 - 3.4", ">=1.2.3 <3.5.0-0"],
1476        minor_minor_range => ["1.2 - 3.4", ">=1.2.0 <3.5.0-0"],
1477        single_sided_only_major => ["1", ">=1.0.0 <2.0.0-0"],
1478        single_sided_lower_equals_bound =>  [">=1.0.0", ">=1.0.0"],
1479        single_sided_lower_equals_bound_2 => [">=0.1.97", ">=0.1.97"],
1480        single_sided_lower_bound => [">1.0.0", ">1.0.0"],
1481        single_sided_upper_equals_bound => ["<=2.0.0", "<=2.0.0"],
1482        single_sided_upper_equals_bound_with_minor => ["<=2.0", "<=2.0.0-0"],
1483        single_sided_upper_bound => ["<2.0.0", "<2.0.0"],
1484        major_and_minor => ["2.3", ">=2.3.0 <2.4.0-0"],
1485        major_dot_x => ["2.x", ">=2.0.0 <3.0.0-0"],
1486        x_and_asterisk_version => ["2.x.x", ">=2.0.0 <3.0.0-0"],
1487        patch_x => ["1.2.x", ">=1.2.0 <1.3.0-0"],
1488        minor_asterisk_patch_asterisk => ["2.*.*", ">=2.0.0 <3.0.0-0"],
1489        patch_asterisk => ["1.2.*", ">=1.2.0 <1.3.0-0"],
1490        caret_zero => ["^0", "<1.0.0-0"],
1491        caret_zero_minor => ["^0.1", ">=0.1.0 <0.2.0-0"],
1492        caret_one => ["^1.0", ">=1.0.0 <2.0.0-0"],
1493        caret_minor => ["^1.2", ">=1.2.0 <2.0.0-0"],
1494        caret_patch => ["^0.0.1", ">=0.0.1 <0.0.2-0"],
1495        caret_with_patch =>   ["^0.1.2", ">=0.1.2 <0.2.0-0"],
1496        caret_with_patch_2 => ["^1.2.3", ">=1.2.3 <2.0.0-0"],
1497        tilde_one => ["~1", ">=1.0.0 <2.0.0-0"],
1498        tilde_minor => ["~1.0", ">=1.0.0 <1.1.0-0"],
1499        tilde_minor_2 => ["~2.4", ">=2.4.0 <2.5.0-0"],
1500        tilde_with_greater_than_patch => ["~>3.2.1", ">=3.2.1 <3.3.0-0"],
1501        tilde_major_minor_zero => ["~1.1.0", ">=1.1.0 <1.2.0-0"],
1502        grater_than_equals_one => [">=1", ">=1.0.0"],
1503        greater_than_one => [">1", ">=2.0.0"],
1504        less_than_one_dot_two => ["<1.2", "<1.2.0-0"],
1505        greater_than_one_dot_two => [">1.2", ">=1.3.0"],
1506        greater_than_with_prerelease => [">1.1.0-beta-10", ">1.1.0-beta-10"],
1507        either_one_version_or_the_other => ["0.1.20 || 1.2.4", "0.1.20||1.2.4"],
1508        either_one_version_range_or_another => [">=0.2.3 || <0.0.1", ">=0.2.3||<0.0.1"],
1509        either_x_version_works => ["1.2.x || 2.x", ">=1.2.0 <1.3.0-0||>=2.0.0 <3.0.0-0"],
1510        either_asterisk_version_works => ["1.2.* || 2.*", ">=1.2.0 <1.3.0-0||>=2.0.0 <3.0.0-0"],
1511        one_two_three_or_greater_than_four => ["1.2.3 || >4", "1.2.3||>=5.0.0"],
1512        any_version_asterisk => ["*", ">=0.0.0"],
1513        any_version_x => ["x", ">=0.0.0"],
1514        whitespace_1 => [">= 1.0.0", ">=1.0.0"],
1515        whitespace_2 => [">=  1.0.0", ">=1.0.0"],
1516        whitespace_3 => [">=   1.0.0", ">=1.0.0"],
1517        whitespace_4 => ["> 1.0.0", ">1.0.0"],
1518        whitespace_5 => [">  1.0.0", ">1.0.0"],
1519        whitespace_6 => ["<=   2.0.0", "<=2.0.0"],
1520        whitespace_7 => ["<= 2.0.0", "<=2.0.0"],
1521        whitespace_8 => ["<=  2.0.0", "<=2.0.0"],
1522        whitespace_9 => ["<    2.0.0", "<2.0.0"],
1523        whitespace_10 => ["<\t2.0.0", "<2.0.0"],
1524        whitespace_11 => ["^ 1", ">=1.0.0 <2.0.0-0"],
1525        whitespace_12 => ["~> 1", ">=1.0.0 <2.0.0-0"],
1526        whitespace_13 => ["~ 1.0", ">=1.0.0 <1.1.0-0"],
1527        beta          => ["^0.0.1-beta", ">=0.0.1-beta <0.0.2-0"],
1528        beta_tilde => ["~1.2.3-beta", ">=1.2.3-beta <1.3.0-0"],
1529        beta_4        => ["^1.2.3-beta.4", ">=1.2.3-beta.4 <2.0.0-0"],
1530        pre_release_on_both => ["1.0.0-alpha - 2.0.0-beta", ">=1.0.0-alpha <=2.0.0-beta"],
1531        single_sided_lower_bound_with_pre_release => [">1.0.0-alpha", ">1.0.0-alpha"],
1532        space_separated1 => [">=1.2.3 <4.5.6", ">=1.2.3 <4.5.6"],
1533        garbage1 => ["1.2.3 foo", "1.2.3"],
1534        garbage2 => ["foo 1.2.3", "1.2.3"],
1535        garbage3 => ["~1.y 1.2.3", "1.2.3"],
1536        garbage4 => ["1.2.3 ~1.y", "1.2.3"],
1537        loose1 => [">01.02.03", ">1.2.3"],
1538        loose2 => ["~1.2.3beta", ">=1.2.3-beta <1.3.0-0"],
1539        caret_weird => ["^ 1.2 ^ 1", ">=1.2.0 <2.0.0-0"],
1540        odd => ["=0.7", "0.7.0"],
1541        consistent => ["^1.0.1", ">=1.0.1 <2.0.0-0"],
1542        consistent2 => [">=1.0.1 <2.0.0-0", ">=1.0.1 <2.0.0-0"],
1543    ];
1544
1545    /*
1546    // And these weirdos that I don't know what to do with.
1547    [">X", "<0.0.0-0"],
1548    ["<X", "<0.0.0-0"],
1549    ["<x <* || >* 2.x", "<0.0.0-0"],
1550    */
1551
1552    #[derive(Serialize, Deserialize, Eq, PartialEq)]
1553    struct WithVersionReq {
1554        req: Range,
1555    }
1556
1557    #[test]
1558    fn read_version_req_from_string() {
1559        let v: WithVersionReq = serde_json::from_str(r#"{"req":"^1.2.3"}"#).unwrap();
1560
1561        assert_eq!(v.req, "^1.2.3".parse().unwrap(),);
1562    }
1563
1564    #[test]
1565    fn serialize_a_versionreq_to_string() {
1566        let output = serde_json::to_string(&WithVersionReq {
1567            req: Range(vec![BoundSet::at_most(Predicate::Excluding(
1568                "1.2.3".parse().unwrap(),
1569            ))
1570            .unwrap()]),
1571        })
1572        .unwrap();
1573        let expected: String = r#"{"req":"<1.2.3"}"#.into();
1574
1575        assert_eq!(output, expected);
1576    }
1577}
1578
1579#[cfg(test)]
1580mod ranges {
1581    use super::*;
1582
1583    #[test]
1584    fn one() {
1585        let r = BoundSet::new(
1586            Bound::Lower(Predicate::Including((1, 2, 0).into())),
1587            Bound::Upper(Predicate::Excluding((3, 3, 4).into())),
1588        )
1589        .unwrap();
1590
1591        assert_eq!(r.to_string(), ">=1.2.0 <3.3.4")
1592    }
1593}