1use std::cmp::{Ord, Ordering, PartialOrd};
2use std::fmt;
3
4use winnow::ascii::{space0, space1};
5use winnow::combinator::{
6 alt, delimited, eof, opt, peek, preceded, repeat_till, separated, terminated,
7};
8use winnow::error::ErrMode;
9use winnow::token::{any, literal};
10use winnow::{PResult, Parser};
11
12#[cfg(feature = "serde")]
13use serde::{de::Deserializer, ser::Serializer, Deserialize, Serialize};
14
15use crate::{
16 extras, number, Identifier, SemverError, SemverErrorKind, SemverParseError, Version,
17 MAX_SAFE_INTEGER,
18};
19
20#[derive(Clone, Debug, Eq, PartialEq, Hash)]
21struct BoundSet {
22 upper: Box<Bound>,
23 lower: Box<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: Box::new(Lower(Including(v1))),
40 upper: Box::new(Upper(Including(v2))),
41 }),
42 (lower, upper) if lower < upper => Some(Self {
43 lower: Box::new(lower),
44 upper: Box::new(upper),
45 }),
46 _ => None,
47 }
48 }
49
50 fn at_least(p: Predicate) -> Option<Self> {
51 BoundSet::new(Bound::Lower(p), Bound::upper())
52 }
53
54 fn at_most(p: Predicate) -> Option<Self> {
55 BoundSet::new(Bound::lower(), Bound::Upper(p))
56 }
57
58 fn exact(version: Version) -> Option<Self> {
59 BoundSet::new(
60 Bound::Lower(Predicate::Including(version.clone())),
61 Bound::Upper(Predicate::Including(version)),
62 )
63 }
64
65 fn satisfies(&self, version: &Version) -> bool {
66 use Bound::*;
67 use Predicate::*;
68
69 let lower_bound = match &self.lower.as_ref() {
70 Lower(Including(lower)) => lower <= version,
71 Lower(Excluding(lower)) => lower < version,
72 Lower(Unbounded) => true,
73 _ => unreachable!(
74 "There should not have been an upper bound: {:#?}",
75 self.lower
76 ),
77 };
78
79 let upper_bound = match &self.upper.as_ref() {
80 Upper(Including(upper)) => version <= upper,
81 Upper(Excluding(upper)) => version < upper,
82 Upper(Unbounded) => true,
83 _ => unreachable!(
84 "There should not have been an lower bound: {:#?}",
85 self.lower
86 ),
87 };
88
89 if !lower_bound || !upper_bound {
90 return false;
91 }
92
93 if version.is_prerelease() {
94 let lower_version = match &self.lower.as_ref() {
95 Lower(Including(v)) => Some(v),
96 Lower(Excluding(v)) => Some(v),
97 _ => None,
98 };
99 if let Some(lower_version) = lower_version {
100 if lower_version.is_prerelease()
101 && version.major == lower_version.major
102 && version.minor == lower_version.minor
103 && version.patch == lower_version.patch
104 {
105 return true;
106 }
107 }
108
109 let upper_version = match &self.upper.as_ref() {
110 Upper(Including(v)) => Some(v),
111 Upper(Excluding(v)) => Some(v),
112 _ => None,
113 };
114 if let Some(upper_version) = upper_version {
115 if upper_version.is_prerelease()
116 && version.major == upper_version.major
117 && version.minor == upper_version.minor
118 && version.patch == upper_version.patch
119 {
120 return true;
121 }
122 }
123
124 return false;
125 }
126
127 true
128 }
129
130 fn allows_all(&self, other: &BoundSet) -> bool {
131 self.lower <= other.lower && other.upper <= self.upper
132 }
133
134 fn allows_any(&self, other: &BoundSet) -> bool {
135 if other.upper < self.lower {
136 return false;
137 }
138
139 if self.upper < other.lower {
140 return false;
141 }
142
143 true
144 }
145
146 fn intersect(&self, other: &Self) -> Option<Self> {
147 let lower: &Bound = std::cmp::max(&self.lower, &other.lower);
148 let upper: &Bound = std::cmp::min(&self.upper, &other.upper);
149
150 BoundSet::new(lower.clone(), upper.clone())
151 }
152
153 fn difference(&self, other: &Self) -> Option<Vec<Self>> {
154 use Bound::*;
155
156 if let Some(overlap) = self.intersect(other) {
157 if &overlap == self {
158 return None;
159 }
160
161 if self.lower < overlap.lower && overlap.upper < self.upper {
162 return Some(vec![
163 BoundSet::new(*self.lower.clone(), Upper(overlap.lower.predicate().flip()))
164 .unwrap(),
165 BoundSet::new(Lower(overlap.upper.predicate().flip()), *self.upper.clone())
166 .unwrap(),
167 ]);
168 }
169
170 if self.lower < overlap.lower {
171 return BoundSet::new(*self.lower.clone(), Upper(overlap.lower.predicate().flip()))
172 .map(|f| vec![f]);
173 }
174
175 BoundSet::new(Lower(overlap.upper.predicate().flip()), *self.upper.clone())
176 .map(|f| vec![f])
177 } else {
178 Some(vec![self.clone()])
179 }
180 }
181}
182
183impl fmt::Display for BoundSet {
184 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
185 use Bound::*;
186 use Predicate::*;
187 match (&self.lower.as_ref(), &self.upper.as_ref()) {
188 (Lower(Unbounded), Upper(Unbounded)) => write!(f, "*"),
189 (Lower(Unbounded), Upper(Including(v))) => write!(f, "<={}", v),
190 (Lower(Unbounded), Upper(Excluding(v))) => write!(f, "<{}", v),
191 (Lower(Including(v)), Upper(Unbounded)) => write!(f, ">={}", v),
192 (Lower(Excluding(v)), Upper(Unbounded)) => write!(f, ">{}", v),
193 (Lower(Including(v)), Upper(Including(v2))) if v == v2 => write!(f, "{}", v),
194 (Lower(Including(v)), Upper(Including(v2))) => write!(f, ">={} <={}", v, v2),
195 (Lower(Including(v)), Upper(Excluding(v2))) => write!(f, ">={} <{}", v, v2),
196 (Lower(Excluding(v)), Upper(Including(v2))) => write!(f, ">{} <={}", v, v2),
197 (Lower(Excluding(v)), Upper(Excluding(v2))) => write!(f, ">{} <{}", v, v2),
198 _ => unreachable!("does not make sense"),
199 }
200 }
201}
202
203#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
204enum Operation {
205 Exact,
206 GreaterThan,
207 GreaterThanEquals,
208 LessThan,
209 LessThanEquals,
210}
211
212#[derive(Debug, Clone, Eq, PartialEq, Hash)]
213enum Predicate {
214 Excluding(Version), Including(Version), Unbounded, }
218
219impl Predicate {
220 fn flip(self) -> Self {
221 use Predicate::*;
222 match self {
223 Excluding(v) => Including(v),
224 Including(v) => Excluding(v),
225 Unbounded => Unbounded,
226 }
227 }
228}
229
230#[derive(Debug, Clone, Eq, PartialEq, Hash)]
231enum Bound {
232 Lower(Predicate),
233 Upper(Predicate),
234}
235
236impl Bound {
237 fn upper() -> Self {
238 Bound::Upper(Predicate::Unbounded)
239 }
240
241 fn lower() -> Self {
242 Bound::Lower(Predicate::Unbounded)
243 }
244
245 fn predicate(self) -> Predicate {
246 use Bound::*;
247
248 match self {
249 Lower(p) => p,
250 Upper(p) => p,
251 }
252 }
253}
254
255impl Ord for Bound {
256 fn cmp(&self, other: &Self) -> Ordering {
257 use Bound::*;
258 use Predicate::*;
259
260 match (self, other) {
261 (Lower(Unbounded), Lower(Unbounded)) | (Upper(Unbounded), Upper(Unbounded)) => {
262 Ordering::Equal
263 }
264 (Upper(Unbounded), _) | (_, Lower(Unbounded)) => Ordering::Greater,
265 (Lower(Unbounded), _) | (_, Upper(Unbounded)) => Ordering::Less,
266
267 (Upper(Including(v1)), Upper(Including(v2)))
268 | (Upper(Including(v1)), Lower(Including(v2)))
269 | (Upper(Excluding(v1)), Upper(Excluding(v2)))
270 | (Upper(Excluding(v1)), Lower(Excluding(v2)))
271 | (Lower(Including(v1)), Upper(Including(v2)))
272 | (Lower(Including(v1)), Lower(Including(v2)))
273 | (Lower(Excluding(v1)), Lower(Excluding(v2))) => v1.cmp(v2),
274
275 (Lower(Excluding(v1)), Upper(Excluding(v2)))
276 | (Lower(Including(v1)), Upper(Excluding(v2))) => {
277 if v2 <= v1 {
278 Ordering::Greater
279 } else {
280 Ordering::Less
281 }
282 }
283 (Upper(Including(v1)), Upper(Excluding(v2)))
284 | (Upper(Including(v1)), Lower(Excluding(v2)))
285 | (Lower(Excluding(v1)), Upper(Including(v2))) => {
286 if v2 < v1 {
287 Ordering::Greater
288 } else {
289 Ordering::Less
290 }
291 }
292 (Lower(Excluding(v1)), Lower(Including(v2))) => {
293 if v1 < v2 {
294 Ordering::Less
295 } else {
296 Ordering::Greater
297 }
298 }
299 (Lower(Including(v1)), Lower(Excluding(v2)))
300 | (Upper(Excluding(v1)), Lower(Including(v2)))
301 | (Upper(Excluding(v1)), Upper(Including(v2))) => {
302 if v1 <= v2 {
303 Ordering::Less
304 } else {
305 Ordering::Greater
306 }
307 }
308 }
309 }
310}
311
312impl PartialOrd for Bound {
313 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
314 Some(self.cmp(other))
315 }
316}
317
318#[derive(Clone, Debug, Eq, PartialEq, Hash)]
327pub struct Range(Vec<BoundSet>);
328
329impl fmt::Display for Operation {
330 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
331 use Operation::*;
332 match self {
333 Exact => write!(f, ""),
334 GreaterThan => write!(f, ">"),
335 GreaterThanEquals => write!(f, ">="),
336 LessThan => write!(f, "<"),
337 LessThanEquals => write!(f, "<="),
338 }
339 }
340}
341
342#[cfg(feature = "serde")]
343impl Serialize for Range {
344 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
345 s.collect_str(self)
346 }
347}
348
349#[cfg(feature = "serde")]
350impl<'de> Deserialize<'de> for Range {
351 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
352 let s = String::deserialize(d)?;
353 s.parse().map_err(serde::de::Error::custom)
354 }
355}
356
357impl Range {
358 pub fn parse<S: AsRef<str>>(input: S) -> Result<Self, SemverError> {
362 let mut input = input.as_ref();
363
364 match range_set.parse_next(&mut input) {
365 Ok(range) => Ok(range),
366 Err(err) => Err(match err {
367 ErrMode::Backtrack(e) | ErrMode::Cut(e) => SemverError {
368 input: input.into(),
369 span: (e.input.as_ptr() as usize - input.as_ptr() as usize, 0).into(),
370 kind: if let Some(kind) = e.kind {
371 kind
372 } else if let Some(ctx) = e.context {
373 SemverErrorKind::Context(ctx)
374 } else {
375 SemverErrorKind::Other
376 },
377 },
378 ErrMode::Incomplete(_) => SemverError {
379 input: input.into(),
380 span: (input.len() - 1, 0).into(),
381 kind: SemverErrorKind::IncompleteInput,
382 },
383 }),
384 }
385 }
386
387 pub fn any() -> Self {
391 Self(vec![BoundSet::new(Bound::lower(), Bound::upper()).unwrap()])
392 }
393
394 pub fn satisfies(&self, version: &Version) -> bool {
398 for range in &self.0 {
399 if range.satisfies(version) {
400 return true;
401 }
402 }
403
404 false
405 }
406
407 pub fn allows_all(&self, other: &Range) -> bool {
411 for this in &self.0 {
412 for that in &other.0 {
413 if this.allows_all(that) {
414 return true;
415 }
416 }
417 }
418
419 false
420 }
421
422 pub fn allows_any(&self, other: &Range) -> bool {
426 for this in &self.0 {
427 for that in &other.0 {
428 if this.allows_any(that) {
429 return true;
430 }
431 }
432 }
433
434 false
435 }
436
437 pub fn intersect(&self, other: &Self) -> Option<Self> {
441 let mut sets = Vec::new();
442
443 for lefty in &self.0 {
444 for righty in &other.0 {
445 if let Some(set) = lefty.intersect(righty) {
446 sets.push(set)
447 }
448 }
449 }
450
451 if sets.is_empty() {
452 None
453 } else {
454 Some(Self(sets))
455 }
456 }
457
458 pub fn difference(&self, other: &Self) -> Option<Self> {
462 let mut predicates = Vec::new();
463
464 for lefty in &self.0 {
465 for righty in &other.0 {
466 if let Some(mut range) = lefty.difference(righty) {
467 predicates.append(&mut range)
468 }
469 }
470 }
471
472 if predicates.is_empty() {
473 None
474 } else {
475 Some(Self(predicates))
476 }
477 }
478
479 #[doc = include_str!("../examples/max_satisfying.rs")]
484 pub fn max_satisfying<'v>(&self, versions: &'v [Version]) -> Option<&'v Version> {
486 let filtered: Vec<_> = versions.iter().filter(|v| self.satisfies(v)).collect();
487
488 filtered.into_iter().max()
489 }
490
491 #[doc = include_str!("../examples/min_satisfying.rs")]
496 pub fn min_satisfying<'v>(&self, versions: &'v [Version]) -> Option<&'v Version> {
498 let filtered: Vec<_> = versions.iter().filter(|v| self.satisfies(v)).collect();
499
500 filtered.into_iter().min()
501 }
502
503 pub fn min_version(&self) -> Option<Version> {
507 if let Some(min_bound) = self.0.iter().map(|range| &range.lower).min() {
508 let min_bound = min_bound.as_ref();
509 match min_bound {
510 Bound::Lower(pred) => match pred {
511 Predicate::Including(v) => Some(v.clone()),
512 Predicate::Excluding(v) => {
513 let mut v = v.clone();
514 if v.is_prerelease() {
515 v.pre_release.push(Identifier::Numeric(0))
516 } else {
517 v.patch += 1;
518 }
519 Some(v)
520 }
521 Predicate::Unbounded => {
522 let mut zero = Version::from((0, 0, 0));
523 if self.satisfies(&zero) {
524 return Some(zero);
525 }
526
527 zero.pre_release.push(Identifier::Numeric(0));
528 if self.satisfies(&zero) {
529 return Some(zero);
530 }
531 None
532 }
533 },
534 Bound::Upper(_) => None,
535 }
536 } else {
537 None
538 }
539 }
540}
541
542impl fmt::Display for Range {
543 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
544 for (i, range) in self.0.iter().enumerate() {
545 if i > 0 {
546 write!(f, "||")?;
547 }
548 write!(f, "{}", range)?;
549 }
550 Ok(())
551 }
552}
553
554impl std::str::FromStr for Range {
555 type Err = SemverError;
556 fn from_str(s: &str) -> Result<Self, Self::Err> {
557 Range::parse(s)
558 }
559}
560
561fn range_set<'s>(input: &mut &'s str) -> PResult<Range, SemverParseError<&'s str>> {
600 Parser::try_map(bound_sets, |sets| {
601 if sets.is_empty() {
602 Err(SemverParseError {
603 input,
604 kind: Some(SemverErrorKind::NoValidRanges),
605 context: None,
606 })
607 } else {
608 Ok(Range(sets))
609 }
610 })
611 .parse_next(input)
612}
613
614fn bound_sets<'s>(input: &mut &'s str) -> PResult<Vec<BoundSet>, SemverParseError<&'s str>> {
616 Parser::map(
617 separated(0.., range, logical_or),
618 |sets: Vec<Vec<BoundSet>>| sets.into_iter().flatten().collect(),
619 )
620 .parse_next(input)
621}
622fn logical_or<'s>(input: &mut &'s str) -> PResult<(), SemverParseError<&'s str>> {
623 Parser::map(delimited(space0, literal("||"), space0), |_| ()).parse_next(input)
624}
625
626fn range<'s>(input: &mut &'s str) -> PResult<Vec<BoundSet>, SemverParseError<&'s str>> {
627 Parser::map(
630 separated(0.., simple, space1),
631 |bs: Vec<Option<BoundSet>>| {
632 bs.into_iter()
633 .flatten()
634 .fold(Vec::new(), |mut acc: Vec<BoundSet>, bs| {
635 if let Some(last) = acc.pop() {
636 if let Some(bound) = last.intersect(&bs) {
637 acc.push(bound);
638 } else {
639 acc.push(last);
640 acc.push(bs);
641 }
642 } else {
643 acc.push(bs)
644 }
645 acc
646 })
647 },
648 )
649 .parse_next(input)
650}
651
652fn simple<'s>(input: &mut &'s str) -> PResult<Option<BoundSet>, SemverParseError<&'s str>> {
654 alt((
655 terminated(hyphen, peek(alt((space1, literal("||"), eof)))),
656 terminated(primitive, peek(alt((space1, literal("||"), eof)))),
657 terminated(partial, peek(alt((space1, literal("||"), eof)))),
658 terminated(tilde, peek(alt((space1, literal("||"), eof)))),
659 terminated(caret, peek(alt((space1, literal("||"), eof)))),
660 garbage,
661 ))
662 .parse_next(input)
663}
664
665fn garbage<'s>(input: &mut &'s str) -> PResult<Option<BoundSet>, SemverParseError<&'s str>> {
666 Parser::map(
667 repeat_till(0.., any, alt((peek(space1), peek(literal("||")), eof))),
668 |_: ((), &str)| None,
669 )
670 .parse_next(input)
671}
672
673fn primitive<'s>(input: &mut &'s str) -> PResult<Option<BoundSet>, SemverParseError<&'s str>> {
675 use Operation::*;
676
677 Parser::map(
678 (operation, preceded(space0, partial_version)),
679 |parsed| match parsed {
680 (GreaterThanEquals, partial) => {
681 BoundSet::at_least(Predicate::Including(partial.into()))
682 }
683 (
684 GreaterThan,
685 Partial {
686 major: Some(major),
687 minor: Some(minor),
688 patch: None,
689 ..
690 },
691 ) => BoundSet::at_least(Predicate::Including((major, minor + 1, 0).into())),
692 (
693 GreaterThan,
694 Partial {
695 major: Some(major),
696 minor: None,
697 patch: None,
698 ..
699 },
700 ) => BoundSet::at_least(Predicate::Including((major + 1, 0, 0).into())),
701 (GreaterThan, partial) => BoundSet::at_least(Predicate::Excluding(partial.into())),
702 (
703 LessThan,
704 Partial {
705 major: Some(major),
706 minor: Some(minor),
707 patch: None,
708 ..
709 },
710 ) => BoundSet::at_most(Predicate::Excluding((major, minor, 0, 0).into())),
711 (
712 LessThan,
713 Partial {
714 major,
715 minor,
716 patch,
717 pre_release,
718 build,
719 ..
720 },
721 ) => BoundSet::at_most(Predicate::Excluding(Version {
722 major: major.unwrap_or(0),
723 minor: minor.unwrap_or(0),
724 patch: patch.unwrap_or(0),
725 build,
726 pre_release,
727 })),
728 (
729 LessThanEquals,
730 Partial {
731 major,
732 minor: None,
733 patch: None,
734 ..
735 },
736 ) => BoundSet::at_most(Predicate::Including(
737 (major.unwrap_or(0), MAX_SAFE_INTEGER, MAX_SAFE_INTEGER).into(),
738 )),
739 (
740 LessThanEquals,
741 Partial {
742 major,
743 minor,
744 patch: None,
745 ..
746 },
747 ) => BoundSet::at_most(Predicate::Including(
748 (major.unwrap_or(0), minor.unwrap_or(0), MAX_SAFE_INTEGER).into(),
749 )),
750 (LessThanEquals, partial) => BoundSet::at_most(Predicate::Including(partial.into())),
751 (
752 Exact,
753 Partial {
754 major: Some(major),
755 minor: Some(minor),
756 patch: Some(patch),
757 pre_release,
758 ..
759 },
760 ) => BoundSet::exact(Version {
761 major,
762 minor,
763 patch,
764 pre_release,
765 build: vec![],
766 }),
767 (
768 Exact,
769 Partial {
770 major: Some(major),
771 minor: Some(minor),
772 ..
773 },
774 ) => BoundSet::new(
775 Bound::Lower(Predicate::Including((major, minor, 0).into())),
776 Bound::Upper(Predicate::Excluding(Version {
777 major,
778 minor: minor + 1,
779 patch: 0,
780 pre_release: vec![Identifier::Numeric(0)],
781 build: vec![],
782 })),
783 ),
784 (
785 Exact,
786 Partial {
787 major: Some(major), ..
788 },
789 ) => BoundSet::new(
790 Bound::Lower(Predicate::Including((major, 0, 0).into())),
791 Bound::Upper(Predicate::Excluding(Version {
792 major: major + 1,
793 minor: 0,
794 patch: 0,
795 pre_release: vec![Identifier::Numeric(0)],
796 build: vec![],
797 })),
798 ),
799 _ => None,
800 },
801 )
802 .context("operation range (ex: >= 1.2.3)")
803 .parse_next(input)
804}
805
806fn operation<'s>(input: &mut &'s str) -> PResult<Operation, SemverParseError<&'s str>> {
807 use Operation::*;
808 alt((
809 Parser::map(literal(">="), |_| GreaterThanEquals),
810 Parser::map(literal(">"), |_| GreaterThan),
811 Parser::map(literal("="), |_| Exact),
812 Parser::map(literal("<="), |_| LessThanEquals),
813 Parser::map(literal("<"), |_| LessThan),
814 ))
815 .parse_next(input)
816}
817
818fn partial<'s>(input: &mut &'s str) -> PResult<Option<BoundSet>, SemverParseError<&'s str>> {
819 Parser::map(partial_version, |partial| match partial {
820 Partial { major: None, .. } => BoundSet::at_least(Predicate::Including((0, 0, 0).into())),
821 Partial {
822 major: Some(major),
823 minor: None,
824 ..
825 } => BoundSet::new(
826 Bound::Lower(Predicate::Including((major, 0, 0).into())),
827 Bound::Upper(Predicate::Excluding(Version {
828 major: major + 1,
829 minor: 0,
830 patch: 0,
831 pre_release: vec![Identifier::Numeric(0)],
832 build: vec![],
833 })),
834 ),
835 Partial {
836 major: Some(major),
837 minor: Some(minor),
838 patch: None,
839 ..
840 } => BoundSet::new(
841 Bound::Lower(Predicate::Including((major, minor, 0).into())),
842 Bound::Upper(Predicate::Excluding(Version {
843 major,
844 minor: minor + 1,
845 patch: 0,
846 pre_release: vec![Identifier::Numeric(0)],
847 build: vec![],
848 })),
849 ),
850 partial => BoundSet::exact(partial.into()),
851 })
852 .context("plain version range (ex: 1.2)")
853 .parse_next(input)
854}
855
856#[derive(Debug, Clone)]
857struct Partial {
858 major: Option<u64>,
859 minor: Option<u64>,
860 patch: Option<u64>,
861 pre_release: Vec<Identifier>,
862 build: Vec<Identifier>,
863}
864
865impl From<Partial> for Version {
866 fn from(partial: Partial) -> Self {
867 Version {
868 major: partial.major.unwrap_or(0),
869 minor: partial.minor.unwrap_or(0),
870 patch: partial.patch.unwrap_or(0),
871 pre_release: partial.pre_release,
872 build: partial.build,
873 }
874 }
875}
876
877fn partial_version<'s>(input: &mut &'s str) -> PResult<Partial, SemverParseError<&'s str>> {
882 let _ = opt(literal("v")).parse_next(input)?;
883 let _ = space0(input)?;
884 let major = component(input)?;
885 let minor = opt(preceded(literal("."), component)).parse_next(input)?;
886 let patch = opt(preceded(literal("."), component)).parse_next(input)?;
887 let (pre, build) = if patch.is_some() {
888 extras(input)?
889 } else {
890 (vec![], vec![])
891 };
892 Ok(Partial {
893 major,
894 minor: minor.flatten(),
895 patch: patch.flatten(),
896 pre_release: pre,
897 build,
898 })
899}
900
901fn component<'s>(input: &mut &'s str) -> PResult<Option<u64>, SemverParseError<&'s str>> {
902 alt((
903 Parser::map(x_or_asterisk, |_| None),
904 Parser::map(number, Some),
905 ))
906 .parse_next(input)
907}
908
909fn x_or_asterisk<'s>(input: &mut &'s str) -> PResult<(), SemverParseError<&'s str>> {
910 Parser::map(alt((literal("x"), literal("X"), literal("*"))), |_| ()).parse_next(input)
911}
912
913fn tilde_gt<'s>(input: &mut &'s str) -> PResult<Option<&'s str>, SemverParseError<&'s str>> {
914 Parser::map(
915 (literal("~"), space0, opt(literal(">")), space0),
916 |(_, _, gt, _)| gt,
917 )
918 .parse_next(input)
919}
920
921fn tilde<'s>(input: &mut &'s str) -> PResult<Option<BoundSet>, SemverParseError<&'s str>> {
922 Parser::map((tilde_gt, partial_version), |parsed| match parsed {
923 (
924 Some(_gt),
925 Partial {
926 major: Some(major),
927 minor: None,
928 patch: None,
929 ..
930 },
931 ) => BoundSet::new(
932 Bound::Lower(Predicate::Including((major, 0, 0).into())),
933 Bound::Upper(Predicate::Excluding((major + 1, 0, 0, 0).into())),
934 ),
935 (
936 Some(_gt),
937 Partial {
938 major: Some(major),
939 minor: Some(minor),
940 patch,
941 pre_release,
942 ..
943 },
944 ) => BoundSet::new(
945 Bound::Lower(Predicate::Including(Version {
946 major,
947 minor,
948 patch: patch.unwrap_or(0),
949 pre_release,
950 build: vec![],
951 })),
952 Bound::Upper(Predicate::Excluding((major, minor + 1, 0, 0).into())),
953 ),
954 (
955 None,
956 Partial {
957 major: Some(major),
958 minor: Some(minor),
959 patch: Some(patch),
960 pre_release,
961 ..
962 },
963 ) => BoundSet::new(
964 Bound::Lower(Predicate::Including(Version {
965 major,
966 minor,
967 patch,
968 pre_release,
969 build: vec![],
970 })),
971 Bound::Upper(Predicate::Excluding((major, minor + 1, 0, 0).into())),
972 ),
973 (
974 None,
975 Partial {
976 major: Some(major),
977 minor: Some(minor),
978 patch: None,
979 ..
980 },
981 ) => BoundSet::new(
982 Bound::Lower(Predicate::Including((major, minor, 0).into())),
983 Bound::Upper(Predicate::Excluding((major, minor + 1, 0, 0).into())),
984 ),
985 (
986 None,
987 Partial {
988 major: Some(major),
989 minor: None,
990 patch: None,
991 ..
992 },
993 ) => BoundSet::new(
994 Bound::Lower(Predicate::Including((major, 0, 0).into())),
995 Bound::Upper(Predicate::Excluding((major + 1, 0, 0, 0).into())),
996 ),
997 _ => None,
998 })
999 .context("tilde version range (ex: ~1.2.3)")
1000 .parse_next(input)
1001}
1002
1003fn caret<'s>(input: &mut &'s str) -> PResult<Option<BoundSet>, SemverParseError<&'s str>> {
1004 Parser::map(
1005 preceded((literal("^"), space0), partial_version),
1006 |parsed| match parsed {
1007 Partial {
1008 major: Some(0),
1009 minor: None,
1010 patch: None,
1011 ..
1012 } => BoundSet::at_most(Predicate::Excluding((1, 0, 0, 0).into())),
1013 Partial {
1014 major: Some(0),
1015 minor: Some(minor),
1016 patch: None,
1017 ..
1018 } => BoundSet::new(
1019 Bound::Lower(Predicate::Including((0, minor, 0).into())),
1020 Bound::Upper(Predicate::Excluding((0, minor + 1, 0, 0).into())),
1021 ),
1022 Partial {
1024 major: Some(major),
1025 minor: None,
1026 patch: None,
1027 ..
1028 } => BoundSet::new(
1029 Bound::Lower(Predicate::Including((major, 0, 0).into())),
1030 Bound::Upper(Predicate::Excluding((major + 1, 0, 0, 0).into())),
1031 ),
1032 Partial {
1033 major: Some(major),
1034 minor: Some(minor),
1035 patch: None,
1036 ..
1037 } => BoundSet::new(
1038 Bound::Lower(Predicate::Including((major, minor, 0).into())),
1039 Bound::Upper(Predicate::Excluding((major + 1, 0, 0, 0).into())),
1040 ),
1041 Partial {
1042 major: Some(major),
1043 minor: Some(minor),
1044 patch: Some(patch),
1045 pre_release,
1046 ..
1047 } => BoundSet::new(
1048 Bound::Lower(Predicate::Including(Version {
1049 major,
1050 minor,
1051 patch,
1052 pre_release,
1053 build: vec![],
1054 })),
1055 Bound::Upper(Predicate::Excluding(match (major, minor, patch) {
1056 (0, 0, n) => Version::from((0, 0, n + 1, 0)),
1057 (0, n, _) => Version::from((0, n + 1, 0, 0)),
1058 (n, _, _) => Version::from((n + 1, 0, 0, 0)),
1059 })),
1060 ),
1061 _ => None,
1062 },
1063 )
1064 .context("caret version range (ex: ^1.2.3)")
1065 .parse_next(input)
1066}
1067
1068fn hyphen<'s>(input: &mut &'s str) -> PResult<Option<BoundSet>, SemverParseError<&'s str>> {
1070 fn parser<'s>(input: &mut &'s str) -> PResult<Option<BoundSet>, SemverParseError<&'s str>> {
1071 let lower = opt(partial_version).parse_next(input)?;
1072 let _ = space1(input)?;
1073 let _ = literal("-").parse_next(input)?;
1074 let _ = space1(input)?;
1075 let upper = partial_version(input)?;
1076 let upper = match upper {
1077 Partial {
1078 major: None,
1079 minor: None,
1080 patch: None,
1081 ..
1082 } => Predicate::Excluding(Version {
1083 major: 0,
1084 minor: 0,
1085 patch: 0,
1086 pre_release: vec![Identifier::Numeric(0)],
1087 build: vec![],
1088 }),
1089 Partial {
1090 major: Some(major),
1091 minor: None,
1092 patch: None,
1093 ..
1094 } => Predicate::Excluding(Version {
1095 major: major + 1,
1096 minor: 0,
1097 patch: 0,
1098 pre_release: vec![Identifier::Numeric(0)],
1099 build: vec![],
1100 }),
1101 Partial {
1102 major: Some(major),
1103 minor: Some(minor),
1104 patch: None,
1105 ..
1106 } => Predicate::Excluding(Version {
1107 major,
1108 minor: minor + 1,
1109 patch: 0,
1110 pre_release: vec![Identifier::Numeric(0)],
1111 build: vec![],
1112 }),
1113 partial => Predicate::Including(partial.into()),
1114 };
1115 let bounds = if let Some(lower) = lower {
1116 BoundSet::new(
1117 Bound::Lower(Predicate::Including(lower.into())),
1118 Bound::Upper(upper),
1119 )
1120 } else {
1121 BoundSet::at_most(upper)
1122 };
1123 Ok(bounds)
1124 }
1125
1126 parser
1127 .context("hyphenated version range (ex: 1.2 - 2)")
1128 .parse_next(input)
1129}
1130
1131macro_rules! create_tests_for {
1132 ($func:ident $($name:ident => $version_range:expr , { $x:ident => $allows:expr, $y:ident => $denies:expr$(,)? }),+ ,$(,)?) => {
1133
1134 #[cfg(test)]
1135 mod $func {
1136 use super::*;
1137
1138 $(
1139 #[test]
1140 fn $name() {
1141 let version_range = Range::parse($version_range).unwrap();
1142
1143 let allows: Vec<Range> = $allows.iter().map(|v| Range::parse(v).unwrap()).collect();
1144 for version in &allows {
1145 assert!(version_range.$func(version), "should have allowed: {}", version);
1146 }
1147
1148 let ranges: Vec<Range> = $denies.iter().map(|v| Range::parse(v).unwrap()).collect();
1149 for version in &ranges {
1150 assert!(!version_range.$func(version), "should have denied: {}", version);
1151 }
1152 }
1153 )+
1154 }
1155 }
1156}
1157
1158create_tests_for! {
1159 allows_all
1161
1162 greater_than_eq_123 => ">=1.2.3", {
1163 allows => [">=2.0.0", ">2", "2.0.0", "0.1 || 1.4", "1.2.3", "2 - 7", ">2.0.0"],
1164 denies => ["1.0.0", "<1.2", ">=1.2.2", "1 - 3", "0.1 || <1.2.0", ">1.0.0"],
1165 },
1166
1167 greater_than_123 => ">1.2.3", {
1168 allows => [">=2.0.0", ">2", "2.0.0", "0.1 || 1.4", ">2.0.0"],
1169 denies => ["1.0.0", "<1.2", ">=1.2.3", "1 - 3", "0.1 || <1.2.0", "<=3"],
1170 },
1171
1172 eq_123 => "1.2.3", {
1173 allows => ["1.2.3"],
1174 denies => ["1.0.0", "<1.2", "1.x", ">=1.2.2", "1 - 3", "0.1 || <1.2.0"],
1175 },
1176
1177 lt_123 => "<1.2.3", {
1178 allows => ["<=1.2.0", "<1", "1.0.0", "0.1 || 1.4"],
1179 denies => ["1 - 3", ">1", "2.0.0", "2.0 || >9", ">1.0.0"],
1180 },
1181
1182 lt_eq_123 => "<=1.2.3", {
1183 allows => ["<=1.2.0", "<1", "1.0.0", "0.1 || 1.4", "1.2.3"],
1184 denies => ["1 - 3", ">1.0.0", ">=1.0.0"],
1185 },
1186
1187 eq_123_or_gt_400 => "1.2.3 || >4", {
1188 allows => [ "1.2.3", ">4", "5.x", "5.2.x", ">=8.2.1", "2.0 || 5.6.7"],
1189 denies => ["<2", "1 - 7", "1.9.4 || 2 - 3"],
1190 },
1191
1192 between_two_and_eight => "2 - 8", {
1193 allows => [ "2.2.3", "4 - 5"],
1194 denies => ["1 - 4", "5 - 9", ">3", "<=5"],
1195 },
1196}
1197
1198create_tests_for! {
1199 allows_any
1201
1202 greater_than_eq_123 => ">=1.2.3", {
1203 allows => ["<=1.2.4", "3.0.0", "<2", ">=3", ">3.0.0"],
1204 denies => ["<=1.2.0", "1.0.0", "<1"],
1205 },
1206
1207 greater_than_123 => ">1.2.3", {
1208 allows => ["<=1.2.4", "3.0.0", "<2", ">=3", ">3.0.0"],
1209 denies => ["<=1.2.3", "1.0.0", "<1"],
1210 },
1211
1212 eq_123 => "1.2.3", {
1213 allows => ["1.2.3", "1 - 2"],
1214 denies => ["<1.2.3", "1.0.0", ">4.5.6", ">5"],
1215 },
1216
1217 lt_eq_123 => "<=1.2.3", {
1218 allows => ["<=1.2.0", "<1.0.0", "1.0.0", ">1.0.0", ">=1.2.0"],
1219 denies => ["4.5.6", ">2.0.0", ">=2.0.0"],
1220 },
1221
1222 lt_123 => "<1.2.3", {
1223 allows => ["<=2.2.0", "<2.0.0", "1.0.0", ">1.0.0", ">=1.2.0"],
1224 denies => ["2.0.0", ">1.8.0", ">=1.8.0"],
1225 },
1226
1227 between_two_and_eight => "2 - 8", {
1228 allows => ["2.2.3", "4 - 10", ">4", ">4.0.0", "<=4.0.0", "<9.1.2"],
1229 denies => [">10", "10 - 11", "0 - 1"],
1230 },
1231
1232 eq_123_or_gt_400 => "1.2.3 || >4", {
1233 allows => [ "1.2.3", ">3", "5.x", "5.2.x", ">=8.2.1", "2 - 7", "2.0 || 5.6.7"],
1234 denies => [ "1.9.4 || 2 - 3"],
1235 },
1236}
1237
1238#[cfg(test)]
1239mod intersection {
1240 use super::*;
1241
1242 fn v(range: &'static str) -> Range {
1243 range.parse().unwrap()
1244 }
1245
1246 #[test]
1247 fn gt_eq_123() {
1248 let base_range = v(">=1.2.3");
1249
1250 let samples = vec![
1251 ("<=2.0.0", Some(">=1.2.3 <=2.0.0")),
1252 ("<2.0.0", Some(">=1.2.3 <2.0.0")),
1253 (">=2.0.0", Some(">=2.0.0")),
1254 (">2.0.0", Some(">2.0.0")),
1255 (">1.0.0", Some(">=1.2.3")),
1256 (">1.2.3", Some(">1.2.3")),
1257 ("<=1.2.3", Some("1.2.3")),
1258 ("2.0.0", Some("2.0.0")),
1259 ("1.1.1", None),
1260 ("<1.0.0", None),
1261 ];
1262
1263 assert_ranges_match(base_range, samples);
1264 }
1265
1266 #[test]
1267 fn gt_123() {
1268 let base_range = v(">1.2.3");
1269
1270 let samples = vec![
1271 ("<=2.0.0", Some(">1.2.3 <=2.0.0")),
1272 ("<2.0.0", Some(">1.2.3 <2.0.0")),
1273 (">=2.0.0", Some(">=2.0.0")),
1274 (">2.0.0", Some(">2.0.0")),
1275 ("2.0.0", Some("2.0.0")),
1276 (">1.2.3", Some(">1.2.3")),
1277 ("<=1.2.3", None),
1278 ("1.1.1", None),
1279 ("<1.0.0", None),
1280 ];
1281
1282 assert_ranges_match(base_range, samples);
1283 }
1284
1285 #[test]
1286 fn eq_123() {
1287 let base_range = v("1.2.3");
1288
1289 let samples = vec![
1290 ("<=2.0.0", Some("1.2.3")),
1291 ("<2.0.0", Some("1.2.3")),
1292 (">=2.0.0", None),
1293 (">2.0.0", None),
1294 ("2.0.0", None),
1295 ("1.2.3", Some("1.2.3")),
1296 (">1.2.3", None),
1297 ("<=1.2.3", Some("1.2.3")),
1298 ("1.1.1", None),
1299 ("<1.0.0", None),
1300 ];
1301
1302 assert_ranges_match(base_range, samples);
1303 }
1304
1305 #[test]
1306 fn lt_123() {
1307 let base_range = v("<1.2.3");
1308
1309 let samples = vec![
1310 ("<=2.0.0", Some("<1.2.3")),
1311 ("<2.0.0", Some("<1.2.3")),
1312 (">=2.0.0", None),
1313 (">=1.0.0", Some(">=1.0.0 <1.2.3")),
1314 (">2.0.0", None),
1315 ("2.0.0", None),
1316 ("1.2.3", None),
1317 (">1.2.3", None),
1318 ("<=1.2.3", Some("<1.2.3")),
1319 ("1.1.1", Some("1.1.1")),
1320 ("<1.0.0", Some("<1.0.0")),
1321 ];
1322
1323 assert_ranges_match(base_range, samples);
1324 }
1325
1326 #[test]
1327 fn lt_eq_123() {
1328 let base_range = v("<=1.2.3");
1329
1330 let samples = vec![
1331 ("<=2.0.0", Some("<=1.2.3")),
1332 ("<2.0.0", Some("<=1.2.3")),
1333 (">=2.0.0", None),
1334 (">=1.0.0", Some(">=1.0.0 <=1.2.3")),
1335 (">2.0.0", None),
1336 ("2.0.0", None),
1337 ("1.2.3", Some("1.2.3")),
1338 (">1.2.3", None),
1339 ("<=1.2.3", Some("<=1.2.3")),
1340 ("1.1.1", Some("1.1.1")),
1341 ("<1.0.0", Some("<1.0.0")),
1342 ];
1343
1344 assert_ranges_match(base_range, samples);
1345 }
1346
1347 #[test]
1348 fn multiple() {
1349 let base_range = v("<1 || 3 - 4");
1350
1351 let samples = vec![("0.5 - 3.5.0", Some(">=0.5.0 <1.0.0||>=3.0.0 <=3.5.0"))];
1352
1353 assert_ranges_match(base_range, samples);
1354 }
1355
1356 fn assert_ranges_match(base: Range, samples: Vec<(&'static str, Option<&'static str>)>) {
1357 for (other, expected) in samples {
1358 let other = v(other);
1359 let resulting_range = base.intersect(&other).map(|v| v.to_string());
1360 assert_eq!(
1361 resulting_range.clone(),
1362 expected.map(|e| e.to_string()),
1363 "{} ∩ {} := {}",
1364 base,
1365 other,
1366 resulting_range.unwrap_or_else(|| "⊗".into())
1367 );
1368 }
1369 }
1370}
1371
1372#[cfg(test)]
1373mod difference {
1374 use super::*;
1375
1376 fn v(range: &'static str) -> Range {
1377 range.parse().unwrap()
1378 }
1379
1380 #[test]
1381 fn gt_eq_123() {
1382 let base_range = v(">=1.2.3");
1383
1384 let samples = vec![
1385 ("<=2.0.0", Some(">2.0.0")),
1386 ("<2.0.0", Some(">=2.0.0")),
1387 (">=2.0.0", Some(">=1.2.3 <2.0.0")),
1388 (">2.0.0", Some(">=1.2.3 <=2.0.0")),
1389 (">1.0.0", None),
1390 (">1.2.3", Some("1.2.3")),
1391 ("<=1.2.3", Some(">1.2.3")),
1392 ("1.1.1", Some(">=1.2.3")),
1393 ("<1.0.0", Some(">=1.2.3")),
1394 ("2.0.0", Some(">=1.2.3 <2.0.0||>2.0.0")),
1395 ];
1396
1397 assert_ranges_match(base_range, samples);
1398 }
1399
1400 #[test]
1401 fn gt_123() {
1402 let base_range = v(">1.2.3");
1403
1404 let samples = vec![
1405 ("<=2.0.0", Some(">2.0.0")),
1406 ("<2.0.0", Some(">=2.0.0")),
1407 (">=2.0.0", Some(">1.2.3 <2.0.0")),
1408 (">2.0.0", Some(">1.2.3 <=2.0.0")),
1409 (">1.0.0", None),
1410 (">1.2.3", None),
1411 ("<=1.2.3", Some(">1.2.3")),
1412 ("1.1.1", Some(">1.2.3")),
1413 ("<1.0.0", Some(">1.2.3")),
1414 ("2.0.0", Some(">1.2.3 <2.0.0||>2.0.0")),
1415 ];
1416
1417 assert_ranges_match(base_range, samples);
1418 }
1419
1420 #[test]
1421 fn eq_123() {
1422 let base_range = v("1.2.3");
1423
1424 let samples = vec![
1425 ("<=2.0.0", None),
1426 ("<2.0.0", None),
1427 (">=2.0.0", Some("1.2.3")),
1428 (">2.0.0", Some("1.2.3")),
1429 (">1.0.0", None),
1430 (">1.2.3", Some("1.2.3")),
1431 ("1.2.3", None),
1432 ("<=1.2.3", None),
1433 ("1.1.1", Some("1.2.3")),
1434 ("<1.0.0", Some("1.2.3")),
1435 ("2.0.0", Some("1.2.3")),
1436 ];
1437
1438 assert_ranges_match(base_range, samples);
1439 }
1440
1441 #[test]
1442 fn lt_123() {
1443 let base_range = v("<1.2.3");
1444
1445 let samples = vec![
1446 ("<=2.0.0", None),
1447 ("<2.0.0", None),
1448 (">=2.0.0", Some("<1.2.3")),
1449 (">2.0.0", Some("<1.2.3")),
1450 (">1.0.0", Some("<=1.0.0")),
1451 (">1.2.3", Some("<1.2.3")),
1452 ("<=1.2.3", None),
1453 ("1.1.1", Some("<1.1.1||>1.1.1 <1.2.3")),
1454 ("<1.0.0", Some(">=1.0.0 <1.2.3")),
1455 ("2.0.0", Some("<1.2.3")),
1456 ];
1457
1458 assert_ranges_match(base_range, samples);
1459 }
1460
1461 #[test]
1462 fn lt_eq_123() {
1463 let base_range = v("<=1.2.3");
1464
1465 let samples = vec![
1466 ("<=2.0.0", None),
1467 ("<2.0.0", None),
1468 (">=2.0.0", Some("<=1.2.3")),
1469 (">2.0.0", Some("<=1.2.3")),
1470 (">1.0.0", Some("<=1.0.0")),
1471 (">1.2.3", Some("<=1.2.3")),
1472 ("<=1.2.3", None),
1473 ("1.1.1", Some("<1.1.1||>1.1.1 <=1.2.3")),
1474 ("<1.0.0", Some(">=1.0.0 <=1.2.3")),
1475 ("2.0.0", Some("<=1.2.3")),
1476 ];
1477
1478 assert_ranges_match(base_range, samples);
1479 }
1480
1481 #[test]
1482 fn multiple() {
1483 let base_range = v("<1 || 3 - 4");
1484
1485 let samples = vec![("0.5 - 3.5.0", Some("<0.5.0||>3.5.0 <5.0.0-0"))];
1486
1487 assert_ranges_match(base_range, samples);
1488 }
1489
1490 fn assert_ranges_match(base: Range, samples: Vec<(&'static str, Option<&'static str>)>) {
1491 for (other, expected) in samples {
1492 let other = v(other);
1493 let resulting_range = base.difference(&other).map(|v| v.to_string());
1494 assert_eq!(
1495 resulting_range.clone(),
1496 expected.map(|e| e.to_string()),
1497 "{} \\ {} := {}",
1498 base,
1499 other,
1500 resulting_range.unwrap_or_else(|| "⊗".into())
1501 );
1502 }
1503 }
1504}
1505
1506#[cfg(test)]
1507mod satisfies_ranges_tests {
1508 use super::*;
1509
1510 macro_rules! refute {
1511 ($e:expr) => {
1512 assert!(!$e)
1513 };
1514 ($e:expr, $msg:expr) => {
1515 assert!(!$e, $msg)
1516 };
1517 }
1518
1519 #[test]
1520 fn greater_than_equals() {
1521 let parsed = Range::parse(">=1.2.3").expect("unable to parse");
1522
1523 refute!(parsed.satisfies(&(0, 2, 3).into()), "major too low");
1524 refute!(parsed.satisfies(&(1, 1, 3).into()), "minor too low");
1525 refute!(parsed.satisfies(&(1, 2, 2).into()), "patch too low");
1526 assert!(parsed.satisfies(&(1, 2, 3).into()), "exact");
1527 assert!(parsed.satisfies(&(2, 2, 3).into()), "above");
1528 }
1529
1530 #[test]
1531 fn greater_than() {
1532 let parsed = Range::parse(">1.2.3").expect("unable to parse");
1533
1534 refute!(parsed.satisfies(&(0, 2, 3).into()), "major too low");
1535 refute!(parsed.satisfies(&(1, 1, 3).into()), "minor too low");
1536 refute!(parsed.satisfies(&(1, 2, 2).into()), "patch too low");
1537 refute!(parsed.satisfies(&(1, 2, 3).into()), "exact");
1538 assert!(parsed.satisfies(&(1, 2, 4).into()), "above");
1539 }
1540
1541 #[test]
1542 fn exact() {
1543 let parsed = Range::parse("=1.2.3").expect("unable to parse");
1544
1545 refute!(parsed.satisfies(&(1, 2, 2).into()), "patch too low");
1546 assert!(parsed.satisfies(&(1, 2, 3).into()), "exact");
1547 refute!(parsed.satisfies(&(1, 2, 4).into()), "above");
1548 }
1549
1550 #[test]
1551 fn less_than() {
1552 let parsed = Range::parse("<1.2.3").expect("unable to parse");
1553
1554 assert!(parsed.satisfies(&(0, 2, 3).into()), "major below");
1555 assert!(parsed.satisfies(&(1, 1, 3).into()), "minor below");
1556 assert!(parsed.satisfies(&(1, 2, 2).into()), "patch below");
1557 refute!(parsed.satisfies(&(1, 2, 3).into()), "exact");
1558 refute!(parsed.satisfies(&(1, 2, 4).into()), "above");
1559 }
1560
1561 #[test]
1562 fn less_than_equals() {
1563 let parsed = Range::parse("<=1.2.3").expect("unable to parse");
1564
1565 assert!(parsed.satisfies(&(0, 2, 3).into()), "major below");
1566 assert!(parsed.satisfies(&(1, 1, 3).into()), "minor below");
1567 assert!(parsed.satisfies(&(1, 2, 2).into()), "patch below");
1568 assert!(parsed.satisfies(&(1, 2, 3).into()), "exact");
1569 refute!(parsed.satisfies(&(1, 2, 4).into()), "above");
1570 }
1571
1572 #[test]
1573 fn less_than_equals_major() {
1574 let parsed = Range::parse("<=1").expect("unable to parse");
1575
1576 assert!(parsed.satisfies(&(0, 2, 3).into()), "major below");
1577 assert!(parsed.satisfies(&(1, 1, 3).into()), "minor below");
1578 assert!(parsed.satisfies(&(1, 2, 2).into()), "minor below");
1579 assert!(parsed.satisfies(&(1, 2, 3).into()), "minor below");
1580 assert!(parsed.satisfies(&(1, 2, 4).into()), "minor below");
1581 refute!(parsed.satisfies(&(2, 0, 0).into()), "above");
1582 }
1583
1584 #[test]
1585 fn less_than_equals_minor() {
1586 let parsed = Range::parse("<=1.2").expect("unable to parse");
1587
1588 assert!(parsed.satisfies(&(0, 2, 3).into()), "major below");
1589 assert!(parsed.satisfies(&(1, 1, 3).into()), "minor below");
1590 assert!(parsed.satisfies(&(1, 2, 1).into()), "patch below");
1591 assert!(parsed.satisfies(&(1, 2, 5).into()), "patch below");
1592 refute!(parsed.satisfies(&(1, 3, 0).into()), "above");
1593 }
1594
1595 #[test]
1596 fn only_major() {
1597 let parsed = Range::parse("1").expect("unable to parse");
1598
1599 refute!(parsed.satisfies(&(0, 2, 3).into()), "major below");
1600 assert!(parsed.satisfies(&(1, 0, 0).into()), "exact bottom of range");
1601 assert!(parsed.satisfies(&(1, 2, 2).into()), "middle");
1602 refute!(parsed.satisfies(&(2, 0, 0).into()), "exact top of range");
1603 refute!(parsed.satisfies(&(2, 7, 3).into()), "above");
1604 }
1605
1606 #[test]
1607 fn pre_release_version() {
1608 let range = Range::parse("^2").unwrap();
1609
1610 refute!(
1611 range.satisfies(&Version::parse("2.0.0-alpha.0").unwrap()),
1612 "below"
1613 );
1614 refute!(
1615 range.satisfies(&Version::parse("2.1.0-alpha.0").unwrap()),
1616 "above but pre-release"
1617 );
1618 }
1619
1620 #[test]
1621 fn pre_release_range() {
1622 let range = Range::parse("^1.2.3-rc.4").unwrap();
1623
1624 refute!(range.satisfies(&Version::parse("1.2.2").unwrap()), "below");
1625 assert!(
1626 range.satisfies(&Version::parse("1.2.3").unwrap()),
1627 "equal non-prerelease"
1628 );
1629 assert!(range.satisfies(&Version::parse("1.2.4").unwrap()), "above");
1630 }
1631
1632 #[test]
1633 fn pre_release_version_and_range() {
1634 let range = Range::parse("^1.2.3-rc.4").unwrap();
1635
1636 refute!(
1637 range.satisfies(&Version::parse("1.2.3-rc.3").unwrap()),
1638 "below"
1639 );
1640 assert!(
1641 range.satisfies(&Version::parse("1.2.3-rc.4").unwrap()),
1642 "equal"
1643 );
1644 assert!(
1645 range.satisfies(&Version::parse("1.2.3-rc.5").unwrap()),
1646 "above"
1647 );
1648 refute!(
1649 range.satisfies(&Version::parse("1.2.4-rc.6").unwrap()),
1650 "above patch but pre-release"
1651 );
1652 }
1653}
1654
1655#[cfg(test)]
1657mod tests {
1658 use super::*;
1659
1660 use pretty_assertions::assert_eq;
1661
1662 macro_rules! range_parse_tests {
1663 ($($name:ident => $vals:expr),+ ,$(,)?) => {
1664 $(
1665 #[test]
1666 fn $name() {
1667 let [input, expected] = $vals;
1668
1669 let parsed = Range::parse(input).expect("unable to parse");
1670
1671 assert_eq!(expected, parsed.to_string());
1672 }
1673 )+
1674 }
1675
1676 }
1677
1678 range_parse_tests![
1679 exact => ["1.0.0", "1.0.0"],
1681 major_minor_patch_range => ["1.0.0 - 2.0.0", ">=1.0.0 <=2.0.0"],
1682 only_major_versions => ["1 - 2", ">=1.0.0 <3.0.0-0"],
1683 only_major_and_minor => ["1.0 - 2.0", ">=1.0.0 <2.1.0-0"],
1684 mixed_major_minor => ["1.2 - 3.4.5", ">=1.2.0 <=3.4.5"],
1685 mixed_major_minor_2 => ["1.2.3 - 3.4", ">=1.2.3 <3.5.0-0"],
1686 minor_minor_range => ["1.2 - 3.4", ">=1.2.0 <3.5.0-0"],
1687 single_sided_only_major => ["1", ">=1.0.0 <2.0.0-0"],
1688 single_sided_lower_equals_bound => [">=1.0.0", ">=1.0.0"],
1689 single_sided_lower_equals_bound_2 => [">=0.1.97", ">=0.1.97"],
1690 single_sided_lower_bound => [">1.0.0", ">1.0.0"],
1691 single_sided_upper_equals_bound => ["<=2.0.0", "<=2.0.0"],
1692 single_sided_upper_equals_bound_with_minor => ["<=2.0", "<=2.0.900719925474099"],
1693 single_sided_upper_bound => ["<2.0.0", "<2.0.0"],
1694 major_and_minor => ["2.3", ">=2.3.0 <2.4.0-0"],
1695 major_dot_x => ["2.x", ">=2.0.0 <3.0.0-0"],
1696 x_and_asterisk_version => ["2.x.x", ">=2.0.0 <3.0.0-0"],
1697 patch_x => ["1.2.x", ">=1.2.0 <1.3.0-0"],
1698 minor_asterisk_patch_asterisk => ["2.*.*", ">=2.0.0 <3.0.0-0"],
1699 patch_asterisk => ["1.2.*", ">=1.2.0 <1.3.0-0"],
1700 caret_zero => ["^0", "<1.0.0-0"],
1701 caret_zero_minor => ["^0.1", ">=0.1.0 <0.2.0-0"],
1702 caret_one => ["^1.0", ">=1.0.0 <2.0.0-0"],
1703 caret_minor => ["^1.2", ">=1.2.0 <2.0.0-0"],
1704 caret_patch => ["^0.0.1", ">=0.0.1 <0.0.2-0"],
1705 caret_with_patch => ["^0.1.2", ">=0.1.2 <0.2.0-0"],
1706 caret_with_patch_2 => ["^1.2.3", ">=1.2.3 <2.0.0-0"],
1707 tilde_one => ["~1", ">=1.0.0 <2.0.0-0"],
1708 tilde_minor => ["~1.0", ">=1.0.0 <1.1.0-0"],
1709 tilde_minor_2 => ["~2.4", ">=2.4.0 <2.5.0-0"],
1710 tilde_with_greater_than_patch => ["~>3.2.1", ">=3.2.1 <3.3.0-0"],
1711 tilde_major_minor_zero => ["~1.1.0", ">=1.1.0 <1.2.0-0"],
1712 grater_than_equals_one => [">=1", ">=1.0.0"],
1713 greater_than_one => [">1", ">=2.0.0"],
1714 less_than_one_dot_two => ["<1.2", "<1.2.0-0"],
1715 greater_than_one_dot_two => [">1.2", ">=1.3.0"],
1716 greater_than_with_prerelease => [">1.1.0-beta-10", ">1.1.0-beta-10"],
1717 either_one_version_or_the_other => ["0.1.20 || 1.2.4", "0.1.20||1.2.4"],
1718 either_one_version_range_or_another => [">=0.2.3 || <0.0.1", ">=0.2.3||<0.0.1"],
1719 either_x_version_works => ["1.2.x || 2.x", ">=1.2.0 <1.3.0-0||>=2.0.0 <3.0.0-0"],
1720 either_asterisk_version_works => ["1.2.* || 2.*", ">=1.2.0 <1.3.0-0||>=2.0.0 <3.0.0-0"],
1721 one_two_three_or_greater_than_four => ["1.2.3 || >4", "1.2.3||>=5.0.0"],
1722 any_version_asterisk => ["*", ">=0.0.0"],
1723 any_version_x => ["x", ">=0.0.0"],
1724 whitespace_1 => [">= 1.0.0", ">=1.0.0"],
1725 whitespace_2 => [">= 1.0.0", ">=1.0.0"],
1726 whitespace_3 => [">= 1.0.0", ">=1.0.0"],
1727 whitespace_4 => ["> 1.0.0", ">1.0.0"],
1728 whitespace_5 => ["> 1.0.0", ">1.0.0"],
1729 whitespace_6 => ["<= 2.0.0", "<=2.0.0"],
1730 whitespace_7 => ["<= 2.0.0", "<=2.0.0"],
1731 whitespace_8 => ["<= 2.0.0", "<=2.0.0"],
1732 whitespace_9 => ["< 2.0.0", "<2.0.0"],
1733 whitespace_10 => ["<\t2.0.0", "<2.0.0"],
1734 whitespace_11 => ["^ 1", ">=1.0.0 <2.0.0-0"],
1735 whitespace_12 => ["~> 1", ">=1.0.0 <2.0.0-0"],
1736 whitespace_13 => ["~ 1.0", ">=1.0.0 <1.1.0-0"],
1737 beta => ["^0.0.1-beta", ">=0.0.1-beta <0.0.2-0"],
1738 beta_tilde => ["~1.2.3-beta", ">=1.2.3-beta <1.3.0-0"],
1739 beta_4 => ["^1.2.3-beta.4", ">=1.2.3-beta.4 <2.0.0-0"],
1740 pre_release_on_both => ["1.0.0-alpha - 2.0.0-beta", ">=1.0.0-alpha <=2.0.0-beta"],
1741 single_sided_lower_bound_with_pre_release => [">1.0.0-alpha", ">1.0.0-alpha"],
1742 space_separated1 => [">=1.2.3 <4.5.6", ">=1.2.3 <4.5.6"],
1743 garbage1 => ["1.2.3 foo", "1.2.3"],
1744 garbage2 => ["foo 1.2.3", "1.2.3"],
1745 garbage3 => ["~1.y 1.2.3", "1.2.3"],
1746 garbage4 => ["1.2.3 ~1.y", "1.2.3"],
1747 loose1 => [">01.02.03", ">1.2.3"],
1748 loose2 => ["~1.2.3beta", ">=1.2.3-beta <1.3.0-0"],
1749 caret_weird => ["^ 1.2 ^ 1", ">=1.2.0 <2.0.0-0"],
1750 loose_eq1 => ["=0.7", ">=0.7.0 <0.8.0-0"],
1751 loose_eq2 => ["=1", ">=1.0.0 <2.0.0-0"],
1752 consistent => ["^1.0.1", ">=1.0.1 <2.0.0-0"],
1753 consistent2 => [">=1.0.1 <2.0.0-0", ">=1.0.1 <2.0.0-0"],
1754 ];
1755
1756 }
1763
1764#[cfg(test)]
1765mod ranges {
1766 use super::*;
1767
1768 #[test]
1769 fn one() {
1770 let r = BoundSet::new(
1771 Bound::Lower(Predicate::Including((1, 2, 0).into())),
1772 Bound::Upper(Predicate::Excluding((3, 3, 4).into())),
1773 )
1774 .unwrap();
1775
1776 assert_eq!(r.to_string(), ">=1.2.0 <3.3.4")
1777 }
1778}
1779
1780#[cfg(test)]
1781mod max_satisfying {
1782 use super::*;
1783
1784 fn assert_max_satisfying(versions: Vec<&str>, range: &str, expected: &str) {
1785 let versions: Vec<_> = versions
1786 .into_iter()
1787 .map(|s| Version::parse(s).unwrap())
1788 .collect();
1789 let range = Range::parse(range).unwrap();
1790 let result = range.max_satisfying(&versions);
1791
1792 assert_eq!(
1793 result,
1794 Some(&Version::parse(expected).unwrap()),
1795 "expected: {}, got: {:?}",
1796 expected,
1797 result
1798 );
1799 }
1800
1801 #[test]
1802 fn test_max_satisfying() {
1803 let cases = vec![
1804 (vec!["1.2.3", "1.2.4"], "1.2", "1.2.4"),
1805 (vec!["1.2.4", "1.2.3"], "1.2", "1.2.4"),
1806 (vec!["1.2.3", "1.2.4", "1.2.5", "1.2.6"], "~1.2.3", "1.2.6"),
1807 (
1808 vec!["1.1.0", "1.2.0", "1.2.1", "1.3.0", "2.0.0", "2.1.0"],
1809 "~2.0.0",
1810 "2.0.0",
1811 ),
1812 ];
1813
1814 for case in cases {
1815 assert_max_satisfying(case.0, case.1, case.2);
1816 }
1817 }
1818
1819 #[test]
1820 fn test_max_satisfying_empty() {
1821 let range = Range::parse("~1.2.3").unwrap();
1822 let versions = vec![];
1823 let result = range.max_satisfying(&versions);
1824
1825 assert_eq!(result, None);
1826 }
1827
1828 #[test]
1829 fn test_max_satisfying_none() {
1830 let range = Range::parse(">=1.0.0 <2.0.0").unwrap();
1831 let versions: Vec<_> = vec!["2.0.0", "0.1.0"]
1832 .iter()
1833 .map(|s| Version::parse(s).unwrap())
1834 .collect();
1835 let result = range.max_satisfying(&versions);
1836
1837 assert_eq!(result, None);
1838 }
1839}
1840
1841#[cfg(test)]
1842mod min_satisfying {
1843 use super::*;
1844
1845 fn assert_min_satisfying(versions: Vec<&str>, range: &str, expected: &str) {
1846 let versions: Vec<_> = versions
1847 .into_iter()
1848 .map(|s| Version::parse(s).unwrap())
1849 .collect();
1850 let range = Range::parse(range).unwrap();
1851 let result = range.min_satisfying(&versions);
1852
1853 assert_eq!(
1854 result,
1855 Some(&Version::parse(expected).unwrap()),
1856 "expected: {}, got: {:?}",
1857 expected,
1858 result
1859 );
1860 }
1861
1862 #[test]
1863 fn test_min_satisfying() {
1864 let cases = vec![
1865 (vec!["1.2.3", "1.2.4"], "1.2", "1.2.3"),
1866 (vec!["1.2.4", "1.2.3"], "1.2", "1.2.3"),
1867 (vec!["1.2.3", "1.2.4", "1.2.5", "1.2.6"], "~1.2.3", "1.2.3"),
1868 (
1869 vec!["1.1.0", "1.2.0", "1.2.1", "1.3.0", "2.0.0", "2.1.0"],
1870 "~2.0.0",
1871 "2.0.0",
1872 ),
1873 ];
1874
1875 for case in cases {
1876 assert_min_satisfying(case.0, case.1, case.2);
1877 }
1878 }
1879
1880 #[test]
1881 fn test_min_satisfying_empty() {
1882 let range = Range::parse("~1.2.3").unwrap();
1883 let versions = vec![];
1884 let result = range.min_satisfying(&versions);
1885
1886 assert_eq!(result, None);
1887 }
1888
1889 #[test]
1890 fn test_min_satisfying_none() {
1891 let range = Range::parse(">=1.0.0 <2.0.0").unwrap();
1892 let versions: Vec<_> = vec!["2.0.0", "0.1.0"]
1893 .iter()
1894 .map(|s| Version::parse(s).unwrap())
1895 .collect();
1896 let result = range.min_satisfying(&versions);
1897
1898 assert_eq!(result, None);
1899 }
1900}
1901
1902#[cfg(test)]
1903mod min_version {
1904 use super::*;
1905
1906 #[test]
1907 fn min_version_test() {
1908 let tests = vec![
1910 ("*", Some("0.0.0")),
1912 ("* || >=2", Some("0.0.0")),
1913 (">=2 || *", Some("0.0.0")),
1914 (">2 || *", Some("0.0.0")),
1915 ("1.0.0", Some("1.0.0")),
1917 ("1.0", Some("1.0.0")),
1918 ("1.0.x", Some("1.0.0")),
1919 ("1.0.*", Some("1.0.0")),
1920 ("1", Some("1.0.0")),
1921 ("1.x.x", Some("1.0.0")),
1922 ("1.x.x", Some("1.0.0")),
1923 ("1.*.x", Some("1.0.0")),
1924 ("1.x.*", Some("1.0.0")),
1925 ("1.x", Some("1.0.0")),
1926 ("1.*", Some("1.0.0")),
1927 ("=1.0.0", Some("1.0.0")),
1928 ("~1.1.1", Some("1.1.1")),
1930 ("~1.1.1-beta", Some("1.1.1-beta")),
1931 ("~1.1.1 || >=2", Some("1.1.1")),
1932 ("^1.1.1", Some("1.1.1")),
1934 ("^1.1.1-beta", Some("1.1.1-beta")),
1935 ("^1.1.1 || >=2", Some("1.1.1")),
1936 ("^2.16.2 ^2.16", Some("2.16.2")),
1937 ("1.1.1 - 1.8.0", Some("1.1.1")),
1939 ("1.1 - 1.8.0", Some("1.1.0")),
1940 ("<2", Some("0.0.0")),
1942 ("<0.0.0-beta", Some("0.0.0-0")),
1943 ("<0.0.1-beta", Some("0.0.0")),
1944 ("<2 || >4", Some("0.0.0")),
1945 (">4 || <2", Some("0.0.0")),
1946 ("<=2 || >=4", Some("0.0.0")),
1947 (">=4 || <=2", Some("0.0.0")),
1948 ("<0.0.0-beta >0.0.0-alpha", Some("0.0.0-alpha.0")),
1949 (">0.0.0-alpha <0.0.0-beta", Some("0.0.0-alpha.0")),
1950 (">=1.1.1 <2 || >=2.2.2 <3", Some("1.1.1")),
1952 (">=2.2.2 <3 || >=1.1.1 <2", Some("1.1.1")),
1953 (">1.0.0", Some("1.0.1")),
1955 (">1.0.0-0", Some("1.0.0-0.0")),
1956 (">1.0.0-beta", Some("1.0.0-beta.0")),
1957 (">2 || >1.0.0", Some("1.0.1")),
1958 (">2 || >1.0.0-0", Some("1.0.0-0.0")),
1959 (">2 || >1.0.0-beta", Some("1.0.0-beta.0")),
1960 ];
1961
1962 for (range, version) in tests {
1963 let parsed_range = Range::parse(range).unwrap();
1964 let parsed_version = version.map(|v| Version::parse(v).unwrap());
1965 assert_eq!(
1966 parsed_range.min_version(),
1967 parsed_version,
1968 "expected min_version of {:?} to be {:?}",
1969 range,
1970 version
1971 );
1972 }
1973 }
1974}
1975
1976#[cfg(feature = "serde")]
1977#[cfg(test)]
1978mod serde_tests {
1979 use super::*;
1980
1981 #[test]
1982 fn test_serialize() {
1983 let range = Range::parse("~1.2.3").unwrap();
1984 let serialized = serde_json::to_string(&range).unwrap();
1985 let deserialized: Range = serde_json::from_str(&serialized).unwrap();
1986
1987 assert_eq!(range, deserialized);
1988 }
1989}