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