Merge pull request #3586 from jfinkels/mktemp-multiple-x-sequences

mktemp: only replace last contiguous block of Xs
This commit is contained in:
Sylvestre Ledru 2022-06-06 10:06:44 +02:00 committed by GitHub
commit 3f203c7ab1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 60 additions and 4 deletions

View file

@ -6,7 +6,7 @@
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
// spell-checker:ignore (paths) GPGHome
// spell-checker:ignore (paths) GPGHome findxs
use clap::{crate_version, Arg, ArgMatches, Command};
use uucore::display::{println_verbatim, Quotable};
@ -205,12 +205,29 @@ struct Params {
suffix: String,
}
/// Find the start and end indices of the last contiguous block of Xs.
///
/// If no contiguous block of at least three Xs could be found, this
/// function returns `None`.
///
/// # Examples
///
/// ```rust,ignore
/// assert_eq!(find_last_contiguous_block_of_xs("XXX_XXX"), Some((4, 7)));
/// assert_eq!(find_last_contiguous_block_of_xs("aXbXcX"), None);
/// ```
fn find_last_contiguous_block_of_xs(s: &str) -> Option<(usize, usize)> {
let j = s.rfind("XXX")? + 3;
let i = s[..j].rfind(|c| c != 'X').map_or(0, |i| i + 1);
Some((i, j))
}
impl Params {
fn from(options: Options) -> Result<Self, MkTempError> {
// Get the start and end indices of the randomized part of the template.
//
// For example, if the template is "abcXXXXyz", then `i` is 3 and `j` is 7.
let i = match options.template.find("XXX") {
let (i, j) = match find_last_contiguous_block_of_xs(&options.template) {
None => {
let s = match options.suffix {
None => options.template,
@ -218,9 +235,8 @@ impl Params {
};
return Err(MkTempError::TooFewXs(s));
}
Some(i) => i,
Some(indices) => indices,
};
let j = options.template.rfind("XXX").unwrap() + 3;
// Combine the directory given as an option and the prefix of the template.
//
@ -450,3 +466,21 @@ fn exec(dir: &str, prefix: &str, rand: usize, suffix: &str, make_dir: bool) -> U
println_verbatim(path).map_err_context(|| "failed to print directory name".to_owned())
}
#[cfg(test)]
mod tests {
use crate::find_last_contiguous_block_of_xs as findxs;
#[test]
fn test_find_last_contiguous_block_of_xs() {
assert_eq!(findxs("XXX"), Some((0, 3)));
assert_eq!(findxs("XXX_XXX"), Some((4, 7)));
assert_eq!(findxs("XXX_XXX_XXX"), Some((8, 11)));
assert_eq!(findxs("aaXXXbb"), Some((2, 5)));
assert_eq!(findxs(""), None);
assert_eq!(findxs("X"), None);
assert_eq!(findxs("XX"), None);
assert_eq!(findxs("aXbXcX"), None);
assert_eq!(findxs("aXXbXXcXX"), None);
}
}

View file

@ -597,3 +597,25 @@ fn test_too_few_xs_suffix_directory() {
fn test_too_many_arguments() {
new_ucmd!().args(&["-q", "a", "b"]).fails().code_is(1);
}
#[test]
fn test_two_contiguous_wildcard_blocks() {
let (at, mut ucmd) = at_and_ucmd!();
let template = "XXX_XXX";
let result = ucmd.arg(template).succeeds();
let filename = result.no_stderr().stdout_str().trim_end();
assert_eq!(&filename[..4], "XXX_");
assert_matches_template!(template, filename);
assert!(at.file_exists(filename));
}
#[test]
fn test_three_contiguous_wildcard_blocks() {
let (at, mut ucmd) = at_and_ucmd!();
let template = "XXX_XXX_XXX";
let result = ucmd.arg(template).succeeds();
let filename = result.no_stderr().stdout_str().trim_end();
assert_eq!(&filename[..8], "XXX_XXX_");
assert_matches_template!(template, filename);
assert!(at.file_exists(filename));
}