Skip to main content

semver_common/models/
version.rs

1use std::str::FromStr;
2
3use crate::{Alert, CommitMap};
4use derive_getters::Getters;
5use serde::{Deserialize, Serialize};
6
7/// Data structure that contains a version with a major, minor, and patch number as well as a map
8/// of commits that represent changes since the previous version.
9#[derive(Serialize, Deserialize, Getters, Clone)]
10pub struct Version {
11    major: u32,
12    minor: u32,
13    patch: u32,
14    changes: CommitMap,
15}
16
17impl Default for Version {
18    fn default() -> Self {
19        Self::new(0, 0, 0, CommitMap::new())
20    }
21}
22
23impl FromStr for Version {
24    type Err = Alert;
25
26    fn from_str(s: &str) -> Result<Self, Self::Err> {
27        let config: Version = serde_json::from_str(s)?;
28        Ok(config)
29    }
30}
31
32impl<T> From<T> for Version
33where
34    T: ToString,
35{
36    fn from(value: T) -> Self {
37        Self::from_str(&value.to_string()).unwrap()
38    }
39}
40
41impl Version {
42    /// Gets the version in string form. Formatted, "v(major).(minor).(patch)"
43    pub fn get(&self) -> String {
44        format!("v{}.{}.{}", self.major, self.minor, self.patch)
45    }
46
47    /// Gets the version in short string form. Formatted, "(major).(minor).(patch)"
48    pub fn short(&self) -> String {
49        format!("{}.{}.{}", self.major, self.minor, self.patch)
50    }
51
52    /// Parse a string into the appropriate version numbers. Returns a tuple containing
53    /// the major, minor, and patch version numbers extracted from the string, if available.
54    pub fn parse(version: &str) -> Option<(u32, u32, u32)> {
55        if version.len() <= 1 {
56            return None;
57        }
58        let separated: Vec<&str> = version[1..].split(".").collect();
59        if separated.len() == 3 {
60            let major_version = separated.first()?;
61            let minor_version = separated.get(1)?;
62            let patch_version = separated.get(2)?;
63            return Some((
64                major_version.parse().ok()?,
65                minor_version.parse().ok()?,
66                patch_version.parse().ok()?,
67            ));
68        }
69        None
70    }
71
72    pub fn new(major: u32, minor: u32, patch: u32, changes: CommitMap) -> Self {
73        Version {
74            major,
75            minor,
76            patch,
77            changes,
78        }
79    }
80}
81
82#[cfg(test)]
83mod test {
84    use super::*;
85
86    #[test]
87    fn test_version_parse_valid() {
88        let parse_value = Version::parse("v1.9.2");
89        assert_eq!(parse_value, Some((1, 9, 2)));
90    }
91
92    #[test]
93    fn test_version_parse_invalid_full_len() {
94        let parse_value = Version::parse("oopasdf91.9.2ff");
95        assert_eq!(parse_value, None);
96    }
97
98    #[test]
99    fn test_version_parse_invalid_one_len() {
100        let parse_value = Version::parse("v");
101        assert_eq!(parse_value, None);
102    }
103
104    #[test]
105    fn test_version_parse_invalid_no_input() {
106        let parse_value = Version::parse("");
107        assert_eq!(parse_value, None);
108    }
109
110    #[test]
111    fn test_version_parse_invalid_no_int() {
112        let parse_value = Version::parse("vIU.AB.PE");
113        assert_eq!(parse_value, None);
114    }
115
116    #[test]
117    fn test_version_get() {
118        let (major, minor, patch) = Version::parse("v1.9.2").unwrap();
119        let changes = CommitMap::new();
120        let version = Version::new(major, minor, patch, changes);
121        assert_eq!(version.get(), "v1.9.2");
122    }
123}