diff --git a/src/uu/mktemp/src/mktemp.rs b/src/uu/mktemp/src/mktemp.rs index f999d6675..b14318679 100644 --- a/src/uu/mktemp/src/mktemp.rs +++ b/src/uu/mktemp/src/mktemp.rs @@ -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()); + } +}