Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 0 additions & 115 deletions src/uu/shuf/src/random_seed.rs

This file was deleted.

21 changes: 1 addition & 20 deletions src/uu/shuf/src/shuf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,9 @@ use uucore::translate;

mod compat_random_source;
mod nonrepeating_iterator;
mod random_seed;

use compat_random_source::RandomSourceAdapter;
use nonrepeating_iterator::NonrepeatingIterator;
use random_seed::SeededRng;

enum Mode {
Default(PathBuf),
Expand All @@ -50,7 +48,7 @@ struct Options {

enum RandomSource {
None,
Seed(String),
//Seed(String),
File(PathBuf),
}

Expand All @@ -60,7 +58,6 @@ mod options {
pub static HEAD_COUNT: &str = "head-count";
pub static OUTPUT: &str = "output";
pub static RANDOM_SOURCE: &str = "random-source";
pub static RANDOM_SEED: &str = "random-seed";
pub static REPEAT: &str = "repeat";
pub static ZERO_TERMINATED: &str = "zero-terminated";
pub static FILE_OR_ARGS: &str = "file-or-args";
Expand Down Expand Up @@ -96,8 +93,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {

let random_source = if let Some(filename) = matches.get_one(options::RANDOM_SOURCE).cloned() {
RandomSource::File(filename)
} else if let Some(seed) = matches.get_one(options::RANDOM_SEED).cloned() {
RandomSource::Seed(seed)
} else {
RandomSource::None
};
Expand Down Expand Up @@ -140,7 +135,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
// file untouched, matching GNU and avoiding silent data loss.
let mut rng = match options.random_source {
RandomSource::None => WrappedRng::Default(rand::rng()),
RandomSource::Seed(ref seed) => WrappedRng::Seed(SeededRng::new(seed)),
RandomSource::File(ref r) => {
let file = File::open(r).map_err_context(
|| translate!("shuf-error-failed-to-open-random-source", "file" => r.quote()),
Expand Down Expand Up @@ -218,15 +212,6 @@ pub fn uu_app() -> Command {
.value_parser(ValueParser::path_buf())
.value_hint(clap::ValueHint::FilePath),
)
.arg(
Arg::new(options::RANDOM_SEED)
.long(options::RANDOM_SEED)
.value_name("STRING")
.help(translate!("shuf-help-random-seed"))
.value_parser(ValueParser::string())
.value_hint(clap::ValueHint::Other)
.conflicts_with(options::RANDOM_SOURCE),
)
.arg(
Arg::new(options::RANDOM_SOURCE)
.long(options::RANDOM_SOURCE)
Expand Down Expand Up @@ -461,31 +446,27 @@ fn parse_range(input_range: &str) -> Result<RangeInclusive<u64>, String> {

enum WrappedRng {
Default(ThreadRng),
Seed(SeededRng),
File(RandomSourceAdapter<BufReader<File>>),
}

impl WrappedRng {
fn choose<T: Copy>(&mut self, vals: &[T]) -> UResult<T> {
match self {
Self::Default(rng) => Ok(*vals.choose(rng).unwrap()),
Self::Seed(rng) => Ok(rng.choose_from_slice(vals)),
Self::File(rng) => rng.choose_from_slice(vals),
}
}

fn shuffle<'a, T>(&mut self, vals: &'a mut [T], amount: usize) -> UResult<&'a mut [T]> {
match self {
Self::Default(rng) => Ok(vals.partial_shuffle(rng, amount).0),
Self::Seed(rng) => Ok(rng.shuffle(vals, amount)),
Self::File(rng) => rng.shuffle(vals, amount),
}
}

fn choose_from_range(&mut self, range: RangeInclusive<u64>) -> UResult<u64> {
match self {
Self::Default(rng) => Ok(rng.random_range(range)),
Self::Seed(rng) => Ok(rng.choose_from_range(range)),
Self::File(rng) => rng.choose_from_range(range),
}
}
Expand Down
90 changes: 0 additions & 90 deletions tests/by-util/test_shuf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
// file that was distributed with this source code.

// spell-checker:ignore (ToDO) unwritable GHSA
use std::fmt::Write;

use uutests::at_and_ucmd;
use uutests::new_ucmd;
Expand Down Expand Up @@ -1070,95 +1069,6 @@ fn test_gnu_compat_range_no_repeat() {
.stdout_is("10\n2\n8\n7\n3\n9\n6\n5\n1\n4\n");
}

// Test reproducibility of --random-seed.
// These results are arbitrary but they should not change unless we choose to break compatibility.

#[test]
fn test_seed_args_repeat() {
new_ucmd!()
.arg("--random-seed=🌱")
.arg("-e")
.arg("-r")
.arg("-n10")
.args(&["foo", "bar", "baz", "qux"])
.succeeds()
.no_stderr()
.stdout_is("qux\nbar\nbaz\nfoo\nbaz\nqux\nqux\nfoo\nqux\nqux\n");
}

#[test]
fn test_seed_args_no_repeat() {
new_ucmd!()
.arg("--random-seed=🌱")
.arg("-e")
.args(&["foo", "bar", "baz", "qux"])
.succeeds()
.no_stderr()
.stdout_is("qux\nbaz\nfoo\nbar\n");
}

#[test]
fn test_seed_range_repeat() {
new_ucmd!()
.arg("--random-seed=🦀")
.arg("-r")
.arg("-i1-99")
.arg("-n10")
.succeeds()
.no_stderr()
.stdout_is("60\n44\n38\n41\n63\n43\n31\n71\n46\n90\n");
}

#[test]
fn test_seed_range_no_repeat() {
let expected = "8\n9\n1\n5\n2\n6\n4\n3\n10\n7\n";

new_ucmd!()
.arg("--random-seed=12345")
.arg("-i1-10")
.succeeds()
.no_stderr()
.stdout_is(expected);

// Piping from e.g. seq gives identical results.
new_ucmd!()
.arg("--random-seed=12345")
.pipe_in("1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n")
.succeeds()
.no_stderr()
.stdout_is(expected);
}

// Test a longer input to exercise some more code paths in the sparse representation.
#[test]
fn test_seed_long_range_no_repeat() {
let expected = "\
1\n3\n35\n37\n36\n45\n72\n17\n18\n40\n67\n74\n81\n77\n14\n90\n\
7\n12\n80\n54\n23\n61\n29\n41\n15\n56\n6\n32\n82\n76\n11\n2\n100\n\
50\n60\n97\n73\n79\n91\n89\n85\n86\n66\n70\n22\n55\n8\n83\n39\n27\n";

new_ucmd!()
.arg("--random-seed=67890")
.arg("-i1-100")
.arg("-n50")
.succeeds()
.no_stderr()
.stdout_is(expected);

let mut test_input = String::new();
for n in 1..=100 {
writeln!(&mut test_input, "{n}").unwrap();
}

new_ucmd!()
.arg("--random-seed=67890")
.pipe_in(test_input.as_bytes())
.arg("-n50")
.succeeds()
.no_stderr()
.stdout_is(expected);
}

#[test]
fn test_empty_range_no_repeat() {
new_ucmd!().arg("-i4-3").succeeds().no_output();
Expand Down
Loading