1 use crate::*;
2 
3 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
4 pub struct Range {
5     pub comparator_set: Vec<Comparator>,
6     pub compat: range_set::Compat,
7 }
8 
9 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
10 pub struct Comparator {
11     pub op: Op,
12     pub major: u64,
13     pub minor: u64,
14     pub patch: u64,
15     pub pre: Vec<Identifier>,
16 }
17 
18 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
19 pub enum Op {
20     Lt,
21     Lte,
22     Gt,
23     Gte,
24     Eq,
25 }
26 
27 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
28 pub enum Identifier {
29     Numeric(u64),
30     AlphaNumeric(String),
31 }
32 
33 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
34 pub struct Partial {
35     major: Option<u64>,
36     minor: Option<u64>,
37     patch: Option<u64>,
38     pre: Vec<Identifier>,
39     kind: PartialKind,
40 }
41 
42 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
43 pub enum PartialKind {
44     XRangeOnly,
45     MajorOnly,
46     MajorMinor,
47     MajorMinorPatch,
48 }
49 
50 impl Partial {
new() -> Self51     pub fn new() -> Self {
52         Self {
53             major: None,
54             minor: None,
55             patch: None,
56             pre: Vec::new(),
57             kind: PartialKind::XRangeOnly,
58         }
59     }
60 
as_comparator(&self, op: Op) -> Comparator61     pub fn as_comparator(&self, op: Op) -> Comparator {
62         Comparator {
63             op,
64             major: self.major.unwrap_or(0),
65             minor: self.minor.unwrap_or(0),
66             patch: self.patch.unwrap_or(0),
67             pre: self.pre.clone(),
68         }
69     }
70 
inc_major(&mut self) -> &mut Self71     pub fn inc_major(&mut self) -> &mut Self {
72         self.major = Some(self.major.unwrap_or(0) + 1);
73         self
74     }
75 
inc_minor(&mut self) -> &mut Self76     pub fn inc_minor(&mut self) -> &mut Self {
77         self.minor = Some(self.minor.unwrap_or(0) + 1);
78         self
79     }
80 
inc_patch(&mut self) -> &mut Self81     pub fn inc_patch(&mut self) -> &mut Self {
82         self.patch = Some(self.patch.unwrap_or(0) + 1);
83         self
84     }
85 
zero_missing(&mut self) -> &mut Self86     pub fn zero_missing(&mut self) -> &mut Self {
87         self.major = Some(self.major.unwrap_or(0));
88         self.minor = Some(self.minor.unwrap_or(0));
89         self.patch = Some(self.patch.unwrap_or(0));
90         self
91     }
92 
zero_minor(&mut self) -> &mut Self93     pub fn zero_minor(&mut self) -> &mut Self {
94         self.minor = Some(0);
95         self
96     }
97 
zero_patch(&mut self) -> &mut Self98     pub fn zero_patch(&mut self) -> &mut Self {
99         self.patch = Some(0);
100         self
101     }
102 
no_pre(&mut self) -> &mut Self103     pub fn no_pre(&mut self) -> &mut Self {
104         self.pre = Vec::new();
105         self
106     }
107 }
108 
from_pair_iterator( parsed_range: pest::iterators::Pair<'_, Rule>, compat: range_set::Compat, ) -> Result<Range, String>109 pub fn from_pair_iterator(
110     parsed_range: pest::iterators::Pair<'_, Rule>,
111     compat: range_set::Compat,
112 ) -> Result<Range, String> {
113     // First of all, do we have the correct iterator?
114     if parsed_range.as_rule() != Rule::range {
115         return Err(String::from("Error parsing range"));
116     }
117 
118     let mut comparator_set = Vec::new();
119 
120     // Now we need to parse each comparator set out of the range
121     for record in parsed_range.into_inner() {
122         match record.as_rule() {
123             Rule::hyphen => {
124                 let mut hyphen_set = simple::from_hyphen_range(record)?;
125                 comparator_set.append(&mut hyphen_set);
126             }
127             Rule::simple => {
128                 let mut comparators = simple::from_pair_iterator(record, compat)?;
129                 comparator_set.append(&mut comparators);
130             }
131             Rule::empty => {
132                 comparator_set.push(Partial::new().zero_missing().as_comparator(Op::Gte));
133             }
134             _ => unreachable!(),
135         }
136     }
137 
138     Ok(Range {
139         comparator_set,
140         compat,
141     })
142 }
143 
144 pub mod simple {
145     use super::*;
146 
from_pair_iterator( parsed_simple: pest::iterators::Pair<'_, Rule>, compat: range_set::Compat, ) -> Result<Vec<Comparator>, String>147     pub fn from_pair_iterator(
148         parsed_simple: pest::iterators::Pair<'_, Rule>,
149         compat: range_set::Compat,
150     ) -> Result<Vec<Comparator>, String> {
151         // First of all, do we have the correct iterator?
152         if parsed_simple.as_rule() != Rule::simple {
153             return Err(String::from("Error parsing comparator set"));
154         }
155 
156         let mut comparators = Vec::new();
157 
158         // Now we need to parse each comparator set out of the range
159         for record in parsed_simple.into_inner() {
160             match record.as_rule() {
161                 Rule::partial => {
162                     let components: Vec<_> = record.into_inner().collect();
163 
164                     let mut partial = parse_partial(components);
165 
166                     match partial.kind {
167                         PartialKind::XRangeOnly => {
168                             // '*', 'x', 'X' --> ">=0.0.0"
169                             comparators.push(partial.zero_missing().as_comparator(Op::Gte));
170                         }
171                         PartialKind::MajorOnly => {
172                             // "1", "1.*", or "1.*.*" --> ">=1.0.0 <2.0.0"
173                             // "1.*.3" == "1.*"
174                             comparators.push(partial.clone().zero_missing().as_comparator(Op::Gte));
175                             comparators
176                                 .push(partial.inc_major().zero_missing().as_comparator(Op::Lt));
177                         }
178                         PartialKind::MajorMinor => {
179                             // "1.2" or "1.2.*" --> ">=1.2.0 <1.3.0"
180                             comparators.push(partial.clone().zero_patch().as_comparator(Op::Gte));
181                             comparators
182                                 .push(partial.inc_minor().zero_patch().as_comparator(Op::Lt));
183                         }
184                         PartialKind::MajorMinorPatch => {
185                             match compat {
186                                 range_set::Compat::Npm => {
187                                     // for node, "1.2.3" is "=1.2.3"
188                                     comparators.push(partial.as_comparator(Op::Eq));
189                                 }
190                                 range_set::Compat::Cargo => {
191                                     // for cargo, "1.2.3" is parsed as "^1.2.3"
192                                     handle_caret_range(partial, &mut comparators);
193                                 }
194                             }
195                         }
196                     }
197                 }
198                 Rule::primitive => {
199                     let mut components: Vec<_> = record.into_inner().collect();
200                     let op_component = components.remove(0);
201 
202                     let op = match op_component.as_str() {
203                         "=" => Op::Eq,
204                         "<" => Op::Lt,
205                         "<=" => Op::Lte,
206                         ">" => Op::Gt,
207                         ">=" => Op::Gte,
208                         _ => unreachable!(),
209                     };
210 
211                     let partial_component = components.remove(0);
212                     let components: Vec<_> = partial_component.into_inner().collect();
213                     let mut partial = parse_partial(components);
214 
215                     // equal is different because it can be a range with 2 comparators
216                     if op == Op::Eq {
217                         match partial.kind {
218                             PartialKind::XRangeOnly => {
219                                 // '=*' --> ">=0.0.0"
220                                 comparators.push(partial.zero_missing().as_comparator(Op::Gte));
221                             }
222                             PartialKind::MajorOnly => {
223                                 // "=1", "=1.*", or "=1.*.*" --> ">=1.0.0 <2.0.0"
224                                 comparators
225                                     .push(partial.clone().zero_missing().as_comparator(Op::Gte));
226                                 comparators
227                                     .push(partial.inc_major().zero_missing().as_comparator(Op::Lt));
228                             }
229                             PartialKind::MajorMinor => {
230                                 // "=1.2" or "=1.2.*" --> ">=1.2.0 <1.3.0"
231                                 comparators
232                                     .push(partial.clone().zero_patch().as_comparator(Op::Gte));
233                                 comparators
234                                     .push(partial.inc_minor().zero_patch().as_comparator(Op::Lt));
235                             }
236                             PartialKind::MajorMinorPatch => {
237                                 comparators.push(partial.as_comparator(Op::Eq));
238                             }
239                         }
240                     } else {
241                         match partial.kind {
242                             PartialKind::XRangeOnly => {
243                                 match op {
244                                     Op::Eq => comparators
245                                         .push(partial.zero_missing().as_comparator(Op::Gte)),
246                                     Op::Lt => comparators
247                                         .push(partial.zero_missing().as_comparator(Op::Lt)),
248                                     Op::Lte => comparators
249                                         .push(partial.zero_missing().as_comparator(Op::Gte)),
250                                     Op::Gt => comparators
251                                         .push(partial.zero_missing().as_comparator(Op::Lt)),
252                                     Op::Gte => comparators
253                                         .push(partial.zero_missing().as_comparator(Op::Gte)),
254                                 }
255                             }
256                             PartialKind::MajorOnly => {
257                                 // ">1", "=1", etc.
258                                 // ">1.*.3" == ">1.*"
259                                 match op {
260                                     Op::Lte => comparators.push(
261                                         partial
262                                             .inc_major()
263                                             .zero_minor()
264                                             .zero_patch()
265                                             .as_comparator(Op::Lt),
266                                     ),
267                                     _ => comparators.push(partial.zero_missing().as_comparator(op)),
268                                 }
269                             }
270                             PartialKind::MajorMinor => {
271                                 // ">1.2", "<1.2.*", etc.
272                                 match op {
273                                     Op::Lte => comparators.push(
274                                         partial.inc_minor().zero_patch().as_comparator(Op::Lt),
275                                     ),
276                                     _ => comparators.push(partial.zero_patch().as_comparator(op)),
277                                 }
278                             }
279                             PartialKind::MajorMinorPatch => {
280                                 comparators.push(partial.as_comparator(op));
281                             }
282                         }
283                     }
284                 }
285                 Rule::caret => {
286                     let mut components: Vec<_> = record.into_inner().collect();
287 
288                     let partial_component = components.remove(0);
289                     let components: Vec<_> = partial_component.into_inner().collect();
290                     let partial = parse_partial(components);
291 
292                     handle_caret_range(partial, &mut comparators);
293                 }
294                 Rule::tilde => {
295                     let mut components: Vec<_> = record.into_inner().collect();
296 
297                     let partial_component = components.remove(0);
298                     let components: Vec<_> = partial_component.into_inner().collect();
299                     let mut partial = parse_partial(components);
300 
301                     comparators.push(partial.clone().zero_missing().as_comparator(Op::Gte));
302 
303                     match partial.kind {
304                         PartialKind::XRangeOnly => {
305                             // "~*" --> ">=0.0.0"
306                             // which has already been added, so nothing to do here
307                         }
308                         PartialKind::MajorOnly => {
309                             // "~0" --> ">=0.0.0 <1.0.0"
310                             comparators.push(
311                                 partial
312                                     .inc_major()
313                                     .zero_missing()
314                                     .no_pre()
315                                     .as_comparator(Op::Lt),
316                             );
317                         }
318                         PartialKind::MajorMinor | PartialKind::MajorMinorPatch => {
319                             // "~1.2" --> ">=1.2.0 <1.3.0"
320                             // "~1.2.3" --> ">=1.2.3 <1.3.0"
321                             comparators.push(
322                                 partial
323                                     .inc_minor()
324                                     .zero_patch()
325                                     .no_pre()
326                                     .as_comparator(Op::Lt),
327                             );
328                         }
329                     }
330                 }
331                 _ => unreachable!(),
332             }
333         }
334 
335         Ok(comparators)
336     }
337 
handle_caret_range(mut partial: Partial, comparators: &mut Vec<Comparator>)338     fn handle_caret_range(mut partial: Partial, comparators: &mut Vec<Comparator>) {
339         // major version 0 is a special case for caret
340         if partial.major == Some(0) {
341             match partial.kind {
342                 PartialKind::XRangeOnly => unreachable!(),
343                 PartialKind::MajorOnly => {
344                     // "^0", "^0.*" --> ">=0.0.0 <1.0.0"
345                     comparators.push(partial.clone().zero_missing().as_comparator(Op::Gte));
346                     comparators.push(
347                         partial
348                             .inc_major()
349                             .zero_missing()
350                             .no_pre()
351                             .as_comparator(Op::Lt),
352                     );
353                 }
354                 PartialKind::MajorMinor => {
355                     // "^0.2", "^0.2.*" --> ">=0.2.0 <0.3.0"
356                     comparators.push(partial.clone().zero_missing().as_comparator(Op::Gte));
357                     comparators.push(
358                         partial
359                             .inc_minor()
360                             .zero_patch()
361                             .no_pre()
362                             .as_comparator(Op::Lt),
363                     );
364                 }
365                 PartialKind::MajorMinorPatch => {
366                     if partial.minor == Some(0) {
367                         // "^0.0.1" --> ">=0.0.1 <0.0.2"
368                         comparators.push(partial.as_comparator(Op::Gte));
369                         comparators.push(partial.inc_patch().no_pre().as_comparator(Op::Lt));
370                     } else {
371                         // "^0.2.3" --> ">=0.2.3 <0.3.0"
372                         comparators.push(partial.as_comparator(Op::Gte));
373                         comparators.push(
374                             partial
375                                 .inc_minor()
376                                 .zero_patch()
377                                 .no_pre()
378                                 .as_comparator(Op::Lt),
379                         );
380                     }
381                 }
382             }
383         } else {
384             match partial.kind {
385                 PartialKind::XRangeOnly => {
386                     // "^*" --> ">=0.0.0"
387                     comparators.push(partial.zero_missing().as_comparator(Op::Gte));
388                 }
389                 _ => {
390                     // "^1", "^1.*" --> ">=1.0.0 <2.0.0"
391                     // "^1.2", "^1.2.*" --> ">=1.2.0 <2.0.0"
392                     // "^1.2.3" --> ">=1.2.3 <2.0.0"
393                     comparators.push(partial.clone().zero_missing().as_comparator(Op::Gte));
394                     comparators.push(
395                         partial
396                             .inc_major()
397                             .zero_minor()
398                             .zero_patch()
399                             .no_pre()
400                             .as_comparator(Op::Lt),
401                     );
402                 }
403             }
404         }
405     }
406 
from_hyphen_range( parsed_simple: pest::iterators::Pair<'_, Rule>, ) -> Result<Vec<Comparator>, String>407     pub fn from_hyphen_range(
408         parsed_simple: pest::iterators::Pair<'_, Rule>,
409     ) -> Result<Vec<Comparator>, String> {
410         // First of all, do we have the correct iterator?
411         if parsed_simple.as_rule() != Rule::hyphen {
412             return Err(String::from("Error parsing comparator set"));
413         }
414 
415         let mut comparators = Vec::new();
416 
417         // At this point, we have 2 partial records
418         let mut records = parsed_simple.into_inner();
419 
420         let components1: Vec<_> = records.next().unwrap().into_inner().collect();
421         let mut partial1 = parse_partial(components1);
422         match partial1.kind {
423             PartialKind::XRangeOnly => {
424                 // don't need to include this - the range will be limited by the 2nd part of hyphen
425                 // range
426             }
427             _ => comparators.push(partial1.zero_missing().as_comparator(Op::Gte)),
428         }
429 
430         let components2: Vec<_> = records.next().unwrap().into_inner().collect();
431         let mut partial2 = parse_partial(components2);
432 
433         match partial2.kind {
434             PartialKind::XRangeOnly => {
435                 // only include this if the first part of the hyphen range was also '*'
436                 if partial1.kind == PartialKind::XRangeOnly {
437                     comparators.push(partial2.zero_missing().as_comparator(Op::Gte));
438                 }
439             }
440             PartialKind::MajorOnly => {
441                 // "1.2.3 - 2" --> ">=1.2.3 <3.0.0"
442                 comparators.push(
443                     partial2
444                         .inc_major()
445                         .zero_minor()
446                         .zero_patch()
447                         .as_comparator(Op::Lt),
448                 );
449             }
450             PartialKind::MajorMinor => {
451                 // "1.2.3 - 2.3.x" --> ">=1.2.3 <2.4.0"
452                 comparators.push(partial2.inc_minor().zero_patch().as_comparator(Op::Lt));
453             }
454             PartialKind::MajorMinorPatch => {
455                 // "1.2.3 - 2.3.4" --> ">=1.2.3 <=2.3.4"
456                 comparators.push(partial2.as_comparator(Op::Lte));
457             }
458         }
459 
460         Ok(comparators)
461     }
462 
parse_partial(mut components: Vec<pest::iterators::Pair<'_, Rule>>) -> Partial463     fn parse_partial(mut components: Vec<pest::iterators::Pair<'_, Rule>>) -> Partial {
464         let mut partial = Partial::new();
465 
466         // there will be at least one component
467         let one = components.remove(0);
468 
469         match one.as_rule() {
470             Rule::xr => {
471                 let inner = one.into_inner().next().unwrap();
472                 match inner.as_rule() {
473                     Rule::xr_op => {
474                         // for "*", ">=*", etc.
475                         partial.major = None;
476                         partial.kind = PartialKind::XRangeOnly;
477                         // end the pattern here
478                         return partial;
479                     }
480                     Rule::nr => {
481                         partial.major = Some(inner.as_str().parse::<u64>().unwrap());
482                     }
483                     _ => unreachable!(),
484                 }
485             }
486             _ => unreachable!(),
487         }
488 
489         if components.is_empty() {
490             // only the major has been given
491             partial.kind = PartialKind::MajorOnly;
492             return partial;
493         } else {
494             let two = components.remove(0);
495 
496             match two.as_rule() {
497                 Rule::xr => {
498                     let inner = two.into_inner().next().unwrap();
499                     match inner.as_rule() {
500                         Rule::xr_op => {
501                             partial.minor = None;
502                             // only the major has been given, minor is xrange (ignore anything after)
503                             partial.kind = PartialKind::MajorOnly;
504                             return partial;
505                         }
506                         Rule::nr => {
507                             partial.minor = Some(inner.as_str().parse::<u64>().unwrap());
508                         }
509                         _ => unreachable!(),
510                     }
511                 }
512                 _ => unreachable!(),
513             }
514         }
515 
516         if components.is_empty() {
517             // only major and minor have been given
518             partial.kind = PartialKind::MajorMinor;
519             return partial;
520         } else {
521             let three = components.remove(0);
522 
523             match three.as_rule() {
524                 Rule::xr => {
525                     let inner = three.into_inner().next().unwrap();
526                     match inner.as_rule() {
527                         Rule::xr_op => {
528                             partial.patch = None;
529                             // only major and minor have been given, patch is xrange
530                             partial.kind = PartialKind::MajorMinor;
531                             return partial;
532                         }
533                         Rule::nr => {
534                             partial.patch = Some(inner.as_str().parse::<u64>().unwrap());
535                         }
536                         _ => unreachable!(),
537                     }
538                 }
539                 _ => unreachable!(),
540             }
541         }
542 
543         // at this point we at least have all three fields
544         partial.kind = PartialKind::MajorMinorPatch;
545 
546         if !components.is_empty() {
547             // there's only going to be one, let's move it out
548             let pre = components.remove(0);
549             // now we want to look at the inner bit, so that we don't have the leading -
550             let mut pre: Vec<_> = pre.into_inner().collect();
551             let pre = pre.remove(0);
552             let pre = pre.as_str();
553 
554             // now we have all of the stuff in pre, so we split by . to get each bit
555             for bit in pre.split('.') {
556                 let identifier = match bit.parse::<u64>() {
557                     Ok(num) => Identifier::Numeric(num),
558                     Err(_) => Identifier::AlphaNumeric(bit.to_string()),
559                 };
560 
561                 partial.pre.push(identifier);
562             }
563         }
564 
565         partial
566     }
567 }
568 
569 #[cfg(test)]
570 mod tests {
571     use super::*;
572     use pest::Parser;
573 
parse_range(input: &str) -> pest::iterators::Pair<'_, Rule>574     fn parse_range(input: &str) -> pest::iterators::Pair<'_, Rule> {
575         match SemverParser::parse(Rule::range, input) {
576             Ok(mut parsed) => match parsed.next() {
577                 Some(parsed) => parsed,
578                 None => panic!("Could not parse {}", input),
579             },
580             Err(e) => panic!("Parse error:\n{}", e),
581         }
582     }
583 
584     // macros to handle the test boilerplate
585 
586     macro_rules! range_tests {
587         ( $( $name:ident: $value:expr, )* ) => {
588             $(
589                 #[test]
590                 fn $name() {
591                     let (input, expected_range) = $value;
592 
593                     let parsed_range = parse_range(input);
594                     let range = from_pair_iterator(parsed_range, range_set::Compat::Cargo).expect("parsing failed");
595 
596                     // get the expected length from the input range
597                     let num_comparators = range.comparator_set.len();
598                     let expected_comparators = expected_range.comparator_set.len();
599                     assert_eq!(expected_comparators, num_comparators, "expected number of comparators: {}, got: {}", expected_comparators, num_comparators);
600 
601                     assert_eq!(range, expected_range);
602                 }
603              )*
604         };
605     }
606 
607     macro_rules! range_tests_nodecompat {
608         ( $( $name:ident: $value:expr, )* ) => {
609             $(
610                 #[test]
611                 fn $name() {
612                     let (input, expected_range) = $value;
613 
614                     let parsed_range = parse_range(input);
615                     let range = from_pair_iterator(parsed_range, range_set::Compat::Npm).expect("parsing failed");
616 
617                     // get the expected length from the input range
618                     let num_comparators = range.comparator_set.len();
619                     let expected_comparators = expected_range.comparator_set.len();
620                     assert_eq!(expected_comparators, num_comparators, "expected number of comparators: {}, got: {}", expected_comparators, num_comparators);
621 
622                     assert_eq!(range, expected_range);
623                 }
624              )*
625         };
626     }
627 
628     macro_rules! comp_sets {
629         ( $( [$op:expr, $major:expr, $minor:expr, $patch:expr] ),* ) => {
630             Range {
631                 comparator_set: vec![
632                     $(
633                         Comparator {
634                             op: $op,
635                             major: $major,
636                             minor: $minor,
637                             patch: $patch,
638                             pre: pre!(None),
639                         },
640                     )*
641                 ],
642                 compat: range_set::Compat::Cargo
643             }
644         };
645         // if you specify pre for one item, you have to do it for all of them
646         ( $( [$op:expr, $major:expr, $minor:expr, $patch:expr, $pre:expr] ),* ) => {
647             Range {
648                 comparator_set: vec![
649                     $(
650                         Comparator {
651                             op: $op,
652                             major: $major,
653                             minor: $minor,
654                             patch: $patch,
655                             pre: $pre,
656                         },
657                     )*
658                 ],
659                 compat: range_set::Compat::Cargo
660             }
661         };
662     }
663 
664     // for node compatibility
665     macro_rules! comp_sets_node {
666         ( $( [$op:expr, $major:expr, $minor:expr, $patch:expr] ),* ) => {
667             Range {
668                 comparator_set: vec![
669                     $(
670                         Comparator {
671                             op: $op,
672                             major: $major,
673                             minor: $minor,
674                             patch: $patch,
675                             pre: pre!(None),
676                         },
677                     )*
678                 ],
679                 compat: range_set::Compat::Npm
680             }
681         };
682     }
683 
684     macro_rules! id_num {
685         ( $num:expr ) => {
686             Identifier::Numeric($num)
687         };
688     }
689 
690     macro_rules! id_alpha {
691         ( $alpha:expr ) => {
692             Identifier::AlphaNumeric(String::from($alpha))
693         };
694     }
695 
696     macro_rules! pre {
697         ( None ) => {
698             Vec::new()
699         };
700         ( $( $e:expr ),* ) => {
701             vec![
702                 $(
703                     $e,
704                 )*
705             ]
706         };
707     }
708 
709     macro_rules! op {
710         ( "=" ) => {
711             Op::Eq
712         };
713         ( "<" ) => {
714             Op::Lt
715         };
716         ( "<=" ) => {
717             Op::Lte
718         };
719         ( ">" ) => {
720             Op::Gt
721         };
722         ( ">=" ) => {
723             Op::Gte
724         };
725     }
726 
727     // tests
728 
729     range_tests! {
730         major: ("1", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )),
731         major_minor: ("1.2", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 1, 3, 0] )),
732         major_minor_patch: ("1.2.3", comp_sets!( [op!(">="), 1, 2, 3], [op!("<"), 2, 0, 0] )),
733         major_0_minor_patch: ("0.2.3", comp_sets!( [op!(">="), 0, 2, 3], [op!("<"), 0, 3, 0] )),
734         major_0_minor_0_patch: ("0.0.1", comp_sets!( [op!(">="), 0, 0, 1], [op!("<"), 0, 0, 2] )),
735 
736         eq_major: ("=1", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )),
737         eq_major_minor: ("=1.2", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 1, 3, 0] )),
738         eq_major_minor_patch: ("=1.2.3", comp_sets!( [op!("="), 1, 2, 3] )),
739         eq_all: ("=*", comp_sets!( [op!(">="), 0, 0, 0] )),
740         eq_major_star: ("=1.*", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )),
741         eq_major_minor_star: ("=1.2.*", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 1, 3, 0] )),
742 
743         lt_major: ("<1", comp_sets!( [op!("<"), 1, 0, 0] )),
744         lt_major_minor: ("<1.2", comp_sets!( [op!("<"), 1, 2, 0] )),
745         lt_major_minor_patch: ("<1.2.3", comp_sets!( [op!("<"), 1, 2, 3] )),
746         lt_all: ("<*", comp_sets!( [op!("<"), 0, 0, 0] )),
747         lt_major_star: ("<1.*", comp_sets!( [op!("<"), 1, 0, 0] )),
748         lt_major_minor_star: ("<1.2.*", comp_sets!( [op!("<"), 1, 2, 0] )),
749 
750         lte_major: ("<=1", comp_sets!( [op!("<"), 2, 0, 0] )),
751         lte_major_minor: ("<=1.2", comp_sets!( [op!("<"), 1, 3, 0] )),
752         lte_major_minor_patch: ("<=1.2.3", comp_sets!( [op!("<="), 1, 2, 3] )),
753         lte_all: ("<=*", comp_sets!( [op!(">="), 0, 0, 0] )),
754         lte_major_star: ("<=1.*", comp_sets!( [op!("<"), 2, 0, 0] )),
755         lte_major_minor_star: ("<=1.2.*", comp_sets!( [op!("<"), 1, 3, 0] )),
756 
757         gt_major: (">1", comp_sets!( [op!(">"), 1, 0, 0] )),
758         gt_major_minor: (">1.2", comp_sets!( [op!(">"), 1, 2, 0] )),
759         gt_major_minor_patch: (">1.2.3", comp_sets!( [op!(">"), 1, 2, 3] )),
760         gt_all: (">*", comp_sets!( [op!("<"), 0, 0, 0] )),
761         gt_major_star: (">1.*", comp_sets!( [op!(">"), 1, 0, 0] )),
762         gt_major_minor_star: (">1.2.*", comp_sets!( [op!(">"), 1, 2, 0] )),
763 
764         gte_major: (">=1", comp_sets!( [op!(">="), 1, 0, 0] )),
765         gte_major_minor: (">=1.2", comp_sets!( [op!(">="), 1, 2, 0] )),
766         gte_major_minor_patch: (">=1.2.3", comp_sets!( [op!(">="), 1, 2, 3] )),
767         gte_all: (">=*", comp_sets!( [op!(">="), 0, 0, 0] )),
768         gte_major_star: (">=1.*", comp_sets!( [op!(">="), 1, 0, 0] )),
769         gte_major_minor_star: (">=1.2.*", comp_sets!( [op!(">="), 1, 2, 0] )),
770 
771         tilde_major: ("~1", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )),
772         tilde_major_0: ("~0", comp_sets!( [op!(">="), 0, 0, 0], [op!("<"), 1, 0, 0] )),
773         tilde_major_xrange: ("~1.x", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )),
774         tilde_major_2: ("~>1", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )),
775         tilde_major_minor: ("~1.2", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 1, 3, 0] )),
776         tilde_major_minor_xrange: ("~1.2.x", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 1, 3, 0] )),
777         tilde_major_minor_2: ("~>1.2", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 1, 3, 0] )),
778         tilde_major_minor_patch: ("~1.2.3", comp_sets!( [op!(">="), 1, 2, 3], [op!("<"), 1, 3, 0] )),
779         tilde_major_minor_patch_pre: ("~1.2.3-beta", comp_sets!( [op!(">="), 1, 2, 3, pre!(id_alpha!("beta"))], [op!("<"), 1, 3, 0, pre!()] )),
780         tilde_major_minor_patch_2: ("~>1.2.3", comp_sets!( [op!(">="), 1, 2, 3], [op!("<"), 1, 3, 0] )),
781         tilde_major_0_minor_patch: ("~0.2.3", comp_sets!( [op!(">="), 0, 2, 3], [op!("<"), 0, 3, 0] )),
782         tilde_all: ("~*", comp_sets!( [op!(">="), 0, 0, 0] )),
783 
784         caret_major: ("^1", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )),
785         caret_major_xrange: ("^1.x", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )),
786         caret_major_minor: ("^1.2", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 2, 0, 0] )),
787         caret_major_minor_xrange: ("^1.2.x", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 2, 0, 0] )),
788         caret_major_minor_patch: ("^1.2.3", comp_sets!( [op!(">="), 1, 2, 3], [op!("<"), 2, 0, 0] )),
789         caret_major_minor_patch_pre: ("^1.2.3-beta.4", comp_sets!( [op!(">="), 1, 2, 3, pre!(id_alpha!("beta"), id_num!(4))], [op!("<"), 2, 0, 0, pre!()] )),
790 
791         caret_major_0: ("^0", comp_sets!( [op!(">="), 0, 0, 0], [op!("<"), 1, 0, 0] )),
792         caret_major_0_xrange: ("^0.x", comp_sets!( [op!(">="), 0, 0, 0], [op!("<"), 1, 0, 0] )),
793         caret_major_0_minor_0: ("^0.0", comp_sets!( [op!(">="), 0, 0, 0], [op!("<"), 0, 1, 0] )),
794         caret_major_0_minor_0_xrange: ("^0.0.x", comp_sets!( [op!(">="), 0, 0, 0], [op!("<"), 0, 1, 0] )),
795         caret_major_0_minor: ("^0.1", comp_sets!( [op!(">="), 0, 1, 0], [op!("<"), 0, 2, 0] )),
796         caret_major_0_minor_xrange: ("^0.1.x", comp_sets!( [op!(">="), 0, 1, 0], [op!("<"), 0, 2, 0] )),
797         caret_major_0_minor_patch: ("^0.1.2", comp_sets!( [op!(">="), 0, 1, 2], [op!("<"), 0, 2, 0] )),
798         caret_major_0_minor_0_patch: ("^0.0.1", comp_sets!( [op!(">="), 0, 0, 1], [op!("<"), 0, 0, 2] )),
799         caret_major_0_minor_0_pre: ("^0.0.1-beta", comp_sets!( [op!(">="), 0, 0, 1, pre!(id_alpha!("beta"))], [op!("<"), 0, 0, 2, pre!()] )),
800         caret_all: ("^*", comp_sets!( [op!(">="), 0, 0, 0] )),
801 
802         two_comparators_1: (">1.2.3 <4.5.6", comp_sets!( [op!(">"), 1, 2, 3], [op!("<"), 4, 5, 6] )),
803         two_comparators_2: ("^1.2 ^1", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 2, 0, 0], [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )),
804 
805         comparator_with_pre: ("=1.2.3-rc.1", comp_sets!( [op!("="), 1, 2, 3, pre!(id_alpha!("rc"), id_num!(1))] )),
806 
807         hyphen_major: ("1 - 4", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 5, 0, 0] )),
808         hyphen_major_x: ("1.* - 4.*", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 5, 0, 0] )),
809         hyphen_major_minor_x: ("1.2.x - 4.5.x", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 4, 6, 0] )),
810         hyphen_major_minor_patch: ("1.2.3 - 4.5.6", comp_sets!( [op!(">="), 1, 2, 3], [op!("<="), 4, 5, 6] )),
811         hyphen_with_pre: ("1.2.3-rc1 - 4.5.6", comp_sets!( [op!(">="), 1, 2, 3, pre!(id_alpha!("rc1"))], [op!("<="), 4, 5, 6, pre!()] )),
812         hyphen_xrange_minor_only1: ("1.*.3 - 3.4.5", comp_sets!( [op!(">="), 1, 0, 0], [op!("<="), 3, 4, 5] )),
813         hyphen_xrange_minor_only2: ("1.2.3 - 3.*.5", comp_sets!( [op!(">="), 1, 2, 3], [op!("<"), 4, 0, 0] )),
814 
815         hyphen_all_to_something: ("* - 3.4.5", comp_sets!( [op!("<="), 3, 4, 5] )),
816         hyphen_to_all: ("1.2.3 - *", comp_sets!( [op!(">="), 1, 2, 3] )),
817         hyphen_all_to_all: ("* - *", comp_sets!( [op!(">="), 0, 0, 0] )),
818 
819         gte_space: (">= 1.2.3", comp_sets!( [op!(">="), 1, 2, 3] )),
820         gte_tab: (">=\t1.2.3", comp_sets!( [op!(">="), 1, 2, 3] )),
821         gte_two_spaces: (">=  1.2.3", comp_sets!( [op!(">="), 1, 2, 3] )),
822         gt_space: ("> 1.2.3", comp_sets!( [op!(">"), 1, 2, 3] )),
823         gt_two_spaces: (">  1.2.3", comp_sets!( [op!(">"), 1, 2, 3] )),
824         lte_space: ("<= 1.2.3", comp_sets!( [op!("<="), 1, 2, 3] )),
825         lte_two_spaces: ("<=  1.2.3", comp_sets!( [op!("<="), 1, 2, 3] )),
826         lt_space: ("< 1.2.3", comp_sets!( [op!("<"), 1, 2, 3] )),
827         lt_two_spaces: ("<  1.2.3", comp_sets!( [op!("<"), 1, 2, 3] )),
828         eq_space: ("= 1.2.3", comp_sets!( [op!("="), 1, 2, 3] )),
829         eq_two_spaces: ("=  1.2.3", comp_sets!( [op!("="), 1, 2, 3] )),
830         caret_space: ("^ 1.2.3", comp_sets!( [op!(">="), 1, 2, 3], [op!("<"), 2, 0, 0] )),
831         tilde_space: ("~ 1.2.3", comp_sets!( [op!(">="), 1, 2, 3], [op!("<"), 1, 3, 0] )),
832         hyphen_spacing: ("1.2.3 -  4.5.6", comp_sets!( [op!(">="), 1, 2, 3], [op!("<="), 4, 5, 6] )),
833 
834         // digit options
835         digits: ("=0.2.3", comp_sets!( [op!("="), 0, 2, 3] )),
836         digits_2: ("=11.2.3", comp_sets!( [op!("="), 11, 2, 3] )),
837         digits_3: ("=1.12.3", comp_sets!( [op!("="), 1, 12, 3] )),
838         digits_4: ("=1.2.13", comp_sets!( [op!("="), 1, 2, 13] )),
839         digits_5: ("=1.2.5678", comp_sets!( [op!("="), 1, 2, 5678] )),
840 
841         xrange_major_x: ("1.x", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )),
842         xrange_major_x_x: ("1.x.x", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )),
843         xrange_major_minor_x: ("1.2.x", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 1, 3, 0] )),
844         xrange_major_xx: ("1.X", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )),
845         xrange_major_xx_xx: ("1.X.X", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )),
846         xrange_major_minor_xx: ("1.2.X", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 1, 3, 0] )),
847         xrange_star: ("*", comp_sets!( [op!(">="), 0, 0, 0] )),
848         xrange_x: ("x", comp_sets!( [op!(">="), 0, 0, 0] )),
849         xrange_xx: ("X", comp_sets!( [op!(">="), 0, 0, 0] )),
850         xrange_major_star: ("1.*", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )),
851         xrange_major_star_star: ("1.*.*", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )),
852         xrange_major_minor_star: ("1.2.*", comp_sets!( [op!(">="), 1, 2, 0], [op!("<"), 1, 3, 0] )),
853         xrange_with_pre: ("1.*.*-beta", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )),
854         // this is handled as "1.*":
855         xrange_minor_only: ("1.*.3", comp_sets!( [op!(">="), 1, 0, 0], [op!("<"), 2, 0, 0] )),
856 
857         // special cases
858         gte_star: (">=*", comp_sets!( [op!(">="), 0, 0, 0] )),
859         empty: ("", comp_sets!( [op!(">="), 0, 0, 0] )),
860     }
861 
862     range_tests_nodecompat! {
863         node_major_minor_patch: ("1.2.3", comp_sets_node!( [op!("="), 1, 2, 3] )),
864     }
865 }
866