1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-29 12:07:46 +00:00

mktemp: return MkTempError from parse_template()

Change the return type of the `parse_template()` helper function in
the `mktemp` program so that it returns `Result<..., MkTempError>`
instead of `UResult<...>`. This separates the lower level helper
function from the higher level `UResult` abstraction and will make it
easier to refactor this code in future commits.
This commit is contained in:
Jeffrey Finkelstein 2022-05-05 17:58:37 -04:00
parent 309347e218
commit e691330f02

View file

@ -205,20 +205,41 @@ pub fn uu_app<'a>() -> Command<'a> {
)
}
/// Parse a template string into prefix, suffix, and random components.
///
/// `temp` is the template string, with three or more consecutive `X`s
/// representing a placeholder for randomly generated characters (for
/// example, `"abc_XXX.txt"`). If `temp` ends in an `X`, then a suffix
/// can be specified by `suffix` instead.
///
/// # Errors
///
/// * If there are fewer than three consecutive `X`s in `temp`.
/// * If `suffix` is a [`Some`] object but `temp` does not end in `X`.
/// * If the suffix (specified either way) contains a path separator.
///
/// # Examples
///
/// ```rust,ignore
/// assert_eq!(parse_template("XXX", None).unwrap(), ("", 3, ""));
/// assert_eq!(parse_template("abcXXX", None).unwrap(), ("abc", 3, ""));
/// assert_eq!(parse_template("XXXdef", None).unwrap(), ("", 3, "def"));
/// assert_eq!(parse_template("abcXXXdef", None).unwrap(), ("abc", 3, "def"));
/// ```
fn parse_template<'a>(
temp: &'a str,
suffix: Option<&'a str>,
) -> UResult<(&'a str, usize, &'a str)> {
) -> Result<(&'a str, usize, &'a str), MkTempError> {
let right = match temp.rfind('X') {
Some(r) => r + 1,
None => return Err(MkTempError::TooFewXs(temp.into()).into()),
None => return Err(MkTempError::TooFewXs(temp.into())),
};
let left = temp[..right].rfind(|c| c != 'X').map_or(0, |i| i + 1);
let prefix = &temp[..left];
let rand = right - left;
if rand < 3 {
return Err(MkTempError::TooFewXs(temp.into()).into());
return Err(MkTempError::TooFewXs(temp.into()));
}
let mut suf = &temp[right..];
@ -227,12 +248,12 @@ fn parse_template<'a>(
if suf.is_empty() {
suf = s;
} else {
return Err(MkTempError::MustEndInX(temp.into()).into());
return Err(MkTempError::MustEndInX(temp.into()));
}
};
if suf.chars().any(is_separator) {
return Err(MkTempError::ContainsDirSeparator(suf.into()).into());
return Err(MkTempError::ContainsDirSeparator(suf.into()));
}
Ok((prefix, rand, suf))
@ -304,3 +325,41 @@ fn exec(dir: &Path, prefix: &str, rand: usize, suffix: &str, make_dir: bool) ->
println_verbatim(path).map_err_context(|| "failed to print directory name".to_owned())
}
#[cfg(test)]
mod tests {
use crate::parse_template;
#[test]
fn test_parse_template_no_suffix() {
assert_eq!(parse_template("XXX", None).unwrap(), ("", 3, ""));
assert_eq!(parse_template("abcXXX", None).unwrap(), ("abc", 3, ""));
assert_eq!(parse_template("XXXdef", None).unwrap(), ("", 3, "def"));
assert_eq!(
parse_template("abcXXXdef", None).unwrap(),
("abc", 3, "def")
);
}
#[test]
fn test_parse_template_suffix() {
assert_eq!(parse_template("XXX", Some("def")).unwrap(), ("", 3, "def"));
assert_eq!(
parse_template("abcXXX", Some("def")).unwrap(),
("abc", 3, "def")
);
}
#[test]
fn test_parse_template_errors() {
// TODO This should be an error as well, but we are not
// catching it just yet. A future commit will correct this.
//
// assert!(parse_template("a/bXXX", None).is_err());
//
assert!(parse_template("XXXa/b", None).is_err());
assert!(parse_template("XX", None).is_err());
assert!(parse_template("XXXabc", Some("def")).is_err());
assert!(parse_template("XXX", Some("a/b")).is_err());
}
}