reproto_semver/
version.rs

1// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11//! The `version` module gives you tools to create and compare SemVer-compliant
12//! versions.
13
14use errors::Error;
15use parser;
16#[cfg(feature = "serde")]
17use serde::de::{self, Deserialize, Deserializer, Visitor};
18#[cfg(feature = "serde")]
19use serde::ser::{Serialize, Serializer};
20use std::cmp::{self, Ordering};
21use std::fmt;
22use std::hash;
23use std::str;
24
25/// An identifier in the pre-release or build metadata.
26///
27/// See sections 9 and 10 of the spec for more about pre-release identifers and
28/// build metadata.
29#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
30pub enum Identifier {
31    /// An identifier that's solely numbers.
32    Numeric(u64),
33    /// An identifier with letters and numbers.
34    AlphaNumeric(String),
35}
36
37impl fmt::Display for Identifier {
38    #[inline]
39    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
40        match *self {
41            Identifier::Numeric(ref n) => fmt::Display::fmt(n, f),
42            Identifier::AlphaNumeric(ref s) => fmt::Display::fmt(s, f),
43        }
44    }
45}
46
47#[cfg(feature = "serde")]
48impl Serialize for Identifier {
49    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
50    where
51        S: Serializer,
52    {
53        // Serialize Identifier as a number or string.
54        match *self {
55            Identifier::Numeric(n) => serializer.serialize_u64(n),
56            Identifier::AlphaNumeric(ref s) => serializer.serialize_str(s),
57        }
58    }
59}
60
61#[cfg(feature = "serde")]
62impl<'de> Deserialize<'de> for Identifier {
63    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
64    where
65        D: Deserializer<'de>,
66    {
67        struct IdentifierVisitor;
68
69        // Deserialize Identifier from a number or string.
70        impl<'de> Visitor<'de> for IdentifierVisitor {
71            type Value = Identifier;
72
73            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
74                formatter.write_str("a SemVer pre-release or build identifier")
75            }
76
77            fn visit_u64<E>(self, numeric: u64) -> Result<Self::Value, E>
78            where
79                E: de::Error,
80            {
81                Ok(Identifier::Numeric(numeric))
82            }
83
84            fn visit_str<E>(self, alphanumeric: &str) -> Result<Self::Value, E>
85            where
86                E: de::Error,
87            {
88                Ok(Identifier::AlphaNumeric(alphanumeric.to_owned()))
89            }
90        }
91
92        deserializer.deserialize_any(IdentifierVisitor)
93    }
94}
95
96/// Represents a version number conforming to the semantic versioning scheme.
97#[derive(Clone, Eq, Debug)]
98pub struct Version {
99    /// The major version, to be incremented on incompatible changes.
100    pub major: u64,
101    /// The minor version, to be incremented when functionality is added in a
102    /// backwards-compatible manner.
103    pub minor: u64,
104    /// The patch version, to be incremented when backwards-compatible bug
105    /// fixes are made.
106    pub patch: u64,
107    /// The pre-release version identifier, if one exists.
108    pub pre: Vec<Identifier>,
109    /// The build metadata, ignored when determining version precedence.
110    pub build: Vec<Identifier>,
111}
112
113#[cfg(feature = "serde")]
114impl Serialize for Version {
115    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
116    where
117        S: Serializer,
118    {
119        // Serialize Version as a string.
120        serializer.collect_str(self)
121    }
122}
123
124#[cfg(feature = "serde")]
125impl<'de> Deserialize<'de> for Version {
126    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
127    where
128        D: Deserializer<'de>,
129    {
130        struct VersionVisitor;
131
132        // Deserialize Version from a string.
133        impl<'de> Visitor<'de> for VersionVisitor {
134            type Value = Version;
135
136            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
137                formatter.write_str("a SemVer version as a string")
138            }
139
140            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
141            where
142                E: de::Error,
143            {
144                Version::parse(v).map_err(de::Error::custom)
145            }
146        }
147
148        deserializer.deserialize_str(VersionVisitor)
149    }
150}
151
152impl Version {
153    /// Contructs the simple case without pre or build.
154    pub fn new(major: u64, minor: u64, patch: u64) -> Version {
155        Version {
156            major: major,
157            minor: minor,
158            patch: patch,
159            pre: Vec::new(),
160            build: Vec::new(),
161        }
162    }
163
164    /// Parse a string into a semver object.
165    ///
166    /// # Errors
167    ///
168    /// Returns an error variant if the input could not be parsed as a semver object.
169    ///
170    /// In general, this means that the provided string does not conform to the
171    /// [semver spec][semver].
172    ///
173    /// An error for overflow is returned if any numeric component is larger than what can be
174    /// stored in `u64`.
175    ///
176    /// The following are examples for other common error causes:
177    ///
178    /// * `1.0` - too few numeric components are used. Exactly 3 are expected.
179    /// * `1.0.01` - a numeric component has a leading zero.
180    /// * `1.0.foo` - uses a non-numeric components where one is expected.
181    /// * `1.0.0foo` - metadata is not separated using a legal character like, `+` or `-`.
182    /// * `1.0.0+foo_123` - contains metadata with an illegal character (`_`).
183    ///   Legal characters for metadata include `a-z`, `A-Z`, `0-9`, `-`, and `.` (dot).
184    ///
185    /// [semver]: https://semver.org
186    pub fn parse(version: &str) -> Result<Version, Error> {
187        let mut parser = parser::Parser::new(version)?;
188        let version = parser.version()?;
189
190        if !parser.is_eof() {
191            return Err(Error::MoreInput);
192        }
193
194        Ok(version)
195    }
196
197    /// Clears the build metadata
198    fn clear_metadata(&mut self) {
199        self.build = Vec::new();
200        self.pre = Vec::new();
201    }
202
203    /// Increments the patch number for this Version (Must be mutable)
204    pub fn increment_patch(&mut self) {
205        self.patch += 1;
206        self.clear_metadata();
207    }
208
209    /// Increments the minor version number for this Version (Must be mutable)
210    ///
211    /// As instructed by section 7 of the spec, the patch number is reset to 0.
212    pub fn increment_minor(&mut self) {
213        self.minor += 1;
214        self.patch = 0;
215        self.clear_metadata();
216    }
217
218    /// Increments the major version number for this Version (Must be mutable)
219    ///
220    /// As instructed by section 8 of the spec, the minor and patch numbers are
221    /// reset to 0
222    pub fn increment_major(&mut self) {
223        self.major += 1;
224        self.minor = 0;
225        self.patch = 0;
226        self.clear_metadata();
227    }
228
229    /// Checks to see if the current Version is in pre-release status
230    pub fn is_prerelease(&self) -> bool {
231        !self.pre.is_empty()
232    }
233}
234
235impl fmt::Display for Version {
236    #[inline]
237    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
238        try!(write!(f, "{}.{}.{}", self.major, self.minor, self.patch));
239        if !self.pre.is_empty() {
240            try!(write!(f, "-"));
241            for (i, x) in self.pre.iter().enumerate() {
242                if i != 0 {
243                    try!(write!(f, "."))
244                }
245                try!(write!(f, "{}", x));
246            }
247        }
248        if !self.build.is_empty() {
249            try!(write!(f, "+"));
250            for (i, x) in self.build.iter().enumerate() {
251                if i != 0 {
252                    try!(write!(f, "."))
253                }
254                try!(write!(f, "{}", x));
255            }
256        }
257        Ok(())
258    }
259}
260
261impl cmp::PartialEq for Version {
262    #[inline]
263    fn eq(&self, other: &Version) -> bool {
264        // We should ignore build metadata here, otherwise versions v1 and v2
265        // can exist such that !(v1 < v2) && !(v1 > v2) && v1 != v2, which
266        // violate strict total ordering rules.
267        self.major == other.major && self.minor == other.minor && self.patch == other.patch
268            && self.pre == other.pre
269    }
270}
271
272impl cmp::PartialOrd for Version {
273    fn partial_cmp(&self, other: &Version) -> Option<Ordering> {
274        Some(self.cmp(other))
275    }
276}
277
278impl cmp::Ord for Version {
279    fn cmp(&self, other: &Version) -> Ordering {
280        match self.major.cmp(&other.major) {
281            Ordering::Equal => {}
282            r => return r,
283        }
284
285        match self.minor.cmp(&other.minor) {
286            Ordering::Equal => {}
287            r => return r,
288        }
289
290        match self.patch.cmp(&other.patch) {
291            Ordering::Equal => {}
292            r => return r,
293        }
294
295        // NB: semver spec says 0.0.0-pre < 0.0.0
296        // but the version of ord defined for vec
297        // says that [] < [pre] so we alter it here
298        match (self.pre.len(), other.pre.len()) {
299            (0, 0) => Ordering::Equal,
300            (0, _) => Ordering::Greater,
301            (_, 0) => Ordering::Less,
302            (_, _) => self.pre.cmp(&other.pre),
303        }
304    }
305}
306
307impl hash::Hash for Version {
308    fn hash<H: hash::Hasher>(&self, into: &mut H) {
309        self.major.hash(into);
310        self.minor.hash(into);
311        self.patch.hash(into);
312        self.pre.hash(into);
313    }
314}
315
316impl From<(u64, u64, u64)> for Version {
317    fn from(tuple: (u64, u64, u64)) -> Version {
318        let (major, minor, patch) = tuple;
319        Version::new(major, minor, patch)
320    }
321}
322
323#[cfg(test)]
324mod tests {
325    use super::*;
326    use range::Range;
327
328    #[test]
329    fn test_parse() {
330        assert_eq!(
331            Version::parse("1.2.3"),
332            Ok(Version {
333                major: 1,
334                minor: 2,
335                patch: 3,
336                pre: Vec::new(),
337                build: Vec::new(),
338            },)
339        );
340
341        assert_eq!(Version::parse("1.2.3"), Ok(Version::new(1, 2, 3)));
342
343        assert_eq!(
344            Version::parse("  1.2.3  "),
345            Ok(Version {
346                major: 1,
347                minor: 2,
348                patch: 3,
349                pre: Vec::new(),
350                build: Vec::new(),
351            },)
352        );
353        assert_eq!(
354            Version::parse("1.2.3-alpha1"),
355            Ok(Version {
356                major: 1,
357                minor: 2,
358                patch: 3,
359                pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],
360                build: Vec::new(),
361            },)
362        );
363        assert_eq!(
364            Version::parse("  1.2.3-alpha1  "),
365            Ok(Version {
366                major: 1,
367                minor: 2,
368                patch: 3,
369                pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],
370                build: Vec::new(),
371            },)
372        );
373        assert_eq!(
374            Version::parse("1.2.3+build5"),
375            Ok(Version {
376                major: 1,
377                minor: 2,
378                patch: 3,
379                pre: Vec::new(),
380                build: vec![Identifier::AlphaNumeric(String::from("build5"))],
381            },)
382        );
383        assert_eq!(
384            Version::parse("  1.2.3+build5  "),
385            Ok(Version {
386                major: 1,
387                minor: 2,
388                patch: 3,
389                pre: Vec::new(),
390                build: vec![Identifier::AlphaNumeric(String::from("build5"))],
391            },)
392        );
393        assert_eq!(
394            Version::parse("1.2.3-alpha1+build5"),
395            Ok(Version {
396                major: 1,
397                minor: 2,
398                patch: 3,
399                pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],
400                build: vec![Identifier::AlphaNumeric(String::from("build5"))],
401            },)
402        );
403        assert_eq!(
404            Version::parse("  1.2.3-alpha1+build5  "),
405            Ok(Version {
406                major: 1,
407                minor: 2,
408                patch: 3,
409                pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],
410                build: vec![Identifier::AlphaNumeric(String::from("build5"))],
411            },)
412        );
413        assert_eq!(
414            Version::parse("1.2.3-1.alpha1.9+build5.7.3aedf  "),
415            Ok(Version {
416                major: 1,
417                minor: 2,
418                patch: 3,
419                pre: vec![
420                    Identifier::Numeric(1),
421                    Identifier::AlphaNumeric(String::from("alpha1")),
422                    Identifier::Numeric(9),
423                ],
424                build: vec![
425                    Identifier::AlphaNumeric(String::from("build5")),
426                    Identifier::Numeric(7),
427                    Identifier::AlphaNumeric(String::from("3aedf")),
428                ],
429            },)
430        );
431        assert_eq!(
432            Version::parse("0.4.0-beta.1+0851523"),
433            Ok(Version {
434                major: 0,
435                minor: 4,
436                patch: 0,
437                pre: vec![
438                    Identifier::AlphaNumeric(String::from("beta")),
439                    Identifier::Numeric(1),
440                ],
441                build: vec![Identifier::AlphaNumeric(String::from("0851523"))],
442            },)
443        );
444    }
445
446    #[test]
447    fn test_increment_patch() {
448        let mut buggy_release = Version::parse("0.1.0").unwrap();
449        buggy_release.increment_patch();
450        assert_eq!(buggy_release, Version::parse("0.1.1").unwrap());
451    }
452
453    #[test]
454    fn test_increment_minor() {
455        let mut feature_release = Version::parse("1.4.6").unwrap();
456        feature_release.increment_minor();
457        assert_eq!(feature_release, Version::parse("1.5.0").unwrap());
458    }
459
460    #[test]
461    fn test_increment_major() {
462        let mut chrome_release = Version::parse("46.1.246773").unwrap();
463        chrome_release.increment_major();
464        assert_eq!(chrome_release, Version::parse("47.0.0").unwrap());
465    }
466
467    #[test]
468    fn test_increment_keep_prerelease() {
469        let mut release = Version::parse("1.0.0-alpha").unwrap();
470        release.increment_patch();
471
472        assert_eq!(release, Version::parse("1.0.1").unwrap());
473
474        release.increment_minor();
475
476        assert_eq!(release, Version::parse("1.1.0").unwrap());
477
478        release.increment_major();
479
480        assert_eq!(release, Version::parse("2.0.0").unwrap());
481    }
482
483    #[test]
484    fn test_increment_clear_metadata() {
485        let mut release = Version::parse("1.0.0+4442").unwrap();
486        release.increment_patch();
487
488        assert_eq!(release, Version::parse("1.0.1").unwrap());
489        release = Version::parse("1.0.1+hello").unwrap();
490
491        release.increment_minor();
492
493        assert_eq!(release, Version::parse("1.1.0").unwrap());
494        release = Version::parse("1.1.3747+hello").unwrap();
495
496        release.increment_major();
497
498        assert_eq!(release, Version::parse("2.0.0").unwrap());
499    }
500
501    #[test]
502    fn test_eq() {
503        assert_eq!(Version::parse("1.2.3"), Version::parse("1.2.3"));
504        assert_eq!(
505            Version::parse("1.2.3-alpha1"),
506            Version::parse("1.2.3-alpha1")
507        );
508        assert_eq!(
509            Version::parse("1.2.3+build.42"),
510            Version::parse("1.2.3+build.42")
511        );
512        assert_eq!(
513            Version::parse("1.2.3-alpha1+42"),
514            Version::parse("1.2.3-alpha1+42")
515        );
516        assert_eq!(Version::parse("1.2.3+23"), Version::parse("1.2.3+42"));
517    }
518
519    #[test]
520    fn test_ne() {
521        assert!(Version::parse("0.0.0") != Version::parse("0.0.1"));
522        assert!(Version::parse("0.0.0") != Version::parse("0.1.0"));
523        assert!(Version::parse("0.0.0") != Version::parse("1.0.0"));
524        assert!(Version::parse("1.2.3-alpha") != Version::parse("1.2.3-beta"));
525    }
526
527    #[test]
528    fn test_show() {
529        assert_eq!(
530            format!("{}", Version::parse("1.2.3").unwrap()),
531            "1.2.3".to_string()
532        );
533        assert_eq!(
534            format!("{}", Version::parse("1.2.3-alpha1").unwrap()),
535            "1.2.3-alpha1".to_string()
536        );
537        assert_eq!(
538            format!("{}", Version::parse("1.2.3+build.42").unwrap()),
539            "1.2.3+build.42".to_string()
540        );
541        assert_eq!(
542            format!("{}", Version::parse("1.2.3-alpha1+42").unwrap()),
543            "1.2.3-alpha1+42".to_string()
544        );
545    }
546
547    #[test]
548    fn test_to_string() {
549        assert_eq!(
550            Version::parse("1.2.3").unwrap().to_string(),
551            "1.2.3".to_string()
552        );
553        assert_eq!(
554            Version::parse("1.2.3-alpha1").unwrap().to_string(),
555            "1.2.3-alpha1".to_string()
556        );
557        assert_eq!(
558            Version::parse("1.2.3+build.42").unwrap().to_string(),
559            "1.2.3+build.42".to_string()
560        );
561        assert_eq!(
562            Version::parse("1.2.3-alpha1+42").unwrap().to_string(),
563            "1.2.3-alpha1+42".to_string()
564        );
565    }
566
567    #[test]
568    fn test_lt() {
569        assert!(Version::parse("0.0.0") < Version::parse("1.2.3-alpha2"));
570        assert!(Version::parse("1.0.0") < Version::parse("1.2.3-alpha2"));
571        assert!(Version::parse("1.2.0") < Version::parse("1.2.3-alpha2"));
572        assert!(Version::parse("1.2.3-alpha1") < Version::parse("1.2.3"));
573        assert!(Version::parse("1.2.3-alpha1") < Version::parse("1.2.3-alpha2"));
574        assert!(!(Version::parse("1.2.3-alpha2") < Version::parse("1.2.3-alpha2")));
575        assert!(!(Version::parse("1.2.3+23") < Version::parse("1.2.3+42")));
576    }
577
578    #[test]
579    fn test_le() {
580        assert!(Version::parse("0.0.0") <= Version::parse("1.2.3-alpha2"));
581        assert!(Version::parse("1.0.0") <= Version::parse("1.2.3-alpha2"));
582        assert!(Version::parse("1.2.0") <= Version::parse("1.2.3-alpha2"));
583        assert!(Version::parse("1.2.3-alpha1") <= Version::parse("1.2.3-alpha2"));
584        assert!(Version::parse("1.2.3-alpha2") <= Version::parse("1.2.3-alpha2"));
585        assert!(Version::parse("1.2.3+23") <= Version::parse("1.2.3+42"));
586    }
587
588    #[test]
589    fn test_gt() {
590        assert!(Version::parse("1.2.3-alpha2") > Version::parse("0.0.0"));
591        assert!(Version::parse("1.2.3-alpha2") > Version::parse("1.0.0"));
592        assert!(Version::parse("1.2.3-alpha2") > Version::parse("1.2.0"));
593        assert!(Version::parse("1.2.3-alpha2") > Version::parse("1.2.3-alpha1"));
594        assert!(Version::parse("1.2.3") > Version::parse("1.2.3-alpha2"));
595        assert!(!(Version::parse("1.2.3-alpha2") > Version::parse("1.2.3-alpha2")));
596        assert!(!(Version::parse("1.2.3+23") > Version::parse("1.2.3+42")));
597    }
598
599    #[test]
600    fn test_ge() {
601        assert!(Version::parse("1.2.3-alpha2") >= Version::parse("0.0.0"));
602        assert!(Version::parse("1.2.3-alpha2") >= Version::parse("1.0.0"));
603        assert!(Version::parse("1.2.3-alpha2") >= Version::parse("1.2.0"));
604        assert!(Version::parse("1.2.3-alpha2") >= Version::parse("1.2.3-alpha1"));
605        assert!(Version::parse("1.2.3-alpha2") >= Version::parse("1.2.3-alpha2"));
606        assert!(Version::parse("1.2.3+23") >= Version::parse("1.2.3+42"));
607    }
608
609    #[test]
610    fn test_prerelease_check() {
611        assert!(Version::parse("1.0.0").unwrap().is_prerelease() == false);
612        assert!(Version::parse("0.0.1").unwrap().is_prerelease() == false);
613        assert!(Version::parse("4.1.4-alpha").unwrap().is_prerelease());
614        assert!(Version::parse("1.0.0-beta294296").unwrap().is_prerelease());
615    }
616
617    #[test]
618    fn test_spec_order() {
619        let vs = [
620            "1.0.0-alpha",
621            "1.0.0-alpha.1",
622            "1.0.0-alpha.beta",
623            "1.0.0-beta",
624            "1.0.0-beta.2",
625            "1.0.0-beta.11",
626            "1.0.0-rc.1",
627            "1.0.0",
628        ];
629        let mut i = 1;
630        while i < vs.len() {
631            let a = Version::parse(vs[i - 1]);
632            let b = Version::parse(vs[i]);
633            assert!(a < b, "nope {:?} < {:?}", a, b);
634            i += 1;
635        }
636    }
637
638    #[test]
639    fn test_from_str() {
640        assert_eq!(
641            Version::parse("1.2.3"),
642            Ok(Version {
643                major: 1,
644                minor: 2,
645                patch: 3,
646                pre: Vec::new(),
647                build: Vec::new(),
648            },)
649        );
650        assert_eq!(
651            Version::parse("  1.2.3  "),
652            Ok(Version {
653                major: 1,
654                minor: 2,
655                patch: 3,
656                pre: Vec::new(),
657                build: Vec::new(),
658            },)
659        );
660        assert_eq!(
661            Version::parse("1.2.3-alpha1"),
662            Ok(Version {
663                major: 1,
664                minor: 2,
665                patch: 3,
666                pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],
667                build: Vec::new(),
668            },)
669        );
670        assert_eq!(
671            Version::parse("  1.2.3-alpha1  "),
672            Ok(Version {
673                major: 1,
674                minor: 2,
675                patch: 3,
676                pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],
677                build: Vec::new(),
678            },)
679        );
680        assert_eq!(
681            Version::parse("1.2.3+build5"),
682            Ok(Version {
683                major: 1,
684                minor: 2,
685                patch: 3,
686                pre: Vec::new(),
687                build: vec![Identifier::AlphaNumeric(String::from("build5"))],
688            },)
689        );
690        assert_eq!(
691            Version::parse("  1.2.3+build5  "),
692            Ok(Version {
693                major: 1,
694                minor: 2,
695                patch: 3,
696                pre: Vec::new(),
697                build: vec![Identifier::AlphaNumeric(String::from("build5"))],
698            },)
699        );
700        assert_eq!(
701            Version::parse("1.2.3-alpha1+build5"),
702            Ok(Version {
703                major: 1,
704                minor: 2,
705                patch: 3,
706                pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],
707                build: vec![Identifier::AlphaNumeric(String::from("build5"))],
708            },)
709        );
710        assert_eq!(
711            Version::parse("  1.2.3-alpha1+build5  "),
712            Ok(Version {
713                major: 1,
714                minor: 2,
715                patch: 3,
716                pre: vec![Identifier::AlphaNumeric(String::from("alpha1"))],
717                build: vec![Identifier::AlphaNumeric(String::from("build5"))],
718            },)
719        );
720        assert_eq!(
721            Version::parse("1.2.3-1.alpha1.9+build5.7.3aedf  "),
722            Ok(Version {
723                major: 1,
724                minor: 2,
725                patch: 3,
726                pre: vec![
727                    Identifier::Numeric(1),
728                    Identifier::AlphaNumeric(String::from("alpha1")),
729                    Identifier::Numeric(9),
730                ],
731                build: vec![
732                    Identifier::AlphaNumeric(String::from("build5")),
733                    Identifier::Numeric(7),
734                    Identifier::AlphaNumeric(String::from("3aedf")),
735                ],
736            },)
737        );
738        assert_eq!(
739            Version::parse("0.4.0-beta.1+0851523"),
740            Ok(Version {
741                major: 0,
742                minor: 4,
743                patch: 0,
744                pre: vec![
745                    Identifier::AlphaNumeric(String::from("beta")),
746                    Identifier::Numeric(1),
747                ],
748                build: vec![Identifier::AlphaNumeric(String::from("0851523"))],
749            },)
750        );
751    }
752
753    struct SemverTest(&'static str, &'static str, bool);
754
755    /// Declare range tests.
756    macro_rules! semver_tests {
757        ($(($($test:tt)*),)+) => {
758            [$(semver_tests!(@test $($test)*),)+]
759        };
760
761        (@test $req:expr, $version:expr) => {
762            SemverTest($req, $version, false)
763        };
764
765        (@test $req:expr, $version:expr, true) => {
766            SemverTest($req, $version, true)
767        };
768    }
769
770    /// Tests ported from:
771    /// https://raw.githubusercontent.com/npm/node-semver/master/test/index.js
772    #[test]
773    fn node_semver_comparisons() {
774        let input = semver_tests![
775            ("0.0.0", "0.0.0-foo"),
776            ("0.0.1", "0.0.0"),
777            ("1.0.0", "0.9.9"),
778            ("0.10.0", "0.9.0"),
779            ("0.99.0", "0.10.0"),
780            ("2.0.0", "1.2.3"),
781            ("v0.0.0", "0.0.0-foo", true),
782            ("v0.0.1", "0.0.0", true),
783            ("v1.0.0", "0.9.9", true),
784            ("v0.10.0", "0.9.0", true),
785            ("v0.99.0", "0.10.0", true),
786            ("v2.0.0", "1.2.3", true),
787            ("0.0.0", "v0.0.0-foo", true),
788            ("0.0.1", "v0.0.0", true),
789            ("1.0.0", "v0.9.9", true),
790            ("0.10.0", "v0.9.0", true),
791            ("0.99.0", "v0.10.0", true),
792            ("2.0.0", "v1.2.3", true),
793            ("1.2.3", "1.2.3-asdf"),
794            ("1.2.3", "1.2.3-4"),
795            ("1.2.3", "1.2.3-4-foo"),
796            ("1.2.3-5-foo", "1.2.3-5"),
797            ("1.2.3-5", "1.2.3-4"),
798            ("1.2.3-5-foo", "1.2.3-5-Foo"),
799            ("3.0.0", "2.7.2+asdf"),
800            ("1.2.3-a.10", "1.2.3-a.5"),
801            ("1.2.3-a.b", "1.2.3-a.5"),
802            ("1.2.3-a.b", "1.2.3-a"),
803            ("1.2.3-a.b.c.10.d.5", "1.2.3-a.b.c.5.d.100"),
804            ("1.2.3-r2", "1.2.3-r100"),
805            ("1.2.3-r100", "1.2.3-R2"),
806        ];
807
808        for (i, &SemverTest(left, right, loose)) in input.into_iter().enumerate() {
809            // NOTE: we don't support loose parsing.
810            if loose {
811                continue;
812            }
813
814            let left = Version::parse(left)
815                .map_err(|e| format!("failed to parse: {}: {}", left, e))
816                .unwrap();
817
818            let right = Version::parse(right)
819                .map_err(|e| format!("failed to parse: {}: {}", right, e))
820                .unwrap();
821
822            assert!(left > right, "#{}: {} > {}", i, left, right);
823            assert!(!(left < right));
824            assert!(!(left <= right));
825            assert!(!(left == right));
826            assert!(left != right);
827        }
828    }
829
830    /// Tests ported from:
831    /// https://raw.githubusercontent.com/npm/node-semver/master/test/index.js
832    #[test]
833    fn node_semver_range() {
834        // NOTE: we support multiple predicates separated by comma (,) instead of spaces.
835        let input = semver_tests![
836            // ("1.0.0 - 2.0.0", "1.2.3", ignore),
837            ("^1.2.3+build", "1.2.3"),
838            ("^1.2.3+build", "1.3.0"),
839            // NOTE: not supported.
840            // ("1.2.3-pre+asdf - 2.4.3-pre+asdf", "1.2.3"),
841            // ("1.2.3pre+asdf - 2.4.3-pre+asdf", "1.2.3", true),
842            // ("1.2.3-pre+asdf - 2.4.3pre+asdf", "1.2.3", true),
843            // ("1.2.3pre+asdf - 2.4.3pre+asdf", "1.2.3", true),
844            // ("1.2.3-pre+asdf - 2.4.3-pre+asdf", "1.2.3-pre.2"),
845            // ("1.2.3-pre+asdf - 2.4.3-pre+asdf", "2.4.3-alpha"),
846            // ("1.2.3+asdf - 2.4.3+asdf", "1.2.3"),
847            ("1.0.0", "1.0.0"),
848            (">=*", "0.2.4"),
849            ("", "1.0.0"),
850            ("*", "1.2.3"),
851            ("*", "v1.2.3", true),
852            (">=1.0.0", "1.0.0"),
853            (">=1.0.0", "1.0.1"),
854            (">=1.0.0", "1.1.0"),
855            (">1.0.0", "1.0.1"),
856            (">1.0.0", "1.1.0"),
857            ("<=2.0.0", "2.0.0"),
858            ("<=2.0.0", "1.9999.9999"),
859            ("<=2.0.0", "0.2.9"),
860            ("<2.0.0", "1.9999.9999"),
861            ("<2.0.0", "0.2.9"),
862            (">= 1.0.0", "1.0.0"),
863            (">=  1.0.0", "1.0.1"),
864            (">=   1.0.0", "1.1.0"),
865            ("> 1.0.0", "1.0.1"),
866            (">  1.0.0", "1.1.0"),
867            ("<=   2.0.0", "2.0.0"),
868            ("<= 2.0.0", "1.9999.9999"),
869            ("<=  2.0.0", "0.2.9"),
870            ("<    2.0.0", "1.9999.9999"),
871            ("<\t2.0.0", "0.2.9"),
872            (">=0.1.97", "v0.1.97", true),
873            (">=0.1.97", "0.1.97"),
874            // ("0.1.20 || 1.2.4", "1.2.4"),
875            // (">=0.2.3 || <0.0.1", "0.0.0"),
876            // (">=0.2.3 || <0.0.1", "0.2.3"),
877            // (">=0.2.3 || <0.0.1", "0.2.4"),
878            // ("||", "1.3.4"),
879            ("2.x.x", "2.1.3"),
880            ("1.2.x", "1.2.3"),
881            // ("1.2.x || 2.x", "2.1.3"),
882            // ("1.2.x || 2.x", "1.2.3"),
883            ("x", "1.2.3"),
884            ("2.*.*", "2.1.3"),
885            ("1.2.*", "1.2.3"),
886            // ("1.2.* || 2.*", "2.1.3"),
887            // ("1.2.* || 2.*", "1.2.3"),
888            ("*", "1.2.3"),
889            ("2", "2.1.2"),
890            ("2.3", "2.3.1"),
891            ("~x", "0.0.9"),   // >=2.4.0 <2.5.0
892            ("~2", "2.0.9"),   // >=2.4.0 <2.5.0
893            ("~2.4", "2.4.0"), // >=2.4.0 <2.5.0
894            ("~2.4", "2.4.5"),
895            // ("~>3.2.1", "3.2.2"), // >=3.2.1 <3.3.0,
896            ("~1", "1.2.3"), // >=1.0.0 <2.0.0
897            // ("~>1", "1.2.3"),
898            // ("~> 1", "1.2.3"),
899            ("~1.0", "1.0.2"), // >=1.0.0 <1.1.0,
900            ("~ 1.0", "1.0.2"),
901            ("~ 1.0.3", "1.0.12"),
902            (">=1", "1.0.0"),
903            (">= 1", "1.0.0"),
904            ("<1.2", "1.1.1"),
905            ("< 1.2", "1.1.1"),
906            // ("~v0.5.4-pre", "0.5.5"),
907            // ("~v0.5.4-pre", "0.5.4"),
908            ("=0.7.x", "0.7.2"),
909            // NOTE: mixing operations and wildcards are _not_ supported.
910            // ("<=0.7.x", "0.7.2"),
911            // (">=0.7.x", "0.7.2"),
912            // ("<=0.7.x", "0.6.2"),
913            ("~1.2.1, >=1.2.3", "1.2.3"),
914            ("~1.2.1, =1.2.3", "1.2.3"),
915            ("~1.2.1, 1.2.3", "1.2.3"),
916            ("~1.2.1, >=1.2.3, 1.2.3", "1.2.3"),
917            ("~1.2.1, 1.2.3, >=1.2.3", "1.2.3"),
918            ("~1.2.1, 1.2.3", "1.2.3"),
919            (">=1.2.1, 1.2.3", "1.2.3"),
920            ("1.2.3, >=1.2.1", "1.2.3"),
921            (">=1.2.3, >=1.2.1", "1.2.3"),
922            (">=1.2.1, >=1.2.3", "1.2.3"),
923            (">=1.2", "1.2.8"),
924            ("^1.2.3", "1.8.1"),
925            ("^0.1.2", "0.1.2"),
926            ("^0.1", "0.1.2"),
927            ("^0.0.1", "0.0.1"),
928            ("^1.2", "1.4.2"),
929            ("^1.2, ^1", "1.4.2"),
930            ("^1.2.3-alpha", "1.2.3-pre"),
931            ("^1.2.0-alpha", "1.2.0-pre"),
932            ("^0.0.1-alpha", "0.0.1-beta"),
933            ("^0.1.1-alpha", "0.1.1-beta"),
934            ("^x", "1.2.3"),
935            // ("x - 1.0.0", "0.9.7"),
936            // ("x - 1.x", "0.9.7"),
937            // ("1.0.0 - x", "1.9.7"),
938            // ("1.x - x", "1.9.7"),
939            // NOTE: mixing operations and wildcards are _not_ supported.
940            // ("<=7.x", "7.9.9"),
941        ];
942
943        for (i, &SemverTest(req, version, loose)) in input.into_iter().enumerate() {
944            // NOTE: loose mode not supported.
945            if loose {
946                continue;
947            }
948
949            let req = Range::parse(req)
950                .map_err(|e| format!("{}: {}", e, req))
951                .unwrap();
952            let version = Version::parse(version).unwrap();
953
954            assert!(
955                req.matches(&version),
956                "#{}: ({}).matches({})",
957                i,
958                req,
959                version
960            );
961        }
962    }
963}