1use std::cmp::{Ord, Ordering, PartialOrd};
2use std::convert::TryFrom;
3use std::fmt;
4use std::ops::Deref;
5
6#[cfg(feature = "serde")]
7use serde::{Deserialize, Serialize, de::Deserializer, ser::Serializer};
8use smallvec::SmallVec;
9use thiserror::Error;
10
11use crate::{Identifier, SemverError, Version, scan};
12
13mod fast;
14mod loose;
15
16fn should_skip_range_fallback(input: &str) -> bool {
19 !starts_with_range_token(input) && is_single_token(input)
20}
21
22fn starts_with_range_token(input: &str) -> bool {
23 input
24 .as_bytes()
25 .first()
26 .is_some_and(|ch| is_possible_range_token(*ch))
27}
28
29fn is_possible_range_token(ch: u8) -> bool {
30 matches!(
31 ch,
32 b'0'..=b'9' | b'v' | b'V' | b'x' | b'X' | b'*' | b'>' | b'<' | b'=' | b'^' | b'~'
33 )
34}
35
36fn is_single_token(input: &str) -> bool {
37 let mut previous_was_pipe = false;
38 for (i, &ch) in input.as_bytes().iter().enumerate() {
39 let is_pipe = ch == b'|';
40 if (is_pipe && previous_was_pipe)
41 || (scan::may_start_whitespace(ch) && scan::whitespace_len(input, i) > 0)
42 {
43 return false;
44 }
45 previous_was_pipe = is_pipe;
46 }
47 true
48}
49
50fn trim_range_edges_if_needed(input: &str) -> &str {
52 let bytes = input.as_bytes();
53 let (Some(first), Some(last)) = (bytes.first(), bytes.last()) else {
54 return input;
55 };
56
57 if scan::may_start_whitespace(*first) || scan::may_start_whitespace(*last) {
58 trim_range_edges(input)
59 } else {
60 input
61 }
62}
63
64#[cold]
65#[inline(never)]
66fn trim_range_edges(input: &str) -> &str {
67 scan::trim(input)
68}
69
70fn is_empty_range(input: &str) -> bool {
73 match input.as_bytes().first() {
74 None => true,
75 Some(b'|') => is_empty_or_range(input),
76 Some(_) => false,
77 }
78}
79
80#[cold]
81#[inline(never)]
82fn is_empty_or_range(input: &str) -> bool {
83 input.split("||").all(|part| scan::trim(part).is_empty())
84}
85
86#[derive(Clone, Debug, Eq, PartialEq, Hash)]
87struct BoundSet {
88 bounds: Box<BoundPair>,
89}
90
91#[derive(Clone, Debug, Eq, PartialEq, Hash)]
92struct BoundPair {
93 upper: Bound,
94 lower: Bound,
95}
96
97impl Deref for BoundSet {
98 type Target = BoundPair;
99
100 fn deref(&self) -> &Self::Target {
101 self.bounds.as_ref()
102 }
103}
104
105impl BoundSet {
106 fn new(lower: Bound, upper: Bound) -> Option<Self> {
107 use Bound::*;
108 use Predicate::*;
109
110 match (lower, upper) {
111 (Lower(Excluding(v1)), Upper(Including(v2)))
112 | (Lower(Including(v1)), Upper(Excluding(v2)))
113 if v1 == v2 =>
114 {
115 None
116 }
117 (Lower(Including(v1)), Upper(Including(v2))) if v1 == v2 => Some(Self {
118 bounds: Box::new(BoundPair {
119 lower: Lower(Including(v1)),
120 upper: Upper(Including(v2)),
121 }),
122 }),
123 (lower, upper) if lower < upper => Some(Self {
124 bounds: Box::new(BoundPair { lower, upper }),
125 }),
126 _ => None,
127 }
128 }
129
130 fn at_least(p: Predicate) -> Option<Self> {
131 BoundSet::new(Bound::Lower(p), Bound::upper())
132 }
133
134 fn at_most(p: Predicate) -> Option<Self> {
135 BoundSet::new(Bound::lower(), Bound::Upper(p))
136 }
137
138 fn exact(version: Version) -> Option<Self> {
139 BoundSet::new(
140 Bound::Lower(Predicate::Including(version.clone())),
141 Bound::Upper(Predicate::Including(version)),
142 )
143 }
144
145 fn satisfies(&self, version: &Version, include_prerelease: bool) -> bool {
146 use Bound::*;
147 use Predicate::*;
148
149 let lower_bound = match &self.lower {
150 Lower(Including(lower)) => lower <= version,
151 Lower(Excluding(lower)) => lower < version,
152 Lower(Unbounded) => true,
153 _ => unreachable!(
154 "There should not have been an upper bound: {:#?}",
155 self.lower
156 ),
157 };
158
159 let upper_bound = match &self.upper {
160 Upper(Including(upper)) => version <= upper,
161 Upper(Excluding(upper)) => version < upper,
162 Upper(Unbounded) => true,
163 _ => unreachable!(
164 "There should not have been an lower bound: {:#?}",
165 self.lower
166 ),
167 };
168
169 if !lower_bound || !upper_bound {
170 return false;
171 }
172
173 if version.is_prerelease() && !include_prerelease {
174 let lower_version = match &self.lower {
175 Lower(Including(v)) => Some(v),
176 Lower(Excluding(v)) => Some(v),
177 _ => None,
178 };
179 if let Some(lower_version) = lower_version {
180 if lower_version.is_prerelease()
181 && version.major == lower_version.major
182 && version.minor == lower_version.minor
183 && version.patch == lower_version.patch
184 {
185 return true;
186 }
187 }
188
189 let upper_version = match &self.upper {
190 Upper(Including(v)) => Some(v),
191 Upper(Excluding(v)) => Some(v),
192 _ => None,
193 };
194 if let Some(upper_version) = upper_version {
195 if upper_version.is_prerelease()
196 && version.major == upper_version.major
197 && version.minor == upper_version.minor
198 && version.patch == upper_version.patch
199 {
200 return true;
201 }
202 }
203
204 return false;
205 }
206
207 true
208 }
209
210 fn allows_all(&self, other: &BoundSet) -> bool {
211 self.lower <= other.lower && other.upper <= self.upper
212 }
213
214 fn allows_any(&self, other: &BoundSet) -> bool {
215 if other.upper < self.lower {
216 return false;
217 }
218
219 if self.upper < other.lower {
220 return false;
221 }
222
223 true
224 }
225
226 fn intersect(&self, other: &Self) -> Option<Self> {
227 let lower: &Bound = std::cmp::max(&self.lower, &other.lower);
228 let upper: &Bound = std::cmp::min(&self.upper, &other.upper);
229
230 BoundSet::new(lower.clone(), upper.clone())
231 }
232
233 fn difference(&self, other: &Self) -> Option<Vec<Self>> {
234 use Bound::*;
235
236 if let Some(overlap) = self.intersect(other) {
237 if &overlap == self {
238 return None;
239 }
240
241 if self.lower < overlap.lower && overlap.upper < self.upper {
242 return Some(vec![
243 BoundSet::new(
244 self.lower.clone(),
245 Upper(overlap.lower.clone().predicate().flip()),
246 )
247 .unwrap(),
248 BoundSet::new(
249 Lower(overlap.upper.clone().predicate().flip()),
250 self.upper.clone(),
251 )
252 .unwrap(),
253 ]);
254 }
255
256 if self.lower < overlap.lower {
257 return BoundSet::new(
258 self.lower.clone(),
259 Upper(overlap.lower.clone().predicate().flip()),
260 )
261 .map(|f| vec![f]);
262 }
263
264 BoundSet::new(
265 Lower(overlap.upper.clone().predicate().flip()),
266 self.upper.clone(),
267 )
268 .map(|f| vec![f])
269 } else {
270 Some(vec![self.clone()])
271 }
272 }
273
274 fn comparators(&self) -> impl Iterator<Item = Comparator> + '_ {
275 ComparatorIter::new(self)
276 }
277}
278
279impl fmt::Display for BoundSet {
280 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
281 use Bound::*;
282 use Predicate::*;
283 match (&self.lower, &self.upper) {
284 (Lower(Unbounded), Upper(Unbounded)) => write!(f, "*"),
285 (Lower(Unbounded), Upper(Including(v))) => write!(f, "<={}", v),
286 (Lower(Unbounded), Upper(Excluding(v))) => write!(f, "<{}", v),
287 (Lower(Including(v)), Upper(Unbounded)) => write!(f, ">={}", v),
288 (Lower(Excluding(v)), Upper(Unbounded)) => write!(f, ">{}", v),
289 (Lower(Including(v)), Upper(Including(v2))) if v == v2 => write!(f, "{}", v),
290 (Lower(Including(v)), Upper(Including(v2))) => write!(f, ">={} <={}", v, v2),
291 (Lower(Including(v)), Upper(Excluding(v2))) => write!(f, ">={} <{}", v, v2),
292 (Lower(Excluding(v)), Upper(Including(v2))) => write!(f, ">{} <={}", v, v2),
293 (Lower(Excluding(v)), Upper(Excluding(v2))) => write!(f, ">{} <{}", v, v2),
294 _ => unreachable!("does not make sense"),
295 }
296 }
297}
298
299#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
300enum Operation {
301 Exact,
302 GreaterThan,
303 GreaterThanEquals,
304 LessThan,
305 LessThanEquals,
306}
307
308#[derive(Debug, Clone, Eq, PartialEq, Hash)]
309enum Predicate {
310 Excluding(Version), Including(Version), Unbounded, }
314
315impl Predicate {
316 fn flip(self) -> Self {
317 use Predicate::*;
318 match self {
319 Excluding(v) => Including(v),
320 Including(v) => Excluding(v),
321 Unbounded => Unbounded,
322 }
323 }
324}
325
326#[derive(Debug, Clone, Eq, PartialEq, Hash)]
327enum Bound {
328 Lower(Predicate),
329 Upper(Predicate),
330}
331
332impl Bound {
333 fn upper() -> Self {
334 Bound::Upper(Predicate::Unbounded)
335 }
336
337 fn lower() -> Self {
338 Bound::Lower(Predicate::Unbounded)
339 }
340
341 fn predicate(self) -> Predicate {
342 use Bound::*;
343
344 match self {
345 Lower(p) => p,
346 Upper(p) => p,
347 }
348 }
349
350 fn rank(&self) -> (&Version, i8) {
351 use Bound::*;
352 use Predicate::*;
353
354 match self {
355 Upper(Excluding(v)) => (v, 0),
356 Lower(Including(v)) => (v, 1),
357 Upper(Including(v)) => (v, 2),
358 Lower(Excluding(v)) => (v, 3),
359 Lower(Unbounded) | Upper(Unbounded) => {
360 unreachable!("cannot rank unbounded bounds")
361 }
362 }
363 }
364}
365
366impl Ord for Bound {
367 fn cmp(&self, other: &Self) -> Ordering {
368 use Bound::*;
369 use Predicate::*;
370
371 match (self, other) {
372 (Lower(Unbounded), Lower(Unbounded)) | (Upper(Unbounded), Upper(Unbounded)) => {
373 Ordering::Equal
374 }
375 (Lower(Unbounded), _) => Ordering::Less,
376 (_, Lower(Unbounded)) => Ordering::Greater,
377 (Upper(Unbounded), _) => Ordering::Greater,
378 (_, Upper(Unbounded)) => Ordering::Less,
379 _ => {
380 let (self_version, self_rank) = self.rank();
381 let (other_version, other_rank) = other.rank();
382
383 match self_version.cmp(other_version) {
384 Ordering::Equal => self_rank.cmp(&other_rank),
385 ord => ord,
386 }
387 }
388 }
389 }
390}
391
392impl PartialOrd for Bound {
393 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
394 Some(self.cmp(other))
395 }
396}
397
398#[derive(Clone, Debug)]
399struct Comparator {
400 op: Operation,
401 version: Version,
402}
403
404struct ComparatorIter {
405 state: ComparatorIterState,
406}
407
408enum ComparatorIterState {
409 Exact(Option<Comparator>),
410 Pair {
411 items: [Option<Comparator>; 2],
412 index: usize,
413 },
414 Fallback(Option<Comparator>),
415 Done,
416}
417
418impl ComparatorIter {
419 fn new(bound_set: &BoundSet) -> Self {
420 match (&bound_set.lower, &bound_set.upper) {
421 (Bound::Lower(Predicate::Including(low)), Bound::Upper(Predicate::Including(high)))
422 if low == high =>
423 {
424 return Self {
425 state: ComparatorIterState::Exact(Some(Comparator {
426 op: Operation::Exact,
427 version: low.clone(),
428 })),
429 };
430 }
431 _ => {}
432 }
433
434 let upper = Comparator::from_bound(&bound_set.upper);
435 let lower = Comparator::from_bound(&bound_set.lower);
436
437 if upper.is_none() && lower.is_none() {
438 return Self {
439 state: ComparatorIterState::Fallback(Some(Comparator {
440 op: Operation::GreaterThanEquals,
441 version: Version::from((0, 0, 0)),
442 })),
443 };
444 }
445
446 Self {
447 state: ComparatorIterState::Pair {
448 items: [upper, lower],
449 index: 0,
450 },
451 }
452 }
453}
454
455impl Iterator for ComparatorIter {
456 type Item = Comparator;
457
458 fn next(&mut self) -> Option<Self::Item> {
459 use ComparatorIterState::*;
460
461 match &mut self.state {
462 Exact(opt) => {
463 let next = opt.take();
464 if next.is_none() {
465 self.state = Done;
466 }
467 next
468 }
469 Pair { items, index } => {
470 while *index < items.len() {
471 let candidate = items[*index].take();
472 *index += 1;
473 if candidate.is_some() {
474 return candidate;
475 }
476 }
477 self.state = Done;
478 None
479 }
480 Fallback(opt) => {
481 let next = opt.take();
482 if next.is_none() {
483 self.state = Done;
484 }
485 next
486 }
487 Done => None,
488 }
489 }
490}
491
492impl Comparator {
493 fn from_bound(bound: &Bound) -> Option<Self> {
494 match bound {
495 Bound::Lower(Predicate::Including(v)) => Some(Self {
496 op: Operation::GreaterThanEquals,
497 version: v.clone(),
498 }),
499 Bound::Lower(Predicate::Excluding(v)) => Some(Self {
500 op: Operation::GreaterThan,
501 version: v.clone(),
502 }),
503 Bound::Upper(Predicate::Including(v)) => Some(Self {
504 op: Operation::LessThanEquals,
505 version: v.clone(),
506 }),
507 Bound::Upper(Predicate::Excluding(v)) => Some(Self {
508 op: Operation::LessThan,
509 version: v.clone(),
510 }),
511 Bound::Lower(Predicate::Unbounded) | Bound::Upper(Predicate::Unbounded) => None,
512 }
513 }
514}
515
516#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
518pub enum OutsideDirection {
519 Higher,
521 Lower,
523}
524
525impl TryFrom<char> for OutsideDirection {
526 type Error = RangeError;
527
528 fn try_from(value: char) -> Result<Self, Self::Error> {
529 match value {
530 '>' => Ok(Self::Higher),
531 '<' => Ok(Self::Lower),
532 other => Err(RangeError::InvalidOutsideDirection(other)),
533 }
534 }
535}
536
537#[derive(Debug, Clone, Copy, Error, Eq, PartialEq)]
539pub enum RangeError {
540 #[error(
541 "outside() only supports checking whether a version is above or below a range, found `{0}`"
542 )]
543 InvalidOutsideDirection(char),
544 #[error("outside() could not determine comparator bounds for this range")]
545 MissingComparatorBounds,
546}
547
548#[derive(Clone, Debug, Eq, PartialEq, Hash)]
557pub struct Range(SmallVec<[BoundSet; 1]>);
558
559impl fmt::Display for OutsideDirection {
560 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
561 match self {
562 OutsideDirection::Higher => write!(f, ">"),
563 OutsideDirection::Lower => write!(f, "<"),
564 }
565 }
566}
567
568#[cfg(feature = "serde")]
569impl Serialize for Range {
570 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
571 s.collect_str(self)
572 }
573}
574
575#[cfg(feature = "serde")]
576impl<'de> Deserialize<'de> for Range {
577 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
578 let s = String::deserialize(d)?;
579 s.parse().map_err(serde::de::Error::custom)
580 }
581}
582
583impl Range {
584 fn from_bound_set(bound_set: BoundSet) -> Self {
585 let mut bound_sets = SmallVec::new();
586 bound_sets.push(bound_set);
587 Self(bound_sets)
588 }
589
590 fn from_bound_sets(bound_sets: Vec<BoundSet>) -> Option<Self> {
591 (!bound_sets.is_empty()).then(|| Self(SmallVec::from_vec(bound_sets)))
592 }
593
594 fn append_bound_sets_to(self, bound_sets: &mut Vec<BoundSet>) {
595 bound_sets.extend(self.0);
596 }
597
598 fn iter(&self) -> std::slice::Iter<'_, BoundSet> {
599 self.0.iter()
600 }
601
602 pub fn parse<S: AsRef<str>>(input: S) -> Result<Self, SemverError> {
606 let input = trim_range_edges_if_needed(input.as_ref());
607
608 if is_empty_range(input) {
609 return Ok(Self::any());
610 }
611
612 if let Some(range) = fast::parse(input) {
613 return Ok(range);
614 }
615
616 if should_skip_range_fallback(input) {
617 return Err(SemverError);
618 }
619
620 loose::parse(input).ok_or(SemverError)
621 }
622
623 pub fn any() -> Self {
627 Self::from_bound_set(BoundSet::new(Bound::lower(), Bound::upper()).unwrap())
628 }
629
630 pub fn satisfies(&self, version: &Version) -> bool {
634 self.satisfies_with_prerelease(version, false)
635 }
636
637 pub fn satisfies_with_prerelease(&self, version: &Version, include_prerelease: bool) -> bool {
644 self.0
645 .iter()
646 .any(|range| range.satisfies(version, include_prerelease))
647 }
648
649 pub fn allows_all(&self, other: &Range) -> bool {
653 for this in self.iter() {
654 for that in other.iter() {
655 if this.allows_all(that) {
656 return true;
657 }
658 }
659 }
660
661 false
662 }
663
664 pub fn allows_any(&self, other: &Range) -> bool {
668 for this in self.iter() {
669 for that in other.iter() {
670 if this.allows_any(that) {
671 return true;
672 }
673 }
674 }
675
676 false
677 }
678
679 pub fn intersect(&self, other: &Self) -> Option<Self> {
683 let mut sets = Vec::new();
684
685 for lefty in self.iter() {
686 for righty in other.iter() {
687 if let Some(set) = lefty.intersect(righty) {
688 sets.push(set)
689 }
690 }
691 }
692
693 Self::from_bound_sets(sets)
694 }
695
696 pub fn difference(&self, other: &Self) -> Option<Self> {
700 let mut predicates = Vec::new();
701
702 for lefty in self.iter() {
703 for righty in other.iter() {
704 if let Some(mut range) = lefty.difference(righty) {
705 predicates.append(&mut range)
706 }
707 }
708 }
709
710 Self::from_bound_sets(predicates)
711 }
712
713 #[doc = include_str!("../examples/max_satisfying.rs")]
718 pub fn max_satisfying<'v>(&self, versions: &'v [Version]) -> Option<&'v Version> {
720 versions.iter().filter(|v| self.satisfies(v)).max()
721 }
722
723 #[doc = include_str!("../examples/min_satisfying.rs")]
728 pub fn min_satisfying<'v>(&self, versions: &'v [Version]) -> Option<&'v Version> {
730 versions.iter().filter(|v| self.satisfies(v)).min()
731 }
732
733 pub fn min_version(&self) -> Option<Version> {
737 if let Some(min_bound) = self.iter().map(|range| &range.lower).min() {
738 match min_bound {
739 Bound::Lower(pred) => match pred {
740 Predicate::Including(v) => Some(v.clone()),
741 Predicate::Excluding(v) => {
742 let mut v = v.clone();
743 if v.is_prerelease() {
744 v.push_pre_release(Identifier::Numeric(0))
745 } else {
746 v.patch += 1;
747 }
748 Some(v)
749 }
750 Predicate::Unbounded => {
751 let mut zero = Version::from((0, 0, 0));
752 if self.satisfies(&zero) {
753 return Some(zero);
754 }
755
756 zero.push_pre_release(Identifier::Numeric(0));
757 if self.satisfies(&zero) {
758 return Some(zero);
759 }
760 None
761 }
762 },
763 Bound::Upper(_) => None,
764 }
765 } else {
766 None
767 }
768 }
769
770 #[inline]
771 fn outside_higher(
772 &self,
773 version: &Version,
774 include_prerelease: bool,
775 ) -> Result<bool, RangeError> {
776 if self.satisfies_with_prerelease(version, include_prerelease) {
777 return Ok(false);
778 }
779
780 for range in self.iter() {
781 let mut high: Option<Comparator> = None;
782 let mut low: Option<Comparator> = None;
783
784 for comparator in range.comparators() {
785 if high.as_ref().is_none_or(|h| comparator.version > h.version) {
786 high = Some(comparator.clone());
787 }
788
789 if low.as_ref().is_none_or(|l| comparator.version < l.version) {
790 low = Some(comparator);
791 }
792 }
793
794 let (Some(high), Some(low)) = (high.as_ref(), low.as_ref()) else {
795 return Err(RangeError::MissingComparatorBounds);
796 };
797
798 if matches!(
799 high.op,
800 Operation::GreaterThan | Operation::GreaterThanEquals
801 ) {
802 return Ok(false);
803 }
804
805 let low_is_empty = matches!(low.op, Operation::Exact);
806
807 if ((low_is_empty || matches!(low.op, Operation::GreaterThan))
808 && version <= &low.version)
809 || (matches!(low.op, Operation::GreaterThanEquals) && version < &low.version)
810 {
811 return Ok(false);
812 }
813 }
814
815 Ok(true)
816 }
817
818 #[inline]
819 fn outside_lower(
820 &self,
821 version: &Version,
822 include_prerelease: bool,
823 ) -> Result<bool, RangeError> {
824 if self.satisfies_with_prerelease(version, include_prerelease) {
825 return Ok(false);
826 }
827
828 for range in self.iter() {
829 let mut high: Option<Comparator> = None;
830 let mut low: Option<Comparator> = None;
831
832 for comparator in range.comparators() {
833 if high.as_ref().is_none_or(|h| comparator.version < h.version) {
834 high = Some(comparator.clone());
835 }
836
837 if low.as_ref().is_none_or(|l| comparator.version > l.version) {
838 low = Some(comparator);
839 }
840 }
841
842 let (Some(high), Some(low)) = (high.as_ref(), low.as_ref()) else {
843 return Err(RangeError::MissingComparatorBounds);
844 };
845
846 if matches!(high.op, Operation::LessThan | Operation::LessThanEquals) {
847 return Ok(false);
848 }
849
850 let low_is_empty = matches!(low.op, Operation::Exact);
851
852 if ((low_is_empty || matches!(low.op, Operation::LessThan)) && version >= &low.version)
853 || (matches!(low.op, Operation::LessThanEquals) && version > &low.version)
854 {
855 return Ok(false);
856 }
857 }
858
859 Ok(true)
860 }
861
862 pub fn outside(
875 &self,
876 version: &Version,
877 direction: OutsideDirection,
878 include_prerelease: bool,
879 ) -> Result<bool, RangeError> {
880 match direction {
881 OutsideDirection::Higher => self.outside_higher(version, include_prerelease),
882 OutsideDirection::Lower => self.outside_lower(version, include_prerelease),
883 }
884 }
885}
886
887impl fmt::Display for Range {
888 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
889 for (i, range) in self.iter().enumerate() {
890 if i > 0 {
891 write!(f, "||")?;
892 }
893 write!(f, "{}", range)?;
894 }
895 Ok(())
896 }
897}
898
899impl std::str::FromStr for Range {
900 type Err = SemverError;
901 fn from_str(s: &str) -> Result<Self, Self::Err> {
902 Range::parse(s)
903 }
904}
905
906macro_rules! create_tests_for {
907 ($func:ident $($name:ident => $version_range:expr , { $x:ident => $allows:expr, $y:ident => $denies:expr$(,)? }),+ ,$(,)?) => {
908
909 #[cfg(test)]
910 mod $func {
911 use super::*;
912
913 $(
914 #[test]
915 fn $name() {
916 let version_range = Range::parse($version_range).unwrap();
917
918 let allows: Vec<Range> = $allows.iter().map(|v| Range::parse(v).unwrap()).collect();
919 for version in &allows {
920 assert!(version_range.$func(version), "should have allowed: {}", version);
921 }
922
923 let ranges: Vec<Range> = $denies.iter().map(|v| Range::parse(v).unwrap()).collect();
924 for version in &ranges {
925 assert!(!version_range.$func(version), "should have denied: {}", version);
926 }
927 }
928 )+
929 }
930 }
931}
932
933create_tests_for! {
934 allows_all
936
937 greater_than_eq_123 => ">=1.2.3", {
938 allows => [">=2.0.0", ">2", "2.0.0", "0.1 || 1.4", "1.2.3", "2 - 7", ">2.0.0"],
939 denies => ["1.0.0", "<1.2", ">=1.2.2", "1 - 3", "0.1 || <1.2.0", ">1.0.0"],
940 },
941
942 greater_than_123 => ">1.2.3", {
943 allows => [">=2.0.0", ">2", "2.0.0", "0.1 || 1.4", ">2.0.0"],
944 denies => ["1.0.0", "<1.2", ">=1.2.3", "1 - 3", "0.1 || <1.2.0", "<=3"],
945 },
946
947 eq_123 => "1.2.3", {
948 allows => ["1.2.3"],
949 denies => ["1.0.0", "<1.2", "1.x", ">=1.2.2", "1 - 3", "0.1 || <1.2.0"],
950 },
951
952 lt_123 => "<1.2.3", {
953 allows => ["<=1.2.0", "<1", "1.0.0", "0.1 || 1.4"],
954 denies => ["1 - 3", ">1", "2.0.0", "2.0 || >9", ">1.0.0"],
955 },
956
957 lt_eq_123 => "<=1.2.3", {
958 allows => ["<=1.2.0", "<1", "1.0.0", "0.1 || 1.4", "1.2.3"],
959 denies => ["1 - 3", ">1.0.0", ">=1.0.0"],
960 },
961
962 eq_123_or_gt_400 => "1.2.3 || >4", {
963 allows => [ "1.2.3", ">4", "5.x", "5.2.x", ">=8.2.1", "2.0 || 5.6.7"],
964 denies => ["<2", "1 - 7", "1.9.4 || 2 - 3"],
965 },
966
967 between_two_and_eight => "2 - 8", {
968 allows => [ "2.2.3", "4 - 5"],
969 denies => ["1 - 4", "5 - 9", ">3", "<=5"],
970 },
971}
972
973create_tests_for! {
974 allows_any
976
977 greater_than_eq_123 => ">=1.2.3", {
978 allows => ["<=1.2.4", "3.0.0", "<2", ">=3", ">3.0.0"],
979 denies => ["<=1.2.0", "1.0.0", "<1"],
980 },
981
982 greater_than_123 => ">1.2.3", {
983 allows => ["<=1.2.4", "3.0.0", "<2", ">=3", ">3.0.0"],
984 denies => ["<=1.2.3", "1.0.0", "<1"],
985 },
986
987 eq_123 => "1.2.3", {
988 allows => ["1.2.3", "1 - 2"],
989 denies => ["<1.2.3", "1.0.0", ">4.5.6", ">5"],
990 },
991
992 lt_eq_123 => "<=1.2.3", {
993 allows => ["<=1.2.0", "<1.0.0", "1.0.0", ">1.0.0", ">=1.2.0"],
994 denies => ["4.5.6", ">2.0.0", ">=2.0.0"],
995 },
996
997 lt_123 => "<1.2.3", {
998 allows => ["<=2.2.0", "<2.0.0", "1.0.0", ">1.0.0", ">=1.2.0"],
999 denies => ["2.0.0", ">1.8.0", ">=1.8.0"],
1000 },
1001
1002 between_two_and_eight => "2 - 8", {
1003 allows => ["2.2.3", "4 - 10", ">4", ">4.0.0", "<=4.0.0", "<9.1.2"],
1004 denies => [">10", "10 - 11", "0 - 1"],
1005 },
1006
1007 eq_123_or_gt_400 => "1.2.3 || >4", {
1008 allows => [ "1.2.3", ">3", "5.x", "5.2.x", ">=8.2.1", "2 - 7", "2.0 || 5.6.7"],
1009 denies => [ "1.9.4 || 2 - 3"],
1010 },
1011}
1012
1013#[cfg(test)]
1014mod intersection {
1015 use super::*;
1016
1017 fn v(range: &'static str) -> Range {
1018 range.parse().unwrap()
1019 }
1020
1021 #[test]
1022 fn gt_eq_123() {
1023 let base_range = v(">=1.2.3");
1024
1025 let samples = vec![
1026 ("<=2.0.0", Some(">=1.2.3 <=2.0.0")),
1027 ("<2.0.0", Some(">=1.2.3 <2.0.0")),
1028 (">=2.0.0", Some(">=2.0.0")),
1029 (">2.0.0", Some(">2.0.0")),
1030 (">1.0.0", Some(">=1.2.3")),
1031 (">1.2.3", Some(">1.2.3")),
1032 ("<=1.2.3", Some("1.2.3")),
1033 ("2.0.0", Some("2.0.0")),
1034 ("1.1.1", None),
1035 ("<1.0.0", None),
1036 ];
1037
1038 assert_ranges_match(base_range, samples);
1039 }
1040
1041 #[test]
1042 fn gt_123() {
1043 let base_range = v(">1.2.3");
1044
1045 let samples = vec![
1046 ("<=2.0.0", Some(">1.2.3 <=2.0.0")),
1047 ("<2.0.0", Some(">1.2.3 <2.0.0")),
1048 (">=2.0.0", Some(">=2.0.0")),
1049 (">2.0.0", Some(">2.0.0")),
1050 ("2.0.0", Some("2.0.0")),
1051 (">1.2.3", Some(">1.2.3")),
1052 ("<=1.2.3", None),
1053 ("1.1.1", None),
1054 ("<1.0.0", None),
1055 ];
1056
1057 assert_ranges_match(base_range, samples);
1058 }
1059
1060 #[test]
1061 fn eq_123() {
1062 let base_range = v("1.2.3");
1063
1064 let samples = vec![
1065 ("<=2.0.0", Some("1.2.3")),
1066 ("<2.0.0", Some("1.2.3")),
1067 (">=2.0.0", None),
1068 (">2.0.0", None),
1069 ("2.0.0", None),
1070 ("1.2.3", Some("1.2.3")),
1071 (">1.2.3", None),
1072 ("<=1.2.3", Some("1.2.3")),
1073 ("1.1.1", None),
1074 ("<1.0.0", None),
1075 ];
1076
1077 assert_ranges_match(base_range, samples);
1078 }
1079
1080 #[test]
1081 fn lt_123() {
1082 let base_range = v("<1.2.3");
1083
1084 let samples = vec![
1085 ("<=2.0.0", Some("<1.2.3")),
1086 ("<2.0.0", Some("<1.2.3")),
1087 (">=2.0.0", None),
1088 (">=1.0.0", Some(">=1.0.0 <1.2.3")),
1089 (">2.0.0", None),
1090 ("2.0.0", None),
1091 ("1.2.3", None),
1092 (">1.2.3", None),
1093 ("<=1.2.3", Some("<1.2.3")),
1094 ("1.1.1", Some("1.1.1")),
1095 ("<1.0.0", Some("<1.0.0")),
1096 ];
1097
1098 assert_ranges_match(base_range, samples);
1099 }
1100
1101 #[test]
1102 fn lt_eq_123() {
1103 let base_range = v("<=1.2.3");
1104
1105 let samples = vec![
1106 ("<=2.0.0", Some("<=1.2.3")),
1107 ("<2.0.0", Some("<=1.2.3")),
1108 (">=2.0.0", None),
1109 (">=1.0.0", Some(">=1.0.0 <=1.2.3")),
1110 (">2.0.0", None),
1111 ("2.0.0", None),
1112 ("1.2.3", Some("1.2.3")),
1113 (">1.2.3", None),
1114 ("<=1.2.3", Some("<=1.2.3")),
1115 ("1.1.1", Some("1.1.1")),
1116 ("<1.0.0", Some("<1.0.0")),
1117 ];
1118
1119 assert_ranges_match(base_range, samples);
1120 }
1121
1122 #[test]
1123 fn multiple() {
1124 let base_range = v("<1 || 3 - 4");
1125
1126 let samples = vec![("0.5 - 3.5.0", Some(">=0.5.0 <1.0.0||>=3.0.0 <=3.5.0"))];
1127
1128 assert_ranges_match(base_range, samples);
1129 }
1130
1131 fn assert_ranges_match(base: Range, samples: Vec<(&'static str, Option<&'static str>)>) {
1132 for (other, expected) in samples {
1133 let other = v(other);
1134 let resulting_range = base.intersect(&other).map(|v| v.to_string());
1135 assert_eq!(
1136 resulting_range.clone(),
1137 expected.map(|e| e.to_string()),
1138 "{} ∩ {} := {}",
1139 base,
1140 other,
1141 resulting_range.unwrap_or_else(|| "⊗".into())
1142 );
1143 }
1144 }
1145}
1146
1147#[cfg(test)]
1148mod difference {
1149 use super::*;
1150
1151 fn v(range: &'static str) -> Range {
1152 range.parse().unwrap()
1153 }
1154
1155 #[test]
1156 fn gt_eq_123() {
1157 let base_range = v(">=1.2.3");
1158
1159 let samples = vec![
1160 ("<=2.0.0", Some(">2.0.0")),
1161 ("<2.0.0", Some(">=2.0.0")),
1162 (">=2.0.0", Some(">=1.2.3 <2.0.0")),
1163 (">2.0.0", Some(">=1.2.3 <=2.0.0")),
1164 (">1.0.0", None),
1165 (">1.2.3", Some("1.2.3")),
1166 ("<=1.2.3", Some(">1.2.3")),
1167 ("1.1.1", Some(">=1.2.3")),
1168 ("<1.0.0", Some(">=1.2.3")),
1169 ("2.0.0", Some(">=1.2.3 <2.0.0||>2.0.0")),
1170 ];
1171
1172 assert_ranges_match(base_range, samples);
1173 }
1174
1175 #[test]
1176 fn gt_123() {
1177 let base_range = v(">1.2.3");
1178
1179 let samples = vec![
1180 ("<=2.0.0", Some(">2.0.0")),
1181 ("<2.0.0", Some(">=2.0.0")),
1182 (">=2.0.0", Some(">1.2.3 <2.0.0")),
1183 (">2.0.0", Some(">1.2.3 <=2.0.0")),
1184 (">1.0.0", None),
1185 (">1.2.3", None),
1186 ("<=1.2.3", Some(">1.2.3")),
1187 ("1.1.1", Some(">1.2.3")),
1188 ("<1.0.0", Some(">1.2.3")),
1189 ("2.0.0", Some(">1.2.3 <2.0.0||>2.0.0")),
1190 ];
1191
1192 assert_ranges_match(base_range, samples);
1193 }
1194
1195 #[test]
1196 fn eq_123() {
1197 let base_range = v("1.2.3");
1198
1199 let samples = vec![
1200 ("<=2.0.0", None),
1201 ("<2.0.0", None),
1202 (">=2.0.0", Some("1.2.3")),
1203 (">2.0.0", Some("1.2.3")),
1204 (">1.0.0", None),
1205 (">1.2.3", Some("1.2.3")),
1206 ("1.2.3", None),
1207 ("<=1.2.3", None),
1208 ("1.1.1", Some("1.2.3")),
1209 ("<1.0.0", Some("1.2.3")),
1210 ("2.0.0", Some("1.2.3")),
1211 ];
1212
1213 assert_ranges_match(base_range, samples);
1214 }
1215
1216 #[test]
1217 fn lt_123() {
1218 let base_range = v("<1.2.3");
1219
1220 let samples = vec![
1221 ("<=2.0.0", None),
1222 ("<2.0.0", None),
1223 (">=2.0.0", Some("<1.2.3")),
1224 (">2.0.0", Some("<1.2.3")),
1225 (">1.0.0", Some("<=1.0.0")),
1226 (">1.2.3", Some("<1.2.3")),
1227 ("<=1.2.3", None),
1228 ("1.1.1", Some("<1.1.1||>1.1.1 <1.2.3")),
1229 ("<1.0.0", Some(">=1.0.0 <1.2.3")),
1230 ("2.0.0", Some("<1.2.3")),
1231 ];
1232
1233 assert_ranges_match(base_range, samples);
1234 }
1235
1236 #[test]
1237 fn lt_eq_123() {
1238 let base_range = v("<=1.2.3");
1239
1240 let samples = vec![
1241 ("<=2.0.0", None),
1242 ("<2.0.0", None),
1243 (">=2.0.0", Some("<=1.2.3")),
1244 (">2.0.0", Some("<=1.2.3")),
1245 (">1.0.0", Some("<=1.0.0")),
1246 (">1.2.3", Some("<=1.2.3")),
1247 ("<=1.2.3", None),
1248 ("1.1.1", Some("<1.1.1||>1.1.1 <=1.2.3")),
1249 ("<1.0.0", Some(">=1.0.0 <=1.2.3")),
1250 ("2.0.0", Some("<=1.2.3")),
1251 ];
1252
1253 assert_ranges_match(base_range, samples);
1254 }
1255
1256 #[test]
1257 fn multiple() {
1258 let base_range = v("<1 || 3 - 4");
1259
1260 let samples = vec![("0.5 - 3.5.0", Some("<0.5.0||>3.5.0 <5.0.0-0"))];
1261
1262 assert_ranges_match(base_range, samples);
1263 }
1264
1265 fn assert_ranges_match(base: Range, samples: Vec<(&'static str, Option<&'static str>)>) {
1266 for (other, expected) in samples {
1267 let other = v(other);
1268 let resulting_range = base.difference(&other).map(|v| v.to_string());
1269 assert_eq!(
1270 resulting_range.clone(),
1271 expected.map(|e| e.to_string()),
1272 "{} \\ {} := {}",
1273 base,
1274 other,
1275 resulting_range.unwrap_or_else(|| "⊗".into())
1276 );
1277 }
1278 }
1279}
1280
1281#[cfg(test)]
1282mod outside {
1283 use super::*;
1284 use std::convert::TryFrom;
1285
1286 const VERSION_GT_RANGE: &[(&str, &str, bool)] = &[
1287 ("~1.2.2", "1.3.0", false),
1288 ("~0.6.1-1", "0.7.1-1", false),
1289 ("1.0.0 - 2.0.0", "2.0.1", false),
1290 ("1.0.0", "1.0.1-beta1", false),
1291 ("1.0.0", "2.0.0", false),
1292 ("<=2.0.0", "2.1.1", false),
1293 ("<=2.0.0", "3.2.9", false),
1294 ("<2.0.0", "2.0.0", false),
1295 ("0.1.20 || 1.2.4", "1.2.5", false),
1296 ("2.x.x", "3.0.0", false),
1297 ("1.2.x", "1.3.0", false),
1298 ("1.2.x || 2.x", "3.0.0", false),
1299 ("2.*.*", "5.0.1", false),
1300 ("1.2.*", "1.3.3", false),
1301 ("1.2.* || 2.*", "4.0.0", false),
1302 ("2", "3.0.0", false),
1303 ("2.3", "2.4.2", false),
1304 ("~2.4", "2.5.0", false),
1305 ("~2.4", "2.5.5", false),
1306 ("~>3.2.1", "3.3.0", false),
1307 ("~1", "2.2.3", false),
1308 ("~>1", "2.2.4", false),
1309 ("~> 1", "3.2.3", false),
1310 ("~1.0", "1.1.2", false),
1311 ("~ 1.0", "1.1.0", false),
1312 ("<1.2", "1.2.0", false),
1313 ("< 1.2", "1.2.1", false),
1314 ("1", "2.0.0beta", false),
1315 ("~v0.5.4-pre", "0.6.0", false),
1316 ("~v0.5.4-pre", "0.6.1-pre", false),
1317 ("=0.7.x", "0.8.0", false),
1318 ("=0.7.x", "0.8.0-asdf", false),
1319 ("<0.7.x", "0.7.0", false),
1320 ("1.0.0 - 2.0.0", "2.2.3", false),
1321 ("1.0.0", "1.0.1", false),
1322 ("<=2.0.0", "3.0.0", false),
1323 ("<=2.0.0", "2.9999.9999", false),
1324 ("<=2.0.0", "2.2.9", false),
1325 ("<2.0.0", "2.9999.9999", false),
1326 ("<2.0.0", "2.2.9", false),
1327 ("2.x.x", "3.1.3", false),
1328 ("1.2.x", "1.3.3", false),
1329 ("1.2.x || 2.x", "3.1.3", false),
1330 ("2.*.*", "3.1.3", false),
1331 ("1.2.* || 2.*", "3.1.3", false),
1332 ("2", "3.1.2", false),
1333 ("2.3", "2.4.1", false),
1334 ("~>3.2.1", "3.3.2", false),
1335 ("~>1", "2.2.3", false),
1336 ("~1.0", "1.1.0", false),
1337 ("<1", "1.0.0", false),
1338 ("<1", "1.0.0beta", false),
1339 ("< 1", "1.0.0beta", false),
1340 ("=0.7.x", "0.8.2", false),
1341 ("<0.7.x", "0.7.2", false),
1342 ("0.7.x", "0.7.2-beta", false),
1343 ];
1344
1345 const VERSION_NOT_GT_RANGE: &[(&str, &str, bool)] = &[
1346 ("~0.6.1-1", "0.6.1-1", false),
1347 ("1.0.0 - 2.0.0", "1.2.3", false),
1348 ("1.0.0 - 2.0.0", "0.9.9", false),
1349 ("1.0.0", "1.0.0", false),
1350 (">=*", "0.2.4", false),
1351 ("", "1.0.0", false),
1352 ("*", "1.2.3", false),
1353 ("*", "v1.2.3-foo", false),
1354 (">=1.0.0", "1.0.0", false),
1355 (">=1.0.0", "1.0.1", false),
1356 (">=1.0.0", "1.1.0", false),
1357 (">1.0.0", "1.0.1", false),
1358 (">1.0.0", "1.1.0", false),
1359 ("<=2.0.0", "2.0.0", false),
1360 ("<=2.0.0", "1.9999.9999", false),
1361 ("<=2.0.0", "0.2.9", false),
1362 ("<2.0.0", "1.9999.9999", false),
1363 ("<2.0.0", "0.2.9", false),
1364 (">= 1.0.0", "1.0.0", false),
1365 (">= 1.0.0", "1.0.1", false),
1366 (">= 1.0.0", "1.1.0", false),
1367 ("> 1.0.0", "1.0.1", false),
1368 ("> 1.0.0", "1.1.0", false),
1369 ("<= 2.0.0", "2.0.0", false),
1370 ("<= 2.0.0", "1.9999.9999", false),
1371 ("<= 2.0.0", "0.2.9", false),
1372 ("< 2.0.0", "1.9999.9999", false),
1373 ("<\t2.0.0", "0.2.9", false),
1374 (">=0.1.97", "v0.1.97", false),
1375 (">=0.1.97", "0.1.97", false),
1376 ("0.1.20 || 1.2.4", "1.2.4", false),
1377 ("0.1.20 || >1.2.4", "1.2.4", false),
1378 ("0.1.20 || 1.2.4", "1.2.3", false),
1379 ("0.1.20 || 1.2.4", "0.1.20", false),
1380 (">=0.2.3 || <0.0.1", "0.0.0", false),
1381 (">=0.2.3 || <0.0.1", "0.2.3", false),
1382 (">=0.2.3 || <0.0.1", "0.2.4", false),
1383 ("||", "1.3.4", false),
1384 ("2.x.x", "2.1.3", false),
1385 ("1.2.x", "1.2.3", false),
1386 ("1.2.x || 2.x", "2.1.3", false),
1387 ("1.2.x || 2.x", "1.2.3", false),
1388 ("x", "1.2.3", false),
1389 ("2.*.*", "2.1.3", false),
1390 ("1.2.*", "1.2.3", false),
1391 ("1.2.* || 2.*", "2.1.3", false),
1392 ("1.2.* || 2.*", "1.2.3", false),
1393 ("2", "2.1.2", false),
1394 ("2.3", "2.3.1", false),
1395 ("~2.4", "2.4.0", false),
1396 ("~2.4", "2.4.5", false),
1397 ("~>3.2.1", "3.2.2", false),
1398 ("~1", "1.2.3", false),
1399 ("~>1", "1.2.3", false),
1400 ("~> 1", "1.2.3", false),
1401 ("~1.0", "1.0.2", false),
1402 ("~ 1.0", "1.0.2", false),
1403 (">=1", "1.0.0", false),
1404 (">= 1", "1.0.0", false),
1405 ("<1.2", "1.1.1", false),
1406 ("< 1.2", "1.1.1", false),
1407 ("1", "1.0.0beta", false),
1408 ("~v0.5.4-pre", "0.5.5", false),
1409 ("~v0.5.4-pre", "0.5.4", false),
1410 ("=0.7.x", "0.7.2", false),
1411 (">=0.7.x", "0.7.2", false),
1412 ("=0.7.x", "0.7.0-asdf", false),
1413 (">=0.7.x", "0.7.0-asdf", false),
1414 ("<=0.7.x", "0.6.2", false),
1415 (">0.2.3 >0.2.4 <=0.2.5", "0.2.5", false),
1416 (">=0.2.3 <=0.2.4", "0.2.4", false),
1417 ("1.0.0 - 2.0.0", "2.0.0", false),
1418 ("^1", "0.0.0-0", false),
1419 ("^3.0.0", "2.0.0", false),
1420 ("^1.0.0 || ~2.0.1", "2.0.0", false),
1421 ("^0.1.0 || ~3.0.1 || 5.0.0", "3.2.0", false),
1422 ("^0.1.0 || ~3.0.1 || 5.0.0", "1.0.0beta", false),
1423 ("^0.1.0 || ~3.0.1 || 5.0.0", "5.0.0-0", false),
1424 ("^0.1.0 || ~3.0.1 || >4 <=5.0.0", "3.5.0", false),
1425 ("0.7.x", "0.7.2-beta", true),
1426 ];
1427
1428 const VERSION_LT_RANGE: &[(&str, &str, bool)] = &[
1429 ("~1.2.2", "1.2.1", false),
1430 ("~0.6.1-1", "0.6.1-0", false),
1431 ("1.0.0 - 2.0.0", "0.0.1", false),
1432 ("1.0.0-beta.2", "1.0.0-beta.1", false),
1433 ("1.0.0", "0.0.0", false),
1434 (">=2.0.0", "1.1.1", false),
1435 (">=2.0.0", "1.2.9", false),
1436 (">2.0.0", "2.0.0", false),
1437 ("0.1.20 || 1.2.4", "0.1.5", false),
1438 ("2.x.x", "1.0.0", false),
1439 ("1.2.x", "1.1.0", false),
1440 ("1.2.x || 2.x", "1.0.0", false),
1441 ("2.*.*", "1.0.1", false),
1442 ("1.2.*", "1.1.3", false),
1443 ("1.2.* || 2.*", "1.1.9999", false),
1444 ("2", "1.0.0", false),
1445 ("2.3", "2.2.2", false),
1446 ("~2.4", "2.3.0", false),
1447 ("~2.4", "2.3.5", false),
1448 ("~>3.2.1", "3.2.0", false),
1449 ("~1", "0.2.3", false),
1450 ("~>1", "0.2.4", false),
1451 ("~> 1", "0.2.3", false),
1452 ("~1.0", "0.1.2", false),
1453 ("~ 1.0", "0.1.0", false),
1454 (">1.2", "1.2.0", false),
1455 ("> 1.2", "1.2.1", false),
1456 ("1", "0.0.0beta", false),
1457 ("~v0.5.4-pre", "0.5.4-alpha", false),
1458 ("=0.7.x", "0.6.0", false),
1459 ("=0.7.x", "0.6.0-asdf", false),
1460 (">=0.7.x", "0.6.0", false),
1461 ("1.0.0 - 2.0.0", "0.2.3", false),
1462 ("1.0.0", "0.0.1", false),
1463 (">=2.0.0", "1.0.0", false),
1464 (">=2.0.0", "1.9999.9999", false),
1465 (">2.0.0", "1.2.9", false),
1466 ("2.x.x", "1.1.3", false),
1467 ("1.2.x", "1.1.3", false),
1468 ("1.2.x || 2.x", "1.1.3", false),
1469 ("2.*.*", "1.1.3", false),
1470 ("1.2.* || 2.*", "1.1.3", false),
1471 ("2", "1.9999.9999", false),
1472 ("2.3", "2.2.1", false),
1473 ("~>3.2.1", "2.3.2", false),
1474 ("~>1", "0.2.3", false),
1475 ("~1.0", "0.0.0", false),
1476 (">1", "1.0.0", false),
1477 ("2", "1.0.0beta", false),
1478 (">1", "1.0.0beta", false),
1479 ("> 1", "1.0.0beta", false),
1480 ("=0.7.x", "0.6.2", false),
1481 ("=0.7.x", "0.7.0-asdf", false),
1482 ("^1", "1.0.0-0", false),
1483 (">=0.7.x", "0.7.0-asdf", false),
1484 ("1", "1.0.0beta", false),
1485 (">=0.7.x", "0.6.2", false),
1486 (">1.2.3", "1.3.0-alpha", false),
1487 ];
1488
1489 const VERSION_NOT_LT_RANGE: &[(&str, &str, bool)] = &[
1490 ("~ 1.0", "1.1.0", false),
1491 ("~0.6.1-1", "0.6.1-1", false),
1492 ("1.0.0 - 2.0.0", "1.2.3", false),
1493 ("1.0.0 - 2.0.0", "2.9.9", false),
1494 ("1.0.0", "1.0.0", false),
1495 (">=*", "0.2.4", false),
1496 ("", "1.0.0", false),
1497 ("*", "1.2.3", false),
1498 (">=1.0.0", "1.0.0", false),
1499 (">=1.0.0", "1.0.1", false),
1500 (">=1.0.0", "1.1.0", false),
1501 (">1.0.0", "1.0.1", false),
1502 (">1.0.0", "1.1.0", false),
1503 ("<=2.0.0", "2.0.0", false),
1504 ("<=2.0.0", "1.9999.9999", false),
1505 ("<=2.0.0", "0.2.9", false),
1506 ("<2.0.0", "1.9999.9999", false),
1507 ("<2.0.0", "0.2.9", false),
1508 (">= 1.0.0", "1.0.0", false),
1509 (">= 1.0.0", "1.0.1", false),
1510 (">= 1.0.0", "1.1.0", false),
1511 ("> 1.0.0", "1.0.1", false),
1512 ("> 1.0.0", "1.1.0", false),
1513 ("<= 2.0.0", "2.0.0", false),
1514 ("<= 2.0.0", "1.9999.9999", false),
1515 ("<= 2.0.0", "0.2.9", false),
1516 ("< 2.0.0", "1.9999.9999", false),
1517 ("<\t2.0.0", "0.2.9", false),
1518 (">=0.1.97", "v0.1.97", false),
1519 (">=0.1.97", "0.1.97", false),
1520 ("0.1.20 || 1.2.4", "1.2.4", false),
1521 ("0.1.20 || >1.2.4", "1.2.4", false),
1522 ("0.1.20 || 1.2.4", "1.2.3", false),
1523 ("0.1.20 || 1.2.4", "0.1.20", false),
1524 (">=0.2.3 || <0.0.1", "0.0.0", false),
1525 (">=0.2.3 || <0.0.1", "0.2.3", false),
1526 (">=0.2.3 || <0.0.1", "0.2.4", false),
1527 ("||", "1.3.4", false),
1528 ("2.x.x", "2.1.3", false),
1529 ("1.2.x", "1.2.3", false),
1530 ("1.2.x || 2.x", "2.1.3", false),
1531 ("1.2.x || 2.x", "1.2.3", false),
1532 ("x", "1.2.3", false),
1533 ("2.*.*", "2.1.3", false),
1534 ("1.2.*", "1.2.3", false),
1535 ("1.2.* || 2.*", "2.1.3", false),
1536 ("1.2.* || 2.*", "1.2.3", false),
1537 ("2", "2.1.2", false),
1538 ("2.3", "2.3.1", false),
1539 ("~2.4", "2.4.0", false),
1540 ("~2.4", "2.4.5", false),
1541 ("~>3.2.1", "3.2.2", false),
1542 ("~1", "1.2.3", false),
1543 ("~>1", "1.2.3", false),
1544 ("~> 1", "1.2.3", false),
1545 ("~1.0", "1.0.2", false),
1546 ("~ 1.0", "1.0.2", false),
1547 (">=1", "1.0.0", false),
1548 (">= 1", "1.0.0", false),
1549 ("<1.2", "1.1.1", false),
1550 ("< 1.2", "1.1.1", false),
1551 ("~v0.5.4-pre", "0.5.5", false),
1552 ("~v0.5.4-pre", "0.5.4", false),
1553 ("=0.7.x", "0.7.2", false),
1554 (">=0.7.x", "0.7.2", false),
1555 ("<=0.7.x", "0.6.2", false),
1556 (">0.2.3 >0.2.4 <=0.2.5", "0.2.5", false),
1557 (">=0.2.3 <=0.2.4", "0.2.4", false),
1558 ("1.0.0 - 2.0.0", "2.0.0", false),
1559 ("^3.0.0", "4.0.0", false),
1560 ("^1.0.0 || ~2.0.1", "2.0.0", false),
1561 ("^0.1.0 || ~3.0.1 || 5.0.0", "3.2.0", false),
1562 ("^0.1.0 || ~3.0.1 || 5.0.0", "1.0.0beta", false),
1563 ("^0.1.0 || ~3.0.1 || 5.0.0", "5.0.0-0", false),
1564 ("^0.1.0 || ~3.0.1 || >4 <=5.0.0", "3.5.0", false),
1565 ("^1.0.0alpha", "1.0.0beta", false),
1566 ("~1.0.0alpha", "1.0.0beta", false),
1567 ("^1.0.0-alpha", "1.0.0beta", false),
1568 ("~1.0.0-alpha", "1.0.0beta", false),
1569 ("^1.0.0-alpha", "1.0.0-beta", false),
1570 ("~1.0.0-alpha", "1.0.0-beta", false),
1571 ("=0.1.0", "1.0.0", false),
1572 (">1.2.3", "1.3.0-alpha", true),
1573 ];
1574
1575 fn assert_outside(
1576 cases: &[(&str, &str, bool)],
1577 direction: OutsideDirection,
1578 include_prerelease: bool,
1579 expected: bool,
1580 ) {
1581 for (range, version, explicit_include) in cases {
1582 let include_prerelease = include_prerelease || *explicit_include;
1583 let range = Range::parse(range).unwrap();
1584 let version = Version::parse(version).unwrap();
1585
1586 let result = range
1587 .outside(&version, direction, include_prerelease)
1588 .expect("outside should always have comparator bounds");
1589 let message = format!(
1590 "{}outside({}, {}, {}, include_prerelease={})",
1591 if expected { "" } else { "!" },
1592 version,
1593 range,
1594 direction,
1595 include_prerelease
1596 );
1597
1598 if expected {
1599 assert!(result, "{}", message);
1600 } else {
1601 assert!(!result, "{}", message);
1602 }
1603 }
1604 }
1605
1606 #[test]
1607 fn greater_than_range() {
1608 assert_outside(VERSION_GT_RANGE, OutsideDirection::Higher, false, true);
1609 }
1610
1611 #[test]
1612 fn less_than_range() {
1613 assert_outside(VERSION_LT_RANGE, OutsideDirection::Lower, false, true);
1614 }
1615
1616 #[test]
1617 fn not_greater_than_range() {
1618 assert_outside(VERSION_NOT_GT_RANGE, OutsideDirection::Higher, false, false);
1619 }
1620
1621 #[test]
1622 fn not_less_than_range() {
1623 assert_outside(VERSION_NOT_LT_RANGE, OutsideDirection::Lower, false, false);
1624 }
1625
1626 #[test]
1627 fn outside_with_bad_direction_returns_error() {
1628 let range = Range::parse(">1.5.0").unwrap();
1629 let version = Version::parse("1.2.3").unwrap();
1630
1631 let result = OutsideDirection::try_from('x')
1632 .and_then(|direction| range.outside(&version, direction, false));
1633
1634 assert!(matches!(
1635 result,
1636 Err(RangeError::InvalidOutsideDirection('x'))
1637 ));
1638 }
1639}
1640
1641#[cfg(test)]
1642mod satisfies_ranges_tests {
1643 use super::*;
1644
1645 macro_rules! refute {
1646 ($e:expr) => {
1647 assert!(!$e)
1648 };
1649 ($e:expr, $msg:expr) => {
1650 assert!(!$e, $msg)
1651 };
1652 }
1653
1654 #[test]
1655 fn greater_than_equals() {
1656 let parsed = Range::parse(">=1.2.3").expect("unable to parse");
1657
1658 refute!(parsed.satisfies(&(0, 2, 3).into()), "major too low");
1659 refute!(parsed.satisfies(&(1, 1, 3).into()), "minor too low");
1660 refute!(parsed.satisfies(&(1, 2, 2).into()), "patch too low");
1661 assert!(parsed.satisfies(&(1, 2, 3).into()), "exact");
1662 assert!(parsed.satisfies(&(2, 2, 3).into()), "above");
1663 }
1664
1665 #[test]
1666 fn greater_than() {
1667 let parsed = Range::parse(">1.2.3").expect("unable to parse");
1668
1669 refute!(parsed.satisfies(&(0, 2, 3).into()), "major too low");
1670 refute!(parsed.satisfies(&(1, 1, 3).into()), "minor too low");
1671 refute!(parsed.satisfies(&(1, 2, 2).into()), "patch too low");
1672 refute!(parsed.satisfies(&(1, 2, 3).into()), "exact");
1673 assert!(parsed.satisfies(&(1, 2, 4).into()), "above");
1674 }
1675
1676 #[test]
1677 fn exact() {
1678 let parsed = Range::parse("=1.2.3").expect("unable to parse");
1679
1680 refute!(parsed.satisfies(&(1, 2, 2).into()), "patch too low");
1681 assert!(parsed.satisfies(&(1, 2, 3).into()), "exact");
1682 refute!(parsed.satisfies(&(1, 2, 4).into()), "above");
1683 }
1684
1685 #[test]
1686 fn less_than() {
1687 let parsed = Range::parse("<1.2.3").expect("unable to parse");
1688
1689 assert!(parsed.satisfies(&(0, 2, 3).into()), "major below");
1690 assert!(parsed.satisfies(&(1, 1, 3).into()), "minor below");
1691 assert!(parsed.satisfies(&(1, 2, 2).into()), "patch below");
1692 refute!(parsed.satisfies(&(1, 2, 3).into()), "exact");
1693 refute!(parsed.satisfies(&(1, 2, 4).into()), "above");
1694 }
1695
1696 #[test]
1697 fn less_than_equals() {
1698 let parsed = Range::parse("<=1.2.3").expect("unable to parse");
1699
1700 assert!(parsed.satisfies(&(0, 2, 3).into()), "major below");
1701 assert!(parsed.satisfies(&(1, 1, 3).into()), "minor below");
1702 assert!(parsed.satisfies(&(1, 2, 2).into()), "patch below");
1703 assert!(parsed.satisfies(&(1, 2, 3).into()), "exact");
1704 refute!(parsed.satisfies(&(1, 2, 4).into()), "above");
1705 }
1706
1707 #[test]
1708 fn less_than_equals_major() {
1709 let parsed = Range::parse("<=1").expect("unable to parse");
1710
1711 assert!(parsed.satisfies(&(0, 2, 3).into()), "major below");
1712 assert!(parsed.satisfies(&(1, 1, 3).into()), "minor below");
1713 assert!(parsed.satisfies(&(1, 2, 2).into()), "minor below");
1714 assert!(parsed.satisfies(&(1, 2, 3).into()), "minor below");
1715 assert!(parsed.satisfies(&(1, 2, 4).into()), "minor below");
1716 refute!(parsed.satisfies(&(2, 0, 0).into()), "above");
1717 }
1718
1719 #[test]
1720 fn less_than_equals_minor() {
1721 let parsed = Range::parse("<=1.2").expect("unable to parse");
1722
1723 assert!(parsed.satisfies(&(0, 2, 3).into()), "major below");
1724 assert!(parsed.satisfies(&(1, 1, 3).into()), "minor below");
1725 assert!(parsed.satisfies(&(1, 2, 1).into()), "patch below");
1726 assert!(parsed.satisfies(&(1, 2, 5).into()), "patch below");
1727 refute!(parsed.satisfies(&(1, 3, 0).into()), "above");
1728 }
1729
1730 #[test]
1731 fn only_major() {
1732 let parsed = Range::parse("1").expect("unable to parse");
1733
1734 refute!(parsed.satisfies(&(0, 2, 3).into()), "major below");
1735 assert!(parsed.satisfies(&(1, 0, 0).into()), "exact bottom of range");
1736 assert!(parsed.satisfies(&(1, 2, 2).into()), "middle");
1737 refute!(parsed.satisfies(&(2, 0, 0).into()), "exact top of range");
1738 refute!(parsed.satisfies(&(2, 7, 3).into()), "above");
1739 }
1740
1741 #[test]
1742 fn pre_release_version() {
1743 let range = Range::parse("^2").unwrap();
1744
1745 refute!(
1746 range.satisfies(&Version::parse("2.0.0-alpha.0").unwrap()),
1747 "below"
1748 );
1749 refute!(
1750 range.satisfies(&Version::parse("2.1.0-alpha.0").unwrap()),
1751 "above but pre-release"
1752 );
1753 }
1754
1755 #[test]
1756 fn pre_release_range() {
1757 let range = Range::parse("^1.2.3-rc.4").unwrap();
1758
1759 refute!(range.satisfies(&Version::parse("1.2.2").unwrap()), "below");
1760 assert!(
1761 range.satisfies(&Version::parse("1.2.3").unwrap()),
1762 "equal non-prerelease"
1763 );
1764 assert!(range.satisfies(&Version::parse("1.2.4").unwrap()), "above");
1765 }
1766
1767 #[test]
1768 fn pre_release_version_and_range() {
1769 let range = Range::parse("^1.2.3-rc.4").unwrap();
1770
1771 refute!(
1772 range.satisfies(&Version::parse("1.2.3-rc.3").unwrap()),
1773 "below"
1774 );
1775 assert!(
1776 range.satisfies(&Version::parse("1.2.3-rc.4").unwrap()),
1777 "equal"
1778 );
1779 assert!(
1780 range.satisfies(&Version::parse("1.2.3-rc.5").unwrap()),
1781 "above"
1782 );
1783 refute!(
1784 range.satisfies(&Version::parse("1.2.4-rc.6").unwrap()),
1785 "above patch but pre-release"
1786 );
1787 }
1788
1789 #[test]
1790 fn npm_compatibility_cases() {
1791 let cases = [
1792 ("3.4.5", ">=3.3.0-beta.1 <3.4.0-beta.3", false),
1793 ("1.0.0", "1.0.x", true),
1794 ("1.2.3", "1.x.x", true),
1795 ("1.2.3", "x.x.x", true),
1796 ("1.0.1", "1.0.0 - 1.0.x", true),
1797 ("2.0.0", "1.0.0 - 1.x", false),
1798 ("1.2.3", "^1 || ^2", true),
1799 ("2.0.0-beta.1", "^1 || ^2", false),
1800 ];
1801
1802 for (version, range, expected) in cases {
1803 let version = Version::parse(version).unwrap();
1804 let range = Range::parse(range).unwrap();
1805
1806 assert_eq!(
1807 range.satisfies(&version),
1808 expected,
1809 "expected satisfies({}, {}) to be {}",
1810 version,
1811 range,
1812 expected
1813 );
1814 }
1815 }
1816}
1817
1818#[cfg(test)]
1820mod tests {
1821 use super::*;
1822
1823 use pretty_assertions::assert_eq;
1824
1825 #[test]
1826 fn detects_empty_ranges() {
1827 let is_empty = |input| is_empty_range(trim_range_edges_if_needed(input));
1828 assert!(is_empty(""));
1829 assert!(is_empty(" "));
1830 assert!(is_empty("\u{2003}"));
1831 assert!(is_empty("\u{FEFF}"));
1832 assert!(is_empty("||"));
1833 assert!(is_empty(" || || "));
1834 assert!(is_empty("\u{3000}||\u{A0}"));
1835
1836 assert!(!is_empty("|"));
1837 assert!(!is_empty("|||"));
1838 assert!(!is_empty("1.2.3"));
1839 assert!(!is_empty("1.2.3 || 2.0.0"));
1840 }
1841
1842 macro_rules! range_parse_tests {
1843 ($($name:ident => $vals:expr),+ ,$(,)?) => {
1844 $(
1845 #[test]
1846 fn $name() {
1847 let [input, expected] = $vals;
1848
1849 let parsed = Range::parse(input).expect("unable to parse");
1850
1851 assert_eq!(expected, parsed.to_string());
1852 }
1853 )+
1854 }
1855
1856 }
1857
1858 range_parse_tests![
1859 exact => ["1.0.0", "1.0.0"],
1861 major_minor_patch_range => ["1.0.0 - 2.0.0", ">=1.0.0 <=2.0.0"],
1862 only_major_versions => ["1 - 2", ">=1.0.0 <3.0.0-0"],
1863 only_major_and_minor => ["1.0 - 2.0", ">=1.0.0 <2.1.0-0"],
1864 mixed_major_minor => ["1.2 - 3.4.5", ">=1.2.0 <=3.4.5"],
1865 mixed_major_minor_2 => ["1.2.3 - 3.4", ">=1.2.3 <3.5.0-0"],
1866 minor_minor_range => ["1.2 - 3.4", ">=1.2.0 <3.5.0-0"],
1867 single_sided_only_major => ["1", ">=1.0.0 <2.0.0-0"],
1868 single_sided_lower_equals_bound => [">=1.0.0", ">=1.0.0"],
1869 single_sided_lower_equals_bound_2 => [">=0.1.97", ">=0.1.97"],
1870 single_sided_lower_bound => [">1.0.0", ">1.0.0"],
1871 single_sided_upper_equals_bound => ["<=2.0.0", "<=2.0.0"],
1872 single_sided_upper_equals_bound_with_minor => ["<=2.0", "<=2.0.900719925474099"],
1873 single_sided_upper_bound => ["<2.0.0", "<2.0.0"],
1874 major_and_minor => ["2.3", ">=2.3.0 <2.4.0-0"],
1875 major_dot_x => ["2.x", ">=2.0.0 <3.0.0-0"],
1876 x_and_asterisk_version => ["2.x.x", ">=2.0.0 <3.0.0-0"],
1877 patch_x => ["1.2.x", ">=1.2.0 <1.3.0-0"],
1878 minor_asterisk_patch_asterisk => ["2.*.*", ">=2.0.0 <3.0.0-0"],
1879 patch_asterisk => ["1.2.*", ">=1.2.0 <1.3.0-0"],
1880 caret_zero => ["^0", "<1.0.0-0"],
1881 caret_zero_minor => ["^0.1", ">=0.1.0 <0.2.0-0"],
1882 caret_one => ["^1.0", ">=1.0.0 <2.0.0-0"],
1883 caret_minor => ["^1.2", ">=1.2.0 <2.0.0-0"],
1884 caret_patch => ["^0.0.1", ">=0.0.1 <0.0.2-0"],
1885 caret_with_patch => ["^0.1.2", ">=0.1.2 <0.2.0-0"],
1886 caret_with_patch_2 => ["^1.2.3", ">=1.2.3 <2.0.0-0"],
1887 tilde_one => ["~1", ">=1.0.0 <2.0.0-0"],
1888 tilde_minor => ["~1.0", ">=1.0.0 <1.1.0-0"],
1889 tilde_minor_2 => ["~2.4", ">=2.4.0 <2.5.0-0"],
1890 tilde_with_greater_than_patch => ["~>3.2.1", ">=3.2.1 <3.3.0-0"],
1891 tilde_major_minor_zero => ["~1.1.0", ">=1.1.0 <1.2.0-0"],
1892 grater_than_equals_one => [">=1", ">=1.0.0"],
1893 greater_than_one => [">1", ">=2.0.0"],
1894 less_than_one_dot_two => ["<1.2", "<1.2.0-0"],
1895 greater_than_one_dot_two => [">1.2", ">=1.3.0"],
1896 greater_than_with_prerelease => [">1.1.0-beta-10", ">1.1.0-beta-10"],
1897 either_one_version_or_the_other => ["0.1.20 || 1.2.4", "0.1.20||1.2.4"],
1898 either_one_version_range_or_another => [">=0.2.3 || <0.0.1", ">=0.2.3||<0.0.1"],
1899 either_x_version_works => ["1.2.x || 2.x", ">=1.2.0 <1.3.0-0||>=2.0.0 <3.0.0-0"],
1900 either_asterisk_version_works => ["1.2.* || 2.*", ">=1.2.0 <1.3.0-0||>=2.0.0 <3.0.0-0"],
1901 one_two_three_or_greater_than_four => ["1.2.3 || >4", "1.2.3||>=5.0.0"],
1902 any_version_asterisk => ["*", ">=0.0.0"],
1903 any_version_x => ["x", ">=0.0.0"],
1904 any_version_upper_x => ["X", ">=0.0.0"],
1905 greater_than_equals_x => [">=x", ">=0.0.0"],
1906 whitespace_1 => [">= 1.0.0", ">=1.0.0"],
1907 whitespace_2 => [">= 1.0.0", ">=1.0.0"],
1908 whitespace_3 => [">= 1.0.0", ">=1.0.0"],
1909 whitespace_4 => ["> 1.0.0", ">1.0.0"],
1910 whitespace_5 => ["> 1.0.0", ">1.0.0"],
1911 whitespace_6 => ["<= 2.0.0", "<=2.0.0"],
1912 whitespace_7 => ["<= 2.0.0", "<=2.0.0"],
1913 whitespace_8 => ["<= 2.0.0", "<=2.0.0"],
1914 whitespace_9 => ["< 2.0.0", "<2.0.0"],
1915 whitespace_10 => ["<\t2.0.0", "<2.0.0"],
1916 whitespace_11 => ["^ 1", ">=1.0.0 <2.0.0-0"],
1917 whitespace_12 => ["~> 1", ">=1.0.0 <2.0.0-0"],
1918 whitespace_13 => ["~ 1.0", ">=1.0.0 <1.1.0-0"],
1919 beta => ["^0.0.1-beta", ">=0.0.1-beta <0.0.2-0"],
1920 beta_tilde => ["~1.2.3-beta", ">=1.2.3-beta <1.3.0-0"],
1921 beta_4 => ["^1.2.3-beta.4", ">=1.2.3-beta.4 <2.0.0-0"],
1922 pre_release_on_both => ["1.0.0-alpha - 2.0.0-beta", ">=1.0.0-alpha <=2.0.0-beta"],
1923 single_sided_lower_bound_with_pre_release => [">1.0.0-alpha", ">1.0.0-alpha"],
1924 space_separated1 => [">=1.2.3 <4.5.6", ">=1.2.3 <4.5.6"],
1925 garbage1 => ["1.2.3 foo", "1.2.3"],
1926 garbage2 => ["foo 1.2.3", "1.2.3"],
1927 garbage3 => ["~1.y 1.2.3", "1.2.3"],
1928 garbage4 => ["1.2.3 ~1.y", "1.2.3"],
1929 loose1 => [">01.02.03", ">1.2.3"],
1930 loose2 => ["~1.2.3beta", ">=1.2.3-beta <1.3.0-0"],
1931 caret_weird => ["^ 1.2 ^ 1", ">=1.2.0 <2.0.0-0"],
1932 loose_eq1 => ["=0.7", ">=0.7.0 <0.8.0-0"],
1933 loose_eq2 => ["=1", ">=1.0.0 <2.0.0-0"],
1934 consistent => ["^1.0.1", ">=1.0.1 <2.0.0-0"],
1935 consistent2 => [">=1.0.1 <2.0.0-0", ">=1.0.1 <2.0.0-0"],
1936 ];
1937
1938 #[test]
1939 fn rejects_single_token_garbage_and_protocols() {
1940 for input in [
1941 "foo",
1942 "workspace:*",
1943 "npm:react-dom@19.3.0-canary-b1786c31-20260618",
1944 ] {
1945 assert!(Range::parse(input).is_err());
1946 }
1947
1948 assert_eq!(Range::parse("foo 1.2.3").unwrap().to_string(), "1.2.3");
1949 }
1950
1951 }
1958
1959#[cfg(test)]
1960mod ranges {
1961 use super::*;
1962
1963 #[test]
1964 fn one() {
1965 let r = BoundSet::new(
1966 Bound::Lower(Predicate::Including((1, 2, 0).into())),
1967 Bound::Upper(Predicate::Excluding((3, 3, 4).into())),
1968 )
1969 .unwrap();
1970
1971 assert_eq!(r.to_string(), ">=1.2.0 <3.3.4")
1972 }
1973}
1974
1975#[cfg(test)]
1976mod max_satisfying {
1977 use super::*;
1978
1979 fn assert_max_satisfying(versions: Vec<&str>, range: &str, expected: &str) {
1980 let versions: Vec<_> = versions
1981 .into_iter()
1982 .map(|s| Version::parse(s).unwrap())
1983 .collect();
1984 let range = Range::parse(range).unwrap();
1985 let result = range.max_satisfying(&versions);
1986
1987 assert_eq!(
1988 result,
1989 Some(&Version::parse(expected).unwrap()),
1990 "expected: {}, got: {:?}",
1991 expected,
1992 result
1993 );
1994 }
1995
1996 #[test]
1997 fn test_max_satisfying() {
1998 let cases = vec![
1999 (vec!["1.2.3", "1.2.4"], "1.2", "1.2.4"),
2000 (vec!["1.2.4", "1.2.3"], "1.2", "1.2.4"),
2001 (vec!["1.2.3", "1.2.4", "1.2.5", "1.2.6"], "~1.2.3", "1.2.6"),
2002 (
2003 vec!["1.1.0", "1.2.0", "1.2.1", "1.3.0", "2.0.0", "2.1.0"],
2004 "~2.0.0",
2005 "2.0.0",
2006 ),
2007 ];
2008
2009 for case in cases {
2010 assert_max_satisfying(case.0, case.1, case.2);
2011 }
2012 }
2013
2014 #[test]
2015 fn test_max_satisfying_empty() {
2016 let range = Range::parse("~1.2.3").unwrap();
2017 let versions = vec![];
2018 let result = range.max_satisfying(&versions);
2019
2020 assert_eq!(result, None);
2021 }
2022
2023 #[test]
2024 fn test_max_satisfying_none() {
2025 let range = Range::parse(">=1.0.0 <2.0.0").unwrap();
2026 let versions: Vec<_> = ["2.0.0", "0.1.0"]
2027 .iter()
2028 .map(|s| Version::parse(s).unwrap())
2029 .collect();
2030 let result = range.max_satisfying(&versions);
2031
2032 assert_eq!(result, None);
2033 }
2034}
2035
2036#[cfg(test)]
2037mod min_satisfying {
2038 use super::*;
2039
2040 fn assert_min_satisfying(versions: Vec<&str>, range: &str, expected: &str) {
2041 let versions: Vec<_> = versions
2042 .into_iter()
2043 .map(|s| Version::parse(s).unwrap())
2044 .collect();
2045 let range = Range::parse(range).unwrap();
2046 let result = range.min_satisfying(&versions);
2047
2048 assert_eq!(
2049 result,
2050 Some(&Version::parse(expected).unwrap()),
2051 "expected: {}, got: {:?}",
2052 expected,
2053 result
2054 );
2055 }
2056
2057 #[test]
2058 fn test_min_satisfying() {
2059 let cases = vec![
2060 (vec!["1.2.3", "1.2.4"], "1.2", "1.2.3"),
2061 (vec!["1.2.4", "1.2.3"], "1.2", "1.2.3"),
2062 (vec!["1.2.3", "1.2.4", "1.2.5", "1.2.6"], "~1.2.3", "1.2.3"),
2063 (
2064 vec!["1.1.0", "1.2.0", "1.2.1", "1.3.0", "2.0.0", "2.1.0"],
2065 "~2.0.0",
2066 "2.0.0",
2067 ),
2068 ];
2069
2070 for case in cases {
2071 assert_min_satisfying(case.0, case.1, case.2);
2072 }
2073 }
2074
2075 #[test]
2076 fn test_min_satisfying_empty() {
2077 let range = Range::parse("~1.2.3").unwrap();
2078 let versions = vec![];
2079 let result = range.min_satisfying(&versions);
2080
2081 assert_eq!(result, None);
2082 }
2083
2084 #[test]
2085 fn test_min_satisfying_none() {
2086 let range = Range::parse(">=1.0.0 <2.0.0").unwrap();
2087 let versions: Vec<_> = ["2.0.0", "0.1.0"]
2088 .iter()
2089 .map(|s| Version::parse(s).unwrap())
2090 .collect();
2091 let result = range.min_satisfying(&versions);
2092
2093 assert_eq!(result, None);
2094 }
2095}
2096
2097#[cfg(test)]
2098mod min_version {
2099 use super::*;
2100
2101 #[test]
2102 fn min_version_test() {
2103 let tests = vec![
2105 ("*", Some("0.0.0")),
2107 ("* || >=2", Some("0.0.0")),
2108 (">=2 || *", Some("0.0.0")),
2109 (">2 || *", Some("0.0.0")),
2110 ("1.0.0", Some("1.0.0")),
2112 ("1.0", Some("1.0.0")),
2113 ("1.0.x", Some("1.0.0")),
2114 ("1.0.*", Some("1.0.0")),
2115 ("1", Some("1.0.0")),
2116 ("1.x.x", Some("1.0.0")),
2117 ("1.x.x", Some("1.0.0")),
2118 ("1.*.x", Some("1.0.0")),
2119 ("1.x.*", Some("1.0.0")),
2120 ("1.x", Some("1.0.0")),
2121 ("1.*", Some("1.0.0")),
2122 ("=1.0.0", Some("1.0.0")),
2123 ("~1.1.1", Some("1.1.1")),
2125 ("~1.1.1-beta", Some("1.1.1-beta")),
2126 ("~1.1.1 || >=2", Some("1.1.1")),
2127 ("^1.1.1", Some("1.1.1")),
2129 ("^1.1.1-beta", Some("1.1.1-beta")),
2130 ("^1.1.1 || >=2", Some("1.1.1")),
2131 ("^2.16.2 ^2.16", Some("2.16.2")),
2132 ("1.1.1 - 1.8.0", Some("1.1.1")),
2134 ("1.1 - 1.8.0", Some("1.1.0")),
2135 ("<2", Some("0.0.0")),
2137 ("<0.0.0-beta", Some("0.0.0-0")),
2138 ("<0.0.1-beta", Some("0.0.0")),
2139 ("<2 || >4", Some("0.0.0")),
2140 (">4 || <2", Some("0.0.0")),
2141 ("<=2 || >=4", Some("0.0.0")),
2142 (">=4 || <=2", Some("0.0.0")),
2143 ("<0.0.0-beta >0.0.0-alpha", Some("0.0.0-alpha.0")),
2144 (">0.0.0-alpha <0.0.0-beta", Some("0.0.0-alpha.0")),
2145 (">=1.1.1 <2 || >=2.2.2 <3", Some("1.1.1")),
2147 (">=2.2.2 <3 || >=1.1.1 <2", Some("1.1.1")),
2148 (">1.0.0", Some("1.0.1")),
2150 (">1.0.0-0", Some("1.0.0-0.0")),
2151 (">1.0.0-beta", Some("1.0.0-beta.0")),
2152 (">2 || >1.0.0", Some("1.0.1")),
2153 (">2 || >1.0.0-0", Some("1.0.0-0.0")),
2154 (">2 || >1.0.0-beta", Some("1.0.0-beta.0")),
2155 ];
2156
2157 for (range, version) in tests {
2158 let parsed_range = Range::parse(range).unwrap();
2159 let parsed_version = version.map(|v| Version::parse(v).unwrap());
2160 assert_eq!(
2161 parsed_range.min_version(),
2162 parsed_version,
2163 "expected min_version of {:?} to be {:?}",
2164 range,
2165 version
2166 );
2167 }
2168 }
2169}
2170
2171#[cfg(feature = "serde")]
2172#[cfg(test)]
2173mod serde_tests {
2174 use super::*;
2175
2176 #[test]
2177 fn test_serialize() {
2178 let range = Range::parse("~1.2.3").unwrap();
2179 let serialized = serde_json::to_string(&range).unwrap();
2180 let deserialized: Range = serde_json::from_str(&serialized).unwrap();
2181
2182 assert_eq!(range, deserialized);
2183 }
2184}