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