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

Merge branch 'master' into pr

This commit is contained in:
Sylvestre Ledru 2021-04-09 22:02:25 +02:00 committed by GitHub
commit 844e318a67
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
235 changed files with 12115 additions and 4330 deletions

View file

@ -3,6 +3,14 @@ extern crate unix_socket;
use crate::common::util::*;
#[test]
fn test_output_simple() {
new_ucmd!()
.args(&["alpha.txt"])
.succeeds()
.stdout_only("abcde\nfghij\nklmno\npqrst\nuvwxyz\n");
}
#[test]
fn test_output_multi_files_print_all_chars() {
new_ucmd!()

View file

@ -4,6 +4,8 @@ use std::os::unix::fs::{OpenOptionsExt, PermissionsExt};
use std::sync::Mutex;
extern crate libc;
use self::chmod::strip_minus_from_mode;
extern crate chmod;
use self::libc::umask;
static TEST_FILE: &'static str = "file";
@ -35,10 +37,10 @@ fn run_single_test(test: &TestCase, at: AtPath, mut ucmd: UCommand) {
mkfile(&at.plus_as_string(TEST_FILE), test.before);
let perms = at.metadata(TEST_FILE).permissions().mode();
if perms != test.before {
panic!(format!(
panic!(
"{}: expected: {:o} got: {:o}",
"setting permissions on test files before actual test run failed", test.after, perms
));
);
}
for arg in &test.args {
@ -47,15 +49,15 @@ fn run_single_test(test: &TestCase, at: AtPath, mut ucmd: UCommand) {
let r = ucmd.run();
if !r.success {
println!("{}", r.stderr);
panic!(format!("{:?}: failed", ucmd.raw));
panic!("{:?}: failed", ucmd.raw);
}
let perms = at.metadata(TEST_FILE).permissions().mode();
if perms != test.after {
panic!(format!(
panic!(
"{:?}: expected: {:o} got: {:o}",
ucmd.raw, test.after, perms
));
);
}
}
@ -327,10 +329,9 @@ fn test_chmod_non_existing_file() {
.arg("-r,a+w")
.arg("dont-exist")
.fails();
assert_eq!(
result.stderr,
"chmod: error: no such file or directory 'dont-exist'\n"
);
assert!(result
.stderr
.contains("cannot access 'dont-exist': No such file or directory"));
}
#[test]
@ -349,28 +350,138 @@ fn test_chmod_preserve_root() {
#[test]
fn test_chmod_symlink_non_existing_file() {
let (at, mut ucmd) = at_and_ucmd!();
at.symlink_file("/non-existing", "test-long.link");
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
let _result = ucmd
.arg("-R")
let non_existing = "test_chmod_symlink_non_existing_file";
let test_symlink = "test_chmod_symlink_non_existing_file_symlink";
let expected_stdout = &format!(
"failed to change mode of '{}' from 0000 (---------) to 0000 (---------)",
test_symlink
);
let expected_stderr = &format!("cannot operate on dangling symlink '{}'", test_symlink);
at.symlink_file(non_existing, test_symlink);
let mut result;
// this cannot succeed since the symbolic link dangles
result = scene.ucmd().arg("755").arg("-v").arg(test_symlink).fails();
println!("stdout = {:?}", result.stdout);
println!("stderr = {:?}", result.stderr);
assert!(result.stdout.contains(expected_stdout));
assert!(result.stderr.contains(expected_stderr));
assert_eq!(result.code, Some(1));
// this should be the same than with just '-v' but without stderr
result = scene
.ucmd()
.arg("755")
.arg("-v")
.arg("test-long.link")
.arg("-f")
.arg(test_symlink)
.fails();
println!("stdout = {:?}", result.stdout);
println!("stderr = {:?}", result.stderr);
assert!(result.stdout.contains(expected_stdout));
assert!(result.stderr.is_empty());
assert_eq!(result.code, Some(1));
}
#[test]
fn test_chmod_symlink_non_existing_recursive() {
let (at, mut ucmd) = at_and_ucmd!();
at.mkdir("tmp");
at.symlink_file("/non-existing", "tmp/test-long.link");
fn test_chmod_symlink_non_existing_file_recursive() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
let result = ucmd.arg("-R").arg("755").arg("-v").arg("tmp").succeeds();
// it should be a success
println!("stderr {}", result.stderr);
println!("stdout {}", result.stdout);
assert!(result
.stderr
.contains("neither symbolic link 'tmp/test-long.link' nor referent has been changed"));
let non_existing = "test_chmod_symlink_non_existing_file_recursive";
let test_symlink = "test_chmod_symlink_non_existing_file_recursive_symlink";
let test_directory = "test_chmod_symlink_non_existing_file_directory";
at.mkdir(test_directory);
at.symlink_file(
non_existing,
&format!("{}/{}", test_directory, test_symlink),
);
let mut result;
// this should succeed
result = scene
.ucmd()
.arg("-R")
.arg("755")
.arg(test_directory)
.succeeds();
assert_eq!(result.code, Some(0));
assert!(result.stdout.is_empty());
assert!(result.stderr.is_empty());
let expected_stdout = &format!(
"mode of '{}' retained as 0755 (rwxr-xr-x)\nneither symbolic link '{}/{}' nor referent has been changed",
test_directory, test_directory, test_symlink
);
// '-v': this should succeed without stderr
result = scene
.ucmd()
.arg("-R")
.arg("-v")
.arg("755")
.arg(test_directory)
.succeeds();
println!("stdout = {:?}", result.stdout);
println!("stderr = {:?}", result.stderr);
assert!(result.stdout.contains(expected_stdout));
assert!(result.stderr.is_empty());
assert_eq!(result.code, Some(0));
// '-vf': this should be the same than with just '-v'
result = scene
.ucmd()
.arg("-R")
.arg("-v")
.arg("-f")
.arg("755")
.arg(test_directory)
.succeeds();
println!("stdout = {:?}", result.stdout);
println!("stderr = {:?}", result.stderr);
assert!(result.stdout.contains(expected_stdout));
assert!(result.stderr.is_empty());
assert_eq!(result.code, Some(0));
}
#[test]
fn test_chmod_strip_minus_from_mode() {
let tests = vec![
// ( before, after )
("chmod -v -xw -R FILE", "chmod -v xw -R FILE"),
("chmod g=rwx FILE -c", "chmod g=rwx FILE -c"),
(
"chmod -c -R -w,o+w FILE --preserve-root",
"chmod -c -R w,o+w FILE --preserve-root",
),
("chmod -c -R +w FILE ", "chmod -c -R +w FILE "),
("chmod a=r,=xX FILE", "chmod a=r,=xX FILE"),
(
"chmod -v --reference RFILE -R FILE",
"chmod -v --reference RFILE -R FILE",
),
("chmod -Rvc -w-x FILE", "chmod -Rvc w-x FILE"),
("chmod 755 -v FILE", "chmod 755 -v FILE"),
("chmod -v +0004 FILE -R", "chmod -v +0004 FILE -R"),
("chmod -v -0007 FILE -R", "chmod -v 0007 FILE -R"),
];
for test in tests {
let mut args: Vec<String> = test.0.split(" ").map(|v| v.to_string()).collect();
let _mode_had_minus_prefix = strip_minus_from_mode(&mut args);
assert_eq!(test.1, args.join(" "));
}
}

View file

@ -24,3 +24,80 @@ fn test_stdin() {
.succeeds()
.stdout_is_fixture("stdin.expected");
}
#[test]
fn test_empty() {
let (at, mut ucmd) = at_and_ucmd!();
at.touch("a");
ucmd.arg("a").succeeds().stdout.ends_with("0 a");
}
#[test]
#[ignore]
fn test_arg_overrides_stdin() {
let (at, mut ucmd) = at_and_ucmd!();
let input = "foobarfoobar";
at.touch("a");
let result = ucmd.arg("a").pipe_in(input.as_bytes()).run();
println!("{}, {}", result.stdout, result.stderr);
assert!(result.stdout.ends_with("0 a\n"))
}
#[test]
fn test_invalid_file() {
let (_, mut ucmd) = at_and_ucmd!();
let ls = TestScenario::new("ls");
let files = ls.cmd("ls").arg("-l").run();
println!("{:?}", files.stdout);
println!("{:?}", files.stderr);
let folder_name = "asdf".to_string();
let result = ucmd.arg(&folder_name).run();
println!("stdout: {:?}", result.stdout);
println!("stderr: {:?}", result.stderr);
assert!(result.stderr.contains("cksum: error: 'asdf'"));
assert!(!result.success);
}
// Make sure crc is correct for files larger than 32 bytes
// but <128 bytes (1 fold pclmul)
#[test]
fn test_crc_for_bigger_than_32_bytes() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg("chars.txt").run();
let mut stdout_splitted = result.stdout.split(" ");
let cksum: i64 = stdout_splitted.next().unwrap().parse().unwrap();
let bytes_cnt: i64 = stdout_splitted.next().unwrap().parse().unwrap();
assert!(result.success);
assert_eq!(cksum, 586047089);
assert_eq!(bytes_cnt, 16);
}
#[test]
fn test_stdin_larger_than_128_bytes() {
let (_, mut ucmd) = at_and_ucmd!();
let result = ucmd.arg("larger_than_2056_bytes.txt").run();
let mut stdout_splitted = result.stdout.split(" ");
let cksum: i64 = stdout_splitted.next().unwrap().parse().unwrap();
let bytes_cnt: i64 = stdout_splitted.next().unwrap().parse().unwrap();
assert!(result.success);
assert_eq!(cksum, 945881979);
assert_eq!(bytes_cnt, 2058);
}

View file

@ -1038,7 +1038,7 @@ fn test_cp_one_file_system() {
.arg("tmpfs")
.arg(mountpoint_path)
.run();
assert!(_r.code == Some(0), _r.stderr);
assert!(_r.code == Some(0), "{}", _r.stderr);
at_src.touch(TEST_MOUNT_OTHER_FILESYSTEM_FILE);
@ -1052,7 +1052,7 @@ fn test_cp_one_file_system() {
// Ditch the mount before the asserts
let _r = scene.cmd("umount").arg(mountpoint_path).run();
assert!(_r.code == Some(0), _r.stderr);
assert!(_r.code == Some(0), "{}", _r.stderr);
assert!(result.success);
assert!(!at_dst.file_exists(TEST_MOUNT_OTHER_FILESYSTEM_FILE));

View file

@ -139,3 +139,21 @@ fn test_zero_terminated_only_delimited() {
.succeeds()
.stdout_only("82\n7\0");
}
#[test]
fn test_directory_and_no_such_file() {
let (at, mut ucmd) = at_and_ucmd!();
at.mkdir("some");
ucmd.arg("-b1")
.arg("some")
.run()
.stderr_is("cut: error: some: Is a directory\n");
new_ucmd!()
.arg("-b1")
.arg("some")
.run()
.stderr_is("cut: error: some: No such file or directory\n");
}

View file

@ -45,7 +45,11 @@ fn test_du_basics_subdir() {
fn _du_basics_subdir(s: String) {
assert_eq!(s, "4\tsubdir/deeper\n");
}
#[cfg(not(target_vendor = "apple"))]
#[cfg(target_os = "windows")]
fn _du_basics_subdir(s: String) {
assert_eq!(s, "0\tsubdir/deeper\n");
}
#[cfg(all(not(target_vendor = "apple"), not(target_os = "windows")))]
fn _du_basics_subdir(s: String) {
// MS-WSL linux has altered expected output
if !is_wsl() {
@ -71,7 +75,7 @@ fn test_du_basics_bad_name() {
fn test_du_soft_link() {
let ts = TestScenario::new("du");
let link = ts.cmd("ln").arg("-s").arg(SUB_FILE).arg(SUB_LINK).run();
let link = ts.ccmd("ln").arg("-s").arg(SUB_FILE).arg(SUB_LINK).run();
assert!(link.success);
let result = ts.ucmd().arg(SUB_DIR_LINKS).run();
@ -85,7 +89,11 @@ fn _du_soft_link(s: String) {
// 'macos' host variants may have `du` output variation for soft links
assert!((s == "12\tsubdir/links\n") || (s == "16\tsubdir/links\n"));
}
#[cfg(not(target_vendor = "apple"))]
#[cfg(target_os = "windows")]
fn _du_soft_link(s: String) {
assert_eq!(s, "8\tsubdir/links\n");
}
#[cfg(all(not(target_vendor = "apple"), not(target_os = "windows")))]
fn _du_soft_link(s: String) {
// MS-WSL linux has altered expected output
if !is_wsl() {
@ -99,7 +107,7 @@ fn _du_soft_link(s: String) {
fn test_du_hard_link() {
let ts = TestScenario::new("du");
let link = ts.cmd("ln").arg(SUB_FILE).arg(SUB_LINK).run();
let link = ts.ccmd("ln").arg(SUB_FILE).arg(SUB_LINK).run();
assert!(link.success);
let result = ts.ucmd().arg(SUB_DIR_LINKS).run();
@ -113,7 +121,11 @@ fn test_du_hard_link() {
fn _du_hard_link(s: String) {
assert_eq!(s, "12\tsubdir/links\n")
}
#[cfg(not(target_vendor = "apple"))]
#[cfg(target_os = "windows")]
fn _du_hard_link(s: String) {
assert_eq!(s, "8\tsubdir/links\n")
}
#[cfg(all(not(target_vendor = "apple"), not(target_os = "windows")))]
fn _du_hard_link(s: String) {
// MS-WSL linux has altered expected output
if !is_wsl() {
@ -137,7 +149,11 @@ fn test_du_d_flag() {
fn _du_d_flag(s: String) {
assert_eq!(s, "16\t./subdir\n20\t./\n");
}
#[cfg(not(target_vendor = "apple"))]
#[cfg(target_os = "windows")]
fn _du_d_flag(s: String) {
assert_eq!(s, "8\t./subdir\n8\t./\n");
}
#[cfg(all(not(target_vendor = "apple"), not(target_os = "windows")))]
fn _du_d_flag(s: String) {
// MS-WSL linux has altered expected output
if !is_wsl() {
@ -146,3 +162,31 @@ fn _du_d_flag(s: String) {
assert_eq!(s, "8\t./subdir\n8\t./\n");
}
}
#[test]
fn test_du_h_flag_empty_file() {
let ts = TestScenario::new("du");
let result = ts.ucmd().arg("-h").arg("empty.txt").run();
assert!(result.success);
assert_eq!(result.stderr, "");
assert_eq!(result.stdout, "0\tempty.txt\n");
}
#[cfg(feature = "touch")]
#[test]
fn test_du_time() {
let ts = TestScenario::new("du");
let touch = ts.ccmd("touch").arg("-a").arg("-m").arg("-t").arg("201505150000").arg("date_test").run();
assert!(touch.success);
let result = ts.ucmd().arg("--time").arg("date_test").run();
// cleanup by removing test file
ts.cmd("rm").arg("date_test").run();
assert!(result.success);
assert_eq!(result.stderr, "");
assert_eq!(result.stdout, "0\t2015-05-15 00:00\tdate_test\n");
}

View file

@ -25,9 +25,521 @@ fn test_40_column_word_boundary() {
}
#[test]
fn test_default_warp_with_newlines() {
fn test_default_wrap_with_newlines() {
new_ucmd!()
.arg("lorem_ipsum_new_line.txt")
.run()
.stdout_is_fixture("lorem_ipsum_new_line_80_column.expected");
}
#[test]
fn test_should_preserve_empty_line_without_final_newline() {
new_ucmd!()
.arg("-w2")
.pipe_in("12\n\n34")
.succeeds()
.stdout_is("12\n\n34");
}
#[test]
fn test_should_preserve_empty_line_and_final_newline() {
new_ucmd!()
.arg("-w2")
.pipe_in("12\n\n34\n")
.succeeds()
.stdout_is("12\n\n34\n");
}
#[test]
fn test_should_preserve_empty_lines() {
new_ucmd!().pipe_in("\n").succeeds().stdout_is("\n");
new_ucmd!()
.arg("-w1")
.pipe_in("0\n1\n\n2\n\n\n")
.succeeds()
.stdout_is("0\n1\n\n2\n\n\n");
}
#[test]
fn test_word_boundary_split_should_preserve_empty_lines() {
new_ucmd!()
.arg("-s")
.pipe_in("\n")
.succeeds()
.stdout_is("\n");
new_ucmd!()
.args(&["-w1", "-s"])
.pipe_in("0\n1\n\n2\n\n\n")
.succeeds()
.stdout_is("0\n1\n\n2\n\n\n");
}
#[test]
fn test_should_not_add_newline_when_line_less_than_fold() {
new_ucmd!().pipe_in("1234").succeeds().stdout_is("1234");
}
#[test]
fn test_should_not_add_newline_when_line_longer_than_fold() {
new_ucmd!()
.arg("-w2")
.pipe_in("1234")
.succeeds()
.stdout_is("12\n34");
}
#[test]
fn test_should_not_add_newline_when_line_equal_to_fold() {
new_ucmd!()
.arg("-w1")
.pipe_in(" ")
.succeeds()
.stdout_is(" ");
}
#[test]
fn test_should_preserve_final_newline_when_line_less_than_fold() {
new_ucmd!().pipe_in("1234\n").succeeds().stdout_is("1234\n");
}
#[test]
fn test_should_preserve_final_newline_when_line_longer_than_fold() {
new_ucmd!()
.arg("-w2")
.pipe_in("1234\n")
.succeeds()
.stdout_is("12\n34\n");
}
#[test]
fn test_should_preserve_final_newline_when_line_equal_to_fold() {
new_ucmd!()
.arg("-w2")
.pipe_in("1\n")
.succeeds()
.stdout_is("1\n");
}
#[test]
fn test_single_tab_should_not_add_extra_newline() {
new_ucmd!()
.arg("-w1")
.pipe_in("\t")
.succeeds()
.stdout_is("\t");
}
#[test]
fn test_initial_tab_counts_as_8_columns() {
new_ucmd!()
.arg("-w8")
.pipe_in("\t1")
.succeeds()
.stdout_is("\t\n1");
}
#[test]
fn test_tab_should_advance_to_next_tab_stop() {
// tab advances the column count to the next tab stop, i.e. the width
// of the tab varies based on the leading text
new_ucmd!()
.args(&["-w8", "tab_stops.input"])
.succeeds()
.stdout_is_fixture("tab_stops_w8.expected");
}
#[test]
fn test_all_tabs_should_advance_to_next_tab_stops() {
new_ucmd!()
.args(&["-w16", "tab_stops.input"])
.succeeds()
.stdout_is_fixture("tab_stops_w16.expected");
}
#[test]
fn test_fold_before_tab_with_narrow_width() {
new_ucmd!()
.arg("-w7")
.pipe_in("a\t1")
.succeeds()
.stdout_is("a\n\t\n1");
}
#[test]
fn test_fold_at_word_boundary() {
new_ucmd!()
.args(&["-w4", "-s"])
.pipe_in("one two")
.succeeds()
.stdout_is("one \ntwo");
}
#[test]
fn test_fold_at_leading_word_boundary() {
new_ucmd!()
.args(&["-w3", "-s"])
.pipe_in(" aaa")
.succeeds()
.stdout_is(" \naaa");
}
#[test]
fn test_fold_at_word_boundary_preserve_final_newline() {
new_ucmd!()
.args(&["-w4", "-s"])
.pipe_in("one two\n")
.succeeds()
.stdout_is("one \ntwo\n");
}
#[test]
fn test_fold_at_tab() {
new_ucmd!()
.arg("-w8")
.pipe_in("a\tbbb\n")
.succeeds()
.stdout_is("a\t\nbbb\n");
}
#[test]
fn test_fold_after_tab() {
new_ucmd!()
.arg("-w10")
.pipe_in("a\tbbb\n")
.succeeds()
.stdout_is("a\tbb\nb\n");
}
#[test]
fn test_fold_at_tab_as_word_boundary() {
new_ucmd!()
.args(&["-w8", "-s"])
.pipe_in("a\tbbb\n")
.succeeds()
.stdout_is("a\t\nbbb\n");
}
#[test]
fn test_fold_after_tab_as_word_boundary() {
new_ucmd!()
.args(&["-w10", "-s"])
.pipe_in("a\tbbb\n")
.succeeds()
.stdout_is("a\t\nbbb\n");
}
#[test]
fn test_fold_at_word_boundary_only_whitespace() {
new_ucmd!()
.args(&["-w2", "-s"])
.pipe_in(" ")
.succeeds()
.stdout_is(" \n ");
}
#[test]
fn test_fold_at_word_boundary_only_whitespace_preserve_final_newline() {
new_ucmd!()
.args(&["-w2", "-s"])
.pipe_in(" \n")
.succeeds()
.stdout_is(" \n \n");
}
#[test]
fn test_backspace_should_be_preserved() {
new_ucmd!().pipe_in("\x08").succeeds().stdout_is("\x08");
}
#[test]
fn test_backspaced_char_should_be_preserved() {
new_ucmd!().pipe_in("x\x08").succeeds().stdout_is("x\x08");
}
#[test]
fn test_backspace_should_decrease_column_count() {
new_ucmd!()
.arg("-w2")
.pipe_in("1\x08345")
.succeeds()
.stdout_is("1\x0834\n5");
}
#[test]
fn test_backspace_should_not_decrease_column_count_past_zero() {
new_ucmd!()
.arg("-w2")
.pipe_in("1\x08\x083456")
.succeeds()
.stdout_is("1\x08\x0834\n56");
}
#[test]
fn test_backspace_is_not_word_boundary() {
new_ucmd!()
.args(&["-w10", "-s"])
.pipe_in("foobar\x086789abcdef")
.succeeds()
.stdout_is("foobar\x086789a\nbcdef");
}
#[test]
fn test_carriage_return_should_be_preserved() {
new_ucmd!().pipe_in("\r").succeeds().stdout_is("\r");
}
#[test]
fn test_carriage_return_overwrriten_char_should_be_preserved() {
new_ucmd!().pipe_in("x\ry").succeeds().stdout_is("x\ry");
}
#[test]
fn test_carriage_return_should_reset_column_count() {
new_ucmd!()
.arg("-w6")
.pipe_in("12345\r123456789abcdef")
.succeeds()
.stdout_is("12345\r123456\n789abc\ndef");
}
#[test]
fn test_carriage_return_is_not_word_boundary() {
new_ucmd!()
.args(&["-w6", "-s"])
.pipe_in("fizz\rbuzz\rfizzbuzz")
.succeeds()
.stdout_is("fizz\rbuzz\rfizzbu\nzz");
}
//
// bytewise tests
#[test]
fn test_bytewise_should_preserve_empty_line_without_final_newline() {
new_ucmd!()
.args(&["-w2", "-b"])
.pipe_in("123\n\n45")
.succeeds()
.stdout_is("12\n3\n\n45");
}
#[test]
fn test_bytewise_should_preserve_empty_line_and_final_newline() {
new_ucmd!()
.args(&["-w2", "-b"])
.pipe_in("12\n\n34\n")
.succeeds()
.stdout_is("12\n\n34\n");
}
#[test]
fn test_bytewise_should_preserve_empty_lines() {
new_ucmd!()
.arg("-b")
.pipe_in("\n")
.succeeds()
.stdout_is("\n");
new_ucmd!()
.args(&["-w1", "-b"])
.pipe_in("0\n1\n\n2\n\n\n")
.succeeds()
.stdout_is("0\n1\n\n2\n\n\n");
}
#[test]
fn test_bytewise_word_boundary_split_should_preserve_empty_lines() {
new_ucmd!()
.args(&["-s", "-b"])
.pipe_in("\n")
.succeeds()
.stdout_is("\n");
new_ucmd!()
.args(&["-w1", "-s", "-b"])
.pipe_in("0\n1\n\n2\n\n\n")
.succeeds()
.stdout_is("0\n1\n\n2\n\n\n");
}
#[test]
fn test_bytewise_should_not_add_newline_when_line_less_than_fold() {
new_ucmd!()
.arg("-b")
.pipe_in("1234")
.succeeds()
.stdout_is("1234");
}
#[test]
fn test_bytewise_should_not_add_newline_when_line_longer_than_fold() {
new_ucmd!()
.args(&["-w2", "-b"])
.pipe_in("1234")
.succeeds()
.stdout_is("12\n34");
}
#[test]
fn test_bytewise_should_not_add_newline_when_line_equal_to_fold() {
new_ucmd!()
.args(&["-w1", "-b"])
.pipe_in(" ")
.succeeds()
.stdout_is(" ");
}
#[test]
fn test_bytewise_should_preserve_final_newline_when_line_less_than_fold() {
new_ucmd!()
.arg("-b")
.pipe_in("1234\n")
.succeeds()
.stdout_is("1234\n");
}
#[test]
fn test_bytewise_should_preserve_final_newline_when_line_longer_than_fold() {
new_ucmd!()
.args(&["-w2", "-b"])
.pipe_in("1234\n")
.succeeds()
.stdout_is("12\n34\n");
}
#[test]
fn test_bytewise_should_preserve_final_newline_when_line_equal_to_fold() {
new_ucmd!()
.args(&["-w2", "-b"])
.pipe_in("1\n")
.succeeds()
.stdout_is("1\n");
}
#[test]
fn test_bytewise_single_tab_should_not_add_extra_newline() {
new_ucmd!()
.args(&["-w1", "-b"])
.pipe_in("\t")
.succeeds()
.stdout_is("\t");
}
#[test]
fn test_tab_counts_as_one_byte() {
new_ucmd!()
.args(&["-w2", "-b"])
.pipe_in("1\t2\n")
.succeeds()
.stdout_is("1\t\n2\n");
}
#[test]
fn test_bytewise_fold_before_tab_with_narrow_width() {
new_ucmd!()
.args(&["-w7", "-b"])
.pipe_in("a\t1")
.succeeds()
.stdout_is("a\t1");
}
#[test]
fn test_bytewise_fold_at_word_boundary_only_whitespace() {
new_ucmd!()
.args(&["-w2", "-s", "-b"])
.pipe_in(" ")
.succeeds()
.stdout_is(" \n ");
}
#[test]
fn test_bytewise_fold_at_word_boundary_only_whitespace_preserve_final_newline() {
new_ucmd!()
.args(&["-w2", "-s", "-b"])
.pipe_in(" \n")
.succeeds()
.stdout_is(" \n \n");
}
#[test]
fn test_bytewise_backspace_should_be_preserved() {
new_ucmd!()
.arg("-b")
.pipe_in("\x08")
.succeeds()
.stdout_is("\x08");
}
#[test]
fn test_bytewise_backspaced_char_should_be_preserved() {
new_ucmd!()
.arg("-b")
.pipe_in("x\x08")
.succeeds()
.stdout_is("x\x08");
}
#[test]
fn test_bytewise_backspace_should_not_decrease_column_count() {
new_ucmd!()
.args(&["-w2", "-b"])
.pipe_in("1\x08345")
.succeeds()
.stdout_is("1\x08\n34\n5");
}
#[test]
fn test_bytewise_backspace_is_not_word_boundary() {
new_ucmd!()
.args(&["-w10", "-s", "-b"])
.pipe_in("foobar\x0889abcdef")
.succeeds()
.stdout_is("foobar\x0889a\nbcdef");
}
#[test]
fn test_bytewise_carriage_return_should_be_preserved() {
new_ucmd!()
.arg("-b")
.pipe_in("\r")
.succeeds()
.stdout_is("\r");
}
#[test]
fn test_bytewise_carriage_return_overwrriten_char_should_be_preserved() {
new_ucmd!()
.arg("-b")
.pipe_in("x\ry")
.succeeds()
.stdout_is("x\ry");
}
#[test]
fn test_bytewise_carriage_return_should_not_reset_column_count() {
new_ucmd!()
.args(&["-w6", "-b"])
.pipe_in("12345\r123456789abcdef")
.succeeds()
.stdout_is("12345\r\n123456\n789abc\ndef");
}
#[test]
fn test_bytewise_carriage_return_is_not_word_boundary() {
new_ucmd!()
.args(&["-w6", "-s", "-b"])
.pipe_in("fizz\rbuzz\rfizzbuzz")
.succeeds()
.stdout_is("fizz\rb\nuzz\rfi\nzzbuzz");
}
#[test]
fn test_obsolete_syntax() {
new_ucmd!()
.arg("-5")
.arg("-s")
.arg("space_separated_words.txt")
.succeeds()
.stdout_is("test1\n \ntest2\n \ntest3\n \ntest4\n \ntest5\n \ntest6\n ");
}

105
tests/by-util/test_head.rs Normal file → Executable file
View file

@ -86,88 +86,74 @@ fn test_verbose() {
.stdout_is_fixture("lorem_ipsum_verbose.expected");
}
#[test]
fn test_zero_terminated() {
new_ucmd!()
.args(&["-z", "zero_terminated.txt"])
.run()
.stdout_is_fixture("zero_terminated.expected");
}
#[test]
#[ignore]
fn test_spams_newline() {
//this test is does not mirror what GNU does
new_ucmd!().pipe_in("a").succeeds().stdout_is("a\n");
}
#[test]
#[ignore]
fn test_unsupported_byte_syntax() {
fn test_byte_syntax() {
new_ucmd!()
.args(&["-1c"])
.pipe_in("abc")
.fails()
//GNU head returns "a"
.stdout_is("")
.stderr_is("head: error: Unrecognized option: \'1\'");
.run()
.stdout_is("a");
}
#[test]
#[ignore]
fn test_unsupported_line_syntax() {
fn test_line_syntax() {
new_ucmd!()
.args(&["-n", "2048m"])
.pipe_in("a\n")
.fails()
//.stdout_is("a\n"); What GNU head returns.
.stdout_is("")
.stderr_is("head: error: invalid line count \'2048m\': invalid digit found in string");
.run()
.stdout_is("a\n");
}
#[test]
#[ignore]
fn test_unsupported_zero_terminated_syntax() {
fn test_zero_terminated_syntax() {
new_ucmd!()
.args(&["-z -n 1"])
.args(&["-z", "-n", "1"])
.pipe_in("x\0y")
.fails()
//GNU Head returns "x\0"
.stderr_is("head: error: Unrecognized option: \'z\'");
.run()
.stdout_is("x\0");
}
#[test]
#[ignore]
fn test_unsupported_zero_terminated_syntax_2() {
fn test_zero_terminated_syntax_2() {
new_ucmd!()
.args(&["-z -n 2"])
.args(&["-z", "-n", "2"])
.pipe_in("x\0y")
.fails()
//GNU Head returns "x\0y"
.stderr_is("head: error: Unrecognized option: \'z\'");
.run()
.stdout_is("x\0y");
}
#[test]
#[ignore]
fn test_unsupported_negative_byte_syntax() {
fn test_negative_byte_syntax() {
new_ucmd!()
.args(&["--bytes=-2"])
.pipe_in("a\n")
.fails()
//GNU Head returns ""
.stderr_is("head: error: invalid byte count \'-2\': invalid digit found in string");
.run()
.stdout_is("");
}
#[test]
#[ignore]
fn test_bug_in_negative_zero_lines() {
fn test_negative_zero_lines() {
new_ucmd!()
.args(&["--lines=-0"])
.pipe_in("a\nb\n")
.succeeds()
//GNU Head returns "a\nb\n"
.stdout_is("");
.stdout_is("a\nb\n");
}
#[test]
fn test_negative_zero_bytes() {
new_ucmd!()
.args(&["--bytes=-0"])
.pipe_in("qwerty")
.succeeds()
.stdout_is("qwerty");
}
#[test]
fn test_no_such_file_or_directory() {
let result = new_ucmd!().arg("no_such_file.toml").run();
@ -179,3 +165,38 @@ fn test_no_such_file_or_directory() {
.contains("cannot open 'no_such_file.toml' for reading: No such file or directory")
)
}
// there was a bug not caught by previous tests
// where for negative n > 3, the total amount of lines
// was correct, but it would eat from the second line
#[test]
fn test_sequence_fixture() {
new_ucmd!()
.args(&["-n", "-10", "sequence"])
.run()
.stdout_is_fixture("sequence.expected");
}
#[test]
fn test_file_backwards() {
new_ucmd!()
.args(&["-c", "-10", "lorem_ipsum.txt"])
.run()
.stdout_is_fixture("lorem_ipsum_backwards_file.expected");
}
#[test]
fn test_zero_terminated() {
new_ucmd!()
.args(&["-z", "zero_terminated.txt"])
.run()
.stdout_is_fixture("zero_terminated.expected");
}
#[test]
fn test_obsolete_extras() {
new_ucmd!()
.args(&["-5zv"])
.pipe_in("1\02\03\04\05\06")
.succeeds()
.stdout_is("==> standard input <==\n1\02\03\04\05\0");
}

View file

@ -1,6 +1,9 @@
use crate::common::util::*;
use filetime::FileTime;
use rust_users::*;
use std::os::unix::fs::PermissionsExt;
#[cfg(target_os = "linux")]
use std::thread::sleep;
#[test]
fn test_install_help() {
@ -84,20 +87,81 @@ fn test_install_unimplemented_arg() {
}
#[test]
fn test_install_component_directories() {
fn test_install_ancestors_directories() {
let (at, mut ucmd) = at_and_ucmd!();
let component1 = "component1";
let component2 = "component2";
let component3 = "component3";
let ancestor1 = "ancestor1";
let ancestor2 = "ancestor1/ancestor2";
let target_dir = "ancestor1/ancestor2/target_dir";
let directories_arg = "-d";
ucmd.args(&[directories_arg, component1, component2, component3])
ucmd.args(&[directories_arg, target_dir])
.succeeds()
.no_stderr();
assert!(at.dir_exists(component1));
assert!(at.dir_exists(component2));
assert!(at.dir_exists(component3));
assert!(at.dir_exists(ancestor1));
assert!(at.dir_exists(ancestor2));
assert!(at.dir_exists(target_dir));
}
#[test]
fn test_install_ancestors_mode_directories() {
let (at, mut ucmd) = at_and_ucmd!();
let ancestor1 = "ancestor1";
let ancestor2 = "ancestor1/ancestor2";
let target_dir = "ancestor1/ancestor2/target_dir";
let directories_arg = "-d";
let mode_arg = "--mode=700";
ucmd.args(&[mode_arg, directories_arg, target_dir])
.succeeds()
.no_stderr();
assert!(at.dir_exists(ancestor1));
assert!(at.dir_exists(ancestor2));
assert!(at.dir_exists(target_dir));
assert_ne!(0o40700 as u32, at.metadata(ancestor1).permissions().mode());
assert_ne!(0o40700 as u32, at.metadata(ancestor2).permissions().mode());
// Expected mode only on the target_dir.
assert_eq!(0o40700 as u32, at.metadata(target_dir).permissions().mode());
}
#[test]
fn test_install_parent_directories() {
let (at, mut ucmd) = at_and_ucmd!();
let ancestor1 = "ancestor1";
let ancestor2 = "ancestor1/ancestor2";
let target_dir = "ancestor1/ancestor2/target_dir";
let directories_arg = "-d";
// Here one of the ancestors already exist and only the target_dir and
// its parent must be created.
at.mkdir(ancestor1);
ucmd.args(&[directories_arg, target_dir])
.succeeds()
.no_stderr();
assert!(at.dir_exists(ancestor2));
assert!(at.dir_exists(target_dir));
}
#[test]
fn test_install_several_directories() {
let (at, mut ucmd) = at_and_ucmd!();
let dir1 = "dir1";
let dir2 = "dir2";
let dir3 = "dir3";
let directories_arg = "-d";
ucmd.args(&[directories_arg, dir1, dir2, dir3])
.succeeds()
.no_stderr();
assert!(at.dir_exists(dir1));
assert!(at.dir_exists(dir2));
assert!(at.dir_exists(dir3));
}
#[test]
@ -351,11 +415,19 @@ fn test_install_copy_file() {
#[test]
#[cfg(target_os = "linux")]
fn test_install_target_file_dev_null() {
let (at, mut ucmd) = at_and_ucmd!();
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
let file1 = "/dev/null";
let file2 = "target_file";
ucmd.arg(file1).arg(file2).succeeds().no_stderr();
let result = scene.ucmd().arg(file1).arg(file2).run();
println!("stderr = {:?}", result.stderr);
println!("stdout = {:?}", result.stdout);
assert!(result.success);
assert!(at.file_exists(file2));
}
@ -407,3 +479,90 @@ fn test_install_failing_no_such_file() {
assert!(r.code == Some(1));
assert!(r.stderr.contains("No such file or directory"));
}
#[test]
fn test_install_copy_then_compare_file() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
let file1 = "test_install_copy_then_compare_file_a1";
let file2 = "test_install_copy_then_compare_file_a2";
at.touch(file1);
scene
.ucmd()
.arg("-C")
.arg(file1)
.arg(file2)
.succeeds()
.no_stderr();
let mut file2_meta = at.metadata(file2);
let before = FileTime::from_last_modification_time(&file2_meta);
scene
.ucmd()
.arg("-C")
.arg(file1)
.arg(file2)
.succeeds()
.no_stderr();
file2_meta = at.metadata(file2);
let after = FileTime::from_last_modification_time(&file2_meta);
assert!(before == after);
}
#[test]
#[cfg(target_os = "linux")]
fn test_install_copy_then_compare_file_with_extra_mode() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
// XXX: can't tests introspect on their own names?
let file1 = "test_install_copy_then_compare_file_with_extra_mode_a1";
let file2 = "test_install_copy_then_compare_file_with_extra_mode_a2";
at.touch(file1);
scene
.ucmd()
.arg("-C")
.arg(file1)
.arg(file2)
.succeeds()
.no_stderr();
let mut file2_meta = at.metadata(file2);
let before = FileTime::from_last_modification_time(&file2_meta);
sleep(std::time::Duration::from_millis(1000));
scene
.ucmd()
.arg("-C")
.arg(file1)
.arg(file2)
.arg("-m")
.arg("1644")
.succeeds()
.no_stderr();
file2_meta = at.metadata(file2);
let after_install_sticky = FileTime::from_last_modification_time(&file2_meta);
assert!(before != after_install_sticky);
sleep(std::time::Duration::from_millis(1000));
// dest file still 1644, so need_copy ought to return `true`
scene
.ucmd()
.arg("-C")
.arg(file1)
.arg(file2)
.succeeds()
.no_stderr();
file2_meta = at.metadata(file2);
let after_install_sticky_again = FileTime::from_last_modification_time(&file2_meta);
assert!(after_install_sticky != after_install_sticky_again);
}

File diff suppressed because it is too large Load diff

View file

@ -1 +1,48 @@
// ToDO: add tests
use crate::common::util::*;
#[test]
fn test_create_fifo_missing_operand() {
new_ucmd!()
.fails()
.stderr_is("mkfifo: error: missing operand");
}
#[test]
fn test_create_one_fifo() {
new_ucmd!().arg("abc").succeeds();
}
#[test]
fn test_create_one_fifo_with_invalid_mode() {
new_ucmd!()
.arg("abcd")
.arg("-m")
.arg("invalid")
.fails()
.stderr
.contains("invalid mode");
}
#[test]
fn test_create_multiple_fifos() {
new_ucmd!()
.arg("abcde")
.arg("def")
.arg("sed")
.arg("dum")
.succeeds();
}
#[test]
fn test_create_one_fifo_with_mode() {
new_ucmd!().arg("abcde").arg("-m600").succeeds();
}
#[test]
fn test_create_one_fifo_already_exists() {
new_ucmd!()
.arg("abcdef")
.arg("abcdef")
.fails()
.stderr_is("mkfifo: error: cannot create fifo 'abcdef': File exists");
}

View file

@ -6,3 +6,14 @@ fn test_more_no_arg() {
let result = ucmd.run();
assert!(!result.success);
}
#[test]
fn test_more_dir_arg() {
let (_, mut ucmd) = at_and_ucmd!();
ucmd.arg(".");
let result = ucmd.run();
assert!(!result.success);
const EXPECTED_ERROR_MESSAGE: &str =
"more: '.' is a directory.\nTry 'more --help' for more information.";
assert_eq!(result.stderr.trim(), EXPECTED_ERROR_MESSAGE);
}

View file

@ -21,6 +21,7 @@ static ALPHA_OUT: &'static str = "
// Test that od can read one file and dump with default format
#[test]
fn test_file() {
// TODO: Can this be replaced by AtPath?
use std::env;
let temp = env::temp_dir();
let tmpdir = Path::new(&temp);
@ -33,15 +34,12 @@ fn test_file() {
}
}
let result = new_ucmd!()
new_ucmd!()
.arg("--endian=little")
.arg(file.as_os_str())
.run();
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(result.stdout, unindent(ALPHA_OUT));
.succeeds()
.no_stderr()
.stdout_is(unindent(ALPHA_OUT));
let _ = remove_file(file);
}
@ -64,16 +62,14 @@ fn test_2files() {
}
}
let result = new_ucmd!()
new_ucmd!()
.arg("--endian=little")
.arg(file1.as_os_str())
.arg(file2.as_os_str())
.run();
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(result.stdout, unindent(ALPHA_OUT));
.succeeds()
.no_stderr()
.stdout_is(unindent(ALPHA_OUT));
// TODO: Handle errors?
let _ = remove_file(file1);
let _ = remove_file(file2);
}
@ -85,22 +81,19 @@ fn test_no_file() {
let tmpdir = Path::new(&temp);
let file = tmpdir.join("}surely'none'would'thus'a'file'name");
let result = new_ucmd!().arg(file.as_os_str()).run();
assert!(!result.success);
new_ucmd!().arg(file.as_os_str()).fails();
}
// Test that od reads from stdin instead of a file
#[test]
fn test_from_stdin() {
let input = "abcdefghijklmnopqrstuvwxyz\n";
let result = new_ucmd!()
new_ucmd!()
.arg("--endian=little")
.run_piped_stdin(input.as_bytes());
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(result.stdout, unindent(ALPHA_OUT));
.run_piped_stdin(input.as_bytes())
.success()
.no_stderr()
.stdout_is(unindent(ALPHA_OUT));
}
// Test that od reads from stdin and also from files
@ -119,40 +112,35 @@ fn test_from_mixed() {
}
}
let result = new_ucmd!()
new_ucmd!()
.arg("--endian=little")
.arg(file1.as_os_str())
.arg("-")
.arg(file3.as_os_str())
.run_piped_stdin(data2.as_bytes());
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(result.stdout, unindent(ALPHA_OUT));
.run_piped_stdin(data2.as_bytes())
.success()
.no_stderr()
.stdout_is(unindent(ALPHA_OUT));
}
#[test]
fn test_multiple_formats() {
let input = "abcdefghijklmnopqrstuvwxyz\n";
let result = new_ucmd!()
new_ucmd!()
.arg("-c")
.arg("-b")
.run_piped_stdin(input.as_bytes());
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(
result.stdout,
unindent(
.run_piped_stdin(input.as_bytes())
.success()
.no_stderr()
.stdout_is(unindent(
"
0000000 a b c d e f g h i j k l m n o p
141 142 143 144 145 146 147 150 151 152 153 154 155 156 157 160
0000020 q r s t u v w x y z \\n
161 162 163 164 165 166 167 170 171 172 012
0000033
"
)
);
",
));
}
#[test]
@ -166,14 +154,13 @@ fn test_dec() {
0000016
",
);
let result = new_ucmd!()
new_ucmd!()
.arg("--endian=little")
.arg("-s")
.run_piped_stdin(&input[..]);
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(result.stdout, expected_output);
.run_piped_stdin(&input[..])
.success()
.no_stderr()
.stdout_is(expected_output);
}
#[test]
@ -185,14 +172,13 @@ fn test_hex16() {
0000011
",
);
let result = new_ucmd!()
new_ucmd!()
.arg("--endian=little")
.arg("-x")
.run_piped_stdin(&input[..]);
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(result.stdout, expected_output);
.run_piped_stdin(&input[..])
.success()
.no_stderr()
.stdout_is(expected_output);
}
#[test]
@ -204,14 +190,13 @@ fn test_hex32() {
0000011
",
);
let result = new_ucmd!()
new_ucmd!()
.arg("--endian=little")
.arg("-X")
.run_piped_stdin(&input[..]);
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(result.stdout, expected_output);
.run_piped_stdin(&input[..])
.success()
.no_stderr()
.stdout_is(expected_output);
}
#[test]
@ -232,15 +217,14 @@ fn test_f16() {
0000016
",
);
let result = new_ucmd!()
new_ucmd!()
.arg("--endian=little")
.arg("-tf2")
.arg("-w8")
.run_piped_stdin(&input[..]);
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(result.stdout, expected_output);
.run_piped_stdin(&input[..])
.success()
.no_stderr()
.stdout_is(expected_output);
}
#[test]
@ -261,14 +245,13 @@ fn test_f32() {
0000034
",
);
let result = new_ucmd!()
new_ucmd!()
.arg("--endian=little")
.arg("-f")
.run_piped_stdin(&input[..]);
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(result.stdout, expected_output);
.run_piped_stdin(&input[..])
.success()
.no_stderr()
.stdout_is(expected_output);
}
#[test]
@ -291,36 +274,31 @@ fn test_f64() {
0000050
",
);
let result = new_ucmd!()
new_ucmd!()
.arg("--endian=little")
.arg("-F")
.run_piped_stdin(&input[..]);
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(result.stdout, expected_output);
.run_piped_stdin(&input[..])
.success()
.no_stderr()
.stdout_is(expected_output);
}
#[test]
fn test_multibyte() {
let result = new_ucmd!()
new_ucmd!()
.arg("-c")
.arg("-w12")
.run_piped_stdin("Universität Tübingen \u{1B000}".as_bytes());
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(
result.stdout,
unindent(
.run_piped_stdin("Universität Tübingen \u{1B000}".as_bytes())
.success()
.no_stderr()
.stdout_is(unindent(
"
0000000 U n i v e r s i t ä ** t
0000014 T ü ** b i n g e n \u{1B000}
0000030 ** ** **
0000033
"
)
);
",
));
}
#[test]
@ -334,11 +312,13 @@ fn test_width() {
",
);
let result = new_ucmd!().arg("-w4").arg("-v").run_piped_stdin(&input[..]);
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(result.stdout, expected_output);
new_ucmd!()
.arg("-w4")
.arg("-v")
.run_piped_stdin(&input[..])
.success()
.no_stderr()
.stdout_is(expected_output);
}
#[test]
@ -352,14 +332,13 @@ fn test_invalid_width() {
",
);
let result = new_ucmd!().arg("-w5").arg("-v").run_piped_stdin(&input[..]);
assert_eq!(
result.stderr,
"od: warning: invalid width 5; using 2 instead\n"
);
assert!(result.success);
assert_eq!(result.stdout, expected_output);
new_ucmd!()
.arg("-w5")
.arg("-v")
.run_piped_stdin(&input[..])
.success()
.stderr_is_bytes("od: warning: invalid width 5; using 2 instead\n".as_bytes())
.stdout_is(expected_output);
}
#[test]
@ -373,14 +352,13 @@ fn test_zero_width() {
",
);
let result = new_ucmd!().arg("-w0").arg("-v").run_piped_stdin(&input[..]);
assert_eq!(
result.stderr,
"od: warning: invalid width 0; using 2 instead\n"
);
assert!(result.success);
assert_eq!(result.stdout, expected_output);
new_ucmd!()
.arg("-w0")
.arg("-v")
.run_piped_stdin(&input[..])
.success()
.stderr_is_bytes("od: warning: invalid width 0; using 2 instead\n".as_bytes())
.stdout_is(expected_output);
}
#[test]
@ -392,11 +370,12 @@ fn test_width_without_value() {
0000050
");
let result = new_ucmd!().arg("-w").run_piped_stdin(&input[..]);
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(result.stdout, expected_output);
new_ucmd!()
.arg("-w")
.run_piped_stdin(&input[..])
.success()
.no_stderr()
.stdout_is(expected_output);
}
#[test]
@ -421,15 +400,14 @@ fn test_suppress_duplicates() {
",
);
let result = new_ucmd!()
new_ucmd!()
.arg("-w4")
.arg("-O")
.arg("-x")
.run_piped_stdin(&input[..]);
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(result.stdout, expected_output);
.run_piped_stdin(&input[..])
.no_stderr()
.success()
.stdout_is(expected_output);
}
#[test]
@ -446,17 +424,16 @@ fn test_big_endian() {
",
);
let result = new_ucmd!()
new_ucmd!()
.arg("--endian=big")
.arg("-F")
.arg("-f")
.arg("-X")
.arg("-x")
.run_piped_stdin(&input[..]);
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(result.stdout, expected_output);
.run_piped_stdin(&input[..])
.no_stderr()
.success()
.stdout_is(expected_output);
}
#[test]
@ -474,16 +451,15 @@ fn test_alignment_Xxa() {
);
// in this case the width of the -a (8-bit) determines the alignment for the other fields
let result = new_ucmd!()
new_ucmd!()
.arg("--endian=little")
.arg("-X")
.arg("-x")
.arg("-a")
.run_piped_stdin(&input[..]);
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(result.stdout, expected_output);
.run_piped_stdin(&input[..])
.no_stderr()
.success()
.stdout_is(expected_output);
}
#[test]
@ -500,15 +476,14 @@ fn test_alignment_Fx() {
);
// in this case the width of the -F (64-bit) determines the alignment for the other field
let result = new_ucmd!()
new_ucmd!()
.arg("--endian=little")
.arg("-F")
.arg("-x")
.run_piped_stdin(&input[..]);
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(result.stdout, expected_output);
.run_piped_stdin(&input[..])
.no_stderr()
.success()
.stdout_is(expected_output);
}
#[test]
@ -528,16 +503,15 @@ fn test_maxuint() {
",
);
let result = new_ucmd!()
new_ucmd!()
.arg("--format=o8")
.arg("-Oobtu8")
.arg("-Dd")
.arg("--format=u1")
.run_piped_stdin(&input[..]);
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(result.stdout, expected_output);
.run_piped_stdin(&input[..])
.no_stderr()
.success()
.stdout_is(expected_output);
}
#[test]
@ -553,15 +527,14 @@ fn test_hex_offset() {
",
);
let result = new_ucmd!()
new_ucmd!()
.arg("-Ax")
.arg("-X")
.arg("-X")
.run_piped_stdin(&input[..]);
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(result.stdout, expected_output);
.run_piped_stdin(&input[..])
.no_stderr()
.success()
.stdout_is(expected_output);
}
#[test]
@ -577,15 +550,14 @@ fn test_dec_offset() {
",
);
let result = new_ucmd!()
new_ucmd!()
.arg("-Ad")
.arg("-X")
.arg("-X")
.run_piped_stdin(&input[..]);
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(result.stdout, expected_output);
.run_piped_stdin(&input[..])
.no_stderr()
.success()
.stdout_is(expected_output);
}
#[test]
@ -594,66 +566,57 @@ fn test_no_offset() {
const LINE: &'static str = " 00000000 00000000 00000000 00000000\n";
let expected_output = [LINE, LINE, LINE, LINE].join("");
let result = new_ucmd!()
new_ucmd!()
.arg("-An")
.arg("-X")
.arg("-X")
.run_piped_stdin(&input[..]);
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(result.stdout, expected_output);
.run_piped_stdin(&input[..])
.no_stderr()
.success()
.stdout_is(expected_output);
}
#[test]
fn test_invalid_offset() {
let result = new_ucmd!().arg("-Ab").run();
assert!(!result.success);
new_ucmd!().arg("-Ab").fails();
}
#[test]
fn test_skip_bytes() {
let input = "abcdefghijklmnopq";
let result = new_ucmd!()
new_ucmd!()
.arg("-c")
.arg("--skip-bytes=5")
.run_piped_stdin(input.as_bytes());
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(
result.stdout,
unindent(
.run_piped_stdin(input.as_bytes())
.no_stderr()
.success()
.stdout_is(unindent(
"
0000005 f g h i j k l m n o p q
0000021
"
)
);
",
));
}
#[test]
fn test_skip_bytes_error() {
let input = "12345";
let result = new_ucmd!()
new_ucmd!()
.arg("--skip-bytes=10")
.run_piped_stdin(input.as_bytes());
assert!(!result.success);
.run_piped_stdin(input.as_bytes())
.failure();
}
#[test]
fn test_read_bytes() {
let input = "abcdefghijklmnopqrstuvwxyz\n12345678";
let result = new_ucmd!()
new_ucmd!()
.arg("--endian=little")
.arg("--read-bytes=27")
.run_piped_stdin(input.as_bytes());
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(result.stdout, unindent(ALPHA_OUT));
.run_piped_stdin(input.as_bytes())
.no_stderr()
.success()
.stdout_is(unindent(ALPHA_OUT));
}
#[test]
@ -662,13 +625,12 @@ fn test_ascii_dump() {
0x00, 0x01, 0x0a, 0x0d, 0x10, 0x1f, 0x20, 0x61, 0x62, 0x63, 0x7d, 0x7e, 0x7f, 0x80, 0x90,
0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff,
];
let result = new_ucmd!().arg("-tx1zacz").run_piped_stdin(&input[..]);
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(
result.stdout,
unindent(
new_ucmd!()
.arg("-tx1zacz")
.run_piped_stdin(&input[..])
.no_stderr()
.success()
.stdout_is(unindent(
r"
0000000 00 01 0a 0d 10 1f 20 61 62 63 7d 7e 7f 80 90 a0 >...... abc}~....<
nul soh nl cr dle us sp a b c } ~ del nul dle sp
@ -677,9 +639,8 @@ fn test_ascii_dump() {
0 @ P ` p del
** 300 320 340 360 377 >......<
0000026
"
)
);
",
));
}
#[test]
@ -687,159 +648,136 @@ fn test_filename_parsing() {
// files "a" and "x" both exists, but are no filenames in the commandline below
// "-f" must be treated as a filename, it contains the text: minus lowercase f
// so "-f" should not be interpreted as a formatting option.
let result = new_ucmd!()
new_ucmd!()
.arg("--format")
.arg("a")
.arg("-A")
.arg("x")
.arg("--")
.arg("-f")
.run();
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(
result.stdout,
unindent(
.succeeds()
.no_stderr()
.stdout_is(unindent(
"
000000 m i n u s sp l o w e r c a s e sp
000010 f nl
000012
"
)
);
",
));
}
#[test]
fn test_stdin_offset() {
let input = "abcdefghijklmnopq";
let result = new_ucmd!()
new_ucmd!()
.arg("-c")
.arg("+5")
.run_piped_stdin(input.as_bytes());
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(
result.stdout,
unindent(
.run_piped_stdin(input.as_bytes())
.no_stderr()
.success()
.stdout_is(unindent(
"
0000005 f g h i j k l m n o p q
0000021
"
)
);
",
));
}
#[test]
fn test_file_offset() {
let result = new_ucmd!().arg("-c").arg("--").arg("-f").arg("10").run();
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(
result.stdout,
unindent(
new_ucmd!()
.arg("-c")
.arg("--")
.arg("-f")
.arg("10")
.succeeds()
.no_stderr()
.stdout_is(unindent(
r"
0000010 w e r c a s e f \n
0000022
"
)
);
",
));
}
#[test]
fn test_traditional() {
// note gnu od does not align both lines
let input = "abcdefghijklmnopq";
let result = new_ucmd!()
new_ucmd!()
.arg("--traditional")
.arg("-a")
.arg("-c")
.arg("-")
.arg("10")
.arg("0")
.run_piped_stdin(input.as_bytes());
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(
result.stdout,
unindent(
.run_piped_stdin(input.as_bytes())
.no_stderr()
.success()
.stdout_is(unindent(
r"
0000010 (0000000) i j k l m n o p q
i j k l m n o p q
0000021 (0000011)
"
)
);
",
));
}
#[test]
fn test_traditional_with_skip_bytes_override() {
// --skip-bytes is ignored in this case
let input = "abcdefghijklmnop";
let result = new_ucmd!()
new_ucmd!()
.arg("--traditional")
.arg("--skip-bytes=10")
.arg("-c")
.arg("0")
.run_piped_stdin(input.as_bytes());
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(
result.stdout,
unindent(
.run_piped_stdin(input.as_bytes())
.no_stderr()
.success()
.stdout_is(unindent(
r"
0000000 a b c d e f g h i j k l m n o p
0000020
"
)
);
",
));
}
#[test]
fn test_traditional_with_skip_bytes_non_override() {
// no offset specified in the traditional way, so --skip-bytes is used
let input = "abcdefghijklmnop";
let result = new_ucmd!()
new_ucmd!()
.arg("--traditional")
.arg("--skip-bytes=10")
.arg("-c")
.run_piped_stdin(input.as_bytes());
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(
result.stdout,
unindent(
.run_piped_stdin(input.as_bytes())
.no_stderr()
.success()
.stdout_is(unindent(
r"
0000012 k l m n o p
0000020
"
)
);
",
));
}
#[test]
fn test_traditional_error() {
// file "0" exists - don't fail on that, but --traditional only accepts a single input
let result = new_ucmd!()
new_ucmd!()
.arg("--traditional")
.arg("0")
.arg("0")
.arg("0")
.arg("0")
.run();
assert!(!result.success);
.fails();
}
#[test]
fn test_traditional_only_label() {
let input = "abcdefghijklmnopqrstuvwxyz";
let result = new_ucmd!()
new_ucmd!()
.arg("-An")
.arg("--traditional")
.arg("-a")
@ -847,20 +785,16 @@ fn test_traditional_only_label() {
.arg("-")
.arg("10")
.arg("0x10")
.run_piped_stdin(input.as_bytes());
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(
result.stdout,
unindent(
.run_piped_stdin(input.as_bytes())
.no_stderr()
.success()
.stdout_is(unindent(
r"
(0000020) i j k l m n o p q r s t u v w x
i j k l m n o p q r s t u v w x
(0000040) y z
y z
(0000042)
"
)
);
",
));
}

View file

@ -5,11 +5,152 @@ fn test_default_mode() {
// test the default mode
// accept some reasonable default
new_ucmd!().args(&["abc/def"]).succeeds().no_stdout();
new_ucmd!().args(&["dir/file"]).succeeds().no_stdout();
// fail on long inputs
// accept non-portable chars
new_ucmd!().args(&["dir#/$file"]).succeeds().no_stdout();
// accept empty path
new_ucmd!().args(&[""]).succeeds().no_stdout();
// fail on long path
new_ucmd!()
.args(&["test".repeat(20000)])
.args(&["dir".repeat(libc::PATH_MAX as usize + 1)])
.fails()
.no_stdout();
// fail on long filename
new_ucmd!()
.args(&[format!(
"dir/{}",
"file".repeat(libc::FILENAME_MAX as usize + 1)
)])
.fails()
.no_stdout();
}
#[test]
fn test_posix_mode() {
// test the posix mode
// accept some reasonable default
new_ucmd!().args(&["-p", "dir/file"]).succeeds().no_stdout();
// fail on long path
new_ucmd!()
.args(&["-p", &"dir".repeat(libc::PATH_MAX as usize + 1).as_str()])
.fails()
.no_stdout();
// fail on long filename
new_ucmd!()
.args(&[
"-p",
&format!("dir/{}", "file".repeat(libc::FILENAME_MAX as usize + 1)).as_str(),
])
.fails()
.no_stdout();
// fail on non-portable chars
new_ucmd!().args(&["-p", "dir#/$file"]).fails().no_stdout();
}
#[test]
fn test_posix_special() {
// test the posix special mode
// accept some reasonable default
new_ucmd!().args(&["-P", "dir/file"]).succeeds().no_stdout();
// accept non-portable chars
new_ucmd!()
.args(&["-P", "dir#/$file"])
.succeeds()
.no_stdout();
// accept non-leading hyphen
new_ucmd!()
.args(&["-P", "dir/file-name"])
.succeeds()
.no_stdout();
// fail on long path
new_ucmd!()
.args(&["-P", &"dir".repeat(libc::PATH_MAX as usize + 1).as_str()])
.fails()
.no_stdout();
// fail on long filename
new_ucmd!()
.args(&[
"-P",
&format!("dir/{}", "file".repeat(libc::FILENAME_MAX as usize + 1)).as_str(),
])
.fails()
.no_stdout();
// fail on leading hyphen char
new_ucmd!().args(&["-P", "dir/-file"]).fails().no_stdout();
// fail on empty path
new_ucmd!().args(&["-P", ""]).fails().no_stdout();
}
#[test]
fn test_posix_all() {
// test the posix special mode
// accept some reasonable default
new_ucmd!()
.args(&["-p", "-P", "dir/file"])
.succeeds()
.no_stdout();
// accept non-leading hyphen
new_ucmd!()
.args(&["-p", "-P", "dir/file-name"])
.succeeds()
.no_stdout();
// fail on long path
new_ucmd!()
.args(&[
"-p",
"-P",
&"dir".repeat(libc::PATH_MAX as usize + 1).as_str(),
])
.fails()
.no_stdout();
// fail on long filename
new_ucmd!()
.args(&[
"-p",
"-P",
&format!("dir/{}", "file".repeat(libc::FILENAME_MAX as usize + 1)).as_str(),
])
.fails()
.no_stdout();
// fail on non-portable chars
new_ucmd!()
.args(&["-p", "-P", "dir#/$file"])
.fails()
.no_stdout();
// fail on leading hyphen char
new_ucmd!()
.args(&["-p", "-P", "dir/-file"])
.fails()
.no_stdout();
// fail on empty path
new_ucmd!().args(&["-p", "-P", ""]).fails().no_stdout();
}
#[test]
fn test_args_parsing() {
// fail on no args
let empty_args: [String; 0] = [];
new_ucmd!().args(&empty_args).fails().no_stdout();
}

View file

@ -1,106 +1,108 @@
use crate::common::util::*;
#[test]
fn test_current_directory() {
fn test_realpath_current_directory() {
let (at, mut ucmd) = at_and_ucmd!();
let actual = ucmd.arg(".").run().stdout;
let expect = at.root_dir_resolved() + "\n";
println!("actual: {:?}", actual);
println!("expect: {:?}", expect);
assert_eq!(actual, expect);
ucmd.arg(".").succeeds().stdout_is(expect);
}
#[test]
fn test_long_redirection_to_current_dir() {
fn test_realpath_long_redirection_to_current_dir() {
let (at, mut ucmd) = at_and_ucmd!();
// Create a 256-character path to current directory
let dir = path_concat!(".", ..128);
let actual = ucmd.arg(dir).run().stdout;
let expect = at.root_dir_resolved() + "\n";
println!("actual: {:?}", actual);
println!("expect: {:?}", expect);
assert_eq!(actual, expect);
ucmd.arg(dir).succeeds().stdout_is(expect);
}
#[test]
fn test_long_redirection_to_root() {
fn test_realpath_long_redirection_to_root() {
// Create a 255-character path to root
let dir = path_concat!("..", ..85);
let actual = new_ucmd!().arg(dir).run().stdout;
let expect = get_root_path().to_owned() + "\n";
println!("actual: {:?}", actual);
println!("expect: {:?}", expect);
assert_eq!(actual, expect);
new_ucmd!().arg(dir).succeeds().stdout_is(expect);
}
#[test]
fn test_file_and_links() {
fn test_realpath_file_and_links() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
at.touch("foo");
at.symlink_file("foo", "bar");
let actual = scene.ucmd().arg("foo").run().stdout;
println!("actual: {:?}", actual);
assert!(actual.contains("foo\n"));
let actual = scene.ucmd().arg("bar").run().stdout;
println!("actual: {:?}", actual);
assert!(actual.contains("foo\n"));
scene.ucmd().arg("foo").succeeds().stdout_contains("foo\n");
scene.ucmd().arg("bar").succeeds().stdout_contains("foo\n");
}
#[test]
fn test_file_and_links_zero() {
fn test_realpath_file_and_links_zero() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
at.touch("foo");
at.symlink_file("foo", "bar");
let actual = scene.ucmd().arg("foo").arg("-z").run().stdout;
println!("actual: {:?}", actual);
assert!(actual.contains("foo"));
assert!(!actual.contains("\n"));
scene
.ucmd()
.arg("foo")
.arg("-z")
.succeeds()
.stdout_contains("foo\u{0}");
let actual = scene.ucmd().arg("bar").arg("-z").run().stdout;
println!("actual: {:?}", actual);
assert!(actual.contains("foo"));
assert!(!actual.contains("\n"));
scene
.ucmd()
.arg("bar")
.arg("-z")
.succeeds()
.stdout_contains("foo\u{0}");
}
#[test]
fn test_file_and_links_strip() {
fn test_realpath_file_and_links_strip() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
at.touch("foo");
at.symlink_file("foo", "bar");
let actual = scene.ucmd().arg("foo").arg("-s").run().stdout;
println!("actual: {:?}", actual);
assert!(actual.contains("foo\n"));
scene
.ucmd()
.arg("foo")
.arg("-s")
.succeeds()
.stdout_contains("foo\n");
let actual = scene.ucmd().arg("bar").arg("-s").run().stdout;
println!("actual: {:?}", actual);
assert!(actual.contains("bar\n"));
scene
.ucmd()
.arg("bar")
.arg("-s")
.succeeds()
.stdout_contains("bar\n");
}
#[test]
fn test_file_and_links_strip_zero() {
fn test_realpath_file_and_links_strip_zero() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
at.touch("foo");
at.symlink_file("foo", "bar");
let actual = scene.ucmd().arg("foo").arg("-s").arg("-z").run().stdout;
println!("actual: {:?}", actual);
assert!(actual.contains("foo"));
assert!(!actual.contains("\n"));
scene
.ucmd()
.arg("foo")
.arg("-s")
.arg("-z")
.succeeds()
.stdout_contains("foo\u{0}");
let actual = scene.ucmd().arg("bar").arg("-s").arg("-z").run().stdout;
println!("actual: {:?}", actual);
assert!(actual.contains("bar"));
assert!(!actual.contains("\n"));
scene
.ucmd()
.arg("bar")
.arg("-s")
.arg("-z")
.succeeds()
.stdout_contains("bar\u{0}");
}

View file

@ -1 +1,177 @@
// ToDO: add tests
use crate::common::util::*;
use std::borrow::Cow;
use std::path::Path;
struct TestCase<'a> {
from: &'a str,
to: &'a str,
expected: &'a str,
}
const TESTS: [TestCase; 10] = [
TestCase {
from: "A/B/C",
to: "A",
expected: "../..",
},
TestCase {
from: "A/B/C",
to: "A/B",
expected: "..",
},
TestCase {
from: "A/B/C",
to: "A/B/C",
expected: "",
},
TestCase {
from: "A/B/C",
to: "A/B/C/D",
expected: "D",
},
TestCase {
from: "A/B/C",
to: "A/B/C/D/E",
expected: "D/E",
},
TestCase {
from: "A/B/C",
to: "A/B/D",
expected: "../D",
},
TestCase {
from: "A/B/C",
to: "A/B/D/E",
expected: "../D/E",
},
TestCase {
from: "A/B/C",
to: "A/D",
expected: "../../D",
},
TestCase {
from: "A/B/C",
to: "D/E/F",
expected: "../../../D/E/F",
},
TestCase {
from: "A/B/C",
to: "A/D/E",
expected: "../../D/E",
},
];
fn convert_path<'a>(path: &'a str) -> Cow<'a, str> {
#[cfg(windows)]
return path.replace("/", "\\").into();
#[cfg(not(windows))]
return path.into();
}
#[test]
fn test_relpath_with_from_no_d() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
for test in TESTS.iter() {
let from: &str = &convert_path(test.from);
let to: &str = &convert_path(test.to);
let expected: &str = &convert_path(test.expected);
at.mkdir_all(to);
at.mkdir_all(from);
scene
.ucmd()
.arg(to)
.arg(from)
.succeeds()
.stdout_only(&format!("{}\n", expected));
}
}
#[test]
fn test_relpath_with_from_with_d() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
for test in TESTS.iter() {
let from: &str = &convert_path(test.from);
let to: &str = &convert_path(test.to);
let pwd = at.as_string();
at.mkdir_all(to);
at.mkdir_all(from);
// d is part of subpath -> expect relative path
let mut result_stdout = scene
.ucmd()
.arg(to)
.arg(from)
.arg(&format!("-d{}", pwd))
.succeeds()
.stdout_move_str();
// relax rules for windows test environment
#[cfg(not(windows))]
assert!(Path::new(&result_stdout).is_relative());
// d is not part of subpath -> expect absolut path
result_stdout = scene
.ucmd()
.arg(to)
.arg(from)
.arg("-dnon_existing")
.succeeds()
.stdout_move_str();
assert!(Path::new(&result_stdout).is_absolute());
}
}
#[test]
fn test_relpath_no_from_no_d() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
for test in TESTS.iter() {
let to: &str = &convert_path(test.to);
at.mkdir_all(to);
let result_stdout = scene.ucmd().arg(to).succeeds().stdout_move_str();
#[cfg(not(windows))]
assert_eq!(result_stdout, format!("{}\n", to));
// relax rules for windows test environment
#[cfg(windows)]
assert!(result_stdout.ends_with(&format!("{}\n", to)));
}
}
#[test]
fn test_relpath_no_from_with_d() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
for test in TESTS.iter() {
let to: &str = &convert_path(test.to);
let pwd = at.as_string();
at.mkdir_all(to);
// d is part of subpath -> expect relative path
let mut result_stdout = scene
.ucmd()
.arg(to)
.arg(&format!("-d{}", pwd))
.succeeds()
.stdout_move_str();
// relax rules for windows test environment
#[cfg(not(windows))]
assert!(Path::new(&result_stdout).is_relative());
// d is not part of subpath -> expect absolut path
result_stdout = scene
.ucmd()
.arg(to)
.arg("-dnon_existing")
.succeeds()
.stdout_move_str();
assert!(Path::new(&result_stdout).is_absolute());
}
}

View file

@ -15,9 +15,12 @@ fn test_rm_one_file() {
#[test]
fn test_rm_failed() {
let (_at, mut ucmd) = at_and_ucmd!();
let file = "test_rm_one_file";
let file = "test_rm_one_file"; // Doesn't exist
ucmd.arg(file).fails(); // Doesn't exist
ucmd.arg(file).fails().stderr_contains(&format!(
"cannot remove '{}': No such file or directory",
file
));
}
#[test]
@ -115,6 +118,39 @@ fn test_rm_empty_directory() {
assert!(!at.dir_exists(dir));
}
#[test]
fn test_rm_empty_directory_verbose() {
let (at, mut ucmd) = at_and_ucmd!();
let dir = "test_rm_empty_directory_verbose";
at.mkdir(dir);
ucmd.arg("-d")
.arg("-v")
.arg(dir)
.succeeds()
.stdout_only(format!("removed directory '{}'\n", dir));
assert!(!at.dir_exists(dir));
}
#[test]
fn test_rm_non_empty_directory() {
let (at, mut ucmd) = at_and_ucmd!();
let dir = "test_rm_non_empty_dir";
let file_a = &format!("{}/test_rm_non_empty_file_a", dir);
at.mkdir(dir);
at.touch(file_a);
ucmd.arg("-d")
.arg(dir)
.fails()
.stderr_contains(&format!("cannot remove '{}': Directory not empty", dir));
assert!(at.file_exists(file_a));
assert!(at.dir_exists(dir));
}
#[test]
fn test_rm_recursive() {
let (at, mut ucmd) = at_and_ucmd!();
@ -134,22 +170,15 @@ fn test_rm_recursive() {
}
#[test]
fn test_rm_errors() {
fn test_rm_directory_without_flag() {
let (at, mut ucmd) = at_and_ucmd!();
let dir = "test_rm_errors_directory";
let file_a = "test_rm_errors_directory/test_rm_errors_file_a";
let file_b = "test_rm_errors_directory/test_rm_errors_file_b";
let dir = "test_rm_directory_without_flag_dir";
at.mkdir(dir);
at.touch(file_a);
at.touch(file_b);
// $ rm test_rm_errors_directory
// rm: error: could not remove directory 'test_rm_errors_directory' (did you mean to pass '-r'?)
ucmd.arg(dir).fails().stderr_is(
"rm: error: could not remove directory 'test_rm_errors_directory' (did you mean \
to pass '-r' or '-R'?)\n",
);
ucmd.arg(dir)
.fails()
.stderr_contains(&format!("cannot remove '{}': Is a directory", dir));
}
#[test]
@ -169,10 +198,13 @@ fn test_rm_verbose() {
}
#[test]
fn test_rm_dir_symlink() {
#[cfg(not(windows))]
// on unix symlink_dir is a file
fn test_rm_symlink_dir() {
let (at, mut ucmd) = at_and_ucmd!();
let dir = "test_rm_dir_symlink_dir";
let link = "test_rm_dir_symlink_link";
let dir = "test_rm_symlink_dir_directory";
let link = "test_rm_symlink_dir_link";
at.mkdir(dir);
at.symlink_dir(dir, link);
@ -180,6 +212,30 @@ fn test_rm_dir_symlink() {
ucmd.arg(link).succeeds();
}
#[test]
#[cfg(windows)]
// on windows removing symlink_dir requires "-r" or "-d"
fn test_rm_symlink_dir() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
let dir = "test_rm_symlink_dir_directory";
let link = "test_rm_symlink_dir_link";
at.mkdir(dir);
at.symlink_dir(dir, link);
scene
.ucmd()
.arg(link)
.fails()
.stderr_contains(&format!("cannot remove '{}': Is a directory", link));
assert!(at.dir_exists(link));
scene.ucmd().arg("-r").arg(link).succeeds();
}
#[test]
fn test_rm_invalid_symlink() {
let (at, mut ucmd) = at_and_ucmd!();
@ -204,3 +260,32 @@ fn test_rm_no_operand() {
ucmd.fails()
.stderr_is("rm: error: missing an argument\nrm: error: for help, try 'rm --help'\n");
}
#[test]
fn test_rm_verbose_slash() {
let (at, mut ucmd) = at_and_ucmd!();
let dir = "test_rm_verbose_slash_directory";
let file_a = &format!("{}/test_rm_verbose_slash_file_a", dir);
at.mkdir(dir);
at.touch(file_a);
let file_a_normalized = &format!(
"{}{}test_rm_verbose_slash_file_a",
dir,
std::path::MAIN_SEPARATOR
);
ucmd.arg("-r")
.arg("-f")
.arg("-v")
.arg(&format!("{}///", dir))
.succeeds()
.stdout_only(format!(
"removed '{}'\nremoved directory '{}'\n",
file_a_normalized, dir
));
assert!(!at.dir_exists(dir));
assert!(!at.file_exists(file_a));
}

View file

@ -1 +1,215 @@
// ToDO: add tests
use crate::common::util::*;
#[test]
fn test_output_is_random_permutation() {
let input_seq = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let input = input_seq
.iter()
.map(|x| x.to_string())
.collect::<Vec<String>>()
.join("\n");
let result = new_ucmd!()
.pipe_in(input.as_bytes())
.succeeds()
.no_stderr()
.stdout
.clone();
let mut result_seq: Vec<i32> = result
.split("\n")
.filter(|x| !x.is_empty())
.map(|x| x.parse().unwrap())
.collect();
result_seq.sort();
assert_ne!(result, input, "Output is not randomised");
assert_eq!(result_seq, input_seq, "Output is not a permutation");
}
#[test]
fn test_zero_termination() {
let input_seq = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let result = new_ucmd!()
.arg("-z")
.arg("-i1-10")
.succeeds()
.no_stderr()
.stdout
.clone();
let mut result_seq: Vec<i32> = result
.split("\0")
.filter(|x| !x.is_empty())
.map(|x| x.parse().unwrap())
.collect();
result_seq.sort();
assert_eq!(result_seq, input_seq, "Output is not a permutation");
}
#[test]
fn test_echo() {
let input_seq = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let result = new_ucmd!()
.arg("-e")
.args(
&input_seq
.iter()
.map(|x| x.to_string())
.collect::<Vec<String>>(),
)
.succeeds()
.no_stderr()
.stdout
.clone();
let mut result_seq: Vec<i32> = result
.split("\n")
.filter(|x| !x.is_empty())
.map(|x| x.parse().unwrap())
.collect();
result_seq.sort();
assert_eq!(result_seq, input_seq, "Output is not a permutation");
}
#[test]
fn test_head_count() {
let repeat_limit = 5;
let input_seq = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let input = input_seq
.iter()
.map(|x| x.to_string())
.collect::<Vec<String>>()
.join("\n");
let result = new_ucmd!()
.args(&["-n", &repeat_limit.to_string()])
.pipe_in(input.as_bytes())
.succeeds()
.no_stderr()
.stdout
.clone();
let mut result_seq: Vec<i32> = result
.split("\n")
.filter(|x| !x.is_empty())
.map(|x| x.parse().unwrap())
.collect();
result_seq.sort();
assert_eq!(result_seq.len(), repeat_limit, "Output is not limited");
assert!(
result_seq.iter().all(|x| input_seq.contains(x)),
"Output includes element not from input: {}",
result
)
}
#[test]
fn test_repeat() {
let repeat_limit = 15000;
let input_seq = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let input = input_seq
.iter()
.map(|x| x.to_string())
.collect::<Vec<String>>()
.join("\n");
let result = new_ucmd!()
.arg("-r")
.args(&["-n", &repeat_limit.to_string()])
.pipe_in(input.as_bytes())
.succeeds()
.no_stderr()
.stdout
.clone();
let result_seq: Vec<i32> = result
.split("\n")
.filter(|x| !x.is_empty())
.map(|x| x.parse().unwrap())
.collect();
assert_eq!(
result_seq.len(),
repeat_limit,
"Output is not repeating forever"
);
assert!(
result_seq.iter().all(|x| input_seq.contains(x)),
"Output includes element not from input: {:?}",
result_seq
.iter()
.filter(|x| !input_seq.contains(x))
.collect::<Vec<&i32>>()
)
}
#[test]
fn test_file_input() {
let expected_seq = vec![11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
let result = new_ucmd!()
.arg("file_input.txt")
.succeeds()
.no_stderr()
.stdout
.clone();
let mut result_seq: Vec<i32> = result
.split("\n")
.filter(|x| !x.is_empty())
.map(|x| x.parse().unwrap())
.collect();
result_seq.sort();
assert_eq!(result_seq, expected_seq, "Output is not a permutation");
}
#[test]
fn test_shuf_echo_and_input_range_not_allowed() {
let result = new_ucmd!().args(&["-e", "0", "-i", "0-2"]).run();
assert!(!result.success);
assert!(result
.stderr
.contains("The argument '--input-range <LO-HI>' cannot be used with '--echo <ARG>...'"));
}
#[test]
fn test_shuf_input_range_and_file_not_allowed() {
let result = new_ucmd!().args(&["-i", "0-9", "file"]).run();
assert!(!result.success);
assert!(result
.stderr
.contains("The argument '<file>' cannot be used with '--input-range <LO-HI>'"));
}
#[test]
fn test_shuf_invalid_input_range_one() {
let result = new_ucmd!().args(&["-i", "0"]).run();
assert!(!result.success);
assert!(result.stderr.contains("invalid input range"));
}
#[test]
fn test_shuf_invalid_input_range_two() {
let result = new_ucmd!().args(&["-i", "a-9"]).run();
assert!(!result.success);
assert!(result.stderr.contains("invalid input range: 'a'"));
}
#[test]
fn test_shuf_invalid_input_range_three() {
let result = new_ucmd!().args(&["-i", "0-b"]).run();
assert!(!result.success);
assert!(result.stderr.contains("invalid input range: 'b'"));
}
#[test]
fn test_shuf_invalid_input_line_count() {
let result = new_ucmd!().args(&["-n", "a"]).run();
assert!(!result.success);
assert!(result.stderr.contains("invalid line count: 'a'"));
}

View file

@ -1,5 +1,64 @@
use crate::common::util::*;
#[test]
fn test_check_zero_terminated_failure() {
new_ucmd!()
.arg("-z")
.arg("-c")
.arg("zero-terminated.txt")
.fails()
.stdout_is("sort: disorder in line 0\n");
}
#[test]
fn test_check_zero_terminated_success() {
new_ucmd!()
.arg("-z")
.arg("-c")
.arg("zero-terminated.expected")
.succeeds();
}
#[test]
fn test_random_shuffle_len() {
// check whether output is the same length as the input
const FILE: &'static str = "default_unsorted_ints.expected";
let (at, _ucmd) = at_and_ucmd!();
let result = new_ucmd!().arg("-R").arg(FILE).run().stdout;
let expected = at.read(FILE);
assert_ne!(result, expected);
assert_eq!(result.len(), expected.len());
}
#[test]
fn test_random_shuffle_contains_all_lines() {
// check whether lines of input are all in output
const FILE: &'static str = "default_unsorted_ints.expected";
let (at, _ucmd) = at_and_ucmd!();
let result = new_ucmd!().arg("-R").arg(FILE).run().stdout;
let expected = at.read(FILE);
let result_sorted = new_ucmd!().pipe_in(result.clone()).run().stdout;
assert_ne!(result, expected);
assert_eq!(result_sorted, expected);
}
#[test]
fn test_random_shuffle_contains_two_runs_not_the_same() {
// check to verify that two random shuffles are not equal; this has the
// potential to fail in the unlikely event that random order is the same
// as the starting order, or if both random sorts end up having the same order.
const FILE: &'static str = "default_unsorted_ints.expected";
let (at, _ucmd) = at_and_ucmd!();
let result = new_ucmd!().arg("-R").arg(FILE).run().stdout;
let expected = at.read(FILE);
let unexpected = new_ucmd!().arg("-R").arg(FILE).run().stdout;
assert_ne!(result, expected);
assert_ne!(result, unexpected);
}
#[test]
fn test_numeric_floats_and_ints() {
test_helper("numeric_floats_and_ints", "-n");
@ -70,6 +129,148 @@ fn test_dictionary_order() {
test_helper("dictionary_order", "-d");
}
#[test]
fn test_dictionary_order2() {
for non_dictionary_order2_param in vec!["-d"] {
new_ucmd!()
.pipe_in("a👦🏻aa b\naaaa b")
.arg(non_dictionary_order2_param)
.succeeds()
.stdout_only("a👦🏻aa b\naaaa b\n");
}
}
#[test]
fn test_non_printing_chars() {
for non_printing_chars_param in vec!["-i"] {
new_ucmd!()
.pipe_in("a👦🏻aa b\naaaa b")
.arg(non_printing_chars_param)
.succeeds()
.stdout_only("aaaa b\na👦🏻aa b\n");
}
}
#[test]
fn test_exponents_positive_general_fixed() {
for exponents_positive_general_param in vec!["-g"] {
new_ucmd!()
.pipe_in("100E6\n\n50e10\n+100000\n\n10000K78\n10E\n\n\n1000EDKLD\n\n\n100E6\n\n50e10\n+100000\n\n")
.arg(exponents_positive_general_param)
.succeeds()
.stdout_only("\n\n\n\n\n\n\n\n10000K78\n1000EDKLD\n10E\n+100000\n+100000\n100E6\n100E6\n50e10\n50e10\n");
}
}
#[test]
fn test_exponents_positive_numeric() {
test_helper("exponents-positive-numeric", "-n");
}
#[test]
fn test_months_dedup() {
test_helper("months-dedup", "-Mu");
}
#[test]
fn test_mixed_floats_ints_chars_numeric() {
test_helper("mixed_floats_ints_chars_numeric", "-n");
}
#[test]
fn test_mixed_floats_ints_chars_numeric_unique() {
test_helper("mixed_floats_ints_chars_numeric_unique", "-nu");
}
#[test]
fn test_mixed_floats_ints_chars_numeric_reverse() {
test_helper("mixed_floats_ints_chars_numeric_unique_reverse", "-nur");
}
#[test]
fn test_mixed_floats_ints_chars_numeric_stable() {
test_helper("mixed_floats_ints_chars_numeric_stable", "-ns");
}
#[test]
fn test_numeric_floats_and_ints2() {
for numeric_sort_param in vec!["-n", "--numeric-sort"] {
let input = "1.444\n8.013\n1\n-8\n1.04\n-1";
new_ucmd!()
.arg(numeric_sort_param)
.pipe_in(input)
.succeeds()
.stdout_only("-8\n-1\n1\n1.04\n1.444\n8.013\n");
}
}
#[test]
fn test_numeric_floats2() {
for numeric_sort_param in vec!["-n", "--numeric-sort"] {
let input = "1.444\n8.013\n1.58590\n-8.90880\n1.040000000\n-.05";
new_ucmd!()
.arg(numeric_sort_param)
.pipe_in(input)
.succeeds()
.stdout_only("-8.90880\n-.05\n1.040000000\n1.444\n1.58590\n8.013\n");
}
}
#[test]
fn test_numeric_floats_with_nan2() {
test_helper("numeric-floats-with-nan2", "-n");
}
#[test]
fn test_human_block_sizes2() {
for human_numeric_sort_param in vec!["-h", "--human-numeric-sort"] {
let input = "8981K\n909991M\n-8T\n21G\n0.8M";
new_ucmd!()
.arg(human_numeric_sort_param)
.pipe_in(input)
.succeeds()
.stdout_only("-8T\n0.8M\n8981K\n21G\n909991M\n");
}
}
#[test]
fn test_month_default2() {
for month_sort_param in vec!["-M", "--month-sort"] {
let input = "JAn\nMAY\n000may\nJun\nFeb";
new_ucmd!()
.arg(month_sort_param)
.pipe_in(input)
.succeeds()
.stdout_only("000may\nJAn\nFeb\nMAY\nJun\n");
}
}
#[test]
fn test_default_unsorted_ints2() {
let input = "9\n1909888\n000\n1\n2";
new_ucmd!()
.pipe_in(input)
.succeeds()
.stdout_only("000\n1\n1909888\n2\n9\n");
}
#[test]
fn test_numeric_unique_ints2() {
for numeric_unique_sort_param in vec!["-nu"] {
let input = "9\n9\n8\n1\n";
new_ucmd!()
.arg(numeric_unique_sort_param)
.pipe_in(input)
.succeeds()
.stdout_only("1\n8\n9\n");
}
}
#[test]
fn test_zero_terminated() {
test_helper("zero-terminated", "-z");
}
#[test]
fn test_multiple_files() {
new_ucmd!()
@ -146,6 +347,15 @@ fn test_check() {
.stdout_is("");
}
#[test]
fn test_check_silent() {
new_ucmd!()
.arg("-C")
.arg("check_fail.txt")
.fails()
.stdout_is("");
}
fn test_helper(file_name: &str, args: &str) {
new_ucmd!()
.arg(args)

View file

@ -52,3 +52,23 @@ fn test_sysv_stdin() {
.succeeds()
.stdout_only_fixture("sysv_stdin.expected");
}
#[test]
fn test_invalid_file() {
let (at, mut ucmd) = at_and_ucmd!();
at.mkdir("a");
ucmd.arg("a")
.fails()
.stderr_is("sum: error: 'a' Is a directory");
}
#[test]
fn test_invalid_metadata() {
let (_, mut ucmd) = at_and_ucmd!();
ucmd.arg("b")
.fails()
.stderr_is("sum: error: 'b' No such file or directory");
}

View file

@ -49,3 +49,21 @@ fn test_single_non_newline_separator_before() {
.run()
.stdout_is_fixture("delimited_primes_before.expected");
}
#[test]
fn test_invalid_input() {
let (_, mut ucmd) = at_and_ucmd!();
ucmd.arg("b")
.run()
.stderr
.contains("tac: error: failed to open 'b' for reading");
let (at, mut ucmd) = at_and_ucmd!();
at.mkdir("a");
ucmd.arg("a")
.run()
.stderr
.contains("tac: error: failed to read 'a'");
}

View file

@ -1 +1,104 @@
// ToDO: add tests
use crate::common::util::*;
// tests for basic tee functionality.
// inspired by:
// https://github.com/coreutils/coreutils/tests/misc/tee.sh
#[test]
fn test_tee_processing_multiple_operands() {
// POSIX says: "Processing of at least 13 file operands shall be supported."
let content = "tee_sample_content";
for &n in [1, 2, 12, 13].iter() {
let files = (1..=n).map(|x| x.to_string()).collect::<Vec<_>>();
let (at, mut ucmd) = at_and_ucmd!();
ucmd.args(&files)
.pipe_in(content)
.succeeds()
.stdout_is(content);
for file in files.iter() {
assert!(at.file_exists(file));
assert_eq!(at.read(file), content);
}
}
}
#[test]
fn test_tee_treat_minus_as_filename() {
// Ensure tee treats '-' as the name of a file, as mandated by POSIX.
let (at, mut ucmd) = at_and_ucmd!();
let content = "tee_sample_content";
let file = "-";
ucmd.arg("-").pipe_in(content).succeeds().stdout_is(content);
assert!(at.file_exists(file));
assert_eq!(at.read(file), content);
}
#[test]
fn test_tee_append() {
let (at, mut ucmd) = at_and_ucmd!();
let content = "tee_sample_content";
let file = "tee_out";
at.touch(file);
at.write(file, content);
assert_eq!(at.read(file), content);
ucmd.arg("-a")
.arg(file)
.pipe_in(content)
.succeeds()
.stdout_is(content);
assert!(at.file_exists(file));
assert_eq!(at.read(file), content.repeat(2));
}
#[test]
#[cfg(target_os = "linux")]
fn test_tee_no_more_writeable_1() {
// equals to 'tee /dev/full out2 <multi_read' call
let (at, mut ucmd) = at_and_ucmd!();
let content = (1..=10)
.map(|x| format!("{}\n", x.to_string()))
.collect::<String>();
let file_out = "tee_file_out";
ucmd.arg("/dev/full")
.arg(file_out)
.pipe_in(&content[..])
.fails()
.stdout_contains(&content)
.stderr_contains(&"No space left on device");
assert_eq!(at.read(file_out), content);
}
#[test]
#[cfg(target_os = "linux")]
fn test_tee_no_more_writeable_2() {
// should be equals to 'tee out1 out2 >/dev/full <multi_read' call
// but currently there is no way to redirect stdout to /dev/full
// so this test is disabled
let (_at, mut ucmd) = at_and_ucmd!();
let _content = (1..=10)
.map(|x| format!("{}\n", x.to_string()))
.collect::<String>();
let file_out_a = "tee_file_out_a";
let file_out_b = "tee_file_out_b";
let _result = ucmd
.arg(file_out_a)
.arg(file_out_b)
.pipe_in("/dev/full")
.succeeds(); // TODO: expected to succeed currently; change to fails() when required
// TODO: comment in after https://github.com/uutils/coreutils/issues/1805 is fixed
// assert_eq!(at.read(file_out_a), content);
// assert_eq!(at.read(file_out_b), content);
// assert!(result.stderr.contains("No space left on device"));
}

View file

@ -1 +1,57 @@
// ToDO: add tests
use crate::common::util::*;
#[test]
#[cfg(not(windows))]
fn test_dev_null() {
new_ucmd!()
.pipe_in("</dev/null")
.fails()
.stdout_is("not a tty\n");
}
#[test]
#[cfg(not(windows))]
fn test_dev_null_silent() {
new_ucmd!()
.args(&["-s"])
.pipe_in("</dev/null")
.fails()
.stdout_is("");
}
#[test]
fn test_close_stdin() {
new_ucmd!().pipe_in("<&-").fails().stdout_is("not a tty\n");
}
#[test]
fn test_close_stdin_silent() {
new_ucmd!()
.args(&["-s"])
.pipe_in("<&-")
.fails()
.stdout_is("");
}
#[test]
fn test_close_stdin_silent_long() {
new_ucmd!()
.args(&["--silent"])
.pipe_in("<&-")
.fails()
.stdout_is("");
}
#[test]
fn test_close_stdin_silent_alias() {
new_ucmd!()
.args(&["--quiet"])
.pipe_in("<&-")
.fails()
.stdout_is("");
}
#[test]
fn test_wrong_argument() {
new_ucmd!().args(&["a"]).fails();
}

View file

@ -147,3 +147,48 @@ fn test_invalid_utf8() {
.failure()
.stderr_only("uniq: error: invalid utf-8 sequence of 1 bytes from index 0");
}
#[test]
fn test_group() {
new_ucmd!()
.args(&["--group"])
.pipe_in_fixture(INPUT)
.run()
.stdout_is_fixture("group.expected");
}
#[test]
fn test_group_prepend() {
new_ucmd!()
.args(&["--group=prepend"])
.pipe_in_fixture(INPUT)
.run()
.stdout_is_fixture("group-prepend.expected");
}
#[test]
fn test_group_append() {
new_ucmd!()
.args(&["--group=append"])
.pipe_in_fixture(INPUT)
.run()
.stdout_is_fixture("group-append.expected");
}
#[test]
fn test_group_both() {
new_ucmd!()
.args(&["--group=both"])
.pipe_in_fixture(INPUT)
.run()
.stdout_is_fixture("group-both.expected");
}
#[test]
fn test_group_separate() {
new_ucmd!()
.args(&["--group=separate"])
.pipe_in_fixture(INPUT)
.run()
.stdout_is_fixture("group.expected");
}

View file

@ -14,7 +14,7 @@ fn test_utf8() {
.args(&["-lwmcL"])
.pipe_in_fixture("UTF_8_test.txt")
.run()
.stdout_is(" 0 0 0 0 0\n");
.stdout_is(" 300 4969 22781 22213 79\n");
// GNU returns " 300 2086 22219 22781 79"
// TODO: we should fix that to match GNU's behavior
}
@ -25,7 +25,7 @@ fn test_stdin_line_len_regression() {
.args(&["-L"])
.pipe_in("\n123456")
.run()
.stdout_is(" 6\n");
.stdout_is("6\n");
}
#[test]
@ -34,7 +34,7 @@ fn test_stdin_only_bytes() {
.args(&["-c"])
.pipe_in_fixture("lorem_ipsum.txt")
.run()
.stdout_is(" 772\n");
.stdout_is("772\n");
}
#[test]
@ -59,7 +59,7 @@ fn test_single_only_lines() {
new_ucmd!()
.args(&["-l", "moby_dick.txt"])
.run()
.stdout_is(" 18 moby_dick.txt\n");
.stdout_is("18 moby_dick.txt\n");
}
#[test]

View file

@ -5,7 +5,7 @@
macro_rules! assert_empty_stderr(
($cond:expr) => (
if $cond.stderr.len() > 0 {
panic!(format!("stderr: {}", $cond.stderr))
panic!("stderr: {}", $cond.stderr_str())
}
);
);
@ -17,7 +17,7 @@ macro_rules! assert_empty_stderr(
macro_rules! assert_empty_stdout(
($cond:expr) => (
if $cond.stdout.len() > 0 {
panic!(format!("stdout: {}", $cond.stdout))
panic!("stdout: {}", $cond.stdout_str())
}
);
);
@ -30,7 +30,7 @@ macro_rules! assert_no_error(
($cond:expr) => (
assert!($cond.success);
if $cond.stderr.len() > 0 {
panic!(format!("stderr: {}", $cond.stderr))
panic!("stderr: {}", $cond.stderr_str())
}
);
);

View file

@ -1,6 +1,10 @@
#![allow(dead_code)]
#[cfg(not(windows))]
use libc;
use std::env;
#[cfg(not(windows))]
use std::ffi::CString;
use std::ffi::OsStr;
use std::fs::{self, File, OpenOptions};
use std::io::{Read, Result, Write};
@ -25,8 +29,8 @@ static TESTS_DIR: &str = "tests";
static FIXTURES_DIR: &str = "fixtures";
static ALREADY_RUN: &str = " you have already run this UCommand, if you want to run \
another command in the same test, use TestScenario::new instead of \
testing();";
another command in the same test, use TestScenario::new instead of \
testing();";
static MULTIPLE_STDIN_MEANINGLESS: &str = "Ucommand is designed around a typical use case of: provide args and input stream -> spawn process -> block until completion -> return output streams. For verifying that a particular section of the input stream is what causes a particular behavior, use the Command type directly.";
/// Test if the program is running under CI
@ -52,9 +56,10 @@ pub fn is_wsl() -> bool {
false
}
fn read_scenario_fixture<S: AsRef<OsStr>>(tmpd: &Option<Rc<TempDir>>, file_rel_path: S) -> String {
/// Read a test scenario fixture, returning its bytes
fn read_scenario_fixture<S: AsRef<OsStr>>(tmpd: &Option<Rc<TempDir>>, file_rel_path: S) -> Vec<u8> {
let tmpdir_path = tmpd.as_ref().unwrap().as_ref().path();
AtPath::new(tmpdir_path).read(file_rel_path.as_ref().to_str().unwrap())
AtPath::new(tmpdir_path).read_bytes(file_rel_path.as_ref().to_str().unwrap())
}
/// A command result is the outputs of a command (streams and status code)
@ -68,64 +73,135 @@ pub struct CmdResult {
/// zero-exit from running the Command?
/// see [`success`]
pub success: bool,
/// captured utf-8 standard output after running the Command
/// captured standard output after running the Command
pub stdout: String,
/// captured utf-8 standard error after running the Command
/// captured standard error after running the Command
pub stderr: String,
}
impl CmdResult {
/// Returns a reference to the program's standard output as a slice of bytes
pub fn stdout(&self) -> &[u8] {
&self.stdout.as_bytes()
}
/// Returns the program's standard output as a string slice
pub fn stdout_str(&self) -> &str {
&self.stdout
}
/// Returns the program's standard output as a string
/// consumes self
pub fn stdout_move_str(self) -> String {
self.stdout
}
/// Returns the program's standard output as a vec of bytes
/// consumes self
pub fn stdout_move_bytes(self) -> Vec<u8> {
Vec::from(self.stdout)
}
/// Returns a reference to the program's standard error as a slice of bytes
pub fn stderr(&self) -> &[u8] {
&self.stderr.as_bytes()
}
/// Returns the program's standard error as a string slice
pub fn stderr_str(&self) -> &str {
&self.stderr
}
/// Returns the program's standard error as a string
/// consumes self
pub fn stderr_move_str(self) -> String {
self.stderr
}
/// Returns the program's standard error as a vec of bytes
/// consumes self
pub fn stderr_move_bytes(self) -> Vec<u8> {
Vec::from(self.stderr)
}
/// Returns the program's exit code
/// Panics if not run
pub fn code(&self) -> i32 {
self.code.expect("Program must be run first")
}
/// Returns the program's TempDir
/// Panics if not present
pub fn tmpd(&self) -> Rc<TempDir> {
match &self.tmpd {
Some(ptr) => ptr.clone(),
None => panic!("Command not associated with a TempDir"),
}
}
/// Returns whether the program succeeded
pub fn succeeded(&self) -> bool {
self.success
}
/// asserts that the command resulted in a success (zero) status code
pub fn success(&self) -> Box<&CmdResult> {
pub fn success(&self) -> &CmdResult {
assert!(self.success);
Box::new(self)
self
}
/// asserts that the command resulted in a failure (non-zero) status code
pub fn failure(&self) -> Box<&CmdResult> {
pub fn failure(&self) -> &CmdResult {
assert!(!self.success);
Box::new(self)
self
}
/// asserts that the command's exit code is the same as the given one
pub fn status_code(&self, code: i32) -> Box<&CmdResult> {
pub fn status_code(&self, code: i32) -> &CmdResult {
assert!(self.code == Some(code));
Box::new(self)
self
}
/// asserts that the command resulted in empty (zero-length) stderr stream output
/// generally, it's better to use stdout_only() instead,
/// but you might find yourself using this function if
/// 1. you can not know exactly what stdout will be
/// or 2. you know that stdout will also be empty
pub fn no_stderr(&self) -> Box<&CmdResult> {
assert_eq!(self.stderr, "");
Box::new(self)
/// 1. you can not know exactly what stdout will be or
/// 2. you know that stdout will also be empty
pub fn no_stderr(&self) -> &CmdResult {
assert!(self.stderr.is_empty());
self
}
/// asserts that the command resulted in empty (zero-length) stderr stream output
/// unless asserting there was neither stdout or stderr, stderr_only is usually a better choice
/// generally, it's better to use stderr_only() instead,
/// but you might find yourself using this function if
/// 1. you can not know exactly what stderr will be
/// or 2. you know that stderr will also be empty
pub fn no_stdout(&self) -> Box<&CmdResult> {
assert_eq!(self.stdout, "");
Box::new(self)
/// 1. you can not know exactly what stderr will be or
/// 2. you know that stderr will also be empty
pub fn no_stdout(&self) -> &CmdResult {
assert!(self.stdout.is_empty());
self
}
/// asserts that the command resulted in stdout stream output that equals the
/// passed in value, trailing whitespace are kept to force strict comparison (#1235)
/// stdout_only is a better choice unless stderr may or will be non-empty
pub fn stdout_is<T: AsRef<str>>(&self, msg: T) -> Box<&CmdResult> {
pub fn stdout_is<T: AsRef<str>>(&self, msg: T) -> &CmdResult {
assert_eq!(self.stdout, String::from(msg.as_ref()));
Box::new(self)
self
}
/// asserts that the command resulted in stdout stream output,
/// whose bytes equal those of the passed in slice
pub fn stdout_is_bytes<T: AsRef<[u8]>>(&self, msg: T) -> &CmdResult {
assert_eq!(self.stdout.as_bytes(), msg.as_ref());
self
}
/// like stdout_is(...), but expects the contents of the file at the provided relative path
pub fn stdout_is_fixture<T: AsRef<OsStr>>(&self, file_rel_path: T) -> Box<&CmdResult> {
pub fn stdout_is_fixture<T: AsRef<OsStr>>(&self, file_rel_path: T) -> &CmdResult {
let contents = read_scenario_fixture(&self.tmpd, file_rel_path);
self.stdout_is(contents)
self.stdout_is_bytes(contents)
}
/// like stdout_is_fixture(...), but replaces the data in fixture file based on values provided in template_vars
/// command output
@ -140,40 +216,73 @@ impl CmdResult {
/// asserts that the command resulted in stderr stream output that equals the
/// passed in value, when both are trimmed of trailing whitespace
/// stderr_only is a better choice unless stdout may or will be non-empty
pub fn stderr_is<T: AsRef<str>>(&self, msg: T) -> Box<&CmdResult> {
pub fn stderr_is<T: AsRef<str>>(&self, msg: T) -> &CmdResult {
assert_eq!(
self.stderr.trim_end(),
String::from(msg.as_ref()).trim_end()
);
Box::new(self)
self
}
/// asserts that the command resulted in stderr stream output,
/// whose bytes equal those of the passed in slice
pub fn stderr_is_bytes<T: AsRef<[u8]>>(&self, msg: T) -> &CmdResult {
assert_eq!(self.stderr.as_bytes(), msg.as_ref());
self
}
/// asserts that
/// 1. the command resulted in stdout stream output that equals the
/// passed in value, when both are trimmed of trailing whitespace
/// and 2. the command resulted in empty (zero-length) stderr stream output
pub fn stdout_only<T: AsRef<str>>(&self, msg: T) -> Box<&CmdResult> {
/// 1. the command resulted in stdout stream output that equals the
/// passed in value
/// 2. the command resulted in empty (zero-length) stderr stream output
pub fn stdout_only<T: AsRef<str>>(&self, msg: T) -> &CmdResult {
self.no_stderr().stdout_is(msg)
}
/// asserts that
/// 1. the command resulted in a stdout stream whose bytes
/// equal those of the passed in value
/// 2. the command resulted in an empty stderr stream
pub fn stdout_only_bytes<T: AsRef<[u8]>>(&self, msg: T) -> &CmdResult {
self.no_stderr().stdout_is_bytes(msg)
}
/// like stdout_only(...), but expects the contents of the file at the provided relative path
pub fn stdout_only_fixture<T: AsRef<OsStr>>(&self, file_rel_path: T) -> Box<&CmdResult> {
pub fn stdout_only_fixture<T: AsRef<OsStr>>(&self, file_rel_path: T) -> &CmdResult {
let contents = read_scenario_fixture(&self.tmpd, file_rel_path);
self.stdout_only(contents)
self.stdout_only_bytes(contents)
}
/// asserts that
/// 1. the command resulted in stderr stream output that equals the
/// passed in value, when both are trimmed of trailing whitespace
/// and 2. the command resulted in empty (zero-length) stdout stream output
pub fn stderr_only<T: AsRef<str>>(&self, msg: T) -> Box<&CmdResult> {
/// 1. the command resulted in stderr stream output that equals the
/// passed in value, when both are trimmed of trailing whitespace
/// 2. the command resulted in empty (zero-length) stdout stream output
pub fn stderr_only<T: AsRef<str>>(&self, msg: T) -> &CmdResult {
self.no_stdout().stderr_is(msg)
}
pub fn fails_silently(&self) -> Box<&CmdResult> {
/// asserts that
/// 1. the command resulted in a stderr stream whose bytes equal the ones
/// of the passed value
/// 2. the command resulted in an empty stdout stream
pub fn stderr_only_bytes<T: AsRef<[u8]>>(&self, msg: T) -> &CmdResult {
self.no_stderr().stderr_is_bytes(msg)
}
pub fn fails_silently(&self) -> &CmdResult {
assert!(!self.success);
assert_eq!(self.stderr, "");
Box::new(self)
assert!(self.stderr.is_empty());
self
}
pub fn stdout_contains<T: AsRef<str>>(&self, cmp: T) -> &CmdResult {
assert!(self.stdout_str().contains(cmp.as_ref()));
self
}
pub fn stderr_contains<T: AsRef<str>>(&self, cmp: &T) -> &CmdResult {
assert!(self.stderr_str().contains(cmp.as_ref()));
self
}
}
@ -259,13 +368,29 @@ impl AtPath {
pub fn read(&self, name: &str) -> String {
let mut f = self.open(name);
let mut contents = String::new();
let _ = f.read_to_string(&mut contents);
f.read_to_string(&mut contents)
.unwrap_or_else(|e| panic!("Couldn't read {}: {}", name, e));
contents
}
pub fn read_bytes(&self, name: &str) -> Vec<u8> {
let mut f = self.open(name);
let mut contents = Vec::new();
f.read_to_end(&mut contents)
.unwrap_or_else(|e| panic!("Couldn't read {}: {}", name, e));
contents
}
pub fn write(&self, name: &str, contents: &str) {
log_info("open(write)", self.plus_as_string(name));
let _ = std::fs::write(self.plus(name), contents);
std::fs::write(self.plus(name), contents)
.unwrap_or_else(|e| panic!("Couldn't write {}: {}", name, e));
}
pub fn write_bytes(&self, name: &str, contents: &[u8]) {
log_info("open(write)", self.plus_as_string(name));
std::fs::write(self.plus(name), contents)
.unwrap_or_else(|e| panic!("Couldn't write {}: {}", name, e));
}
pub fn append(&self, name: &str, contents: &str) {
@ -275,7 +400,19 @@ impl AtPath {
.append(true)
.open(self.plus(name))
.unwrap();
let _ = f.write(contents.as_bytes());
f.write(contents.as_bytes())
.unwrap_or_else(|e| panic!("Couldn't write {}: {}", name, e));
}
pub fn append_bytes(&self, name: &str, contents: &[u8]) {
log_info("open(append)", self.plus_as_string(name));
let mut f = OpenOptions::new()
.write(true)
.append(true)
.open(self.plus(name))
.unwrap();
f.write_all(contents)
.unwrap_or_else(|e| panic!("Couldn't append to {}: {}", name, e));
}
pub fn mkdir(&self, dir: &str) {
@ -299,6 +436,29 @@ impl AtPath {
File::create(&self.plus(file)).unwrap();
}
#[cfg(not(windows))]
pub fn mkfifo(&self, fifo: &str) {
let full_path = self.plus_as_string(fifo);
log_info("mkfifo", &full_path);
unsafe {
let fifo_name: CString = CString::new(full_path).expect("CString creation failed.");
libc::mkfifo(fifo_name.as_ptr(), libc::S_IWUSR | libc::S_IRUSR);
}
}
#[cfg(not(windows))]
pub fn is_fifo(&self, fifo: &str) -> bool {
unsafe {
let name = CString::new(self.plus_as_string(fifo)).unwrap();
let mut stat: libc::stat = std::mem::zeroed();
if libc::stat(name.as_ptr(), &mut stat) >= 0 {
libc::S_IFIFO & stat.st_mode != 0
} else {
false
}
}
}
pub fn symlink_file(&self, src: &str, dst: &str) {
log_info(
"symlink",
@ -439,6 +599,14 @@ impl TestScenario {
UCommand::new_from_tmp(bin, self.tmpd.clone(), true)
}
/// Returns builder for invoking any uutils command. Paths given are treated
/// relative to the environment's unique temporary test directory.
pub fn ccmd<S: AsRef<OsStr>>(&self, bin: S) -> UCommand {
let mut cmd = self.cmd(&self.bin_path);
cmd.arg(bin);
cmd
}
// different names are used rather than an argument
// because the need to keep the environment is exceedingly rare.
pub fn ucmd_keepenv(&self) -> UCommand {
@ -506,21 +674,21 @@ impl UCommand {
/// Add a parameter to the invocation. Path arguments are treated relative
/// to the test environment directory.
pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> Box<&mut UCommand> {
pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut UCommand {
if self.has_run {
panic!(ALREADY_RUN);
panic!("{}", ALREADY_RUN);
}
self.comm_string.push_str(" ");
self.comm_string.push_str(arg.as_ref().to_str().unwrap());
self.raw.arg(arg.as_ref());
Box::new(self)
self
}
/// Add multiple parameters to the invocation. Path arguments are treated relative
/// to the test environment directory.
pub fn args<S: AsRef<OsStr>>(&mut self, args: &[S]) -> Box<&mut UCommand> {
pub fn args<S: AsRef<OsStr>>(&mut self, args: &[S]) -> &mut UCommand {
if self.has_run {
panic!(MULTIPLE_STDIN_MEANINGLESS);
panic!("{}", MULTIPLE_STDIN_MEANINGLESS);
}
for s in args {
self.comm_string.push_str(" ");
@ -528,41 +696,41 @@ impl UCommand {
}
self.raw.args(args.as_ref());
Box::new(self)
self
}
/// provides stdinput to feed in to the command when spawned
pub fn pipe_in<T: Into<Vec<u8>>>(&mut self, input: T) -> Box<&mut UCommand> {
pub fn pipe_in<T: Into<Vec<u8>>>(&mut self, input: T) -> &mut UCommand {
if self.stdin.is_some() {
panic!(MULTIPLE_STDIN_MEANINGLESS);
panic!("{}", MULTIPLE_STDIN_MEANINGLESS);
}
self.stdin = Some(input.into());
Box::new(self)
self
}
/// like pipe_in(...), but uses the contents of the file at the provided relative path as the piped in data
pub fn pipe_in_fixture<S: AsRef<OsStr>>(&mut self, file_rel_path: S) -> Box<&mut UCommand> {
pub fn pipe_in_fixture<S: AsRef<OsStr>>(&mut self, file_rel_path: S) -> &mut UCommand {
let contents = read_scenario_fixture(&self.tmpd, file_rel_path);
self.pipe_in(contents)
}
pub fn env<K, V>(&mut self, key: K, val: V) -> Box<&mut UCommand>
pub fn env<K, V>(&mut self, key: K, val: V) -> &mut UCommand
where
K: AsRef<OsStr>,
V: AsRef<OsStr>,
{
if self.has_run {
panic!(ALREADY_RUN);
panic!("{}", ALREADY_RUN);
}
self.raw.env(key, val);
Box::new(self)
self
}
/// Spawns the command, feeds the stdin if any, and returns the
/// child process immediately.
pub fn run_no_wait(&mut self) -> Child {
if self.has_run {
panic!(ALREADY_RUN);
panic!("{}", ALREADY_RUN);
}
self.has_run = true;
log_info("run", &self.comm_string);
@ -639,7 +807,7 @@ pub fn read_size(child: &mut Child, size: usize) -> String {
.stdout
.as_mut()
.unwrap()
.read(output.as_mut_slice())
.read_exact(output.as_mut_slice())
.unwrap();
String::from_utf8(output).unwrap()
}

1
tests/fixtures/cksum/chars.txt vendored Normal file
View file

@ -0,0 +1 @@
123456789:;<=>?@

View file

@ -0,0 +1 @@
\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377\400\401\402\403\404\405\406\407\410\411\412\413\414\415\416\417\420\421\422\423\424\425\426\427\430\431\432\433\434\435\436\437\440\441\442\443\444\445\446\447\450\451\452\453\454\455\456\457\460\461\462\463\464\465\466\467\470\471\472\473\474\475\476\477\500\501\502\503\504\505\506\507\510\511\512\513\514\515\516\517\520\521\522\523\524\525\526\527\530\531\532\533\534\535\536\537\540\541\542\543\544\545\546\547\550\551\552\553\554\555\556\557\560\561\562\563\564\565\566\567\570\571\572\573\574\575\576\577\600\601\602\603\604\605\606\607\610\611\612\613\614\615\616\617\620\621\622\623\624\625\626\627\630\631\632\633\634\635\636\637\640\641\642\643\644\645\646\647\650\651\652\653\654\655\656\657\660\661\662\663\664\665\666\667\670\671\672\673\674\675\676\677\700\701\702\703\704\705\706\707\710\711\712\713\714\715\716\717\720\721\722\723\724\725\726\727\730\731\732\733\734\735\736\737\740\741\742\743\744\745\746\747\750\751\752\753\754\755\756\757\760\761\762\763\764\765\766\767\770\771\772\773\774\775\776\777\1000\1001

0
tests/fixtures/du/empty.txt vendored Normal file
View file

View file

@ -0,0 +1 @@
test1 test2 test3 test4 test5 test6

11
tests/fixtures/fold/tab_stops.input vendored Normal file
View file

@ -0,0 +1,11 @@
1
12
123
1234
12345
123456
1234567
12345678
123456781
12345678 2
12345678 2 4

View file

@ -0,0 +1,13 @@
1
12
123
1234
12345
123456
1234567
12345678
123456781
12345678
2
12345678
2 4

View file

@ -0,0 +1,18 @@
1
12
123
1234
12345
123456
1234567
12345678
12345678
1
12345678
2
12345678
2
4

View file

@ -0,0 +1,24 @@
Lorem ipsum dolor sit amet,
consectetur adipiscing elit.
Nunc interdum suscipit sem vel ornare.
Proin euismod,
justo sed mollis dictum,
eros urna ultricies augue,
eu pharetra mi ex id ante.
Duis convallis porttitor aliquam.
Nunc vitae tincidunt ex.
Suspendisse iaculis ligula ac diam consectetur lacinia.
Donec vel velit dui.
Etiam fringilla,
dolor quis tempor vehicula,
lacus turpis bibendum velit,
et pellentesque elit odio a magna.
Cras vulputate tortor non libero vehicula euismod.
Aliquam tincidunt nisl eget enim cursus,
viverra sagittis magna commodo.
Cras rhoncus egestas leo nec blandit.
Suspendisse potenti.
Etiam ullamcorper leo vel lacus vestibulum,
cursus semper eros efficitur.
In hac habitasse platea dictumst.
Phasellus scelerisque vehicula f

100
tests/fixtures/head/sequence vendored Normal file
View file

@ -0,0 +1,100 @@
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100

90
tests/fixtures/head/sequence.expected vendored Normal file
View file

@ -0,0 +1,90 @@
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90

10
tests/fixtures/shuf/file_input.txt vendored Normal file
View file

@ -0,0 +1,10 @@
11
12
13
14
15
16
17
18
19
20

View file

@ -0,0 +1,12 @@
10E
1000EDKLD
10000K78
+100000
100E6
50e10

View file

@ -0,0 +1,12 @@
10000K78
10E
1000EDKLD
100E6
50e10
+100000

View file

@ -0,0 +1,12 @@
+100000
10E
50e10
100E6
1000EDKLD
10000K78

View file

@ -0,0 +1,12 @@
10000K78
10E
1000EDKLD
100E6
50e10
+100000

View file

@ -0,0 +1,37 @@
.2T
2G
100M
7800900K
51887300-
1890777
56908-90078
6780.0009866
6780.000986
789----009999 90-0 90-0
1
0001
apr
MAY
JUNNNN
JAN
AUG
APR
0000000
00
-1.4

View file

@ -0,0 +1,37 @@
JAN
0000000
00
0001
1
-1.4
JUNNNN
AUG
apr
APR
MAY
1890777
56908-90078
51887300-
6780.0009866
789----009999 90-0 90-0
6780.000986
100M
7800900K
2G
.2T

View file

@ -0,0 +1,37 @@
-1.4
JAN
0000000
00
JUNNNN
AUG
apr
APR
MAY
0001
1
789----009999 90-0 90-0
6780.000986
6780.0009866
56908-90078
1890777
51887300-
7800900K
100M
2G
.2T

View file

@ -0,0 +1,37 @@
JAN
0000000
00
0001
1
-1.4
JUNNNN
AUG
apr
APR
MAY
1890777
56908-90078
51887300-
6780.0009866
789----009999 90-0 90-0
6780.000986
100M
7800900K
2G
.2T

View file

@ -0,0 +1,13 @@
-1.4
JAN
0001
789----009999 90-0 90-0
6780.000986
6780.0009866
56908-90078
1890777
51887300-
7800900K
100M
2G
.2T

View file

@ -0,0 +1,37 @@
JAN
0000000
00
0001
1
-1.4
JUNNNN
AUG
apr
APR
MAY
1890777
56908-90078
51887300-
6780.0009866
789----009999 90-0 90-0
6780.000986
100M
7800900K
2G
.2T

View file

@ -0,0 +1,37 @@
-1.4
00
0000000
APR
AUG
JAN
JUNNNN
MAY
apr
0001
1
789----009999 90-0 90-0
6780.000986
6780.0009866
56908-90078
1890777
51887300-
7800900K
100M
2G
.2T

View file

@ -0,0 +1,46 @@
JAN
0000000
00
0001
1
-1.4
JUNNNN
AUG
apr
APR
MAY
1890777
56908-90078
51887300-
6780.0009866
789----009999 90-0 90-0
6780.000986
1M
10M
100M
1000M
10000M
7800900K
780090K
78009K
7800K
780K
2G
.2T

View file

@ -0,0 +1,30 @@
-2028789030
-896689
-8.90880
-1
-.05
000
CARAvan
00000001
1
1.040000000
1.444
1.58590
8.013
45
46.89
4567.
37800
576,446.88800000
576,446.890
4798908.340000000000
4798908.45
4798908.8909800

View file

@ -0,0 +1,30 @@
576,446.890
576,446.88800000
4567.
45
46.89
-1
1
00000001
4798908.340000000000
4798908.45
4798908.8909800
37800
-2028789030
-896689
CARAvan
-8.90880
-.05
1.444
1.58590
1.040000000
8.013
000

View file

@ -0,0 +1,30 @@
4798908.8909800
4798908.45
4798908.340000000000
576,446.890
576,446.88800000
37800
4567.
46.89
45
8.013
1.58590
1.444
1.040000000
1
00000001
CARAvan
000
-.05
-1
-8.90880
-896689
-2028789030

View file

@ -0,0 +1,30 @@
4798908.8909800
4798908.45
4798908.340000000000
576,446.890
576,446.88800000
37800
4567.
46.89
45
8.013
1.58590
1.444
1.040000000
1
00000001
CARAvan
000
-.05
-1
-8.90880
-896689
-2028789030

View file

@ -0,0 +1,30 @@
576,446.890
576,446.88800000
4567.
45
46.89
-1
1
00000001
4798908.340000000000
4798908.45
4798908.8909800
37800
-2028789030
-896689
CARAvan
-8.90880
-.05
1.444
1.58590
1.040000000
8.013
000

View file

@ -0,0 +1,30 @@
-2028789030
-896689
-8.90880
-1
-.05
CARAvan
000
1
00000001
1.040000000
1.444
1.58590
8.013
45
46.89
4567.
37800
576,446.88800000
576,446.890
4798908.340000000000
4798908.45
4798908.8909800

View file

@ -0,0 +1,30 @@
576,446.890
576,446.88800000
4567.
45
46.89
-1
1
00000001
4798908.340000000000
4798908.45
4798908.8909800
37800
-2028789030
-896689
CARAvan
-8.90880
-.05
1.444
1.58590
1.040000000
8.013
000

View file

@ -0,0 +1,20 @@
-2028789030
-896689
-8.90880
-1
-.05
1
1.040000000
1.444
1.58590
8.013
45
46.89
4567.
37800
576,446.88800000
576,446.890
4798908.340000000000
4798908.45
4798908.8909800

View file

@ -0,0 +1,30 @@
576,446.890
576,446.88800000
4567.
45
46.89
-1
1
00000001
4798908.340000000000
4798908.45
4798908.8909800
37800
-2028789030
-896689
CARAvan
-8.90880
-.05
1.444
1.58590
1.040000000
8.013
000

View file

@ -0,0 +1,20 @@
4798908.8909800
4798908.45
4798908.340000000000
576,446.890
576,446.88800000
37800
4567.
46.89
45
8.013
1.58590
1.444
1.040000000
1
-.05
-1
-8.90880
-896689
-2028789030

View file

@ -0,0 +1,30 @@
576,446.890
576,446.88800000
4567.
45
46.89
-1
1
00000001
4798908.340000000000
4798908.45
4798908.8909800
37800
-2028789030
-896689
CARAvan
-8.90880
-.05
1.444
1.58590
1.040000000
8.013
000

View file

@ -0,0 +1,20 @@
4798908.8909800
4798908.45
4798908.340000000000
576,446.890
576,446.88800000
37800
4567.
46.89
45
8.013
1.58590
1.444
1.040000000
1
-.05
-1
-8.90880
-896689
-2028789030

View file

@ -0,0 +1,30 @@
576,446.890
576,446.88800000
4567.
45
46.89
-1
1
00000001
4798908.340000000000
4798908.45
4798908.8909800
37800
-2028789030
-896689
CARAvan
-8.90880
-.05
1.444
1.58590
1.040000000
8.013
000

View file

@ -0,0 +1,6 @@
JAN
apr
MAY
JUNNNN
AUG

37
tests/fixtures/sort/months-dedup.txt vendored Normal file
View file

@ -0,0 +1,37 @@
JAN
0000000
00
0001
1
-1.4
JUNNNN
AUG
apr
APR
MAY
1890777
56908-90078
51887300-
6780.0009866
789----009999 90-0 90-0
6780.000986
100M
7800900K
2G
.2T

View file

@ -0,0 +1,23 @@
-8.90880
-.05
Karma
1
1.0/0.0
1.040000000
1.2
1.444
1.58590

View file

@ -0,0 +1,23 @@
Karma
1.0/0.0
-8.90880
-.05
1.040000000
1.444
1.58590
1
1.2

Binary file not shown.

BIN
tests/fixtures/sort/zero-terminated.txt vendored Normal file

Binary file not shown.

View file

@ -0,0 +1,26 @@
aaaaa
bbbbb ⅱ
bbbbb ⅱ
ccccc ⅲ
ccccc ⅲ
ccccc ⅲ
ddddd ⅲ
ddddd ⅲ
ddddd ⅲ
ddddd ⅲ
eeeee ⅲ
fffff ⅲ
fffff ⅲ
ggggg ⅲ
ggggg ⅲ
ggggg ⅲ
GGGGG ⅲ
GGGGG ⅲ

27
tests/fixtures/uniq/group-both.expected vendored Normal file
View file

@ -0,0 +1,27 @@
aaaaa
bbbbb ⅱ
bbbbb ⅱ
ccccc ⅲ
ccccc ⅲ
ccccc ⅲ
ddddd ⅲ
ddddd ⅲ
ddddd ⅲ
ddddd ⅲ
eeeee ⅲ
fffff ⅲ
fffff ⅲ
ggggg ⅲ
ggggg ⅲ
ggggg ⅲ
GGGGG ⅲ
GGGGG ⅲ

View file

@ -0,0 +1,26 @@
aaaaa
bbbbb ⅱ
bbbbb ⅱ
ccccc ⅲ
ccccc ⅲ
ccccc ⅲ
ddddd ⅲ
ddddd ⅲ
ddddd ⅲ
ddddd ⅲ
eeeee ⅲ
fffff ⅲ
fffff ⅲ
ggggg ⅲ
ggggg ⅲ
ggggg ⅲ
GGGGG ⅲ
GGGGG ⅲ

25
tests/fixtures/uniq/group.expected vendored Normal file
View file

@ -0,0 +1,25 @@
aaaaa
bbbbb ⅱ
bbbbb ⅱ
ccccc ⅲ
ccccc ⅲ
ccccc ⅲ
ddddd ⅲ
ddddd ⅲ
ddddd ⅲ
ddddd ⅲ
eeeee ⅲ
fffff ⅲ
fffff ⅲ
ggggg ⅲ
ggggg ⅲ
ggggg ⅲ
GGGGG ⅲ
GGGGG ⅲ