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