alpm_types/version/
buildtool.rs1use std::{
4 fmt::{Display, Formatter},
5 str::FromStr,
6};
7
8use serde::Serialize;
9
10#[cfg(doc)]
11use crate::BuildTool;
12use crate::{Architecture, Error, FullVersion, MinimalVersion, Version};
13
14#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Serialize)]
66pub enum BuildToolVersion {
67 Makepkg(MinimalVersion),
71 DevTools {
75 version: FullVersion,
77 architecture: Architecture,
79 },
80}
81
82impl BuildToolVersion {
83 pub fn architecture(&self) -> Option<Architecture> {
89 if let Self::DevTools {
90 version: _,
91 architecture,
92 } = self
93 {
94 Some(*architecture)
95 } else {
96 None
97 }
98 }
99
100 pub fn version(&self) -> Version {
102 match self {
103 Self::Makepkg(version) => Version::from(version),
104 Self::DevTools {
105 version,
106 architecture: _,
107 } => Version::from(version),
108 }
109 }
110}
111
112impl FromStr for BuildToolVersion {
113 type Err = Error;
114 fn from_str(s: &str) -> Result<Self, Self::Err> {
125 match s.rsplit_once('-') {
126 Some((version, architecture)) => Ok(BuildToolVersion::DevTools {
127 version: FullVersion::from_str(version)?,
128 architecture: Architecture::from_str(architecture)?,
129 }),
130 None => Ok(BuildToolVersion::Makepkg(MinimalVersion::from_str(s)?)),
131 }
132 }
133}
134
135impl Display for BuildToolVersion {
136 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
137 match self {
138 Self::Makepkg(version) => write!(f, "{version}"),
139 Self::DevTools {
140 version,
141 architecture,
142 } => write!(f, "{version}-{architecture}"),
143 }
144 }
145}
146
147#[cfg(test)]
148mod tests {
149 use rstest::rstest;
150 use testresult::TestResult;
151
152 use super::*;
153
154 #[rstest]
157 #[case::devtools_full(
158 "1.0.0-1-any",
159 Ok(BuildToolVersion::DevTools{version: FullVersion::from_str("1.0.0-1")?, architecture: Architecture::from_str("any")?}),
160 )]
161 #[case::devtools_full_with_epoch(
162 "1:1.0.0-1-any",
163 Ok(BuildToolVersion::DevTools{version: FullVersion::from_str("1:1.0.0-1")?, architecture: Architecture::from_str("any")?}),
164 )]
165 #[case::makepkg_minimal(
166 "1.0.0",
167 Ok(BuildToolVersion::Makepkg(MinimalVersion::from_str("1.0.0")?)),
168 )]
169 #[case::makepkg_minimal_with_epoch(
170 "1:1.0.0",
171 Ok(BuildToolVersion::Makepkg(MinimalVersion::from_str("1:1.0.0")?)),
172 )]
173 #[case::minimal_version_with_architecture("1.0.0-any",
174 Err(Error::ParseError(
175 "1.0.0\n^\nexpected alpm-pkgver string, followed by a '-' and an alpm-pkgrel string".to_string()
176 ))
177 )]
178 #[case::minimal_version_with_epoch_and_architecture(
179 "1:1.0.0-any",
180 Err(Error::ParseError(
181 "1:1.0.0\n ^\nexpected alpm-pkgver string, followed by a '-' and an alpm-pkgrel string".to_string()
182 ))
183 )]
184 #[case::full_version_with_bogus_architecture("1.0.0-1-foo", Err(strum::ParseError::VariantNotFound.into()))]
185 fn valid_buildtoolver_new(
186 #[case] input: &str,
187 #[case] expected: Result<BuildToolVersion, Error>,
188 ) -> TestResult {
189 let parse_result = BuildToolVersion::from_str(input);
190 assert_eq!(
191 parse_result, expected,
192 "Expected '{expected:?}' when parsing '{input}' but got '{parse_result:?}'"
193 );
194
195 Ok(())
196 }
197
198 #[rstest]
201 #[case::minimal_version_with_architecture(
202 "1.0.0-any",
203 Error::ParseError(
204 "1.0.0\n^\nexpected alpm-pkgver string, followed by a '-' and an alpm-pkgrel string".to_string()
205 )
206 )]
207 #[case::minimal_version_with_invalid_architecture(
208 "1.0.0-foo",
209 Error::ParseError(
210 "1.0.0\n^\nexpected alpm-pkgver string, followed by a '-' and an alpm-pkgrel string".to_string()
211 )
212 )]
213 #[case::full_version_with_invalid_architecture("1.0.0-1-foo", strum::ParseError::VariantNotFound.into())]
214 fn invalid_buildtoolver_new(#[case] buildtoolver: &str, #[case] expected: Error) {
215 assert_eq!(
216 BuildToolVersion::from_str(buildtoolver),
217 Err(expected),
218 "Expected error during parse of buildtoolver '{buildtoolver}'"
219 );
220 }
221
222 #[rstest]
223 #[case(".1.0.0-1-any", "invalid first pkgver character")]
224 fn invalid_buildtoolver_badpkgver(#[case] buildtoolver: &str, #[case] err_snippet: &str) {
225 let Err(Error::ParseError(err_msg)) = BuildToolVersion::from_str(buildtoolver) else {
226 panic!("'{buildtoolver}' erroneously parsed as BuildToolVersion")
227 };
228 assert!(
229 err_msg.contains(err_snippet),
230 "Error:\n=====\n{err_msg}\n=====\nshould contain snippet:\n\n{err_snippet}"
231 );
232 }
233}