1#![doc = include_str!("../README.md")]
2#![allow(clippy::needless_doctest_main)]
3
4#[cfg(feature = "serde")]
5use serde::{Deserialize, Serialize, de::Deserializer, ser::Serializer};
6
7use std::cmp::{self, Ordering};
8use std::fmt;
9
10use thiserror::Error;
11
12pub use range::*;
13
14mod parse;
15mod range;
16mod scan;
17mod version_fast;
18
19pub const MAX_SAFE_INTEGER: u64 = 900_719_925_474_099;
24
25pub const MAX_LENGTH: usize = 256;
27
28#[derive(Debug, Clone, Copy, Error, Eq, PartialEq)]
32#[error("Invalid semantic version or range")]
33pub struct SemverError;
34
35#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
39pub enum Identifier {
40 Numeric(u64),
42 AlphaNumeric(String),
44}
45
46impl fmt::Display for Identifier {
47 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48 match self {
49 Identifier::Numeric(n) => write!(f, "{}", n),
50 Identifier::AlphaNumeric(s) => write!(f, "{}", s),
51 }
52 }
53}
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
57pub enum VersionDiff {
58 Major,
59 Minor,
60 Patch,
61 PreMajor,
62 PreMinor,
63 PrePatch,
64 PreRelease,
65}
66
67pub type ReleaseType = VersionDiff;
69
70#[derive(Debug, Clone, Copy, PartialEq, Eq)]
71pub enum IdentifierBase {
72 False,
74 Value(u64),
76}
77
78impl Default for IdentifierBase {
79 fn default() -> Self {
80 IdentifierBase::Value(0)
81 }
82}
83
84impl IdentifierBase {
85 fn base_value(self) -> u64 {
86 match self {
87 IdentifierBase::False => 0,
88 IdentifierBase::Value(v) => {
89 if v == 0 {
90 0
91 } else {
92 1
93 }
94 }
95 }
96 }
97}
98
99impl From<bool> for IdentifierBase {
100 fn from(value: bool) -> Self {
101 if value {
102 IdentifierBase::Value(1)
103 } else {
104 IdentifierBase::False
105 }
106 }
107}
108
109impl From<u64> for IdentifierBase {
110 fn from(value: u64) -> Self {
111 IdentifierBase::Value(value)
112 }
113}
114
115impl From<usize> for IdentifierBase {
116 fn from(value: usize) -> Self {
117 IdentifierBase::Value(value as u64)
118 }
119}
120
121#[derive(Debug, Clone, PartialEq, Eq, Error)]
122pub enum IncrementError {
123 #[error("invalid identifier: {0}")]
124 InvalidIdentifier(String),
125 #[error("invalid increment argument: {0}")]
126 InvalidIncrementArgument(String),
127 #[error("version {0} is not a prerelease")]
128 NotAPrerelease(String),
129 #[error("increment would overflow a version component")]
130 Overflow,
131}
132
133impl fmt::Display for VersionDiff {
134 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135 match self {
136 VersionDiff::Major => write!(f, "major"),
137 VersionDiff::Minor => write!(f, "minor"),
138 VersionDiff::Patch => write!(f, "patch"),
139 VersionDiff::PreMajor => write!(f, "premajor"),
140 VersionDiff::PreMinor => write!(f, "preminor"),
141 VersionDiff::PrePatch => write!(f, "prepatch"),
142 VersionDiff::PreRelease => write!(f, "prerelease"),
143 }
144 }
145}
146
147#[derive(Clone, Debug)]
151pub struct Version {
152 major: u64,
153 minor: u64,
154 patch: u64,
155 meta: Option<Box<VersionMeta>>,
156}
157
158#[derive(Clone, Debug, Eq, PartialEq)]
160pub struct VersionParts {
161 pub major: u64,
162 pub minor: u64,
163 pub patch: u64,
164 pub pre_release: Vec<Identifier>,
165 pub build: Vec<Identifier>,
166}
167
168#[derive(Clone, Debug)]
169struct VersionMeta {
170 build: Identifiers,
171 pre_release: Identifiers,
172}
173
174#[derive(Clone, Debug)]
175pub(crate) enum Identifiers {
176 Empty,
177 One(Identifier),
178 Two([Identifier; 2]),
179 Many(Vec<Identifier>),
180}
181
182impl Identifiers {
183 pub(crate) fn from_vec(mut identifiers: Vec<Identifier>) -> Self {
184 match identifiers.len() {
185 0 => Self::Empty,
186 1 => Self::One(identifiers.pop().unwrap()),
187 2 => {
188 let second = identifiers.pop().unwrap();
189 let first = identifiers.pop().unwrap();
190 Self::Two([first, second])
191 }
192 _ => Self::Many(identifiers),
193 }
194 }
195
196 fn into_vec(self) -> Vec<Identifier> {
197 match self {
198 Self::Empty => Vec::new(),
199 Self::One(identifier) => vec![identifier],
200 Self::Two(identifiers) => Vec::from(identifiers),
201 Self::Many(identifiers) => identifiers,
202 }
203 }
204
205 fn as_slice(&self) -> &[Identifier] {
206 match self {
207 Self::Empty => &[],
208 Self::One(identifier) => std::slice::from_ref(identifier),
209 Self::Two(identifiers) => identifiers.as_slice(),
210 Self::Many(identifiers) => identifiers.as_slice(),
211 }
212 }
213
214 fn as_mut_slice(&mut self) -> &mut [Identifier] {
215 match self {
216 Self::Empty => &mut [],
217 Self::One(identifier) => std::slice::from_mut(identifier),
218 Self::Two(identifiers) => identifiers.as_mut_slice(),
219 Self::Many(identifiers) => identifiers.as_mut_slice(),
220 }
221 }
222
223 fn is_empty(&self) -> bool {
224 matches!(self, Self::Empty)
225 }
226
227 fn clear(&mut self) {
228 *self = Self::Empty;
229 }
230
231 pub(crate) fn push(&mut self, identifier: Identifier) {
232 match std::mem::replace(self, Self::Empty) {
233 Self::Empty => *self = Self::One(identifier),
234 Self::One(existing) => *self = Self::Two([existing, identifier]),
235 Self::Two([first, second]) => *self = Self::Many(vec![first, second, identifier]),
236 Self::Many(mut identifiers) => {
237 identifiers.push(identifier);
238 *self = Self::Many(identifiers);
239 }
240 }
241 }
242}
243
244#[cfg(feature = "serde")]
245impl Serialize for Version {
246 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
247 s.collect_str(self)
248 }
249}
250
251#[cfg(feature = "serde")]
252impl<'de> Deserialize<'de> for Version {
253 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
254 let s = String::deserialize(d)?;
255 s.parse().map_err(serde::de::Error::custom)
256 }
257}
258
259impl Version {
260 pub fn major(&self) -> u64 {
262 self.major
263 }
264
265 pub fn minor(&self) -> u64 {
267 self.minor
268 }
269
270 pub fn patch(&self) -> u64 {
272 self.patch
273 }
274
275 pub fn new(
276 major: u64,
277 minor: u64,
278 patch: u64,
279 pre_release: Vec<Identifier>,
280 build: Vec<Identifier>,
281 ) -> Self {
282 let meta = if pre_release.is_empty() && build.is_empty() {
283 return Self::new_empty(major, minor, patch);
284 } else {
285 Some(Box::new(VersionMeta {
286 build: Identifiers::from_vec(build),
287 pre_release: Identifiers::from_vec(pre_release),
288 }))
289 };
290
291 Self {
292 major,
293 minor,
294 patch,
295 meta,
296 }
297 }
298
299 pub(crate) fn new_empty(major: u64, minor: u64, patch: u64) -> Self {
300 Self {
301 major,
302 minor,
303 patch,
304 meta: None,
305 }
306 }
307
308 fn new_with_pre_release_identifier(
309 major: u64,
310 minor: u64,
311 patch: u64,
312 pre_release: Identifier,
313 ) -> Self {
314 Self {
315 major,
316 minor,
317 patch,
318 meta: Some(Box::new(VersionMeta {
319 build: Identifiers::Empty,
320 pre_release: Identifiers::One(pre_release),
321 })),
322 }
323 }
324
325 pub(crate) fn new_with_identifiers(
326 major: u64,
327 minor: u64,
328 patch: u64,
329 pre_release: Identifiers,
330 build: Identifiers,
331 ) -> Self {
332 if pre_release.is_empty() && build.is_empty() {
333 return Self::new_empty(major, minor, patch);
334 }
335
336 Self {
337 major,
338 minor,
339 patch,
340 meta: Some(Box::new(VersionMeta { build, pre_release })),
341 }
342 }
343
344 pub fn build(&self) -> &[Identifier] {
345 self.meta.as_ref().map_or(&[], |meta| meta.build.as_slice())
346 }
347
348 pub fn pre_release(&self) -> &[Identifier] {
349 self.meta
350 .as_ref()
351 .map_or(&[], |meta| meta.pre_release.as_slice())
352 }
353
354 pub fn into_parts(self) -> VersionParts {
384 let Version {
385 major,
386 minor,
387 patch,
388 meta,
389 } = self;
390
391 let (pre_release, build) = match meta {
392 Some(meta) => {
393 let VersionMeta { build, pre_release } = *meta;
394 (pre_release.into_vec(), build.into_vec())
395 }
396 None => (Vec::new(), Vec::new()),
397 };
398
399 VersionParts {
400 major,
401 minor,
402 patch,
403 pre_release,
404 build,
405 }
406 }
407
408 fn metadata_mut(&mut self) -> &mut VersionMeta {
409 self.meta.get_or_insert_with(|| {
410 Box::new(VersionMeta {
411 build: Identifiers::Empty,
412 pre_release: Identifiers::Empty,
413 })
414 })
415 }
416
417 fn clear_pre_release(&mut self) {
418 if let Some(meta) = &mut self.meta {
419 meta.pre_release.clear();
420 if meta.build.is_empty() {
421 self.meta = None;
422 }
423 }
424 }
425
426 pub(crate) fn push_pre_release(&mut self, identifier: Identifier) {
427 self.metadata_mut().pre_release.push(identifier);
428 }
429
430 fn set_pre_release(&mut self, pre_release: Vec<Identifier>) {
431 if pre_release.is_empty() {
432 self.clear_pre_release();
433 } else {
434 self.metadata_mut().pre_release = Identifiers::from_vec(pre_release);
435 }
436 }
437
438 fn pre_release_mut(&mut self) -> &mut Identifiers {
439 &mut self.metadata_mut().pre_release
440 }
441
442 pub fn satisfies(&self, range: &Range) -> bool {
444 range.satisfies(self)
445 }
446
447 pub fn satisfies_with_prerelease(&self, range: &Range, include_prerelease: bool) -> bool {
451 range.satisfies_with_prerelease(self, include_prerelease)
452 }
453
454 pub fn is_prerelease(&self) -> bool {
456 !self.pre_release().is_empty()
457 }
458
459 pub fn inc(
463 &self,
464 release: &str,
465 identifier: Option<&str>,
466 identifier_base: Option<IdentifierBase>,
467 ) -> Result<Version, IncrementError> {
468 let mut cloned = self.clone();
469 cloned.inc_mut(release, identifier, identifier_base)?;
470 Ok(cloned)
471 }
472
473 fn inc_mut(
474 &mut self,
475 release: &str,
476 identifier: Option<&str>,
477 identifier_base: Option<IdentifierBase>,
478 ) -> Result<&mut Self, IncrementError> {
479 let identifier_base = identifier_base.unwrap_or_default();
480 let identifier_base_is_false = identifier_base == IdentifierBase::False;
481 let identifier = identifier.and_then(|id| {
482 if id.is_empty() {
483 None
484 } else {
485 Some(id.to_string())
486 }
487 });
488
489 if release.starts_with("pre") {
490 if identifier.is_none() && identifier_base_is_false {
491 return Err(IncrementError::InvalidIncrementArgument(
492 "identifier is empty".into(),
493 ));
494 }
495 if let Some(id) = identifier.as_deref() {
496 if !is_valid_prerelease_identifier(id) {
497 return Err(IncrementError::InvalidIdentifier(id.to_string()));
498 }
499 }
500 }
501
502 match release {
503 "premajor" => {
504 self.clear_pre_release();
505 self.patch = 0;
506 self.minor = 0;
507 self.major = self.major.checked_add(1).ok_or(IncrementError::Overflow)?;
508 self.inc_mut("pre", identifier.as_deref(), Some(identifier_base))?;
509 }
510 "preminor" => {
511 self.clear_pre_release();
512 self.patch = 0;
513 self.minor = self.minor.checked_add(1).ok_or(IncrementError::Overflow)?;
514 self.inc_mut("pre", identifier.as_deref(), Some(identifier_base))?;
515 }
516 "prepatch" => {
517 self.clear_pre_release();
518 self.inc_mut("patch", identifier.as_deref(), Some(identifier_base))?;
519 self.inc_mut("pre", identifier.as_deref(), Some(identifier_base))?;
520 }
521 "prerelease" => {
522 if self.pre_release().is_empty() {
523 self.inc_mut("patch", identifier.as_deref(), Some(identifier_base))?;
524 }
525 self.inc_mut("pre", identifier.as_deref(), Some(identifier_base))?;
526 }
527 "release" => {
528 if self.pre_release().is_empty() {
529 return Err(IncrementError::NotAPrerelease(self.to_string()));
530 }
531 self.clear_pre_release();
532 }
533 "major" => {
534 if self.minor != 0 || self.patch != 0 || self.pre_release().is_empty() {
535 self.major = self.major.checked_add(1).ok_or(IncrementError::Overflow)?;
536 }
537 self.minor = 0;
538 self.patch = 0;
539 self.clear_pre_release();
540 }
541 "minor" => {
542 if self.patch != 0 || self.pre_release().is_empty() {
543 self.minor = self.minor.checked_add(1).ok_or(IncrementError::Overflow)?;
544 }
545 self.patch = 0;
546 self.clear_pre_release();
547 }
548 "patch" => {
549 if self.pre_release().is_empty() {
550 self.patch = self.patch.checked_add(1).ok_or(IncrementError::Overflow)?;
551 }
552 self.clear_pre_release();
553 }
554 "pre" => {
555 self.apply_pre_increment(identifier.as_deref(), identifier_base)?;
556 }
557 _ => {
558 return Err(IncrementError::InvalidIncrementArgument(
559 release.to_string(),
560 ));
561 }
562 }
563
564 Ok(self)
565 }
566
567 fn apply_pre_increment(
568 &mut self,
569 identifier: Option<&str>,
570 identifier_base: IdentifierBase,
571 ) -> Result<(), IncrementError> {
572 let base = identifier_base.base_value();
573 let identifier_base_is_false = identifier_base == IdentifierBase::False;
574 let identifier = identifier.map(|id| id.to_string());
575
576 if self.pre_release().is_empty() {
577 self.push_pre_release(Identifier::Numeric(base));
578 } else {
579 let mut incremented = false;
580 for ident in self.pre_release_mut().as_mut_slice().iter_mut().rev() {
581 if let Identifier::Numeric(num) = ident {
582 *num = num.checked_add(1).ok_or(IncrementError::Overflow)?;
583 incremented = true;
584 break;
585 }
586 }
587
588 if !incremented {
589 if identifier_base_is_false {
590 if let Some(id) = identifier.as_deref() {
591 if id == join_prerelease_components(self.pre_release()) {
592 return Err(IncrementError::InvalidIncrementArgument(
593 "identifier already exists".into(),
594 ));
595 }
596 }
597 }
598 self.push_pre_release(Identifier::Numeric(base));
599 }
600 }
601
602 if let Some(id) = identifier {
603 let prerelease = if identifier_base_is_false {
604 vec![Identifier::AlphaNumeric(id.clone())]
605 } else {
606 vec![
607 Identifier::AlphaNumeric(id.clone()),
608 Identifier::Numeric(base),
609 ]
610 };
611
612 if let Some(first) = self.pre_release().first() {
613 if compare_identifier_and_str(first, &id) == Ordering::Equal {
614 if !matches!(self.pre_release().get(1), Some(Identifier::Numeric(_))) {
615 self.set_pre_release(prerelease);
616 }
617 } else {
618 self.set_pre_release(prerelease);
619 }
620 } else {
621 self.set_pre_release(prerelease);
622 }
623 }
624
625 Ok(())
626 }
627
628 #[doc = include_str!("../examples/parse.rs")]
632 pub fn parse<S: AsRef<str>>(input: S) -> Result<Version, SemverError> {
634 let input = input.as_ref();
635
636 if input.len() > MAX_LENGTH {
637 return Err(SemverError);
638 }
639
640 if let Some(version) = version_fast::parse(input) {
641 return Ok(version);
642 }
643
644 parse::version(input).ok_or(SemverError)
645 }
646
647 #[doc = include_str!("../examples/diff.rs")]
652 pub fn diff(&self, other: &Self) -> Option<VersionDiff> {
654 let cmp_result = self.cmp(other);
655
656 if cmp_result == Ordering::Equal {
657 return None;
658 }
659
660 let self_higher = cmp_result == Ordering::Greater;
661 let high_version = if self_higher { self } else { other };
662 let low_version = if self_higher { other } else { self };
663 let high_has_pre = high_version.is_prerelease();
664 let low_has_pre = low_version.is_prerelease();
665
666 if low_has_pre && !high_has_pre {
667 if low_version.patch == 0 && low_version.minor == 0 {
675 return Some(VersionDiff::Major);
676 }
677
678 if high_version.patch != 0 {
680 return Some(VersionDiff::Patch);
682 }
683
684 if high_version.minor != 0 {
685 return Some(VersionDiff::Minor);
687 }
688
689 return Some(VersionDiff::Major);
691 }
692
693 if self.major != other.major {
694 if high_has_pre {
695 return Some(VersionDiff::PreMajor);
696 }
697
698 return Some(VersionDiff::Major);
699 }
700
701 if self.minor != other.minor {
702 if high_has_pre {
703 return Some(VersionDiff::PreMinor);
704 }
705
706 return Some(VersionDiff::Minor);
707 }
708
709 if self.patch != other.patch {
710 if high_has_pre {
711 return Some(VersionDiff::PrePatch);
712 }
713
714 return Some(VersionDiff::Patch);
715 }
716
717 Some(VersionDiff::PreRelease)
719 }
720}
721
722impl PartialEq for Version {
723 fn eq(&self, other: &Self) -> bool {
724 self.major == other.major
725 && self.minor == other.minor
726 && self.patch == other.patch
727 && self.pre_release() == other.pre_release()
728 }
729}
730
731impl Eq for Version {}
732
733impl std::hash::Hash for Version {
734 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
735 self.major.hash(state);
736 self.minor.hash(state);
737 self.patch.hash(state);
738 self.pre_release().hash(state);
739 }
740}
741
742impl fmt::Display for Version {
743 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
744 write!(f, "{}.{}.{}", self.major, self.minor, self.patch)?;
745
746 for (i, ident) in self.pre_release().iter().enumerate() {
747 if i == 0 {
748 write!(f, "-")?;
749 } else {
750 write!(f, ".")?;
751 }
752 write!(f, "{}", ident)?;
753 }
754
755 for (i, ident) in self.build().iter().enumerate() {
756 if i == 0 {
757 write!(f, "+")?;
758 } else {
759 write!(f, ".")?;
760 }
761 write!(f, "{}", ident)?;
762 }
763
764 Ok(())
765 }
766}
767
768macro_rules! impl_from_unsigned_for_version {
769 ($($t:ident),+) => {
770 $(
771 impl ::std::convert::From<($t, $t, $t)> for Version {
772 fn from((major, minor, patch): ($t, $t, $t)) -> Self {
773 Version::new_empty(major as u64, minor as u64, patch as u64)
774 }
775 }
776
777 impl ::std::convert::From<($t, $t, $t, $t)> for Version {
778 fn from((major, minor, patch, pre_release): ($t, $t, $t, $t)) -> Self {
779 Version::new_with_pre_release_identifier(
780 major as u64,
781 minor as u64,
782 patch as u64,
783 Identifier::Numeric(pre_release as u64),
784 )
785 }
786 }
787 )+
788 }
789}
790
791macro_rules! impl_from_signed_for_version {
792 ($($t:ident),+) => {
793 $(
794 impl ::std::convert::From<($t, $t, $t)> for Version {
795 fn from((major, minor, patch): ($t, $t, $t)) -> Self {
796 debug_assert!(major >= 0, "Version major must be non-negative, got {}", major);
797 debug_assert!(minor >= 0, "Version minor must be non-negative, got {}", minor);
798 debug_assert!(patch >= 0, "Version patch must be non-negative, got {}", patch);
799
800 Version::new_empty(major as u64, minor as u64, patch as u64)
801 }
802 }
803
804 impl ::std::convert::From<($t, $t, $t, $t)> for Version {
805 fn from((major, minor, patch, pre_release): ($t, $t, $t, $t)) -> Self {
806 debug_assert!(major >= 0, "Version major must be non-negative, got {}", major);
807 debug_assert!(minor >= 0, "Version minor must be non-negative, got {}", minor);
808 debug_assert!(patch >= 0, "Version patch must be non-negative, got {}", patch);
809 debug_assert!(pre_release >= 0, "Version pre-release must be non-negative, got {}", pre_release);
810
811 Version::new_with_pre_release_identifier(
812 major as u64,
813 minor as u64,
814 patch as u64,
815 Identifier::Numeric(pre_release as u64),
816 )
817 }
818 }
819 )+
820 }
821}
822
823impl_from_unsigned_for_version!(u8, u16, u32, u64, usize);
824impl_from_signed_for_version!(i8, i16, i32, i64, isize);
825
826impl std::str::FromStr for Version {
827 type Err = SemverError;
828 fn from_str(s: &str) -> Result<Self, Self::Err> {
829 Version::parse(s)
830 }
831}
832
833impl cmp::PartialOrd for Version {
834 fn partial_cmp(&self, other: &Version) -> Option<Ordering> {
835 Some(self.cmp(other))
836 }
837}
838
839impl cmp::Ord for Version {
840 fn cmp(&self, other: &Version) -> cmp::Ordering {
841 match self.major.cmp(&other.major) {
842 Ordering::Equal => {}
843 order_result => return order_result,
845 }
846
847 match self.minor.cmp(&other.minor) {
848 Ordering::Equal => {}
849 order_result => return order_result,
851 }
852
853 match self.patch.cmp(&other.patch) {
854 Ordering::Equal => {}
855 order_result => return order_result,
857 }
858
859 match (self.pre_release().len(), other.pre_release().len()) {
860 (0, 0) => Ordering::Equal,
862 (0, _) => Ordering::Greater,
864 (_, 0) => Ordering::Less,
866 (_, _) => self.pre_release().cmp(other.pre_release()),
868 }
869 }
870}
871
872fn is_valid_prerelease_identifier(identifier: &str) -> bool {
873 !identifier.is_empty()
874 && identifier.split('.').all(|segment| {
875 !segment.is_empty()
876 && segment
877 .chars()
878 .all(|ch| ch.is_ascii_alphanumeric() || ch == '-')
879 })
880}
881
882fn join_prerelease_components(pre_release: &[Identifier]) -> String {
883 pre_release
884 .iter()
885 .map(|ident| ident.to_string())
886 .collect::<Vec<_>>()
887 .join(".")
888}
889
890fn compare_identifier_and_str(existing: &Identifier, other: &str) -> Ordering {
891 match existing {
892 Identifier::Numeric(value) => {
893 if other.chars().all(|c| c.is_ascii_digit()) {
894 match other.parse::<u128>() {
895 Ok(other_num) => (*value as u128).cmp(&other_num),
896 Err(_) => Ordering::Less,
897 }
898 } else {
899 Ordering::Less
900 }
901 }
902 Identifier::AlphaNumeric(value) => {
903 if other.chars().all(|c| c.is_ascii_digit()) {
904 Ordering::Greater
905 } else {
906 value.as_str().cmp(other)
907 }
908 }
909 }
910}
911
912#[cfg(test)]
913mod tests {
914 use super::Identifier::*;
915 use super::*;
916
917 use pretty_assertions::assert_eq;
918
919 #[derive(Debug)]
920 struct IncrementCase {
921 version: String,
922 release: String,
923 expected: Option<String>,
924 identifier: Option<String>,
925 identifier_base: Option<IdentifierBase>,
926 }
927
928 #[derive(Debug)]
929 struct IncrementCaseRaw {
930 version: &'static str,
931 release: &'static str,
932 expected: Option<&'static str>,
933 identifier: Option<&'static str>,
934 identifier_base: Option<IdentifierBase>,
935 }
936
937 macro_rules! ic {
938 ($v:literal, $r:literal, $e:literal) => {
939 IncrementCaseRaw {
940 version: $v,
941 release: $r,
942 expected: Some($e),
943 identifier: None,
944 identifier_base: None,
945 }
946 };
947 ($v:literal, $r:literal, None) => {
948 IncrementCaseRaw {
949 version: $v,
950 release: $r,
951 expected: None,
952 identifier: None,
953 identifier_base: None,
954 }
955 };
956 ($v:literal, $r:literal, $e:literal, $id:literal) => {
957 IncrementCaseRaw {
958 version: $v,
959 release: $r,
960 expected: Some($e),
961 identifier: Some($id),
962 identifier_base: None,
963 }
964 };
965 ($v:literal, $r:literal, None, $id:literal) => {
966 IncrementCaseRaw {
967 version: $v,
968 release: $r,
969 expected: None,
970 identifier: Some($id),
971 identifier_base: None,
972 }
973 };
974 ($v:literal, $r:literal, $e:literal, $id:literal, $base:expr) => {
975 IncrementCaseRaw {
976 version: $v,
977 release: $r,
978 expected: Some($e),
979 identifier: Some($id),
980 identifier_base: Some($base),
981 }
982 };
983 ($v:literal, $r:literal, None, $id:literal, $base:expr) => {
984 IncrementCaseRaw {
985 version: $v,
986 release: $r,
987 expected: None,
988 identifier: Some($id),
989 identifier_base: Some($base),
990 }
991 };
992 }
993
994 static INCREMENT_CASES: &[IncrementCaseRaw] = &[
996 ic!("1.2.3", "major", "2.0.0"),
997 ic!("1.2.3", "minor", "1.3.0"),
998 ic!("1.2.3", "patch", "1.2.4"),
999 ic!("1.2.3tag", "major", "2.0.0"),
1000 ic!("1.2.3-tag", "major", "2.0.0"),
1001 ic!("1.2.3", "fake", None),
1002 ic!("1.2.0-0", "patch", "1.2.0"),
1003 ic!("fake", "major", None),
1004 ic!("1.2.3-4", "major", "2.0.0"),
1005 ic!("1.2.3-4", "minor", "1.3.0"),
1006 ic!("1.2.3-4", "patch", "1.2.3"),
1007 ic!("1.2.3-alpha.0.beta", "major", "2.0.0"),
1008 ic!("1.2.3-alpha.0.beta", "minor", "1.3.0"),
1009 ic!("1.2.3-alpha.0.beta", "patch", "1.2.3"),
1010 ic!("1.2.4", "prerelease", "1.2.5-0"),
1011 ic!("1.2.3-0", "prerelease", "1.2.3-1"),
1012 ic!("1.2.3-alpha.0", "prerelease", "1.2.3-alpha.1"),
1013 ic!("1.2.3-alpha.1", "prerelease", "1.2.3-alpha.2"),
1014 ic!("1.2.3-alpha.2", "prerelease", "1.2.3-alpha.3"),
1015 ic!("1.2.3-alpha.0.beta", "prerelease", "1.2.3-alpha.1.beta"),
1016 ic!("1.2.3-alpha.1.beta", "prerelease", "1.2.3-alpha.2.beta"),
1017 ic!("1.2.3-alpha.2.beta", "prerelease", "1.2.3-alpha.3.beta"),
1018 ic!(
1019 "1.2.3-alpha.10.0.beta",
1020 "prerelease",
1021 "1.2.3-alpha.10.1.beta"
1022 ),
1023 ic!(
1024 "1.2.3-alpha.10.1.beta",
1025 "prerelease",
1026 "1.2.3-alpha.10.2.beta"
1027 ),
1028 ic!(
1029 "1.2.3-alpha.10.2.beta",
1030 "prerelease",
1031 "1.2.3-alpha.10.3.beta"
1032 ),
1033 ic!(
1034 "1.2.3-alpha.10.beta.0",
1035 "prerelease",
1036 "1.2.3-alpha.10.beta.1"
1037 ),
1038 ic!(
1039 "1.2.3-alpha.10.beta.1",
1040 "prerelease",
1041 "1.2.3-alpha.10.beta.2"
1042 ),
1043 ic!(
1044 "1.2.3-alpha.10.beta.2",
1045 "prerelease",
1046 "1.2.3-alpha.10.beta.3"
1047 ),
1048 ic!("1.2.3-alpha.9.beta", "prerelease", "1.2.3-alpha.10.beta"),
1049 ic!("1.2.3-alpha.10.beta", "prerelease", "1.2.3-alpha.11.beta"),
1050 ic!("1.2.3-alpha.11.beta", "prerelease", "1.2.3-alpha.12.beta"),
1051 ic!("1.0.0", "prepatch", "1.0.1-alpha.1.1a.0", "alpha.1.1a"),
1052 ic!("1.2.0", "prepatch", "1.2.1-0"),
1053 ic!("1.2.0-1", "prepatch", "1.2.1-0"),
1054 ic!("1.2.0", "preminor", "1.3.0-0"),
1055 ic!("1.2.3-1", "preminor", "1.3.0-0"),
1056 ic!("1.2.0", "premajor", "2.0.0-0"),
1057 ic!("1.2.3-1", "premajor", "2.0.0-0"),
1058 ic!("1.2.0-1", "minor", "1.2.0"),
1059 ic!("1.0.0-1", "major", "1.0.0"),
1060 ic!("1.0.0-1", "release", "1.0.0"),
1061 ic!("1.2.0-1", "release", "1.2.0"),
1062 ic!("1.2.3-1", "release", "1.2.3"),
1063 ic!("1.2.3", "release", None),
1064 ic!("1.2.3", "major", "2.0.0", "dev"),
1065 ic!("1.2.3", "minor", "1.3.0", "dev"),
1066 ic!("1.2.3", "patch", "1.2.4", "dev"),
1067 ic!("1.2.3tag", "major", "2.0.0", "dev"),
1068 ic!("1.2.3-tag", "major", "2.0.0", "dev"),
1069 ic!("1.2.3", "fake", None, "dev"),
1070 ic!("1.2.0-0", "patch", "1.2.0", "dev"),
1071 ic!("fake", "major", None, "dev"),
1072 ic!("1.2.3-4", "major", "2.0.0", "dev"),
1073 ic!("1.2.3-4", "minor", "1.3.0", "dev"),
1074 ic!("1.2.3-4", "patch", "1.2.3", "dev"),
1075 ic!("1.2.3-alpha.0.beta", "major", "2.0.0", "dev"),
1076 ic!("1.2.3-alpha.0.beta", "minor", "1.3.0", "dev"),
1077 ic!("1.2.3-alpha.0.beta", "patch", "1.2.3", "dev"),
1078 ic!("1.2.4", "prerelease", "1.2.5-dev.0", "dev"),
1079 ic!("1.2.3-0", "prerelease", "1.2.3-dev.0", "dev"),
1080 ic!("1.2.3-alpha.0", "prerelease", "1.2.3-dev.0", "dev"),
1081 ic!("1.2.3-alpha.0", "prerelease", "1.2.3-alpha.1", "alpha"),
1082 ic!("1.2.3-alpha.0.beta", "prerelease", "1.2.3-dev.0", "dev"),
1083 ic!(
1084 "1.2.3-alpha.0.beta",
1085 "prerelease",
1086 "1.2.3-alpha.1.beta",
1087 "alpha"
1088 ),
1089 ic!("1.2.3-alpha.10.0.beta", "prerelease", "1.2.3-dev.0", "dev"),
1090 ic!(
1091 "1.2.3-alpha.10.0.beta",
1092 "prerelease",
1093 "1.2.3-alpha.10.1.beta",
1094 "alpha"
1095 ),
1096 ic!(
1097 "1.2.3-alpha.10.1.beta",
1098 "prerelease",
1099 "1.2.3-alpha.10.2.beta",
1100 "alpha"
1101 ),
1102 ic!(
1103 "1.2.3-alpha.10.2.beta",
1104 "prerelease",
1105 "1.2.3-alpha.10.3.beta",
1106 "alpha"
1107 ),
1108 ic!("1.2.3-alpha.10.beta.0", "prerelease", "1.2.3-dev.0", "dev"),
1109 ic!(
1110 "1.2.3-alpha.10.beta.0",
1111 "prerelease",
1112 "1.2.3-alpha.10.beta.1",
1113 "alpha"
1114 ),
1115 ic!(
1116 "1.2.3-alpha.10.beta.1",
1117 "prerelease",
1118 "1.2.3-alpha.10.beta.2",
1119 "alpha"
1120 ),
1121 ic!(
1122 "1.2.3-alpha.10.beta.2",
1123 "prerelease",
1124 "1.2.3-alpha.10.beta.3",
1125 "alpha"
1126 ),
1127 ic!("1.2.3-alpha.9.beta", "prerelease", "1.2.3-dev.0", "dev"),
1128 ic!(
1129 "1.2.3-alpha.9.beta",
1130 "prerelease",
1131 "1.2.3-alpha.10.beta",
1132 "alpha"
1133 ),
1134 ic!(
1135 "1.2.3-alpha.10.beta",
1136 "prerelease",
1137 "1.2.3-alpha.11.beta",
1138 "alpha"
1139 ),
1140 ic!(
1141 "1.2.3-alpha.11.beta",
1142 "prerelease",
1143 "1.2.3-alpha.12.beta",
1144 "alpha"
1145 ),
1146 ic!("1.2.0", "prepatch", "1.2.1-dev.0", "dev"),
1147 ic!("1.2.0-1", "prepatch", "1.2.1-dev.0", "dev"),
1148 ic!("1.2.0", "preminor", "1.3.0-dev.0", "dev"),
1149 ic!("1.2.3-1", "preminor", "1.3.0-dev.0", "dev"),
1150 ic!("1.2.0", "premajor", "2.0.0-dev.0", "dev"),
1151 ic!("1.2.3-1", "premajor", "2.0.0-dev.0", "dev"),
1152 ic!(
1153 "1.2.3-1",
1154 "premajor",
1155 "2.0.0-dev.1",
1156 "dev",
1157 IdentifierBase::Value(1)
1158 ),
1159 ic!("1.2.0-1", "minor", "1.2.0", "dev"),
1160 ic!("1.0.0-1", "major", "1.0.0", "dev"),
1161 ic!("1.2.3-dev.bar", "prerelease", "1.2.3-dev.0", "dev"),
1162 ic!("1.2.3-0", "prerelease", "1.2.3-1.0", "1"),
1163 ic!("1.2.3-1.0", "prerelease", "1.2.3-1.1", "1"),
1164 ic!("1.2.3-1.1", "prerelease", "1.2.3-1.2", "1"),
1165 ic!("1.2.3-1.1", "prerelease", "1.2.3-2.0", "2"),
1166 ic!(
1167 "1.2.0-1",
1168 "prerelease",
1169 "1.2.0-alpha.0",
1170 "alpha",
1171 IdentifierBase::Value(0)
1172 ),
1173 ic!(
1174 "1.2.1",
1175 "prerelease",
1176 "1.2.2-alpha.0",
1177 "alpha",
1178 IdentifierBase::Value(0)
1179 ),
1180 ic!(
1181 "0.2.0",
1182 "prerelease",
1183 "0.2.1-alpha.0",
1184 "alpha",
1185 IdentifierBase::Value(0)
1186 ),
1187 ic!(
1188 "1.2.2",
1189 "prerelease",
1190 "1.2.3-alpha.1",
1191 "alpha",
1192 IdentifierBase::Value(1)
1193 ),
1194 ic!(
1195 "1.2.3",
1196 "prerelease",
1197 "1.2.4-alpha.1",
1198 "alpha",
1199 IdentifierBase::Value(1)
1200 ),
1201 ic!(
1202 "1.2.4",
1203 "prerelease",
1204 "1.2.5-alpha.1",
1205 "alpha",
1206 IdentifierBase::Value(1)
1207 ),
1208 ic!(
1209 "1.2.0",
1210 "prepatch",
1211 "1.2.1-dev.1",
1212 "dev",
1213 IdentifierBase::Value(1)
1214 ),
1215 ic!(
1216 "1.2.0-1",
1217 "prepatch",
1218 "1.2.1-dev.1",
1219 "dev",
1220 IdentifierBase::Value(1)
1221 ),
1222 ic!(
1223 "1.2.0",
1224 "premajor",
1225 "2.0.0-dev.0",
1226 "dev",
1227 IdentifierBase::Value(0)
1228 ),
1229 ic!(
1230 "1.2.3-1",
1231 "premajor",
1232 "2.0.0-dev.0",
1233 "dev",
1234 IdentifierBase::Value(0)
1235 ),
1236 ic!(
1237 "1.2.3-dev.bar",
1238 "prerelease",
1239 "1.2.3-dev.0",
1240 "dev",
1241 IdentifierBase::Value(0)
1242 ),
1243 ic!(
1244 "1.2.3-dev.bar",
1245 "prerelease",
1246 "1.2.3-dev.1",
1247 "dev",
1248 IdentifierBase::Value(1)
1249 ),
1250 ic!(
1251 "1.2.3-dev.bar",
1252 "prerelease",
1253 "1.2.3-dev.bar.0",
1254 "",
1255 IdentifierBase::Value(0)
1256 ),
1257 ic!(
1258 "1.2.3-dev.bar",
1259 "prerelease",
1260 "1.2.3-dev.bar.1",
1261 "",
1262 IdentifierBase::Value(1)
1263 ),
1264 ic!(
1265 "1.2.0",
1266 "preminor",
1267 "1.3.0-dev.1",
1268 "dev",
1269 IdentifierBase::Value(1)
1270 ),
1271 ic!("1.2.3-1", "preminor", "1.3.0-dev.0", "dev"),
1272 ic!(
1273 "1.2.0",
1274 "prerelease",
1275 "1.2.1-1",
1276 "",
1277 IdentifierBase::Value(1)
1278 ),
1279 ic!(
1280 "1.2.0-1",
1281 "prerelease",
1282 "1.2.0-alpha",
1283 "alpha",
1284 IdentifierBase::False
1285 ),
1286 ic!(
1287 "1.2.1",
1288 "prerelease",
1289 "1.2.2-alpha",
1290 "alpha",
1291 IdentifierBase::False
1292 ),
1293 ic!(
1294 "1.2.2",
1295 "prerelease",
1296 "1.2.3-alpha",
1297 "alpha",
1298 IdentifierBase::False
1299 ),
1300 ic!(
1301 "1.2.0",
1302 "prepatch",
1303 "1.2.1-dev",
1304 "dev",
1305 IdentifierBase::False
1306 ),
1307 ic!(
1308 "1.2.0-1",
1309 "prepatch",
1310 "1.2.1-dev",
1311 "dev",
1312 IdentifierBase::False
1313 ),
1314 ic!(
1315 "1.2.0",
1316 "premajor",
1317 "2.0.0-dev",
1318 "dev",
1319 IdentifierBase::False
1320 ),
1321 ic!(
1322 "1.2.3-1",
1323 "premajor",
1324 "2.0.0-dev",
1325 "dev",
1326 IdentifierBase::False
1327 ),
1328 ic!(
1329 "1.2.3-dev.bar",
1330 "prerelease",
1331 "1.2.3-dev",
1332 "dev",
1333 IdentifierBase::False
1334 ),
1335 ic!(
1336 "1.2.3-dev.bar",
1337 "prerelease",
1338 "1.2.3-dev.baz",
1339 "dev.baz",
1340 IdentifierBase::False
1341 ),
1342 ic!(
1343 "1.2.0",
1344 "preminor",
1345 "1.3.0-dev",
1346 "dev",
1347 IdentifierBase::False
1348 ),
1349 ic!(
1350 "1.2.3-1",
1351 "preminor",
1352 "1.3.0-dev",
1353 "dev",
1354 IdentifierBase::False
1355 ),
1356 ic!(
1357 "1.2.3-dev",
1358 "prerelease",
1359 None,
1360 "dev",
1361 IdentifierBase::False
1362 ),
1363 ic!(
1364 "1.2.0-dev",
1365 "premajor",
1366 "2.0.0-dev",
1367 "dev",
1368 IdentifierBase::False
1369 ),
1370 ic!(
1371 "1.2.0-dev",
1372 "preminor",
1373 "1.3.0-beta",
1374 "beta",
1375 IdentifierBase::False
1376 ),
1377 ic!(
1378 "1.2.0-dev",
1379 "prepatch",
1380 "1.2.1-dev",
1381 "dev",
1382 IdentifierBase::False
1383 ),
1384 ic!("1.2.0", "prerelease", None, "", IdentifierBase::False),
1385 ic!(
1386 "1.0.0-rc.1+build.4",
1387 "prerelease",
1388 "1.0.0-rc.2",
1389 "rc",
1390 IdentifierBase::False
1391 ),
1392 ic!("1.2.0", "prerelease", None, "invalid/preid"),
1393 ic!("1.2.0", "prerelease", None, "invalid+build"),
1394 ic!("1.2.0beta", "prerelease", None, "invalid/preid"),
1395 ];
1396
1397 fn version_without_build(version: &Version) -> String {
1398 let mut output = format!("{}.{}.{}", version.major, version.minor, version.patch);
1399 if !version.pre_release().is_empty() {
1400 output.push('-');
1401 output.push_str(&join_prerelease_components(version.pre_release()));
1402 }
1403 output
1404 }
1405
1406 fn load_increment_cases() -> Vec<IncrementCase> {
1407 INCREMENT_CASES
1408 .iter()
1409 .map(|raw| IncrementCase {
1410 version: raw.version.to_string(),
1411 release: raw.release.to_string(),
1412 expected: raw.expected.map(str::to_string),
1413 identifier: raw.identifier.map(str::to_string),
1414 identifier_base: raw.identifier_base,
1415 })
1416 .collect()
1417 }
1418
1419 #[test]
1420 fn trivial_version_number() {
1421 let v = Version::parse("1.2.34").unwrap();
1422
1423 assert_eq!((v.major(), v.minor(), v.patch()), (1, 2, 34));
1424 assert_eq!(
1425 v,
1426 Version::new(1, 2, 34, Vec::with_capacity(2), Vec::with_capacity(2))
1427 );
1428 }
1429
1430 #[test]
1431 fn version_with_build() {
1432 let v = Version::parse("1.2.34+123.456").unwrap();
1433
1434 assert_eq!(
1435 v,
1436 Version::new(
1437 1,
1438 2,
1439 34,
1440 Vec::with_capacity(2),
1441 vec![Numeric(123), Numeric(456)]
1442 )
1443 );
1444 }
1445
1446 #[test]
1447 fn version_with_pre_release() {
1448 let v = Version::parse("1.2.34-abc.123").unwrap();
1449
1450 assert_eq!(
1451 v,
1452 Version::new(
1453 1,
1454 2,
1455 34,
1456 vec![AlphaNumeric("abc".into()), Numeric(123)],
1457 Vec::with_capacity(2),
1458 )
1459 );
1460 }
1461
1462 #[test]
1463 fn version_with_pre_release_and_build() {
1464 let v = Version::parse("1.2.34-abc.123+1").unwrap();
1465
1466 assert_eq!(
1467 v,
1468 Version::new(
1469 1,
1470 2,
1471 34,
1472 vec![AlphaNumeric("abc".into()), Numeric(123)],
1473 vec![Numeric(1)],
1474 )
1475 );
1476 }
1477
1478 #[test]
1479 fn into_parts_with_metadata() {
1480 let parts = Version::parse("1.2.34-abc.123+1").unwrap().into_parts();
1481
1482 assert_eq!(
1483 parts,
1484 VersionParts {
1485 major: 1,
1486 minor: 2,
1487 patch: 34,
1488 pre_release: vec![AlphaNumeric("abc".into()), Numeric(123)],
1489 build: vec![Numeric(1)],
1490 }
1491 );
1492 }
1493
1494 #[test]
1495 fn into_parts_without_metadata() {
1496 let parts = Version::parse("1.2.34").unwrap().into_parts();
1497
1498 assert_eq!(
1499 parts,
1500 VersionParts {
1501 major: 1,
1502 minor: 2,
1503 patch: 34,
1504 pre_release: Vec::new(),
1505 build: Vec::new(),
1506 }
1507 );
1508 }
1509
1510 #[test]
1511 fn pre_release_that_could_look_numeric_at_first() {
1512 let v = Version::parse("1.0.0-rc.2-migration").unwrap();
1513
1514 assert_eq!(
1515 v,
1516 Version::new(
1517 1,
1518 0,
1519 0,
1520 vec![
1521 Identifier::AlphaNumeric("rc".into()),
1522 Identifier::AlphaNumeric("2-migration".into())
1523 ],
1524 vec![],
1525 )
1526 );
1527 }
1528
1529 #[test]
1530 fn comparison_with_different_major_version() {
1531 let lesser_version = Version::new(
1532 1,
1533 2,
1534 34,
1535 vec![AlphaNumeric("abc".into()), Numeric(123)],
1536 vec![],
1537 );
1538 let greater_version = Version::new(
1539 2,
1540 2,
1541 34,
1542 vec![AlphaNumeric("abc".into()), Numeric(123)],
1543 vec![],
1544 );
1545 assert_eq!(lesser_version.cmp(&greater_version), Ordering::Less);
1546 assert_eq!(greater_version.cmp(&lesser_version), Ordering::Greater);
1547 }
1548 #[test]
1549 fn comparison_with_different_minor_version() {
1550 let lesser_version = Version::new(
1551 1,
1552 2,
1553 34,
1554 vec![AlphaNumeric("abc".into()), Numeric(123)],
1555 vec![],
1556 );
1557 let greater_version = Version::new(
1558 1,
1559 3,
1560 34,
1561 vec![AlphaNumeric("abc".into()), Numeric(123)],
1562 vec![],
1563 );
1564 assert_eq!(lesser_version.cmp(&greater_version), Ordering::Less);
1565 assert_eq!(greater_version.cmp(&lesser_version), Ordering::Greater);
1566 }
1567
1568 #[test]
1569 fn comparison_with_different_patch_version() {
1570 let lesser_version = Version::new(
1571 1,
1572 2,
1573 34,
1574 vec![AlphaNumeric("abc".into()), Numeric(123)],
1575 vec![],
1576 );
1577 let greater_version = Version::new(
1578 1,
1579 2,
1580 56,
1581 vec![AlphaNumeric("abc".into()), Numeric(123)],
1582 vec![],
1583 );
1584 assert_eq!(lesser_version.cmp(&greater_version), Ordering::Less);
1585 assert_eq!(greater_version.cmp(&lesser_version), Ordering::Greater);
1586 }
1587
1588 #[test]
1589 fn comparison_with_different_pre_release_version() {
1593 let v1_alpha = Version::new(1, 0, 0, vec![AlphaNumeric("alpha".into())], vec![]);
1594 let v1_alpha1 = Version::new(
1595 1,
1596 0,
1597 0,
1598 vec![AlphaNumeric("alpha".into()), Numeric(1)],
1599 vec![],
1600 );
1601 assert_eq!(v1_alpha.cmp(&v1_alpha1), Ordering::Less);
1602 let v1_alpha_beta = Version::new(
1603 1,
1604 0,
1605 0,
1606 vec![AlphaNumeric("alpha".into()), AlphaNumeric("beta".into())],
1607 vec![],
1608 );
1609 assert_eq!(v1_alpha1.cmp(&v1_alpha_beta), Ordering::Less);
1610 let v1_beta = Version::new(1, 0, 0, vec![AlphaNumeric("beta".into())], vec![]);
1611 assert_eq!(v1_alpha_beta.cmp(&v1_beta), Ordering::Less);
1612 let v1_beta2 = Version::new(
1613 1,
1614 0,
1615 0,
1616 vec![AlphaNumeric("beta".into()), Numeric(2)],
1617 vec![],
1618 );
1619 assert_eq!(v1_beta.cmp(&v1_beta2), Ordering::Less);
1620 let v1_beta11 = Version::new(
1621 1,
1622 0,
1623 0,
1624 vec![AlphaNumeric("beta".into()), Numeric(11)],
1625 vec![],
1626 );
1627 assert_eq!(v1_beta2.cmp(&v1_beta11), Ordering::Less);
1628 let v1_rc1 = Version::new(1, 0, 0, vec![AlphaNumeric("rc".into()), Numeric(1)], vec![]);
1629 assert_eq!(v1_beta11.cmp(&v1_rc1), Ordering::Less);
1630 let v1 = Version::new(1, 0, 0, vec![], vec![]);
1631 assert_eq!(v1_rc1.cmp(&v1), Ordering::Less);
1632 }
1633
1634 #[test]
1635 fn individual_version_component_has_an_upper_bound() {
1636 let out_of_range = MAX_SAFE_INTEGER + 1;
1637 let v = Version::parse(format!("1.2.{}", out_of_range));
1638 assert!(v.is_err());
1639 assert!(Version::parse(format!("1.2.{MAX_SAFE_INTEGER}")).is_ok());
1640 }
1641
1642 #[test]
1643 fn version_string_limited_to_256_characters() {
1644 let prebuild = (0..257).map(|_| "X").collect::<Vec<_>>().join("");
1645 let version_string = format!("1.1.1-{}", prebuild);
1646 let v = Version::parse(version_string.clone());
1647
1648 assert!(v.is_err());
1649
1650 let ok_version = version_string[0..255].to_string();
1651 let v = Version::parse(ok_version);
1652 assert!(v.is_ok());
1653 }
1654
1655 #[test]
1656 fn version_prefixed_with_v() {
1657 let v = Version::parse("v1.2.3").unwrap();
1659 assert_eq!(v, Version::new(1, 2, 3, vec![], vec![]));
1660 }
1661
1662 #[test]
1663 fn version_prefixed_with_v_space() {
1664 let v = Version::parse("v 1.2.3").unwrap();
1666 assert_eq!(v, Version::new(1, 2, 3, vec![], vec![]));
1667 }
1668
1669 fn asset_version_diff(left: &str, right: &str, expected: &str) {
1670 let left = Version::parse(left).unwrap();
1671 let right = Version::parse(right).unwrap();
1672 let expected_diff = match expected {
1673 "major" => Some(VersionDiff::Major),
1674 "minor" => Some(VersionDiff::Minor),
1675 "patch" => Some(VersionDiff::Patch),
1676 "premajor" => Some(VersionDiff::PreMajor),
1677 "preminor" => Some(VersionDiff::PreMinor),
1678 "prepatch" => Some(VersionDiff::PrePatch),
1679 "null" => None,
1680 _ => unreachable!("unexpected version diff"),
1681 };
1682
1683 assert_eq!(
1684 left.diff(&right),
1685 expected_diff,
1686 "left: {}, right: {}",
1687 left,
1688 right
1689 );
1690 }
1691
1692 #[test]
1693 fn version_diffs() {
1694 let cases = vec![
1695 ("1.2.3", "0.2.3", "major"),
1696 ("0.2.3", "1.2.3", "major"),
1697 ("1.4.5", "0.2.3", "major"),
1698 ("1.2.3", "2.0.0-pre", "premajor"),
1699 ("2.0.0-pre", "1.2.3", "premajor"),
1700 ("1.2.3", "1.3.3", "minor"),
1701 ("1.0.1", "1.1.0-pre", "preminor"),
1702 ("1.2.3", "1.2.4", "patch"),
1703 ("1.2.3", "1.2.4-pre", "prepatch"),
1704 ("1.0.0", "1.0.0", "null"),
1705 ("1.0.0-1", "1.0.0-1", "null"),
1706 ("0.0.2-1", "0.0.2", "patch"),
1707 ("0.0.2-1", "0.0.3", "patch"),
1708 ("0.0.2-1", "0.1.0", "minor"),
1709 ("0.0.2-1", "1.0.0", "major"),
1710 ("0.1.0-1", "0.1.0", "minor"),
1711 ("1.0.0-1", "2.0.0-1", "premajor"),
1712 ("1.0.0-1", "1.1.0-1", "preminor"),
1713 ("1.0.0-1", "1.0.1-1", "prepatch"),
1714 ];
1715
1716 for case in cases {
1717 asset_version_diff(case.0, case.1, case.2);
1718 }
1719 }
1720
1721 #[test]
1722 fn increments_match_node_semver_fixture() {
1723 for case in load_increment_cases() {
1724 if let Some(expected) = &case.expected {
1725 let version = Version::parse(&case.version).unwrap_or_else(|e| {
1726 panic!("expected to parse {} but failed: {}", case.version, e)
1727 });
1728 let before = version.to_string();
1729 let build = version.build().to_vec();
1730 let incremented = version
1731 .inc(
1732 &case.release,
1733 case.identifier.as_deref(),
1734 case.identifier_base,
1735 )
1736 .unwrap_or_else(|e| {
1737 panic!(
1738 "expected {} {} to succeed but errored: {}",
1739 case.version, case.release, e
1740 )
1741 });
1742
1743 assert_eq!(
1744 version_without_build(&incremented),
1745 expected.as_str(),
1746 "incrementing {} {} {:?} {:?}",
1747 case.version,
1748 case.release,
1749 case.identifier,
1750 case.identifier_base
1751 );
1752 assert_eq!(
1753 incremented.build(),
1754 build.as_slice(),
1755 "build metadata should remain unchanged after increment"
1756 );
1757 assert_eq!(
1758 version.to_string(),
1759 before,
1760 "original version should remain unchanged"
1761 );
1762 } else if let Ok(version) = Version::parse(&case.version) {
1763 let before = version.to_string();
1764 assert!(
1765 version
1766 .inc(
1767 &case.release,
1768 case.identifier.as_deref(),
1769 case.identifier_base
1770 )
1771 .is_err(),
1772 "expected {} {} to fail",
1773 case.version,
1774 case.release
1775 );
1776 assert_eq!(
1777 version.to_string(),
1778 before,
1779 "version should stay unchanged on error"
1780 );
1781 }
1782 }
1783 }
1784
1785 #[test]
1786 fn invalid_increment_errors_match_node_semver() {
1787 let version = Version::parse("1.2.3").unwrap();
1788 let err = version
1789 .inc("prerelease", Some(""), Some(IdentifierBase::False))
1790 .unwrap_err();
1791 assert_eq!(
1792 err.to_string(),
1793 "invalid increment argument: identifier is empty"
1794 );
1795 assert_eq!(version.to_string(), "1.2.3");
1796
1797 let version = Version::parse("1.2.3-dev").unwrap();
1798 let err = version
1799 .inc("prerelease", Some("dev"), Some(IdentifierBase::False))
1800 .unwrap_err();
1801 assert_eq!(
1802 err.to_string(),
1803 "invalid increment argument: identifier already exists"
1804 );
1805 assert_eq!(version.to_string(), "1.2.3-dev");
1806
1807 let version = Version::parse("1.2.3").unwrap();
1808 let err = version
1809 .inc("prerelease", Some("invalid/preid"), None)
1810 .unwrap_err();
1811 assert_eq!(err.to_string(), "invalid identifier: invalid/preid");
1812 assert_eq!(version.to_string(), "1.2.3");
1813 }
1814}
1815
1816#[cfg(feature = "serde")]
1817#[cfg(test)]
1818mod serde_tests {
1819 use super::Identifier::*;
1820 use super::*;
1821
1822 #[test]
1823 fn version_serde() {
1824 let v = Version::new(
1825 1,
1826 2,
1827 3,
1828 vec![AlphaNumeric("abc".into()), Numeric(123)],
1829 vec![AlphaNumeric("build".into())],
1830 );
1831
1832 let serialized = serde_json::to_string(&v).unwrap();
1833 let deserialized: Version = serde_json::from_str(&serialized).unwrap();
1834
1835 assert_eq!(v, deserialized);
1836 }
1837}