mirror of
https://github.com/uutils/coreutils.git
synced 2026-06-10 15:48:22 -07:00
257 lines
6.8 KiB
Rust
257 lines
6.8 KiB
Rust
// This file is part of the uutils coreutils package.
|
|
//
|
|
// For the full copyright and license information, please view the LICENSE
|
|
// file that was distributed with this source code.
|
|
|
|
#[cfg(unix)]
|
|
use std::fs::File;
|
|
#[cfg(unix)]
|
|
use std::fs::{Permissions, set_permissions};
|
|
#[cfg(unix)]
|
|
use std::io::{Read as _, Write as _};
|
|
#[cfg(target_os = "linux")]
|
|
use std::os::unix::ffi::OsStrExt;
|
|
#[cfg(unix)]
|
|
use std::os::unix::fs::PermissionsExt;
|
|
#[cfg(unix)]
|
|
use uutests::util::pty_path;
|
|
#[cfg(unix)]
|
|
use uutests::{at_and_ucmd, new_ucmd};
|
|
|
|
#[cfg(unix)]
|
|
fn run_more_with_pty(
|
|
args: &[&str],
|
|
file: &str,
|
|
content: &str,
|
|
) -> (uutests::util::UChild, File, String) {
|
|
let (path, mut controller, _replica) = pty_path();
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
at.write(file, content);
|
|
|
|
let mut child = ucmd
|
|
.set_stdin(File::open(&path).unwrap())
|
|
.set_stdout(File::create(&path).unwrap())
|
|
.args(args)
|
|
.arg(file)
|
|
.run_no_wait();
|
|
|
|
child.delay(200);
|
|
let mut output = vec![0u8; 1024];
|
|
let n = controller.read(&mut output).unwrap();
|
|
let output_str = String::from_utf8_lossy(&output[..n]).to_string();
|
|
|
|
(child, controller, output_str)
|
|
}
|
|
|
|
#[cfg(unix)]
|
|
fn quit_more(controller: &mut File, mut child: uutests::util::UChild) {
|
|
controller.write_all(b"q").unwrap();
|
|
child.delay(50);
|
|
}
|
|
|
|
#[cfg(unix)]
|
|
#[test]
|
|
fn test_no_arg() {
|
|
let (path, _controller, _replica) = pty_path();
|
|
new_ucmd!()
|
|
.set_stdin(File::open(&path).unwrap())
|
|
.set_stdout(File::create(&path).unwrap())
|
|
.fails()
|
|
.stderr_contains("more: bad usage");
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(unix)]
|
|
fn test_valid_arg() {
|
|
let args_list: Vec<&[&str]> = vec![
|
|
&["-c"],
|
|
&["--clean-print"],
|
|
&["-p"],
|
|
&["--print-over"],
|
|
&["-s"],
|
|
&["--squeeze"],
|
|
&["-u"],
|
|
&["--plain"],
|
|
&["-n", "10"],
|
|
&["--lines", "0"],
|
|
&["--number", "0"],
|
|
&["-F", "10"],
|
|
&["--from-line", "0"],
|
|
&["-P", "something"],
|
|
&["--pattern", "-1"],
|
|
];
|
|
for args in args_list {
|
|
test_alive(args);
|
|
}
|
|
}
|
|
|
|
#[cfg(unix)]
|
|
fn test_alive(args: &[&str]) {
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
let (path, mut controller, _replica) = pty_path();
|
|
|
|
let content = "test content";
|
|
let file = "test_file";
|
|
at.write(file, content);
|
|
|
|
let mut child = ucmd
|
|
.set_stdin(File::open(&path).unwrap())
|
|
.set_stdout(File::create(&path).unwrap())
|
|
.args(args)
|
|
.arg(file)
|
|
.run_no_wait();
|
|
|
|
// wait for more to start and display the file
|
|
child.delay(100);
|
|
|
|
assert!(child.is_alive(), "Command should still be alive");
|
|
|
|
// cleanup
|
|
controller.write_all(b"q").unwrap();
|
|
child.delay(50);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(unix)]
|
|
fn test_invalid_arg() {
|
|
let (path, _controller, _replica) = pty_path();
|
|
new_ucmd!()
|
|
.set_stdin(File::open(&path).unwrap())
|
|
.set_stdout(File::create(&path).unwrap())
|
|
.arg("--invalid")
|
|
.fails();
|
|
|
|
let (path, _controller, _replica) = pty_path();
|
|
new_ucmd!()
|
|
.set_stdin(File::open(&path).unwrap())
|
|
.set_stdout(File::create(&path).unwrap())
|
|
.arg("--lines")
|
|
.arg("-10")
|
|
.fails();
|
|
|
|
let (path, _controller, _replica) = pty_path();
|
|
new_ucmd!()
|
|
.set_stdin(File::open(&path).unwrap())
|
|
.set_stdout(File::create(&path).unwrap())
|
|
.arg("--from-line")
|
|
.arg("-10")
|
|
.fails();
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(unix)]
|
|
fn test_file_arg() {
|
|
// Directory as argument
|
|
let (path, _controller, _replica) = pty_path();
|
|
new_ucmd!()
|
|
.set_stdin(File::open(&path).unwrap())
|
|
.set_stdout(File::create(&path).unwrap())
|
|
.arg(".")
|
|
.succeeds()
|
|
.stderr_contains("'.' is a directory.");
|
|
|
|
// Single argument errors
|
|
let (path, _controller, _replica) = pty_path();
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
at.mkdir_all("folder");
|
|
ucmd.set_stdin(File::open(&path).unwrap())
|
|
.set_stdout(File::create(&path).unwrap())
|
|
.arg("folder")
|
|
.succeeds()
|
|
.stderr_contains("is a directory");
|
|
|
|
let (path, _controller, _replica) = pty_path();
|
|
new_ucmd!()
|
|
.set_stdin(File::open(&path).unwrap())
|
|
.set_stdout(File::create(&path).unwrap())
|
|
.arg("nonexistent_file")
|
|
.succeeds()
|
|
.stderr_contains("No such file or directory");
|
|
|
|
// Multiple nonexistent files
|
|
let (path, _controller, _replica) = pty_path();
|
|
new_ucmd!()
|
|
.set_stdin(File::open(&path).unwrap())
|
|
.set_stdout(File::create(&path).unwrap())
|
|
.arg("file2")
|
|
.arg("file3")
|
|
.succeeds()
|
|
.stderr_contains("file2")
|
|
.stderr_contains("file3");
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(unix)]
|
|
fn test_invalid_file_perms() {
|
|
let (path, _controller, _replica) = pty_path();
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
let permissions = Permissions::from_mode(0o244);
|
|
at.make_file("invalid-perms.txt");
|
|
set_permissions(at.plus("invalid-perms.txt"), permissions).unwrap();
|
|
ucmd.set_stdin(File::open(&path).unwrap())
|
|
.set_stdout(File::create(&path).unwrap())
|
|
.arg("invalid-perms.txt")
|
|
.succeeds()
|
|
.stderr_contains("permission denied");
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(target_os = "linux")]
|
|
fn test_more_non_utf8_paths() {
|
|
let (path, _controller, _replica) = pty_path();
|
|
let (at, mut ucmd) = at_and_ucmd!();
|
|
let file_name = std::ffi::OsStr::from_bytes(b"test_\xFF\xFE.txt");
|
|
// Create test file with normal name first
|
|
at.write(
|
|
&file_name.to_string_lossy(),
|
|
"test content for non-UTF-8 file",
|
|
);
|
|
|
|
// Test that more can handle non-UTF-8 filenames without crashing
|
|
ucmd.set_stdin(File::open(&path).unwrap())
|
|
.set_stdout(File::create(&path).unwrap())
|
|
.arg(file_name)
|
|
.succeeds();
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(unix)]
|
|
fn test_basic_display() {
|
|
let (child, mut controller, output) =
|
|
run_more_with_pty(&[], "test.txt", "line1\nline2\nline3\n");
|
|
assert!(output.contains("line1"));
|
|
quit_more(&mut controller, child);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(unix)]
|
|
fn test_squeeze_blank_lines() {
|
|
let (child, mut controller, output) =
|
|
run_more_with_pty(&["-s"], "test.txt", "line1\n\n\n\nline2\n");
|
|
assert!(output.contains("line1"));
|
|
quit_more(&mut controller, child);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(unix)]
|
|
fn test_pattern_search() {
|
|
let (child, mut controller, output) = run_more_with_pty(
|
|
&["-P", "target"],
|
|
"test.txt",
|
|
"foo\nbar\nbaz\ntarget\nend\n",
|
|
);
|
|
assert!(output.contains("target"));
|
|
assert!(!output.contains("foo"));
|
|
quit_more(&mut controller, child);
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(unix)]
|
|
fn test_from_line_option() {
|
|
let (child, mut controller, output) =
|
|
run_more_with_pty(&["-F", "2"], "test.txt", "line1\nline2\nline3\nline4\n");
|
|
assert!(output.contains("line2"));
|
|
assert!(!output.contains("line1"));
|
|
quit_more(&mut controller, child);
|
|
}
|