Support parsing Script Extender product version fields

They've got a format that matches the format for fixed-size version fields in resource files.
This commit is contained in:
Oliver Hamlet
2018-12-22 22:50:16 +00:00
parent c90814a8ab
commit 5e1ba5709b
+42 -16
View File
@@ -15,7 +15,7 @@ enum Identifier {
impl<'a> From<&'a str> for Identifier {
fn from(string: &'a str) -> Self {
u32::from_str_radix(string, 10)
u32::from_str_radix(string.trim(), 10)
.map(Identifier::Numeric)
.unwrap_or_else(|_| Identifier::NonNumeric(string.to_lowercase()))
}
@@ -91,17 +91,30 @@ fn is_pre_release_separator(c: char) -> bool {
c == '.' || is_separator(c)
}
fn split_version_string(string: &str) -> (&str, &str) {
// Special case for strings of the form "0, 1, 2, 3", which are used in
// OBSE and SKSE, and which should be interpreted as "0.1.2.3".
if let Ok(regex) = regex::Regex::new("\\d+, \\d+, \\d+, \\d+") {
if regex.is_match(string) {
return (string, "");
}
}
match string.find(is_separator) {
Some(i) if i + 1 < string.len() => (&string[..i], &string[i + 1..]),
Some(_) | None => (string, ""),
}
}
impl<'a> From<&'a str> for Version {
fn from(string: &'a str) -> Self {
let trimmed = trim_metadata(string);
let (release, pre_release) = match trimmed.find(is_separator) {
Some(i) if i + 1 < trimmed.len() => (&trimmed[..i], &trimmed[i + 1..]),
Some(_) | None => (trimmed, ""),
};
let (release, pre_release) = split_version_string(trim_metadata(string));
Version {
release_ids: release.split('.').map(Identifier::from).collect(),
release_ids: release
.split(|c| c == '.' || c == ',')
.map(Identifier::from)
.collect(),
pre_release_ids: pre_release
.split_terminator(is_pre_release_separator)
.map(Identifier::from)
@@ -199,11 +212,9 @@ mod tests {
fn version_read_file_version_should_error_with_path_if_path_does_not_exist() {
let error = Version::read_file_version(Path::new("missing")).unwrap_err();
assert!(
error
assert!(error
.to_string()
.starts_with("An error was encountered while accessing the path \"missing\":")
);
.starts_with("An error was encountered while accessing the path \"missing\":"));
}
#[test]
@@ -241,11 +252,9 @@ mod tests {
fn version_read_product_version_should_error_with_path_if_path_does_not_exist() {
let error = Version::read_product_version(Path::new("missing")).unwrap_err();
assert!(
error
assert!(error
.to_string()
.starts_with("An error was encountered while accessing the path \"missing\":")
);
.starts_with("An error was encountered while accessing the path \"missing\":"));
}
#[test]
@@ -451,6 +460,23 @@ mod tests {
mod extensions {
use super::super::*;
#[test]
fn version_from_should_parse_comma_separated_versions() {
// OBSE and SKSE use version string fields of the form "0, 2, 0, 12".
let version = Version::from("0, 2, 0, 12");
assert_eq!(
version.release_ids,
vec![
Identifier::Numeric(0),
Identifier::Numeric(2),
Identifier::Numeric(0),
Identifier::Numeric(12),
]
);
assert!(version.pre_release_ids.is_empty());
}
#[test]
fn version_eq_should_ignore_leading_zeroes_in_major_version_numbers() {
assert_eq!(Version::from("05.0.0"), Version::from("5.0.0"));