lenient_version/
lib.rs

1//! Lenient semantic version.
2//!
3//! Companion version struct for the lenient_semver_parser parser.
4//! Compared to [`semver::Version`], this version:
5//!  - Supports additional numeric identifiers (e.g. 1.2.3.4.5)
6//!  - Does not allocate Strings for metadata
7//! Compared to [`semver::Version`] <= 0.11, this version:
8//!  - Does not allocate Vectors for metadata
9#![deny(
10    bad_style,
11    const_err,
12    dead_code,
13    improper_ctypes,
14    missing_copy_implementations,
15    missing_debug_implementations,
16    missing_docs,
17    no_mangle_generic_items,
18    non_shorthand_field_patterns,
19    overflowing_literals,
20    path_statements,
21    patterns_in_fns_without_body,
22    private_in_public,
23    rust_2018_idioms,
24    trivial_casts,
25    trivial_numeric_casts,
26    unconditional_recursion,
27    unsafe_code,
28    unused_allocation,
29    unused_comparisons,
30    unused_extern_crates,
31    unused_import_braces,
32    unused_parens,
33    unused_qualifications,
34    unused_results,
35    unused,
36    while_true
37)]
38
39use std::{
40    cmp::Ordering,
41    fmt::{self, Display, Write},
42    hash,
43    ops::Deref,
44};
45
46mod metadata;
47pub use metadata::{Additional, Build, PreRelease};
48
49/// Represents a lenient semantic version number.
50///
51/// The version is bound to the lifetime of the input string.
52#[derive(Debug, Clone)]
53pub struct Version<'input> {
54    /// The major version.
55    pub major: u64,
56    /// The minor version.
57    pub minor: u64,
58    /// The patch version.
59    pub patch: u64,
60    /// additional version numbers.
61    pub additional: Additional,
62    /// The pre-release metadata.
63    pub pre: PreRelease<'input>,
64    /// The build metadata.
65    pub build: Build<'input>,
66}
67
68impl<'input> Version<'input> {
69    /// Constructs a new, empty version
70    ///
71    /// ## Examples
72    ///
73    /// ```
74    /// # use lenient_version::Version;
75    /// let version = Version::empty();
76    /// assert_eq!(version.to_string(), "0.0.0")
77    /// ```
78    pub const fn empty() -> Self {
79        Version {
80            major: 0,
81            minor: 0,
82            patch: 0,
83            additional: Additional::empty(),
84            pre: PreRelease::empty(),
85            build: Build::empty(),
86        }
87    }
88
89    /// Constructs a new version out of the three regular version components
90    ///
91    /// ## Examples
92    ///
93    /// ```
94    /// # use lenient_version::Version;
95    /// let version = Version::new(1, 2, 3);
96    /// assert_eq!(version.to_string(), "1.2.3")
97    /// ```
98    pub const fn new(major: u64, minor: u64, patch: u64) -> Self {
99        Version {
100            major,
101            minor,
102            patch,
103            additional: Additional::empty(),
104            pre: PreRelease::empty(),
105            build: Build::empty(),
106        }
107    }
108
109    /// Parse a string slice into a Version.
110    ///
111    /// This parser does not require semver-specification conformant input and is more lenient in what it allows.
112    /// For more information, see [`lenient_semver_parser`].
113    ///
114    ///
115    /// ## Examples
116    ///
117    /// ```rust
118    /// # use lenient_version::Version;
119    ///
120    /// let version = Version::parse("v1.2.3.4.5+build.42");
121    /// assert!(version.is_ok());
122    /// ```
123    #[cfg(feature = "parser")]
124    pub fn parse(input: &'input str) -> Result<Self, lenient_semver_parser::Error<'input>> {
125        lenient_semver_parser::parse::<Self>(input)
126    }
127
128    /// Bumps the major version.
129    ///
130    /// Sets minor, patch, and additional numbers to 0, removes pre-release and build identifier.
131    ///
132    /// ## Examples
133    ///
134    /// ```rust
135    /// # use lenient_version::Version;
136    ///
137    /// let mut version = Version::parse("1.2.3.4.5-pre+build").unwrap();
138    /// version.bump_major();
139    /// assert_eq!(version.to_string(), "2.0.0.0.0");
140    /// ```
141    pub fn bump_major(&mut self) {
142        self.major += 1;
143        self.minor = 0;
144        self.patch = 0;
145        self.additional.set_to_zero();
146        self.clear_metadata();
147    }
148
149    /// Returns a new version with the major version bumped.
150    ///
151    /// Sets minor, patch, and additional numbers to 0, removes pre-release and build identifier.
152    /// The lifetime for the resulting version can differ from the lifetime of this version.
153    ///
154    /// ## Examples
155    ///
156    /// ```rust
157    /// # use lenient_version::Version;
158    ///
159    /// let version = Version::parse("1.2.3.4.5-pre+build").unwrap();
160    /// assert_eq!(version.bumped_major().to_string(), "2.0.0.0.0");
161    /// ```
162    pub fn bumped_major<'a>(&self) -> Version<'a> {
163        Version {
164            major: self.major + 1,
165            minor: 0,
166            patch: 0,
167            additional: self.additional.clone_with_zeroes(),
168            pre: PreRelease::empty(),
169            build: Build::empty(),
170        }
171    }
172
173    /// Bumps the minor version.
174    ///
175    /// Sets patch and additional numbers to 0, removes pre-release and build identifier.
176    ///
177    /// ## Examples
178    ///
179    /// ```rust
180    /// # use lenient_version::Version;
181    ///
182    /// let mut version = Version::parse("1.2.3.4.5-pre+build").unwrap();
183    /// version.bump_minor();
184    /// assert_eq!(version.to_string(), "1.3.0.0.0");
185    /// ```
186    pub fn bump_minor(&mut self) {
187        self.minor += 1;
188        self.patch = 0;
189        self.additional.set_to_zero();
190        self.clear_metadata();
191    }
192
193    /// Returns a new version with the minor version bumped.
194    ///
195    /// Sets patch and additional numbers to 0, removes pre-release and build identifier.
196    /// The lifetime for the resulting version can differ from the lifetime of this version.
197    ///
198    /// ## Examples
199    ///
200    /// ```rust
201    /// # use lenient_version::Version;
202    ///
203    /// let version = Version::parse("1.2.3.4.5-pre+build").unwrap();
204    /// assert_eq!(version.bumped_minor().to_string(), "1.3.0.0.0");
205    /// ```
206    pub fn bumped_minor<'a>(&self) -> Version<'a> {
207        Version {
208            major: self.major,
209            minor: self.minor + 1,
210            patch: 0,
211            additional: self.additional.clone_with_zeroes(),
212            pre: PreRelease::empty(),
213            build: Build::empty(),
214        }
215    }
216
217    /// Bumps the patch version.
218    ///
219    /// Sets any additional numbers to 0, removes pre-release and build identifier.
220    ///
221    /// ## Examples
222    ///
223    /// ```rust
224    /// # use lenient_version::Version;
225    ///
226    /// let mut version = Version::parse("1.2.3.4.5-pre+build").unwrap();
227    /// version.bump_patch();
228    /// assert_eq!(version.to_string(), "1.2.4.0.0");
229    /// ```
230    pub fn bump_patch(&mut self) {
231        self.patch += 1;
232        self.additional.set_to_zero();
233        self.clear_metadata();
234    }
235
236    /// Returns a new version with the patch version bumped.
237    ///
238    /// Sets any additional numbers to 0, removes pre-release and build identifier.
239    /// The lifetime for the resulting version can differ from the lifetime of this version.
240    ///
241    /// ## Examples
242    ///
243    /// ```rust
244    /// # use lenient_version::Version;
245    ///
246    /// let version = Version::parse("1.2.3.4.5-pre+build").unwrap();
247    /// assert_eq!(version.bumped_patch().to_string(), "1.2.4.0.0");
248    /// ```
249    pub fn bumped_patch<'a>(&self) -> Version<'a> {
250        Version {
251            major: self.major,
252            minor: self.minor,
253            patch: self.patch + 1,
254            additional: self.additional.clone_with_zeroes(),
255            pre: PreRelease::empty(),
256            build: Build::empty(),
257        }
258    }
259
260    /// Bumps any additional version.
261    ///
262    /// Sets any following additional numbers to 0, removes pre-release and build identifier.
263    /// If there are not enough additional numbers, only the pre-release and build identifier is removed.
264    ///
265    /// ## Examples
266    ///
267    /// ```rust
268    /// # use lenient_version::Version;
269    ///
270    /// let mut version = Version::parse("1.2.3.4.5-pre+build").unwrap();
271    /// version.bump_additional(0);
272    /// assert_eq!(version.to_string(), "1.2.3.5.0");
273    ///
274    /// let mut version = Version::parse("1.2.3.4.5-pre+build").unwrap();
275    /// version.bump_additional(1);
276    /// assert_eq!(version.to_string(), "1.2.3.4.6");
277    ///
278    /// let mut version = Version::parse("1.2.3.4.5-pre+build").unwrap();
279    /// version.bump_additional(2);
280    /// assert_eq!(version.to_string(), "1.2.3.4.5");
281    /// ```
282    pub fn bump_additional(&mut self, index: usize) {
283        self.additional.bump(index);
284        self.clear_metadata();
285    }
286
287    /// Returns a new version with the minor version bumped.
288    ///
289    /// Sets patch and additional numbers to 0, removes pre-release and build identifier.
290    /// The lifetime for the resulting version can differ from the lifetime of this version.
291    ///
292    /// ## Examples
293    ///
294    /// ```rust
295    /// # use lenient_version::Version;
296    ///
297    /// let version = Version::parse("1.2.3.4.5-pre+build").unwrap();
298    /// assert_eq!(version.bumped_additional(0).to_string(), "1.2.3.5.0");
299    /// assert_eq!(version.bumped_additional(1).to_string(), "1.2.3.4.6");
300    /// assert_eq!(version.bumped_additional(2).to_string(), "1.2.3.4.5");
301    /// ```
302    pub fn bumped_additional<'a>(&self, index: usize) -> Version<'a> {
303        let mut additional = self.additional.clone();
304        additional.bump(index);
305        Version {
306            major: self.major,
307            minor: self.minor,
308            patch: self.patch,
309            additional,
310            pre: PreRelease::empty(),
311            build: Build::empty(),
312        }
313    }
314
315    /// Returns true if this version has pre-release metadata, i.e. it represents a pre-release.
316    ///
317    /// ## Examples
318    ///
319    /// ```rust
320    /// # use lenient_version::Version;
321    ///
322    /// let version = Version::parse("1").unwrap();
323    /// assert!(!version.is_pre_release());
324    ///
325    /// let version = Version::parse("1-pre").unwrap();
326    /// assert!(version.is_pre_release());
327    ///
328    /// let version = Version::parse("1+build").unwrap();
329    /// assert!(!version.is_pre_release());
330    /// ```
331    pub fn is_pre_release(&self) -> bool {
332        self.pre.is_defined()
333    }
334
335    /// Disassociate this Version by changing the lifetime to something new.
336    ///
337    /// The returned is a copy of self without any metadata.
338    /// Nothing in the new version references 'input, so we can change the lifetime to something else.
339    ///
340    /// The existing identifiers for pre-release and build are returned as well,
341    /// so that users can clone and re-add them.
342    ///
343    /// ## Examples
344    ///
345    /// ```rust
346    /// # use lenient_version::Version;
347    /// use lenient_semver_parser::VersionBuilder;
348    ///
349    /// let input = String::from("1-pre+build");
350    /// let version = Version::parse(&input).unwrap();
351    ///
352    /// // couldn't drop input here
353    /// // drop(input);
354    ///
355    /// let (mut version, pre, build) = version.disassociate_metadata::<'static>();
356    ///
357    /// assert_eq!(Some("pre"), *pre);
358    /// assert_eq!(Some("build"), *build);
359    ///
360    /// // now we can drop the input
361    /// drop(input);
362    ///
363    /// // We can use the new version after it has be disassociated from `input`.
364    /// assert_eq!("1.0.0", version.to_string());
365    ///
366    /// // only static metadata references are allowed now (because we said 'static earlier)
367    /// version.add_pre_release("pre2");
368    /// version.add_build("build2");
369    ///
370    /// assert_eq!("1.0.0-pre2+build2", version.to_string());
371    /// ```
372    pub fn disassociate_metadata<'a>(self) -> (Version<'a>, PreRelease<'input>, Build<'input>) {
373        let Version {
374            major,
375            minor,
376            patch,
377            additional,
378            pre,
379            build,
380        } = self;
381        let version = Version {
382            major,
383            minor,
384            patch,
385            additional,
386            pre: PreRelease::empty(),
387            build: Build::empty(),
388        };
389        (version, pre, build)
390    }
391
392    fn clear_metadata(&mut self) {
393        self.pre.clear();
394        self.build.clear();
395    }
396}
397
398impl Default for Version<'_> {
399    fn default() -> Self {
400        Self::empty()
401    }
402}
403
404impl<'input> From<u64> for Version<'input> {
405    fn from(x: u64) -> Self {
406        Version::new(x, 0, 0)
407    }
408}
409
410impl<'input> From<(u64, u64)> for Version<'input> {
411    fn from((x, y): (u64, u64)) -> Self {
412        Version::new(x, y, 0)
413    }
414}
415
416impl<'input> From<(u64, u64, u64)> for Version<'input> {
417    fn from((x, y, z): (u64, u64, u64)) -> Self {
418        Version::new(x, y, z)
419    }
420}
421
422impl<'input> From<[u64; 1]> for Version<'input> {
423    fn from(v: [u64; 1]) -> Self {
424        Version::new(v[0], 0, 0)
425    }
426}
427
428impl<'input> From<[u64; 2]> for Version<'input> {
429    fn from(v: [u64; 2]) -> Self {
430        Version::new(v[0], v[1], 0)
431    }
432}
433
434impl<'input> From<[u64; 3]> for Version<'input> {
435    fn from(v: [u64; 3]) -> Self {
436        Version::new(v[0], v[1], v[2])
437    }
438}
439
440#[cfg(feature = "parser")]
441impl<'input> std::convert::TryFrom<&'input str> for Version<'input> {
442    type Error = lenient_semver_parser::Error<'input>;
443
444    fn try_from(value: &'input str) -> Result<Self, Self::Error> {
445        Self::parse(value)
446    }
447}
448
449impl Display for Version<'_> {
450    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
451        let mut result = String::with_capacity(16);
452        write!(result, "{}.{}.{}", self.major, self.minor, self.patch)?;
453        for &additional in self.additional.iter() {
454            write!(result, ".{}", additional)?;
455        }
456
457        if let Some(pre) = self.pre.deref() {
458            result.push('-');
459            result.push_str(pre);
460        }
461        if let Some(build) = self.build.deref() {
462            result.push('+');
463            result.push_str(build);
464        }
465
466        f.pad(result.as_ref())
467    }
468}
469
470impl PartialEq for Version<'_> {
471    #[inline]
472    fn eq(&self, other: &Self) -> bool {
473        self.major == other.major
474            && self.minor == other.minor
475            && self.patch == other.patch
476            && self.additional == other.additional
477            && self.pre == other.pre
478    }
479}
480
481impl Eq for Version<'_> {}
482
483impl PartialOrd for Version<'_> {
484    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
485        Some(self.cmp(other))
486    }
487}
488
489impl Ord for Version<'_> {
490    fn cmp(&self, other: &Self) -> Ordering {
491        self.major
492            .cmp(&other.major)
493            .then_with(|| self.minor.cmp(&other.minor))
494            .then_with(|| self.patch.cmp(&other.patch))
495            .then_with(|| self.additional.cmp(&other.additional))
496            .then_with(|| self.pre.cmp(&other.pre))
497    }
498}
499
500impl hash::Hash for Version<'_> {
501    fn hash<H: hash::Hasher>(&self, into: &mut H) {
502        self.major.hash(into);
503        self.minor.hash(into);
504        self.patch.hash(into);
505        self.additional.hash(into);
506        self.pre.hash(into);
507    }
508}
509
510#[cfg(feature = "parser")]
511impl<'input> lenient_semver_parser::VersionBuilder<'input> for Version<'input> {
512    type Out = Self;
513
514    fn new() -> Self {
515        Version::default()
516    }
517
518    fn set_major(&mut self, major: u64) {
519        self.major = major;
520    }
521
522    fn set_minor(&mut self, minor: u64) {
523        self.minor = minor;
524    }
525
526    fn set_patch(&mut self, patch: u64) {
527        self.patch = patch;
528    }
529
530    fn add_additional(&mut self, num: u64) {
531        self.additional.push(num);
532    }
533
534    fn add_pre_release(&mut self, pre_release: &'input str) {
535        self.pre.set(pre_release)
536    }
537
538    fn add_build(&mut self, build: &'input str) {
539        self.build.set(build)
540    }
541
542    fn build(self) -> Self::Out {
543        self
544    }
545}
546
547#[cfg(all(feature = "serde", feature = "parser"))]
548use serde::de::{self, Deserialize, Deserializer, Visitor};
549#[cfg(feature = "serde")]
550use serde::ser::{Serialize, Serializer};
551#[cfg(feature = "serde")]
552impl Serialize for Version<'_> {
553    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
554        serializer.collect_str(self)
555    }
556}
557
558#[cfg(all(feature = "serde", feature = "parser"))]
559impl<'de: 'input, 'input> Deserialize<'de> for Version<'input> {
560    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
561        struct VersionVisitor<'input>(std::marker::PhantomData<&'input ()>);
562
563        impl<'de: 'input, 'input> Visitor<'de> for VersionVisitor<'input> {
564            type Value = Version<'input>;
565
566            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
567                formatter.write_str("a version string")
568            }
569
570            fn visit_borrowed_str<E>(self, v: &'input str) -> Result<Self::Value, E>
571            where
572                E: de::Error,
573            {
574                Version::parse(v).map_err(de::Error::custom)
575            }
576        }
577
578        deserializer.deserialize_str(VersionVisitor(std::marker::PhantomData))
579    }
580}
581
582#[cfg(feature = "semver")]
583impl<'input> From<Version<'input>> for semver_v100::Version {
584    fn from(v: Version<'input>) -> Self {
585        let build = if v.additional.is_empty() {
586            v.build.into()
587        } else {
588            let mut build = String::with_capacity(64);
589            for add in v.additional {
590                if !build.is_empty() {
591                    build.push('.');
592                }
593                let _ = write!(build, "{}", add);
594            }
595            if let Some(b) = *v.build {
596                build.push('.');
597                build.push_str(b);
598            }
599            let build = lenient_semver_version_builder::sanitize_build(build);
600            semver_v100::BuildMetadata::new(&build).unwrap()
601        };
602
603        semver_v100::Version {
604            major: v.major,
605            minor: v.minor,
606            patch: v.patch,
607            pre: v.pre.into(),
608            build,
609        }
610    }
611}
612
613#[cfg(feature = "semver011")]
614impl From<Version<'_>> for semver_v011::Version {
615    fn from(v: Version<'_>) -> Self {
616        let mut add: Vec<semver_v011::Identifier> = v.additional.into();
617        let mut build: Vec<semver_v011::Identifier> = v.build.into();
618        add.append(&mut build);
619        semver_v011::Version {
620            major: v.major,
621            minor: v.minor,
622            patch: v.patch,
623            pre: v.pre.into(),
624            build: add,
625        }
626    }
627}
628
629#[cfg(feature = "semver010")]
630impl From<Version<'_>> for semver_v010::Version {
631    fn from(v: Version<'_>) -> Self {
632        let mut add: Vec<semver_v010::Identifier> = v.additional.into();
633        let mut build: Vec<semver_v010::Identifier> = v.build.into();
634        add.append(&mut build);
635        semver_v010::Version {
636            major: v.major,
637            minor: v.minor,
638            patch: v.patch,
639            pre: v.pre.into(),
640            build: add,
641        }
642    }
643}
644
645#[cfg(test)]
646mod tests {
647    use super::Version;
648    use test_case::test_case;
649
650    #[test]
651    fn test_bump_major() {
652        let mut version = Version::parse("1.2.3.4.5-pre+build").unwrap();
653        version.bump_major();
654        assert_eq!(version, Version::parse("2.0.0.0.0").unwrap());
655    }
656
657    #[test]
658    fn test_bumped_major() {
659        let version = Version::parse("1.2.3.4.5-pre+build").unwrap();
660        assert_eq!(version.bumped_major(), Version::parse("2.0.0.0.0").unwrap());
661    }
662
663    #[test]
664    fn test_bump_minor() {
665        let mut version = Version::parse("1.2.3.4.5-pre+build").unwrap();
666        version.bump_minor();
667        assert_eq!(version, Version::parse("1.3.0.0.0").unwrap());
668    }
669
670    #[test]
671    fn test_bumped_minor() {
672        let version = Version::parse("1.2.3.4.5-pre+build").unwrap();
673        assert_eq!(version.bumped_minor(), Version::parse("1.3.0.0.0").unwrap());
674    }
675
676    #[test]
677    fn test_bump_patch() {
678        let mut version = Version::parse("1.2.3.4.5-pre+build").unwrap();
679        version.bump_patch();
680        assert_eq!(version, Version::parse("1.2.4.0.0").unwrap());
681    }
682
683    #[test]
684    fn test_bumped_patch() {
685        let version = Version::parse("1.2.3.4.5-pre+build").unwrap();
686        assert_eq!(version.bumped_patch(), Version::parse("1.2.4.0.0").unwrap());
687    }
688
689    #[test_case(0, "1.2.3.5.0")]
690    #[test_case(1, "1.2.3.4.6")]
691    #[test_case(2, "1.2.3.4.5")]
692    fn test_bump_additional(index: usize, expected: &str) {
693        let mut version = Version::parse("1.2.3.4.5-pre+build").unwrap();
694        version.bump_additional(index);
695        assert_eq!(version, Version::parse(expected).unwrap());
696    }
697
698    #[test_case(0, "1.2.3.5.0")]
699    #[test_case(1, "1.2.3.4.6")]
700    #[test_case(2, "1.2.3.4.5")]
701    fn test_bumped_additional(index: usize, expected: &str) {
702        let version = Version::parse("1.2.3.4.5-pre+build").unwrap();
703        assert_eq!(
704            version.bumped_additional(index),
705            Version::parse(expected).unwrap()
706        );
707    }
708
709    #[test_case("1")]
710    #[test_case("1.2")]
711    #[test_case("1.2.3")]
712    #[test_case("1.2.3.4")]
713    #[test_case("1.2.3.4.5")]
714    #[test_case("1.2.3.4.5+build")]
715    fn test_is_not_pre_release(input: &str) {
716        assert!(!Version::parse(input).unwrap().is_pre_release());
717    }
718
719    #[test_case("1-2")]
720    #[test_case("1-a")]
721    #[test_case("1.2-3")]
722    #[test_case("1.2-a")]
723    #[test_case("1.2.3-4")]
724    #[test_case("1.2.3-a")]
725    #[test_case("1.2.3.4-5")]
726    #[test_case("1.2.3.4-a")]
727    #[test_case("1.2.3.4.5-pre")]
728    fn test_is_pre_release(input: &str) {
729        assert!(Version::parse(input).unwrap().is_pre_release());
730    }
731
732    #[test_case("1", "1.0.0")]
733    #[test_case("1.2", "1.2.0")]
734    #[test_case("1.2.3", "1.2.3")]
735    #[test_case("1.2.3.4", "1.2.3.4")]
736    #[test_case("1.2.3.4.5", "1.2.3.4.5")]
737    #[test_case("1.2.3-pre", "1.2.3-pre")]
738    #[test_case("1.2.3.pre2", "1.2.3-pre2")]
739    #[test_case("1.2.3+build", "1.2.3+build")]
740    #[test_case("1.2.3.4-pre-42+r-1337", "1.2.3.4-pre-42+r-1337")]
741    fn test_to_string(v: &str, expected: &str) {
742        assert_eq!(Version::parse(v).unwrap().to_string(), expected.to_string());
743    }
744
745    #[test]
746    fn test_from_u64() {
747        assert_eq!(Version::from(42), Version::new(42, 0, 0));
748    }
749
750    #[test]
751    fn test_from_u64_u64() {
752        assert_eq!(Version::from((42, 13)), Version::new(42, 13, 0));
753    }
754
755    #[test]
756    fn test_from_u64_u64_u64() {
757        assert_eq!(Version::from((42, 13, 37)), Version::new(42, 13, 37));
758    }
759
760    #[test]
761    fn test_from_u64_1() {
762        assert_eq!(Version::from([42]), Version::new(42, 0, 0));
763    }
764
765    #[test]
766    fn test_from_u64_2() {
767        assert_eq!(Version::from([42, 13]), Version::new(42, 13, 0));
768    }
769
770    #[test]
771    fn test_from_u64_3() {
772        assert_eq!(Version::from([42, 13, 37]), Version::new(42, 13, 37));
773    }
774
775    #[test]
776    fn test_display() {
777        let version = Version::parse("1.2.3.4.5-pre+build").unwrap();
778        assert_eq!(
779            format!("{:42}", version),
780            "1.2.3.4.5-pre+build                       "
781        );
782        assert_eq!(
783            format!("{:>42}", version),
784            "                       1.2.3.4.5-pre+build"
785        );
786        assert_eq!(
787            format!("{:^42}", version),
788            "           1.2.3.4.5-pre+build            "
789        );
790        assert_eq!(
791            format!("{:*<42}", version),
792            "1.2.3.4.5-pre+build***********************"
793        );
794        assert_eq!(
795            format!("{:*>42}", version),
796            "***********************1.2.3.4.5-pre+build"
797        );
798        assert_eq!(
799            format!("{:*^42}", version),
800            "***********1.2.3.4.5-pre+build************"
801        );
802        assert_eq!(format!("{:.7}", version), "1.2.3.4");
803    }
804
805    #[test]
806    fn test_parses_additional() {
807        let version = Version::parse("1.2.3.4.5-alpha1.drop02").unwrap();
808        assert_eq!(vec![4, 5], &*version.additional)
809    }
810
811    #[test_case("1")]
812    #[test_case("1.2")]
813    #[test_case("1.2.3")]
814    #[test_case("1.2.3.4")]
815    #[test_case("1.2.3.4.5")]
816    #[test_case("1.2.3-pre")]
817    #[test_case("1.2.3+build")]
818    #[test_case("1.2.3-pre+build")]
819    fn test_eq(input: &str) {
820        assert_eq!(Version::parse(input), Version::parse(input));
821    }
822
823    #[test_case("1", "1.0.0")]
824    #[test_case("1.2", "1.2.0")]
825    #[test_case("1.2.3+42", "1.2.3+1337")]
826    #[test_case("1.2.3-pre", "1.2.3-pre+build")]
827    fn test_eq2(v1: &str, v2: &str) {
828        assert_eq!(Version::parse(v1), Version::parse(v2));
829    }
830
831    #[test_case("1", "2")]
832    #[test_case("1.2", "1.3")]
833    #[test_case("1.2.3", "1.2.4")]
834    #[test_case("1.2.3-pre", "1.2.3")]
835    #[test_case("1.2.3.4", "1.2.3")]
836    #[test_case("1.2.3.4", "1.2.3.5")]
837    #[test_case("1.2.3.4", "1.2.3.4.5")]
838    #[test_case("1.2.3-pre", "1.2.3-pre2")]
839    fn test_ne(v1: &str, v2: &str) {
840        assert_ne!(Version::parse(v1), Version::parse(v2));
841    }
842
843    #[test_case("0.0.0", "0.0.1")]
844    #[test_case("0.0.0", "0.1.0")]
845    #[test_case("0.0.0", "1.0.0")]
846    #[test_case("1.0.0", "1.0.1")]
847    #[test_case("1.0.0", "1.1.0")]
848    #[test_case("1.0.0", "2.0.0")]
849    #[test_case("1.1.0", "1.1.1")]
850    #[test_case("1.1.0", "1.2.0")]
851    #[test_case("1.1.0", "2.0.0")]
852    #[test_case("1.2.3", "1.2.3.4")]
853    #[test_case("1.2.3.4", "1.2.3.5")]
854    #[test_case("1.2.3.4", "1.2.3.4.5")]
855    #[test_case("1.2.3-pre", "1.2.3")]
856    #[test_case("1.2.3.4-pre", "1.2.3.4")]
857    #[test_case("1.2.3.4.5-pre", "1.2.3.4.5")]
858    #[test_case("1.2.3", "1.2.3.4-pre")]
859    #[test_case("1.2.2", "1.2.3-pre")]
860    #[test_case("1.2.0", "1.2.3-pre")]
861    #[test_case("1.0.0", "1.2.3-pre")]
862    #[test_case("0.4.2", "1.2.3-pre")]
863    #[test_case("0.0.1", "1.2.3-pre")]
864    #[test_case("1.2.3-42", "1.2.3-84")]
865    #[test_case("1.2.3-42", "1.2.3-123")]
866    #[test_case("1.2.3-42", "1.2.3-42foo")]
867    #[test_case("1.2.3-42", "1.2.3-12foo")]
868    #[test_case("1.2.3-42", "1.2.3-1foo")]
869    #[test_case("1.2.3-42", "1.2.3-foo")]
870    fn test_lt(v1: &str, v2: &str) {
871        assert!(Version::parse(v1) < Version::parse(v2));
872    }
873
874    #[test_case("1.2.3", "1.2.3")]
875    #[test_case("1.2.3.4", "1.2.3.4")]
876    #[test_case("1.2.3.4.5", "1.2.3.4.5")]
877    #[test_case("1.2.3", "1.2.3.0.0")]
878    #[test_case("1.2.3.4", "1.2.3.4.0")]
879    #[test_case("1.2.3-pre", "1.2.3-pre")]
880    #[test_case("1.2.3+build", "1.2.3+build")]
881    #[test_case("1.2.3+build2", "1.2.3+build3")]
882    #[test_case("1.2.3+42", "1.2.3+84")]
883    fn test_not_lt(v1: &str, v2: &str) {
884        assert!(!(Version::parse(v1) < Version::parse(v2)));
885    }
886
887    #[test_case("0.0.0", "0.0.1")]
888    #[test_case("0.0.1", "0.0.1")]
889    #[test_case("0.0.0", "0.1.0")]
890    #[test_case("0.1.0", "0.1.0")]
891    #[test_case("0.0.0", "1.0.0")]
892    #[test_case("1.0.0", "1.0.0")]
893    #[test_case("1.2.3", "1.2.3.4")]
894    #[test_case("1.2.3.4", "1.2.3.4")]
895    #[test_case("1.2.3.4", "1.2.3.4.5")]
896    #[test_case("1.2.3.4.5", "1.2.3.4.5")]
897    #[test_case("1.2.3-pre", "1.2.3")]
898    #[test_case("1.2.3", "1.2.3")]
899    #[test_case("1.2.3+build", "1.2.3")]
900    fn test_lte(v1: &str, v2: &str) {
901        assert!(Version::parse(v1) <= Version::parse(v2));
902    }
903
904    #[test_case("0.0.1", "0.0.0")]
905    #[test_case("0.1.0", "0.0.0")]
906    #[test_case("1.0.0", "0.0.0")]
907    #[test_case("1.0.1", "1.0.0")]
908    #[test_case("1.1.0", "1.0.0")]
909    #[test_case("2.0.0", "1.0.0")]
910    #[test_case("1.1.1", "1.1.0")]
911    #[test_case("1.2.0", "1.1.0")]
912    #[test_case("2.0.0", "1.1.0")]
913    #[test_case("1.2.3.4", "1.2.3")]
914    #[test_case("1.2.3.5", "1.2.3.4")]
915    #[test_case("1.2.3.4.5", "1.2.3.4")]
916    #[test_case("1.2.3", "1.2.3-pre")]
917    #[test_case("1.2.3.4", "1.2.3.4-pre")]
918    #[test_case("1.2.3.4.5", "1.2.3.4.5-pre")]
919    #[test_case("1.2.3.4-pre", "1.2.3")]
920    #[test_case("1.2.3-pre", "1.2.2")]
921    #[test_case("1.2.3-pre", "1.2.0")]
922    #[test_case("1.2.3-pre", "1.0.0")]
923    #[test_case("1.2.3-pre", "0.4.2")]
924    #[test_case("1.2.3-pre", "0.0.1")]
925    fn test_gt(v1: &str, v2: &str) {
926        assert!(Version::parse(v1) > Version::parse(v2));
927    }
928
929    #[test_case("1.2.3", "1.2.3")]
930    #[test_case("1.2.3.4", "1.2.3.4")]
931    #[test_case("1.2.3.4.5", "1.2.3.4.5")]
932    #[test_case("1.2.3-pre", "1.2.3-pre")]
933    #[test_case("1.2.3+build", "1.2.3+build")]
934    #[test_case("1.2.3+build3", "1.2.3+build2")]
935    #[test_case("1.2.3+84", "1.2.3+42")]
936    fn test_not_gt(v1: &str, v2: &str) {
937        assert!(!(Version::parse(v1) > Version::parse(v2)));
938    }
939
940    #[test_case("0.0.1", "0.0.0")]
941    #[test_case("0.0.1", "0.0.1")]
942    #[test_case("0.1.0", "0.0.0")]
943    #[test_case("0.1.0", "0.1.0")]
944    #[test_case("1.0.0", "0.0.0")]
945    #[test_case("1.0.0", "1.0.0")]
946    #[test_case("1.2.3.4", "1.2.3")]
947    #[test_case("1.2.3.4", "1.2.3.4")]
948    #[test_case("1.2.3.4.5", "1.2.3.4")]
949    #[test_case("1.2.3.4.5", "1.2.3.4.5")]
950    #[test_case("1.2.3", "1.2.3-pre")]
951    #[test_case("1.2.3", "1.2.3")]
952    #[test_case("1.2.3", "1.2.3+build")]
953    fn test_gte(v1: &str, v2: &str) {
954        assert!(Version::parse(v1) >= Version::parse(v2));
955    }
956
957    #[test]
958    fn test_order_per_spec_11_4() {
959        let versions = [
960            "1.0.0-alpha",
961            "1.0.0-alpha.1",
962            "1.0.0-alpha.beta",
963            "1.0.0-beta",
964            "1.0.0-beta.2",
965            "1.0.0-beta.11",
966            "1.0.0-rc.1",
967            "1.0.0",
968        ]
969        .iter()
970        .map(|v| Version::parse(v))
971        .collect::<Result<Vec<_>, _>>()
972        .unwrap();
973
974        let left = versions.iter();
975        let right = versions.iter().skip(1);
976
977        for (left, right) in left.zip(right) {
978            assert!(left < right, "{} < {} was violated", left, right);
979        }
980    }
981
982    #[cfg(feature = "serde")]
983    #[cfg_attr(feature = "serde", test)]
984    fn test_ser() {
985        let v = Version::new(1, 2, 3);
986        assert_eq!(r#""1.2.3""#, serde_json::to_string(&v).unwrap());
987    }
988
989    #[cfg(feature = "serde")]
990    #[cfg_attr(feature = "serde", test)]
991    fn test_deser() {
992        let v = r#""1.2.3""#;
993        assert_eq!(Version::new(1, 2, 3), serde_json::from_str(v).unwrap());
994    }
995
996    #[cfg(feature = "semver")]
997    #[cfg_attr(feature = "semver", test)]
998    fn test_into_semver() {
999        let v = Version::new(1, 2, 3);
1000        assert_eq!(
1001            semver_v100::Version::new(1, 2, 3),
1002            semver_v100::Version::from(v)
1003        );
1004    }
1005
1006    #[cfg(feature = "semver")]
1007    #[test]
1008    fn test_into_semver_full() {
1009        use lenient_semver_version_builder::VersionBuilder;
1010        let mut v = <Version<'static> as VersionBuilder<'static>>::new();
1011        v.set_major(1);
1012        v.set_minor(2);
1013        v.set_patch(3);
1014        v.add_additional(42);
1015        v.add_additional(1337);
1016        v.add_pre_release("deprecated!alpha.01");
1017        v.add_build("build+42");
1018        let v = v.build();
1019
1020        let expected = semver_v100::Version {
1021            major: 1,
1022            minor: 2,
1023            patch: 3,
1024            pre: semver_v100::Prerelease::new("deprecated-alpha.1").unwrap(),
1025            build: semver_v100::BuildMetadata::new("42.1337.build-42").unwrap(),
1026        };
1027
1028        assert_eq!(expected, semver_v100::Version::from(v));
1029    }
1030
1031    #[cfg(feature = "semver011")]
1032    #[cfg_attr(feature = "semver011", test)]
1033    fn test_into_semver011() {
1034        let v = Version::new(1, 2, 3);
1035        assert_eq!(
1036            semver_v011::Version::new(1, 2, 3),
1037            semver_v011::Version::from(v)
1038        );
1039    }
1040
1041    #[cfg(feature = "semver010")]
1042    #[cfg_attr(feature = "semver010", test)]
1043    fn test_into_semver010() {
1044        let v = Version::new(1, 2, 3);
1045        assert_eq!(
1046            semver_v010::Version::new(1, 2, 3),
1047            semver_v010::Version::from(v)
1048        );
1049    }
1050}