changepacks_utils/
split_version.rs

1use anyhow::Result;
2
3pub fn split_version(version: &str) -> Result<(Option<String>, String)> {
4    let first_digit_pos = version
5        .char_indices()
6        .find(|(_, c)| c.is_ascii_digit())
7        .map(|(pos, _)| pos);
8
9    match first_digit_pos {
10        Some(0) => Ok((None, version.to_string())),
11        Some(pos) => {
12            let prefix = version[..pos].to_string();
13            let version_part = version[pos..].to_string();
14            Ok((Some(prefix), version_part))
15        }
16        None => Ok((None, version.to_string())),
17    }
18}
19
20#[cfg(test)]
21mod tests {
22    use super::*;
23
24    use rstest::rstest;
25
26    #[rstest]
27    #[case("1.0.0", (None, "1.0.0"))]
28    #[case("^1.0.0", (Some("^"), "1.0.0"))]
29    #[case("~1.0.0", (Some("~"), "1.0.0"))]
30    #[case("1.0.0-alpha.1", (None, "1.0.0-alpha.1"))]
31    #[case("1.0.0-alpha.1+build1", (None, "1.0.0-alpha.1+build1"))]
32    #[case(">=1.0.0+build1", (Some(">="), "1.0.0+build1"))]
33    #[case("helloworld-1.0.2", (Some("helloworld-"), "1.0.2"))]
34    #[case("latest", (None, "latest"))]
35    #[case("*", (None, "*"))]
36    fn test_split_version(#[case] input: &str, #[case] expected: (Option<&str>, &str)) {
37        let (prefix, version) = split_version(input).unwrap();
38        assert_eq!(prefix.as_deref(), expected.0);
39        assert_eq!(version.as_str(), expected.1);
40    }
41}