2021-05-30 05:10:54 +00:00
|
|
|
// spell-checker:ignore (words) READMECAREFULLY birthtime doesntexist oneline somebackup somefile somegroup somehiddenbackup somehiddenfile
|
|
|
|
|
2021-03-29 11:10:13 +00:00
|
|
|
#[cfg(unix)]
|
|
|
|
extern crate unix_socket;
|
2020-05-25 17:05:26 +00:00
|
|
|
use crate::common::util::*;
|
2016-03-25 21:25:52 +00:00
|
|
|
|
2020-12-14 20:46:18 +00:00
|
|
|
extern crate regex;
|
|
|
|
use self::regex::Regex;
|
|
|
|
|
2021-05-05 21:03:25 +00:00
|
|
|
use std::collections::HashMap;
|
2021-04-16 16:27:36 +00:00
|
|
|
use std::path::Path;
|
2020-12-14 20:46:18 +00:00
|
|
|
use std::thread::sleep;
|
|
|
|
use std::time::Duration;
|
|
|
|
|
|
|
|
#[cfg(not(windows))]
|
|
|
|
extern crate libc;
|
|
|
|
#[cfg(not(windows))]
|
|
|
|
use self::libc::umask;
|
|
|
|
#[cfg(not(windows))]
|
2021-03-29 11:10:13 +00:00
|
|
|
use std::path::PathBuf;
|
|
|
|
#[cfg(not(windows))]
|
2020-12-14 20:46:18 +00:00
|
|
|
use std::sync::Mutex;
|
2021-03-29 11:10:13 +00:00
|
|
|
#[cfg(not(windows))]
|
2021-05-27 20:47:03 +00:00
|
|
|
extern crate tempfile;
|
2020-12-14 20:46:18 +00:00
|
|
|
|
|
|
|
#[cfg(not(windows))]
|
|
|
|
lazy_static! {
|
|
|
|
static ref UMASK_MUTEX: Mutex<()> = Mutex::new(());
|
|
|
|
}
|
|
|
|
|
2016-03-25 21:25:52 +00:00
|
|
|
#[test]
|
|
|
|
fn test_ls_ls() {
|
2016-08-23 11:52:43 +00:00
|
|
|
new_ucmd!().succeeds();
|
2016-05-22 07:46:54 +00:00
|
|
|
}
|
2016-12-25 05:32:12 +00:00
|
|
|
|
|
|
|
#[test]
|
2020-12-14 20:46:18 +00:00
|
|
|
fn test_ls_i() {
|
2016-12-25 05:32:12 +00:00
|
|
|
new_ucmd!().arg("-i").succeeds();
|
|
|
|
new_ucmd!().arg("-il").succeeds();
|
|
|
|
}
|
ls: implement --color flag
GNU coreutils ls command implements the --color option as follow:
--color[=WHEN]
colorize the output; WHEN can be 'always' (default if omitted),
'auto', or 'never'
With --color=auto, ls emits color codes only when standard output is connected
to a terminal.
Also, add support for the following aliases:
- ‘always’, ‘yes’, ‘force’
- ‘never’, ‘no’, ‘none’
- ‘auto’, ‘tty’, ‘if-tty’
Signed-off-by: Gabriel Ganne <gabriel.ganne@gmail.com>
2019-06-20 07:55:01 +00:00
|
|
|
|
2020-12-14 20:46:18 +00:00
|
|
|
#[test]
|
|
|
|
fn test_ls_a() {
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
at.touch(".test-1");
|
2021-05-02 08:03:01 +00:00
|
|
|
at.mkdir("some-dir");
|
|
|
|
at.touch(
|
|
|
|
Path::new("some-dir")
|
|
|
|
.join(".test-2")
|
|
|
|
.as_os_str()
|
|
|
|
.to_str()
|
|
|
|
.unwrap(),
|
|
|
|
);
|
2020-12-14 20:46:18 +00:00
|
|
|
|
2021-05-29 12:32:35 +00:00
|
|
|
#[allow(clippy::trivial_regex)]
|
2021-05-02 08:03:01 +00:00
|
|
|
let re_pwd = Regex::new(r"^\.\n").unwrap();
|
|
|
|
|
|
|
|
// Using the present working directory
|
|
|
|
scene
|
|
|
|
.ucmd()
|
2021-05-02 12:26:23 +00:00
|
|
|
.arg("-1")
|
2021-05-02 08:03:01 +00:00
|
|
|
.succeeds()
|
|
|
|
.stdout_does_not_contain(".test-1")
|
|
|
|
.stdout_does_not_contain("..")
|
|
|
|
.stdout_does_not_match(&re_pwd);
|
2021-04-07 09:48:01 +00:00
|
|
|
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-a")
|
2021-05-02 12:26:23 +00:00
|
|
|
.arg("-1")
|
2021-04-07 09:48:01 +00:00
|
|
|
.succeeds()
|
|
|
|
.stdout_contains(&".test-1")
|
2021-05-02 08:03:01 +00:00
|
|
|
.stdout_contains(&"..")
|
|
|
|
.stdout_matches(&re_pwd);
|
|
|
|
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-A")
|
2021-05-02 12:26:23 +00:00
|
|
|
.arg("-1")
|
2021-05-02 08:03:01 +00:00
|
|
|
.succeeds()
|
|
|
|
.stdout_contains(".test-1")
|
|
|
|
.stdout_does_not_contain("..")
|
|
|
|
.stdout_does_not_match(&re_pwd);
|
2021-04-07 09:48:01 +00:00
|
|
|
|
2021-05-02 08:03:01 +00:00
|
|
|
// Using a subdirectory
|
|
|
|
scene
|
|
|
|
.ucmd()
|
2021-05-02 12:26:23 +00:00
|
|
|
.arg("-1")
|
2021-05-02 08:03:01 +00:00
|
|
|
.arg("some-dir")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_does_not_contain(".test-2")
|
|
|
|
.stdout_does_not_contain("..")
|
|
|
|
.stdout_does_not_match(&re_pwd);
|
|
|
|
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-a")
|
2021-05-02 12:26:23 +00:00
|
|
|
.arg("-1")
|
2021-05-02 08:03:01 +00:00
|
|
|
.arg("some-dir")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains(&".test-2")
|
|
|
|
.stdout_contains(&"..")
|
|
|
|
.no_stderr()
|
|
|
|
.stdout_matches(&re_pwd);
|
2021-04-07 09:48:01 +00:00
|
|
|
|
2021-05-02 08:03:01 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-A")
|
2021-05-02 12:26:23 +00:00
|
|
|
.arg("-1")
|
2021-05-02 08:03:01 +00:00
|
|
|
.arg("some-dir")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains(".test-2")
|
|
|
|
.stdout_does_not_contain("..")
|
|
|
|
.stdout_does_not_match(&re_pwd);
|
2020-12-14 20:46:18 +00:00
|
|
|
}
|
|
|
|
|
2021-03-22 17:24:23 +00:00
|
|
|
#[test]
|
|
|
|
fn test_ls_width() {
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
at.touch(&at.plus_as_string("test-width-1"));
|
|
|
|
at.touch(&at.plus_as_string("test-width-2"));
|
|
|
|
at.touch(&at.plus_as_string("test-width-3"));
|
|
|
|
at.touch(&at.plus_as_string("test-width-4"));
|
|
|
|
|
|
|
|
for option in &["-w 100", "-w=100", "--width=100", "--width 100"] {
|
2021-04-07 09:48:01 +00:00
|
|
|
scene
|
2021-03-22 17:24:23 +00:00
|
|
|
.ucmd()
|
2021-05-29 12:32:35 +00:00
|
|
|
.args(&option.split(' ').collect::<Vec<_>>())
|
2021-08-11 20:03:41 +00:00
|
|
|
.arg("-C")
|
2021-04-07 09:48:01 +00:00
|
|
|
.succeeds()
|
|
|
|
.stdout_only("test-width-1 test-width-2 test-width-3 test-width-4\n");
|
2021-03-22 17:24:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for option in &["-w 50", "-w=50", "--width=50", "--width 50"] {
|
2021-04-07 09:48:01 +00:00
|
|
|
scene
|
2021-03-22 17:24:23 +00:00
|
|
|
.ucmd()
|
2021-05-29 12:32:35 +00:00
|
|
|
.args(&option.split(' ').collect::<Vec<_>>())
|
2021-08-11 20:03:41 +00:00
|
|
|
.arg("-C")
|
2021-04-07 09:48:01 +00:00
|
|
|
.succeeds()
|
|
|
|
.stdout_only("test-width-1 test-width-3\ntest-width-2 test-width-4\n");
|
2021-03-22 17:24:23 +00:00
|
|
|
}
|
|
|
|
|
2021-08-11 13:53:39 +00:00
|
|
|
for option in &["-w 25", "-w=25", "--width=25", "--width 25"] {
|
2021-04-07 09:48:01 +00:00
|
|
|
scene
|
2021-03-22 17:24:23 +00:00
|
|
|
.ucmd()
|
2021-05-29 12:32:35 +00:00
|
|
|
.args(&option.split(' ').collect::<Vec<_>>())
|
2021-08-11 20:03:41 +00:00
|
|
|
.arg("-C")
|
2021-04-07 09:48:01 +00:00
|
|
|
.succeeds()
|
|
|
|
.stdout_only("test-width-1\ntest-width-2\ntest-width-3\ntest-width-4\n");
|
2021-03-22 17:24:23 +00:00
|
|
|
}
|
2021-04-22 07:19:17 +00:00
|
|
|
|
2021-08-11 13:53:39 +00:00
|
|
|
for option in &["-w 0", "-w=0", "--width=0", "--width 0"] {
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.args(&option.split(' ').collect::<Vec<_>>())
|
2021-08-11 20:03:41 +00:00
|
|
|
.arg("-C")
|
2021-08-11 13:53:39 +00:00
|
|
|
.succeeds()
|
|
|
|
.stdout_only("test-width-1 test-width-2 test-width-3 test-width-4\n");
|
|
|
|
}
|
|
|
|
|
2021-04-21 10:03:48 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-w=bad")
|
2021-08-11 20:03:41 +00:00
|
|
|
.arg("-C")
|
2021-04-21 10:03:48 +00:00
|
|
|
.fails()
|
|
|
|
.stderr_contains("invalid line width");
|
2021-04-22 12:23:35 +00:00
|
|
|
|
2021-04-22 07:19:17 +00:00
|
|
|
for option in &["-w 1a", "-w=1a", "--width=1a", "--width 1a"] {
|
|
|
|
scene
|
|
|
|
.ucmd()
|
2021-05-29 12:32:35 +00:00
|
|
|
.args(&option.split(' ').collect::<Vec<_>>())
|
2021-08-11 20:03:41 +00:00
|
|
|
.arg("-C")
|
2021-04-22 07:19:17 +00:00
|
|
|
.fails()
|
2021-06-21 22:22:30 +00:00
|
|
|
.stderr_only("ls: invalid line width: '1a'");
|
2021-04-22 07:19:17 +00:00
|
|
|
}
|
2021-03-22 17:24:23 +00:00
|
|
|
}
|
|
|
|
|
2021-03-15 12:46:21 +00:00
|
|
|
#[test]
|
|
|
|
fn test_ls_columns() {
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
at.touch(&at.plus_as_string("test-columns-1"));
|
|
|
|
at.touch(&at.plus_as_string("test-columns-2"));
|
2021-03-22 17:24:23 +00:00
|
|
|
at.touch(&at.plus_as_string("test-columns-3"));
|
|
|
|
at.touch(&at.plus_as_string("test-columns-4"));
|
2021-03-15 12:46:21 +00:00
|
|
|
|
|
|
|
// Columns is the default
|
2021-04-07 09:48:01 +00:00
|
|
|
let result = scene.ucmd().succeeds();
|
2021-03-15 12:46:21 +00:00
|
|
|
|
2021-08-11 20:03:41 +00:00
|
|
|
result.stdout_only("test-columns-1\ntest-columns-2\ntest-columns-3\ntest-columns-4\n");
|
2021-03-15 12:46:21 +00:00
|
|
|
|
|
|
|
for option in &["-C", "--format=columns"] {
|
2021-04-07 09:48:01 +00:00
|
|
|
let result = scene.ucmd().arg(option).succeeds();
|
|
|
|
result.stdout_only("test-columns-1 test-columns-2 test-columns-3 test-columns-4\n");
|
2021-03-22 17:24:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for option in &["-C", "--format=columns"] {
|
2021-04-07 09:48:01 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-w=40")
|
|
|
|
.arg(option)
|
|
|
|
.succeeds()
|
|
|
|
.stdout_only("test-columns-1 test-columns-3\ntest-columns-2 test-columns-4\n");
|
2021-03-22 17:24:23 +00:00
|
|
|
}
|
2021-08-11 12:32:46 +00:00
|
|
|
|
2021-08-11 13:53:39 +00:00
|
|
|
// On windows we are always able to get the terminal size, so we can't simulate falling back to the
|
|
|
|
// environment variable.
|
|
|
|
#[cfg(not(windows))]
|
|
|
|
{
|
|
|
|
for option in &["-C", "--format=columns"] {
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.env("COLUMNS", "40")
|
|
|
|
.arg(option)
|
|
|
|
.succeeds()
|
|
|
|
.stdout_only("test-columns-1 test-columns-3\ntest-columns-2 test-columns-4\n");
|
|
|
|
}
|
|
|
|
|
2021-08-11 12:32:46 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
2021-08-11 13:53:39 +00:00
|
|
|
.env("COLUMNS", "garbage")
|
2021-08-11 20:03:41 +00:00
|
|
|
.arg("-C")
|
2021-08-11 12:32:46 +00:00
|
|
|
.succeeds()
|
2021-08-11 13:53:39 +00:00
|
|
|
.stdout_is("test-columns-1 test-columns-2 test-columns-3 test-columns-4\n")
|
|
|
|
.stderr_is("ls: ignoring invalid width in environment variable COLUMNS: 'garbage'");
|
2021-08-11 12:32:46 +00:00
|
|
|
}
|
|
|
|
scene
|
|
|
|
.ucmd()
|
2021-08-11 20:03:41 +00:00
|
|
|
.arg("-Cw0")
|
2021-08-11 13:53:39 +00:00
|
|
|
.succeeds()
|
|
|
|
.stdout_only("test-columns-1 test-columns-2 test-columns-3 test-columns-4\n");
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-mw0")
|
2021-08-11 12:32:46 +00:00
|
|
|
.succeeds()
|
2021-08-11 13:53:39 +00:00
|
|
|
.stdout_only("test-columns-1, test-columns-2, test-columns-3, test-columns-4\n");
|
2021-03-22 17:24:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_ls_across() {
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
at.touch(&at.plus_as_string("test-across-1"));
|
|
|
|
at.touch(&at.plus_as_string("test-across-2"));
|
|
|
|
at.touch(&at.plus_as_string("test-across-3"));
|
|
|
|
at.touch(&at.plus_as_string("test-across-4"));
|
|
|
|
|
|
|
|
for option in &["-x", "--format=across"] {
|
|
|
|
let result = scene.ucmd().arg(option).succeeds();
|
|
|
|
// Because the test terminal has width 0, this is the same output as
|
|
|
|
// the columns option.
|
2021-08-11 12:32:46 +00:00
|
|
|
result.stdout_only("test-across-1 test-across-2 test-across-3 test-across-4\n");
|
2021-03-22 17:24:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for option in &["-x", "--format=across"] {
|
|
|
|
// Because the test terminal has width 0, this is the same output as
|
|
|
|
// the columns option.
|
2021-04-07 09:48:01 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-w=30")
|
|
|
|
.arg(option)
|
|
|
|
.succeeds()
|
|
|
|
.stdout_only("test-across-1 test-across-2\ntest-across-3 test-across-4\n");
|
2021-03-22 17:24:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_ls_commas() {
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
at.touch(&at.plus_as_string("test-commas-1"));
|
|
|
|
at.touch(&at.plus_as_string("test-commas-2"));
|
|
|
|
at.touch(&at.plus_as_string("test-commas-3"));
|
|
|
|
at.touch(&at.plus_as_string("test-commas-4"));
|
|
|
|
|
|
|
|
for option in &["-m", "--format=commas"] {
|
|
|
|
let result = scene.ucmd().arg(option).succeeds();
|
2021-08-11 12:32:46 +00:00
|
|
|
result.stdout_only("test-commas-1, test-commas-2, test-commas-3, test-commas-4\n");
|
2021-03-22 17:24:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for option in &["-m", "--format=commas"] {
|
2021-04-07 09:48:01 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-w=30")
|
|
|
|
.arg(option)
|
|
|
|
.succeeds()
|
|
|
|
.stdout_only("test-commas-1, test-commas-2,\ntest-commas-3, test-commas-4\n");
|
2021-03-22 17:24:23 +00:00
|
|
|
}
|
|
|
|
for option in &["-m", "--format=commas"] {
|
2021-04-07 09:48:01 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-w=45")
|
|
|
|
.arg(option)
|
|
|
|
.succeeds()
|
|
|
|
.stdout_only("test-commas-1, test-commas-2, test-commas-3,\ntest-commas-4\n");
|
2021-03-15 12:46:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-14 20:46:18 +00:00
|
|
|
#[test]
|
|
|
|
fn test_ls_long() {
|
|
|
|
#[cfg(not(windows))]
|
2020-12-15 12:36:12 +00:00
|
|
|
let last;
|
2020-12-14 20:46:18 +00:00
|
|
|
#[cfg(not(windows))]
|
|
|
|
{
|
|
|
|
let _guard = UMASK_MUTEX.lock();
|
|
|
|
last = unsafe { umask(0) };
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
umask(0o002);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-15 12:46:21 +00:00
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
2020-12-14 20:46:18 +00:00
|
|
|
at.touch(&at.plus_as_string("test-long"));
|
|
|
|
|
2021-03-15 12:46:21 +00:00
|
|
|
for arg in &["-l", "--long", "--format=long", "--format=verbose"] {
|
|
|
|
let result = scene.ucmd().arg(arg).arg("test-long").succeeds();
|
|
|
|
#[cfg(not(windows))]
|
2021-04-07 09:48:01 +00:00
|
|
|
result.stdout_contains("-rw-rw-r--");
|
2021-03-15 12:46:21 +00:00
|
|
|
|
|
|
|
#[cfg(windows)]
|
2021-04-07 09:48:01 +00:00
|
|
|
result.stdout_contains("---------- 1 somebody somegroup");
|
2021-03-15 12:46:21 +00:00
|
|
|
}
|
2020-12-14 20:46:18 +00:00
|
|
|
|
|
|
|
#[cfg(not(windows))]
|
|
|
|
{
|
|
|
|
unsafe {
|
|
|
|
umask(last);
|
|
|
|
}
|
2021-05-05 21:03:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_ls_long_total_size() {
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
at.touch(&at.plus_as_string("test-long"));
|
|
|
|
at.append("test-long", "1");
|
|
|
|
at.touch(&at.plus_as_string("test-long2"));
|
|
|
|
at.append("test-long2", "2");
|
|
|
|
|
|
|
|
let expected_prints: HashMap<_, _> = if cfg!(unix) {
|
|
|
|
[
|
|
|
|
("long_vanilla", "total 8"),
|
|
|
|
("long_human_readable", "total 8.0K"),
|
|
|
|
("long_si", "total 8.2k"),
|
|
|
|
]
|
|
|
|
.iter()
|
|
|
|
.cloned()
|
|
|
|
.collect()
|
|
|
|
} else {
|
|
|
|
[
|
|
|
|
("long_vanilla", "total 2"),
|
|
|
|
("long_human_readable", "total 2"),
|
|
|
|
("long_si", "total 2"),
|
|
|
|
]
|
|
|
|
.iter()
|
|
|
|
.cloned()
|
|
|
|
.collect()
|
|
|
|
};
|
|
|
|
|
|
|
|
for arg in &["-l", "--long", "--format=long", "--format=verbose"] {
|
|
|
|
let result = scene.ucmd().arg(arg).succeeds();
|
|
|
|
result.stdout_contains(expected_prints["long_vanilla"]);
|
|
|
|
|
|
|
|
for arg2 in &["-h", "--human-readable", "--si"] {
|
|
|
|
let result = scene.ucmd().arg(arg).arg(arg2).succeeds();
|
|
|
|
result.stdout_contains(if *arg2 == "--si" {
|
|
|
|
expected_prints["long_si"]
|
|
|
|
} else {
|
|
|
|
expected_prints["long_human_readable"]
|
|
|
|
});
|
|
|
|
}
|
2020-12-14 20:46:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
ls: long format author, group and owner (#1850)
This PR adds the options to customize what information is shown in long format regarding author, group & owner. Specifically it adds:
- `--author`: shows the author, which is always the same as the owner. GNU has this feature because GNU/Hurd supports a difference between author and owner, but I don't think Rust supports GNU/Hurd, so I just used the owner.
- `-G` & `--no-group`: hide the group information.
- `-o`: hide the group and use long format (equivalent to `-lG`).
- `-g`: hide the owner and use long format.
The `-o` and `-g` options have some interesting behaviour that I had to account for. Some examples:
- `-og` hides both group and owner.
- `-ol` still hides the group. Same behaviour with variations such as `-o --format=long`, `-gl`, `-g --format=long` and `-ogl`.
- They even retain some information when overridden by another format: `-oCl` (or `-o --format=vertical --format=long`) still hides the group.
My previous solution for handling the behaviour where `-l1` shows the long format did not fit with these additions, so I had to rewrite that as well.
The tests only cover the how many names (author, group and owner) are present in the output, so it can't distinguish between, for example, author & group and group & owner.
2021-03-21 15:18:06 +00:00
|
|
|
#[test]
|
|
|
|
fn test_ls_long_formats() {
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
at.touch(&at.plus_as_string("test-long-formats"));
|
|
|
|
|
|
|
|
// Regex for three names, so all of author, group and owner
|
|
|
|
let re_three = Regex::new(r"[xrw-]{9} \d ([-0-9_a-z]+ ){3}0").unwrap();
|
|
|
|
|
2021-03-26 18:12:01 +00:00
|
|
|
#[cfg(unix)]
|
|
|
|
let re_three_num = Regex::new(r"[xrw-]{9} \d (\d+ ){3}0").unwrap();
|
|
|
|
|
ls: long format author, group and owner (#1850)
This PR adds the options to customize what information is shown in long format regarding author, group & owner. Specifically it adds:
- `--author`: shows the author, which is always the same as the owner. GNU has this feature because GNU/Hurd supports a difference between author and owner, but I don't think Rust supports GNU/Hurd, so I just used the owner.
- `-G` & `--no-group`: hide the group information.
- `-o`: hide the group and use long format (equivalent to `-lG`).
- `-g`: hide the owner and use long format.
The `-o` and `-g` options have some interesting behaviour that I had to account for. Some examples:
- `-og` hides both group and owner.
- `-ol` still hides the group. Same behaviour with variations such as `-o --format=long`, `-gl`, `-g --format=long` and `-ogl`.
- They even retain some information when overridden by another format: `-oCl` (or `-o --format=vertical --format=long`) still hides the group.
My previous solution for handling the behaviour where `-l1` shows the long format did not fit with these additions, so I had to rewrite that as well.
The tests only cover the how many names (author, group and owner) are present in the output, so it can't distinguish between, for example, author & group and group & owner.
2021-03-21 15:18:06 +00:00
|
|
|
// Regex for two names, either:
|
|
|
|
// - group and owner
|
|
|
|
// - author and owner
|
|
|
|
// - author and group
|
|
|
|
let re_two = Regex::new(r"[xrw-]{9} \d ([-0-9_a-z]+ ){2}0").unwrap();
|
|
|
|
|
2021-03-26 18:12:01 +00:00
|
|
|
#[cfg(unix)]
|
|
|
|
let re_two_num = Regex::new(r"[xrw-]{9} \d (\d+ ){2}0").unwrap();
|
|
|
|
|
ls: long format author, group and owner (#1850)
This PR adds the options to customize what information is shown in long format regarding author, group & owner. Specifically it adds:
- `--author`: shows the author, which is always the same as the owner. GNU has this feature because GNU/Hurd supports a difference between author and owner, but I don't think Rust supports GNU/Hurd, so I just used the owner.
- `-G` & `--no-group`: hide the group information.
- `-o`: hide the group and use long format (equivalent to `-lG`).
- `-g`: hide the owner and use long format.
The `-o` and `-g` options have some interesting behaviour that I had to account for. Some examples:
- `-og` hides both group and owner.
- `-ol` still hides the group. Same behaviour with variations such as `-o --format=long`, `-gl`, `-g --format=long` and `-ogl`.
- They even retain some information when overridden by another format: `-oCl` (or `-o --format=vertical --format=long`) still hides the group.
My previous solution for handling the behaviour where `-l1` shows the long format did not fit with these additions, so I had to rewrite that as well.
The tests only cover the how many names (author, group and owner) are present in the output, so it can't distinguish between, for example, author & group and group & owner.
2021-03-21 15:18:06 +00:00
|
|
|
// Regex for one name: author, group or owner
|
|
|
|
let re_one = Regex::new(r"[xrw-]{9} \d [-0-9_a-z]+ 0").unwrap();
|
|
|
|
|
2021-03-26 18:12:01 +00:00
|
|
|
#[cfg(unix)]
|
|
|
|
let re_one_num = Regex::new(r"[xrw-]{9} \d \d+ 0").unwrap();
|
|
|
|
|
ls: long format author, group and owner (#1850)
This PR adds the options to customize what information is shown in long format regarding author, group & owner. Specifically it adds:
- `--author`: shows the author, which is always the same as the owner. GNU has this feature because GNU/Hurd supports a difference between author and owner, but I don't think Rust supports GNU/Hurd, so I just used the owner.
- `-G` & `--no-group`: hide the group information.
- `-o`: hide the group and use long format (equivalent to `-lG`).
- `-g`: hide the owner and use long format.
The `-o` and `-g` options have some interesting behaviour that I had to account for. Some examples:
- `-og` hides both group and owner.
- `-ol` still hides the group. Same behaviour with variations such as `-o --format=long`, `-gl`, `-g --format=long` and `-ogl`.
- They even retain some information when overridden by another format: `-oCl` (or `-o --format=vertical --format=long`) still hides the group.
My previous solution for handling the behaviour where `-l1` shows the long format did not fit with these additions, so I had to rewrite that as well.
The tests only cover the how many names (author, group and owner) are present in the output, so it can't distinguish between, for example, author & group and group & owner.
2021-03-21 15:18:06 +00:00
|
|
|
// Regex for no names
|
|
|
|
let re_zero = Regex::new(r"[xrw-]{9} \d 0").unwrap();
|
|
|
|
|
|
|
|
let result = scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-l")
|
|
|
|
.arg("--author")
|
|
|
|
.arg("test-long-formats")
|
2021-04-07 09:48:01 +00:00
|
|
|
.succeeds();
|
|
|
|
assert!(re_three.is_match(result.stdout_str()));
|
ls: long format author, group and owner (#1850)
This PR adds the options to customize what information is shown in long format regarding author, group & owner. Specifically it adds:
- `--author`: shows the author, which is always the same as the owner. GNU has this feature because GNU/Hurd supports a difference between author and owner, but I don't think Rust supports GNU/Hurd, so I just used the owner.
- `-G` & `--no-group`: hide the group information.
- `-o`: hide the group and use long format (equivalent to `-lG`).
- `-g`: hide the owner and use long format.
The `-o` and `-g` options have some interesting behaviour that I had to account for. Some examples:
- `-og` hides both group and owner.
- `-ol` still hides the group. Same behaviour with variations such as `-o --format=long`, `-gl`, `-g --format=long` and `-ogl`.
- They even retain some information when overridden by another format: `-oCl` (or `-o --format=vertical --format=long`) still hides the group.
My previous solution for handling the behaviour where `-l1` shows the long format did not fit with these additions, so I had to rewrite that as well.
The tests only cover the how many names (author, group and owner) are present in the output, so it can't distinguish between, for example, author & group and group & owner.
2021-03-21 15:18:06 +00:00
|
|
|
|
|
|
|
let result = scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-l1")
|
|
|
|
.arg("--author")
|
|
|
|
.arg("test-long-formats")
|
2021-04-07 09:48:01 +00:00
|
|
|
.succeeds();
|
2021-06-06 19:13:54 +00:00
|
|
|
assert!(re_three.is_match(result.stdout_str()));
|
ls: long format author, group and owner (#1850)
This PR adds the options to customize what information is shown in long format regarding author, group & owner. Specifically it adds:
- `--author`: shows the author, which is always the same as the owner. GNU has this feature because GNU/Hurd supports a difference between author and owner, but I don't think Rust supports GNU/Hurd, so I just used the owner.
- `-G` & `--no-group`: hide the group information.
- `-o`: hide the group and use long format (equivalent to `-lG`).
- `-g`: hide the owner and use long format.
The `-o` and `-g` options have some interesting behaviour that I had to account for. Some examples:
- `-og` hides both group and owner.
- `-ol` still hides the group. Same behaviour with variations such as `-o --format=long`, `-gl`, `-g --format=long` and `-ogl`.
- They even retain some information when overridden by another format: `-oCl` (or `-o --format=vertical --format=long`) still hides the group.
My previous solution for handling the behaviour where `-l1` shows the long format did not fit with these additions, so I had to rewrite that as well.
The tests only cover the how many names (author, group and owner) are present in the output, so it can't distinguish between, for example, author & group and group & owner.
2021-03-21 15:18:06 +00:00
|
|
|
|
2021-03-26 18:12:01 +00:00
|
|
|
#[cfg(unix)]
|
|
|
|
{
|
|
|
|
let result = scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-n")
|
|
|
|
.arg("--author")
|
|
|
|
.arg("test-long-formats")
|
|
|
|
.succeeds();
|
2021-04-07 09:48:01 +00:00
|
|
|
assert!(re_three_num.is_match(result.stdout_str()));
|
2021-03-26 18:12:01 +00:00
|
|
|
}
|
|
|
|
|
ls: long format author, group and owner (#1850)
This PR adds the options to customize what information is shown in long format regarding author, group & owner. Specifically it adds:
- `--author`: shows the author, which is always the same as the owner. GNU has this feature because GNU/Hurd supports a difference between author and owner, but I don't think Rust supports GNU/Hurd, so I just used the owner.
- `-G` & `--no-group`: hide the group information.
- `-o`: hide the group and use long format (equivalent to `-lG`).
- `-g`: hide the owner and use long format.
The `-o` and `-g` options have some interesting behaviour that I had to account for. Some examples:
- `-og` hides both group and owner.
- `-ol` still hides the group. Same behaviour with variations such as `-o --format=long`, `-gl`, `-g --format=long` and `-ogl`.
- They even retain some information when overridden by another format: `-oCl` (or `-o --format=vertical --format=long`) still hides the group.
My previous solution for handling the behaviour where `-l1` shows the long format did not fit with these additions, so I had to rewrite that as well.
The tests only cover the how many names (author, group and owner) are present in the output, so it can't distinguish between, for example, author & group and group & owner.
2021-03-21 15:18:06 +00:00
|
|
|
for arg in &[
|
|
|
|
"-l", // only group and owner
|
|
|
|
"-g --author", // only author and group
|
|
|
|
"-o --author", // only author and owner
|
|
|
|
"-lG --author", // only author and owner
|
|
|
|
"-l --no-group --author", // only author and owner
|
|
|
|
] {
|
|
|
|
let result = scene
|
|
|
|
.ucmd()
|
2021-05-29 12:32:35 +00:00
|
|
|
.args(&arg.split(' ').collect::<Vec<_>>())
|
ls: long format author, group and owner (#1850)
This PR adds the options to customize what information is shown in long format regarding author, group & owner. Specifically it adds:
- `--author`: shows the author, which is always the same as the owner. GNU has this feature because GNU/Hurd supports a difference between author and owner, but I don't think Rust supports GNU/Hurd, so I just used the owner.
- `-G` & `--no-group`: hide the group information.
- `-o`: hide the group and use long format (equivalent to `-lG`).
- `-g`: hide the owner and use long format.
The `-o` and `-g` options have some interesting behaviour that I had to account for. Some examples:
- `-og` hides both group and owner.
- `-ol` still hides the group. Same behaviour with variations such as `-o --format=long`, `-gl`, `-g --format=long` and `-ogl`.
- They even retain some information when overridden by another format: `-oCl` (or `-o --format=vertical --format=long`) still hides the group.
My previous solution for handling the behaviour where `-l1` shows the long format did not fit with these additions, so I had to rewrite that as well.
The tests only cover the how many names (author, group and owner) are present in the output, so it can't distinguish between, for example, author & group and group & owner.
2021-03-21 15:18:06 +00:00
|
|
|
.arg("test-long-formats")
|
|
|
|
.succeeds();
|
2021-04-07 09:48:01 +00:00
|
|
|
assert!(re_two.is_match(result.stdout_str()));
|
2021-03-26 18:12:01 +00:00
|
|
|
|
|
|
|
#[cfg(unix)]
|
|
|
|
{
|
|
|
|
let result = scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-n")
|
2021-05-29 12:32:35 +00:00
|
|
|
.args(&arg.split(' ').collect::<Vec<_>>())
|
2021-03-26 18:12:01 +00:00
|
|
|
.arg("test-long-formats")
|
|
|
|
.succeeds();
|
2021-04-07 09:48:01 +00:00
|
|
|
assert!(re_two_num.is_match(result.stdout_str()));
|
2021-03-26 18:12:01 +00:00
|
|
|
}
|
ls: long format author, group and owner (#1850)
This PR adds the options to customize what information is shown in long format regarding author, group & owner. Specifically it adds:
- `--author`: shows the author, which is always the same as the owner. GNU has this feature because GNU/Hurd supports a difference between author and owner, but I don't think Rust supports GNU/Hurd, so I just used the owner.
- `-G` & `--no-group`: hide the group information.
- `-o`: hide the group and use long format (equivalent to `-lG`).
- `-g`: hide the owner and use long format.
The `-o` and `-g` options have some interesting behaviour that I had to account for. Some examples:
- `-og` hides both group and owner.
- `-ol` still hides the group. Same behaviour with variations such as `-o --format=long`, `-gl`, `-g --format=long` and `-ogl`.
- They even retain some information when overridden by another format: `-oCl` (or `-o --format=vertical --format=long`) still hides the group.
My previous solution for handling the behaviour where `-l1` shows the long format did not fit with these additions, so I had to rewrite that as well.
The tests only cover the how many names (author, group and owner) are present in the output, so it can't distinguish between, for example, author & group and group & owner.
2021-03-21 15:18:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for arg in &[
|
|
|
|
"-g", // only group
|
|
|
|
"-gl", // only group
|
|
|
|
"-o", // only owner
|
|
|
|
"-ol", // only owner
|
|
|
|
"-oG", // only owner
|
|
|
|
"-lG", // only owner
|
|
|
|
"-l --no-group", // only owner
|
|
|
|
"-gG --author", // only author
|
|
|
|
] {
|
|
|
|
let result = scene
|
|
|
|
.ucmd()
|
2021-05-29 12:32:35 +00:00
|
|
|
.args(&arg.split(' ').collect::<Vec<_>>())
|
ls: long format author, group and owner (#1850)
This PR adds the options to customize what information is shown in long format regarding author, group & owner. Specifically it adds:
- `--author`: shows the author, which is always the same as the owner. GNU has this feature because GNU/Hurd supports a difference between author and owner, but I don't think Rust supports GNU/Hurd, so I just used the owner.
- `-G` & `--no-group`: hide the group information.
- `-o`: hide the group and use long format (equivalent to `-lG`).
- `-g`: hide the owner and use long format.
The `-o` and `-g` options have some interesting behaviour that I had to account for. Some examples:
- `-og` hides both group and owner.
- `-ol` still hides the group. Same behaviour with variations such as `-o --format=long`, `-gl`, `-g --format=long` and `-ogl`.
- They even retain some information when overridden by another format: `-oCl` (or `-o --format=vertical --format=long`) still hides the group.
My previous solution for handling the behaviour where `-l1` shows the long format did not fit with these additions, so I had to rewrite that as well.
The tests only cover the how many names (author, group and owner) are present in the output, so it can't distinguish between, for example, author & group and group & owner.
2021-03-21 15:18:06 +00:00
|
|
|
.arg("test-long-formats")
|
|
|
|
.succeeds();
|
2021-04-07 09:48:01 +00:00
|
|
|
assert!(re_one.is_match(result.stdout_str()));
|
2021-03-26 18:12:01 +00:00
|
|
|
|
|
|
|
#[cfg(unix)]
|
|
|
|
{
|
|
|
|
let result = scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-n")
|
2021-05-29 12:32:35 +00:00
|
|
|
.args(&arg.split(' ').collect::<Vec<_>>())
|
2021-03-26 18:12:01 +00:00
|
|
|
.arg("test-long-formats")
|
|
|
|
.succeeds();
|
2021-04-07 09:48:01 +00:00
|
|
|
assert!(re_one_num.is_match(result.stdout_str()));
|
2021-03-26 18:12:01 +00:00
|
|
|
}
|
ls: long format author, group and owner (#1850)
This PR adds the options to customize what information is shown in long format regarding author, group & owner. Specifically it adds:
- `--author`: shows the author, which is always the same as the owner. GNU has this feature because GNU/Hurd supports a difference between author and owner, but I don't think Rust supports GNU/Hurd, so I just used the owner.
- `-G` & `--no-group`: hide the group information.
- `-o`: hide the group and use long format (equivalent to `-lG`).
- `-g`: hide the owner and use long format.
The `-o` and `-g` options have some interesting behaviour that I had to account for. Some examples:
- `-og` hides both group and owner.
- `-ol` still hides the group. Same behaviour with variations such as `-o --format=long`, `-gl`, `-g --format=long` and `-ogl`.
- They even retain some information when overridden by another format: `-oCl` (or `-o --format=vertical --format=long`) still hides the group.
My previous solution for handling the behaviour where `-l1` shows the long format did not fit with these additions, so I had to rewrite that as well.
The tests only cover the how many names (author, group and owner) are present in the output, so it can't distinguish between, for example, author & group and group & owner.
2021-03-21 15:18:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for arg in &[
|
|
|
|
"-og",
|
|
|
|
"-ogl",
|
|
|
|
"-lgo",
|
|
|
|
"-gG",
|
|
|
|
"-g --no-group",
|
|
|
|
"-og --no-group",
|
|
|
|
"-og --format=long",
|
|
|
|
"-ogCl",
|
|
|
|
"-og --format=vertical -l",
|
|
|
|
"-og1",
|
|
|
|
"-og1l",
|
|
|
|
] {
|
|
|
|
let result = scene
|
|
|
|
.ucmd()
|
2021-05-29 12:32:35 +00:00
|
|
|
.args(&arg.split(' ').collect::<Vec<_>>())
|
ls: long format author, group and owner (#1850)
This PR adds the options to customize what information is shown in long format regarding author, group & owner. Specifically it adds:
- `--author`: shows the author, which is always the same as the owner. GNU has this feature because GNU/Hurd supports a difference between author and owner, but I don't think Rust supports GNU/Hurd, so I just used the owner.
- `-G` & `--no-group`: hide the group information.
- `-o`: hide the group and use long format (equivalent to `-lG`).
- `-g`: hide the owner and use long format.
The `-o` and `-g` options have some interesting behaviour that I had to account for. Some examples:
- `-og` hides both group and owner.
- `-ol` still hides the group. Same behaviour with variations such as `-o --format=long`, `-gl`, `-g --format=long` and `-ogl`.
- They even retain some information when overridden by another format: `-oCl` (or `-o --format=vertical --format=long`) still hides the group.
My previous solution for handling the behaviour where `-l1` shows the long format did not fit with these additions, so I had to rewrite that as well.
The tests only cover the how many names (author, group and owner) are present in the output, so it can't distinguish between, for example, author & group and group & owner.
2021-03-21 15:18:06 +00:00
|
|
|
.arg("test-long-formats")
|
|
|
|
.succeeds();
|
2021-04-07 09:48:01 +00:00
|
|
|
assert!(re_zero.is_match(result.stdout_str()));
|
2021-03-26 18:12:01 +00:00
|
|
|
|
|
|
|
#[cfg(unix)]
|
|
|
|
{
|
|
|
|
let result = scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-n")
|
2021-05-29 12:32:35 +00:00
|
|
|
.args(&arg.split(' ').collect::<Vec<_>>())
|
2021-03-26 18:12:01 +00:00
|
|
|
.arg("test-long-formats")
|
|
|
|
.succeeds();
|
2021-04-07 09:48:01 +00:00
|
|
|
assert!(re_zero.is_match(result.stdout_str()));
|
2021-03-26 18:12:01 +00:00
|
|
|
}
|
ls: long format author, group and owner (#1850)
This PR adds the options to customize what information is shown in long format regarding author, group & owner. Specifically it adds:
- `--author`: shows the author, which is always the same as the owner. GNU has this feature because GNU/Hurd supports a difference between author and owner, but I don't think Rust supports GNU/Hurd, so I just used the owner.
- `-G` & `--no-group`: hide the group information.
- `-o`: hide the group and use long format (equivalent to `-lG`).
- `-g`: hide the owner and use long format.
The `-o` and `-g` options have some interesting behaviour that I had to account for. Some examples:
- `-og` hides both group and owner.
- `-ol` still hides the group. Same behaviour with variations such as `-o --format=long`, `-gl`, `-g --format=long` and `-ogl`.
- They even retain some information when overridden by another format: `-oCl` (or `-o --format=vertical --format=long`) still hides the group.
My previous solution for handling the behaviour where `-l1` shows the long format did not fit with these additions, so I had to rewrite that as well.
The tests only cover the how many names (author, group and owner) are present in the output, so it can't distinguish between, for example, author & group and group & owner.
2021-03-21 15:18:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-15 12:46:21 +00:00
|
|
|
#[test]
|
|
|
|
fn test_ls_oneline() {
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
at.touch(&at.plus_as_string("test-oneline-1"));
|
|
|
|
at.touch(&at.plus_as_string("test-oneline-2"));
|
|
|
|
|
|
|
|
// Bit of a weird situation: in the tests oneline and columns have the same output,
|
|
|
|
// except on Windows.
|
|
|
|
for option in &["-1", "--format=single-column"] {
|
2021-04-07 09:48:01 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg(option)
|
|
|
|
.succeeds()
|
|
|
|
.stdout_only("test-oneline-1\ntest-oneline-2\n");
|
2021-03-15 12:46:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-14 20:46:18 +00:00
|
|
|
#[test]
|
|
|
|
fn test_ls_deref() {
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
let path_regexp = r"(.*)test-long.link -> (.*)test-long(.*)";
|
|
|
|
let re = Regex::new(path_regexp).unwrap();
|
|
|
|
|
|
|
|
at.touch(&at.plus_as_string("test-long"));
|
|
|
|
at.symlink_file("test-long", "test-long.link");
|
|
|
|
assert!(at.is_symlink("test-long.link"));
|
|
|
|
|
|
|
|
let result = scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-l")
|
|
|
|
.arg("--color=never")
|
|
|
|
.arg("test-long")
|
|
|
|
.arg("test-long.link")
|
2021-04-07 09:48:01 +00:00
|
|
|
.succeeds();
|
|
|
|
assert!(re.is_match(result.stdout_str().trim()));
|
2020-12-14 20:46:18 +00:00
|
|
|
|
|
|
|
let result = scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-L")
|
|
|
|
.arg("--color=never")
|
|
|
|
.arg("test-long")
|
|
|
|
.arg("test-long.link")
|
2021-04-07 09:48:01 +00:00
|
|
|
.succeeds();
|
|
|
|
assert!(!re.is_match(result.stdout_str().trim()));
|
2020-12-14 20:46:18 +00:00
|
|
|
}
|
|
|
|
|
2021-04-21 10:03:48 +00:00
|
|
|
#[test]
|
|
|
|
fn test_ls_sort_none() {
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
|
|
|
|
at.touch("test-3");
|
|
|
|
at.touch("test-1");
|
|
|
|
at.touch("test-2");
|
|
|
|
|
|
|
|
// Order is not specified so we just check that it doesn't
|
|
|
|
// give any errors.
|
|
|
|
scene.ucmd().arg("--sort=none").succeeds();
|
|
|
|
scene.ucmd().arg("-U").succeeds();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_ls_sort_name() {
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
|
|
|
|
at.touch("test-3");
|
|
|
|
at.touch("test-1");
|
|
|
|
at.touch("test-2");
|
|
|
|
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("--sort=name")
|
|
|
|
.succeeds()
|
2021-08-11 20:03:41 +00:00
|
|
|
.stdout_is("test-1\ntest-2\ntest-3\n");
|
2021-04-25 19:08:05 +00:00
|
|
|
|
|
|
|
let scene_dot = TestScenario::new(util_name!());
|
|
|
|
let at = &scene_dot.fixtures;
|
|
|
|
at.touch(".a");
|
|
|
|
at.touch("a");
|
|
|
|
at.touch(".b");
|
|
|
|
at.touch("b");
|
|
|
|
|
|
|
|
scene_dot
|
|
|
|
.ucmd()
|
|
|
|
.arg("--sort=name")
|
|
|
|
.arg("-A")
|
|
|
|
.succeeds()
|
2021-08-11 20:03:41 +00:00
|
|
|
.stdout_is(".a\n.b\na\nb\n");
|
2021-04-21 10:03:48 +00:00
|
|
|
}
|
|
|
|
|
2020-12-14 20:46:18 +00:00
|
|
|
#[test]
|
|
|
|
fn test_ls_order_size() {
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
|
|
|
|
at.touch("test-1");
|
|
|
|
at.append("test-1", "1");
|
|
|
|
|
|
|
|
at.touch("test-2");
|
|
|
|
at.append("test-2", "22");
|
|
|
|
at.touch("test-3");
|
|
|
|
at.append("test-3", "333");
|
|
|
|
at.touch("test-4");
|
|
|
|
at.append("test-4", "4444");
|
|
|
|
|
2021-04-07 09:48:01 +00:00
|
|
|
scene.ucmd().arg("-al").succeeds();
|
2020-12-14 20:46:18 +00:00
|
|
|
|
2021-04-07 09:48:01 +00:00
|
|
|
let result = scene.ucmd().arg("-S").succeeds();
|
2021-08-11 20:03:41 +00:00
|
|
|
result.stdout_only("test-4\ntest-3\ntest-2\ntest-1\n");
|
2020-12-14 20:46:18 +00:00
|
|
|
|
2021-04-07 09:48:01 +00:00
|
|
|
let result = scene.ucmd().arg("-S").arg("-r").succeeds();
|
2021-08-11 20:03:41 +00:00
|
|
|
result.stdout_only("test-1\ntest-2\ntest-3\ntest-4\n");
|
2021-04-21 10:03:48 +00:00
|
|
|
|
|
|
|
let result = scene.ucmd().arg("--sort=size").succeeds();
|
2021-08-11 20:03:41 +00:00
|
|
|
result.stdout_only("test-4\ntest-3\ntest-2\ntest-1\n");
|
2021-04-21 10:03:48 +00:00
|
|
|
|
|
|
|
let result = scene.ucmd().arg("--sort=size").arg("-r").succeeds();
|
2021-08-11 20:03:41 +00:00
|
|
|
result.stdout_only("test-1\ntest-2\ntest-3\ntest-4\n");
|
2020-12-14 20:46:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2021-03-15 12:46:21 +00:00
|
|
|
fn test_ls_long_ctime() {
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
|
|
|
|
at.touch("test-long-ctime-1");
|
|
|
|
|
2021-04-21 10:03:48 +00:00
|
|
|
for arg in &["-c", "--time=ctime", "--time=status"] {
|
|
|
|
let result = scene.ucmd().arg("-l").arg(arg).succeeds();
|
|
|
|
|
|
|
|
// Should show the time on Unix, but question marks on windows.
|
|
|
|
#[cfg(unix)]
|
|
|
|
result.stdout_contains(":");
|
|
|
|
#[cfg(not(unix))]
|
|
|
|
result.stdout_contains("???");
|
|
|
|
}
|
2021-03-15 12:46:21 +00:00
|
|
|
}
|
|
|
|
|
2021-04-28 18:54:27 +00:00
|
|
|
#[test]
|
2021-05-01 13:55:58 +00:00
|
|
|
#[ignore]
|
2021-04-28 18:54:27 +00:00
|
|
|
fn test_ls_order_birthtime() {
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
|
|
|
|
/*
|
|
|
|
Here we make 2 files with a timeout in between.
|
|
|
|
After creating the first file try to sync it.
|
|
|
|
This ensures the file gets created immediately instead of being saved
|
|
|
|
inside the OS's IO operation buffer.
|
2021-04-29 20:23:04 +00:00
|
|
|
Without this, both files might accidentally be created at the same time.
|
2021-04-28 18:54:27 +00:00
|
|
|
*/
|
|
|
|
at.make_file("test-birthtime-1").sync_all().unwrap();
|
2021-04-29 20:23:04 +00:00
|
|
|
at.make_file("test-birthtime-2").sync_all().unwrap();
|
|
|
|
at.open("test-birthtime-1");
|
2021-04-28 18:54:27 +00:00
|
|
|
|
|
|
|
let result = scene.ucmd().arg("--time=birth").arg("-t").run();
|
|
|
|
|
|
|
|
#[cfg(not(windows))]
|
|
|
|
assert_eq!(result.stdout_str(), "test-birthtime-2\ntest-birthtime-1\n");
|
|
|
|
#[cfg(windows)]
|
|
|
|
assert_eq!(result.stdout_str(), "test-birthtime-2 test-birthtime-1\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_ls_styles() {
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
at.touch("test");
|
|
|
|
|
|
|
|
let re_full = Regex::new(
|
2021-05-17 00:43:53 +00:00
|
|
|
r"[a-z-]* \d* \w* \w* \d* \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d* (\+|\-)\d{4} test\n",
|
2021-04-28 18:54:27 +00:00
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
let re_long =
|
|
|
|
Regex::new(r"[a-z-]* \d* \w* \w* \d* \d{4}-\d{2}-\d{2} \d{2}:\d{2} test\n").unwrap();
|
|
|
|
let re_iso = Regex::new(r"[a-z-]* \d* \w* \w* \d* \d{2}-\d{2} \d{2}:\d{2} test\n").unwrap();
|
|
|
|
let re_locale =
|
2021-05-01 15:29:00 +00:00
|
|
|
Regex::new(r"[a-z-]* \d* \w* \w* \d* [A-Z][a-z]{2} ( |\d)\d \d{2}:\d{2} test\n").unwrap();
|
2021-04-28 18:54:27 +00:00
|
|
|
|
|
|
|
//full-iso
|
|
|
|
let result = scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-l")
|
|
|
|
.arg("--time-style=full-iso")
|
|
|
|
.succeeds();
|
2021-06-06 19:13:54 +00:00
|
|
|
assert!(re_full.is_match(result.stdout_str()));
|
2021-04-28 18:54:27 +00:00
|
|
|
//long-iso
|
|
|
|
let result = scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-l")
|
|
|
|
.arg("--time-style=long-iso")
|
|
|
|
.succeeds();
|
2021-06-06 19:13:54 +00:00
|
|
|
assert!(re_long.is_match(result.stdout_str()));
|
2021-04-28 18:54:27 +00:00
|
|
|
//iso
|
|
|
|
let result = scene.ucmd().arg("-l").arg("--time-style=iso").succeeds();
|
2021-06-06 19:13:54 +00:00
|
|
|
assert!(re_iso.is_match(result.stdout_str()));
|
2021-04-28 18:54:27 +00:00
|
|
|
//locale
|
|
|
|
let result = scene.ucmd().arg("-l").arg("--time-style=locale").succeeds();
|
2021-06-06 19:13:54 +00:00
|
|
|
assert!(re_locale.is_match(result.stdout_str()));
|
2021-04-28 18:54:27 +00:00
|
|
|
|
|
|
|
//Overwrite options tests
|
|
|
|
let result = scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-l")
|
|
|
|
.arg("--time-style=long-iso")
|
|
|
|
.arg("--time-style=iso")
|
|
|
|
.succeeds();
|
2021-06-06 19:13:54 +00:00
|
|
|
assert!(re_iso.is_match(result.stdout_str()));
|
2021-04-28 18:54:27 +00:00
|
|
|
let result = scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("--time-style=iso")
|
|
|
|
.arg("--full-time")
|
|
|
|
.succeeds();
|
2021-06-06 19:13:54 +00:00
|
|
|
assert!(re_full.is_match(result.stdout_str()));
|
2021-04-28 18:54:27 +00:00
|
|
|
let result = scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("--full-time")
|
|
|
|
.arg("--time-style=iso")
|
|
|
|
.succeeds();
|
2021-06-06 19:13:54 +00:00
|
|
|
assert!(re_iso.is_match(result.stdout_str()));
|
2021-04-28 18:54:27 +00:00
|
|
|
|
|
|
|
let result = scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("--full-time")
|
|
|
|
.arg("--time-style=iso")
|
|
|
|
.arg("--full-time")
|
|
|
|
.succeeds();
|
2021-06-06 19:13:54 +00:00
|
|
|
assert!(re_full.is_match(result.stdout_str()));
|
2021-04-28 18:54:27 +00:00
|
|
|
|
|
|
|
let result = scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("--full-time")
|
|
|
|
.arg("-x")
|
|
|
|
.arg("-l")
|
|
|
|
.succeeds();
|
2021-06-06 19:13:54 +00:00
|
|
|
assert!(re_full.is_match(result.stdout_str()));
|
2021-04-28 18:54:27 +00:00
|
|
|
|
|
|
|
at.touch("test2");
|
|
|
|
let result = scene.ucmd().arg("--full-time").arg("-x").succeeds();
|
|
|
|
assert_eq!(result.stdout_str(), "test test2\n");
|
|
|
|
}
|
|
|
|
|
2021-03-15 12:46:21 +00:00
|
|
|
#[test]
|
|
|
|
fn test_ls_order_time() {
|
2020-12-14 20:46:18 +00:00
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
|
|
|
|
at.touch("test-1");
|
|
|
|
at.append("test-1", "1");
|
2021-03-15 12:46:21 +00:00
|
|
|
sleep(Duration::from_millis(100));
|
2020-12-14 20:46:18 +00:00
|
|
|
at.touch("test-2");
|
|
|
|
at.append("test-2", "22");
|
2021-03-22 09:14:59 +00:00
|
|
|
|
2021-03-15 12:46:21 +00:00
|
|
|
sleep(Duration::from_millis(100));
|
2020-12-14 20:46:18 +00:00
|
|
|
at.touch("test-3");
|
|
|
|
at.append("test-3", "333");
|
2021-03-15 12:46:21 +00:00
|
|
|
sleep(Duration::from_millis(100));
|
2020-12-14 20:46:18 +00:00
|
|
|
at.touch("test-4");
|
|
|
|
at.append("test-4", "4444");
|
2021-03-15 12:46:21 +00:00
|
|
|
sleep(Duration::from_millis(100));
|
|
|
|
|
|
|
|
// Read test-3, only changing access time
|
|
|
|
at.read("test-3");
|
|
|
|
|
|
|
|
// Set permissions of test-2, only changing ctime
|
|
|
|
std::fs::set_permissions(
|
|
|
|
at.plus_as_string("test-2"),
|
|
|
|
at.metadata("test-2").permissions(),
|
|
|
|
)
|
|
|
|
.unwrap();
|
2020-12-14 20:46:18 +00:00
|
|
|
|
2021-04-07 09:48:01 +00:00
|
|
|
scene.ucmd().arg("-al").succeeds();
|
2020-12-14 20:46:18 +00:00
|
|
|
|
2021-03-15 12:46:21 +00:00
|
|
|
// ctime was changed at write, so the order is 4 3 2 1
|
2021-04-07 09:48:01 +00:00
|
|
|
let result = scene.ucmd().arg("-t").succeeds();
|
2021-08-11 20:03:41 +00:00
|
|
|
result.stdout_only("test-4\ntest-3\ntest-2\ntest-1\n");
|
2020-12-14 20:46:18 +00:00
|
|
|
|
2021-04-21 10:03:48 +00:00
|
|
|
let result = scene.ucmd().arg("--sort=time").succeeds();
|
2021-08-11 20:03:41 +00:00
|
|
|
result.stdout_only("test-4\ntest-3\ntest-2\ntest-1\n");
|
2021-04-21 10:03:48 +00:00
|
|
|
|
2021-04-07 09:48:01 +00:00
|
|
|
let result = scene.ucmd().arg("-tr").succeeds();
|
2021-08-11 20:03:41 +00:00
|
|
|
result.stdout_only("test-1\ntest-2\ntest-3\ntest-4\n");
|
2021-03-15 12:46:21 +00:00
|
|
|
|
2021-04-21 10:03:48 +00:00
|
|
|
let result = scene.ucmd().arg("--sort=time").arg("-r").succeeds();
|
2021-08-11 20:03:41 +00:00
|
|
|
result.stdout_only("test-1\ntest-2\ntest-3\ntest-4\n");
|
2021-04-21 10:03:48 +00:00
|
|
|
|
2021-03-15 12:46:21 +00:00
|
|
|
// 3 was accessed last in the read
|
|
|
|
// So the order should be 2 3 4 1
|
2021-04-21 10:03:48 +00:00
|
|
|
for arg in &["-u", "--time=atime", "--time=access", "--time=use"] {
|
|
|
|
let result = scene.ucmd().arg("-t").arg(arg).succeeds();
|
|
|
|
let file3_access = at.open("test-3").metadata().unwrap().accessed().unwrap();
|
|
|
|
let file4_access = at.open("test-4").metadata().unwrap().accessed().unwrap();
|
|
|
|
|
|
|
|
// It seems to be dependent on the platform whether the access time is actually set
|
|
|
|
if file3_access > file4_access {
|
2021-08-11 20:03:41 +00:00
|
|
|
result.stdout_only("test-3\ntest-4\ntest-2\ntest-1\n");
|
2021-03-22 09:14:59 +00:00
|
|
|
} else {
|
2021-04-21 10:03:48 +00:00
|
|
|
// Access time does not seem to be set on Windows and some other
|
|
|
|
// systems so the order is 4 3 2 1
|
2021-08-11 20:03:41 +00:00
|
|
|
result.stdout_only("test-4\ntest-3\ntest-2\ntest-1\n");
|
2021-03-22 09:14:59 +00:00
|
|
|
}
|
|
|
|
}
|
2021-03-15 12:46:21 +00:00
|
|
|
|
|
|
|
// test-2 had the last ctime change when the permissions were set
|
|
|
|
// So the order should be 2 4 3 1
|
|
|
|
#[cfg(unix)]
|
|
|
|
{
|
2021-04-07 09:48:01 +00:00
|
|
|
let result = scene.ucmd().arg("-tc").succeeds();
|
2021-08-11 20:03:41 +00:00
|
|
|
result.stdout_only("test-2\ntest-4\ntest-3\ntest-1\n");
|
2021-03-15 12:46:21 +00:00
|
|
|
}
|
2020-12-14 20:46:18 +00:00
|
|
|
}
|
|
|
|
|
2020-12-13 11:09:14 +00:00
|
|
|
#[test]
|
|
|
|
fn test_ls_non_existing() {
|
|
|
|
new_ucmd!().arg("doesntexist").fails();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_ls_files_dirs() {
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
at.mkdir("a");
|
|
|
|
at.mkdir("a/b");
|
|
|
|
at.mkdir("a/b/c");
|
|
|
|
at.mkdir("z");
|
|
|
|
at.touch(&at.plus_as_string("a/a"));
|
|
|
|
at.touch(&at.plus_as_string("a/b/b"));
|
|
|
|
|
|
|
|
scene.ucmd().arg("a").succeeds();
|
|
|
|
scene.ucmd().arg("a/a").succeeds();
|
|
|
|
scene.ucmd().arg("a").arg("z").succeeds();
|
|
|
|
|
|
|
|
// Doesn't exist
|
2021-04-07 09:48:01 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("doesntexist")
|
|
|
|
.fails()
|
2021-05-25 23:45:53 +00:00
|
|
|
.stderr_contains(&"'doesntexist': No such file or directory");
|
2020-12-13 11:09:14 +00:00
|
|
|
|
|
|
|
// One exists, the other doesn't
|
2021-04-07 09:48:01 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("a")
|
|
|
|
.arg("doesntexist")
|
|
|
|
.fails()
|
2021-05-25 23:45:53 +00:00
|
|
|
.stderr_contains(&"'doesntexist': No such file or directory")
|
2021-04-07 09:48:01 +00:00
|
|
|
.stdout_contains(&"a:");
|
2020-12-13 11:09:14 +00:00
|
|
|
}
|
|
|
|
|
2020-12-13 11:22:31 +00:00
|
|
|
#[test]
|
|
|
|
fn test_ls_recursive() {
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
at.mkdir("a");
|
|
|
|
at.mkdir("a/b");
|
|
|
|
at.mkdir("a/b/c");
|
|
|
|
at.mkdir("z");
|
|
|
|
at.touch(&at.plus_as_string("a/a"));
|
|
|
|
at.touch(&at.plus_as_string("a/b/b"));
|
|
|
|
|
|
|
|
scene.ucmd().arg("a").succeeds();
|
|
|
|
scene.ucmd().arg("a/a").succeeds();
|
2021-05-30 12:30:52 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("z")
|
|
|
|
.arg("-R")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains(&"z:");
|
2020-12-13 11:22:31 +00:00
|
|
|
let result = scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("--color=never")
|
|
|
|
.arg("-R")
|
|
|
|
.arg("a")
|
|
|
|
.arg("z")
|
|
|
|
.succeeds();
|
|
|
|
|
2020-12-14 20:46:18 +00:00
|
|
|
#[cfg(not(windows))]
|
2021-04-07 09:48:01 +00:00
|
|
|
result.stdout_contains(&"a/b:\nb");
|
2020-12-14 20:46:18 +00:00
|
|
|
#[cfg(windows)]
|
2021-04-07 09:48:01 +00:00
|
|
|
result.stdout_contains(&"a\\b:\nb");
|
2020-12-13 11:22:31 +00:00
|
|
|
}
|
|
|
|
|
ls: implement --color flag
GNU coreutils ls command implements the --color option as follow:
--color[=WHEN]
colorize the output; WHEN can be 'always' (default if omitted),
'auto', or 'never'
With --color=auto, ls emits color codes only when standard output is connected
to a terminal.
Also, add support for the following aliases:
- ‘always’, ‘yes’, ‘force’
- ‘never’, ‘no’, ‘none’
- ‘auto’, ‘tty’, ‘if-tty’
Signed-off-by: Gabriel Ganne <gabriel.ganne@gmail.com>
2019-06-20 07:55:01 +00:00
|
|
|
#[test]
|
2021-04-21 15:57:17 +00:00
|
|
|
fn test_ls_color() {
|
2020-12-14 20:46:18 +00:00
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
at.mkdir("a");
|
2021-04-21 14:58:37 +00:00
|
|
|
let nested_dir = Path::new("a")
|
|
|
|
.join("nested_dir")
|
|
|
|
.to_string_lossy()
|
|
|
|
.to_string();
|
|
|
|
at.mkdir(&nested_dir);
|
2020-12-14 20:46:18 +00:00
|
|
|
at.mkdir("z");
|
2021-04-21 14:58:37 +00:00
|
|
|
let nested_file = Path::new("a")
|
|
|
|
.join("nested_file")
|
|
|
|
.to_string_lossy()
|
|
|
|
.to_string();
|
|
|
|
at.touch(&nested_file);
|
2021-03-17 22:15:03 +00:00
|
|
|
at.touch("test-color");
|
|
|
|
|
2021-04-21 14:58:37 +00:00
|
|
|
let a_with_colors = "\x1b[1;34ma\x1b[0m";
|
|
|
|
let z_with_colors = "\x1b[1;34mz\x1b[0m";
|
2021-05-31 03:55:28 +00:00
|
|
|
let nested_dir_with_colors = "\x1b[1;34mnested_dir\x1b[0m"; // spell-checker:disable-line
|
2021-03-17 22:15:03 +00:00
|
|
|
|
|
|
|
// Color is disabled by default
|
|
|
|
let result = scene.ucmd().succeeds();
|
2021-04-07 09:48:01 +00:00
|
|
|
assert!(!result.stdout_str().contains(a_with_colors));
|
|
|
|
assert!(!result.stdout_str().contains(z_with_colors));
|
2021-03-17 22:15:03 +00:00
|
|
|
|
|
|
|
// Color should be enabled
|
2021-04-07 09:48:01 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("--color")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains(a_with_colors)
|
2021-04-22 09:39:08 +00:00
|
|
|
.stdout_contains(z_with_colors);
|
2021-03-17 22:15:03 +00:00
|
|
|
|
|
|
|
// Color should be enabled
|
2021-04-07 09:48:01 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("--color=always")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains(a_with_colors)
|
2021-04-22 09:39:08 +00:00
|
|
|
.stdout_contains(z_with_colors);
|
2021-03-17 22:15:03 +00:00
|
|
|
|
|
|
|
// Color should be disabled
|
|
|
|
let result = scene.ucmd().arg("--color=never").succeeds();
|
2021-04-07 09:48:01 +00:00
|
|
|
assert!(!result.stdout_str().contains(a_with_colors));
|
|
|
|
assert!(!result.stdout_str().contains(z_with_colors));
|
2021-03-17 22:15:03 +00:00
|
|
|
|
|
|
|
// Nested dir should be shown and colored
|
2021-04-07 09:48:01 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("--color")
|
|
|
|
.arg("a")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains(nested_dir_with_colors);
|
2021-03-17 22:15:03 +00:00
|
|
|
|
|
|
|
// No output
|
2021-04-07 09:48:01 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("--color=never")
|
|
|
|
.arg("z")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_only("");
|
2021-04-26 12:42:42 +00:00
|
|
|
|
|
|
|
// The colors must not mess up the grid layout
|
|
|
|
at.touch("b");
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("--color")
|
|
|
|
.arg("-w=15")
|
2021-08-11 20:03:41 +00:00
|
|
|
.arg("-C")
|
2021-04-26 12:42:42 +00:00
|
|
|
.succeeds()
|
|
|
|
.stdout_only(format!(
|
|
|
|
"{} test-color\nb {}\n",
|
|
|
|
a_with_colors, z_with_colors
|
|
|
|
));
|
ls: implement --color flag
GNU coreutils ls command implements the --color option as follow:
--color[=WHEN]
colorize the output; WHEN can be 'always' (default if omitted),
'auto', or 'never'
With --color=auto, ls emits color codes only when standard output is connected
to a terminal.
Also, add support for the following aliases:
- ‘always’, ‘yes’, ‘force’
- ‘never’, ‘no’, ‘none’
- ‘auto’, ‘tty’, ‘if-tty’
Signed-off-by: Gabriel Ganne <gabriel.ganne@gmail.com>
2019-06-20 07:55:01 +00:00
|
|
|
}
|
2020-12-15 12:36:12 +00:00
|
|
|
|
ls: long format author, group and owner (#1850)
This PR adds the options to customize what information is shown in long format regarding author, group & owner. Specifically it adds:
- `--author`: shows the author, which is always the same as the owner. GNU has this feature because GNU/Hurd supports a difference between author and owner, but I don't think Rust supports GNU/Hurd, so I just used the owner.
- `-G` & `--no-group`: hide the group information.
- `-o`: hide the group and use long format (equivalent to `-lG`).
- `-g`: hide the owner and use long format.
The `-o` and `-g` options have some interesting behaviour that I had to account for. Some examples:
- `-og` hides both group and owner.
- `-ol` still hides the group. Same behaviour with variations such as `-o --format=long`, `-gl`, `-g --format=long` and `-ogl`.
- They even retain some information when overridden by another format: `-oCl` (or `-o --format=vertical --format=long`) still hides the group.
My previous solution for handling the behaviour where `-l1` shows the long format did not fit with these additions, so I had to rewrite that as well.
The tests only cover the how many names (author, group and owner) are present in the output, so it can't distinguish between, for example, author & group and group & owner.
2021-03-21 15:18:06 +00:00
|
|
|
#[cfg(unix)]
|
|
|
|
#[test]
|
|
|
|
fn test_ls_inode() {
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
|
|
|
|
let file = "test_inode";
|
|
|
|
at.touch(file);
|
|
|
|
|
|
|
|
let re_short = Regex::new(r" *(\d+) test_inode").unwrap();
|
|
|
|
let re_long = Regex::new(r" *(\d+) [xrw-]{10} \d .+ test_inode").unwrap();
|
|
|
|
|
2021-04-07 09:48:01 +00:00
|
|
|
let result = scene.ucmd().arg("test_inode").arg("-i").succeeds();
|
|
|
|
assert!(re_short.is_match(result.stdout_str()));
|
ls: long format author, group and owner (#1850)
This PR adds the options to customize what information is shown in long format regarding author, group & owner. Specifically it adds:
- `--author`: shows the author, which is always the same as the owner. GNU has this feature because GNU/Hurd supports a difference between author and owner, but I don't think Rust supports GNU/Hurd, so I just used the owner.
- `-G` & `--no-group`: hide the group information.
- `-o`: hide the group and use long format (equivalent to `-lG`).
- `-g`: hide the owner and use long format.
The `-o` and `-g` options have some interesting behaviour that I had to account for. Some examples:
- `-og` hides both group and owner.
- `-ol` still hides the group. Same behaviour with variations such as `-o --format=long`, `-gl`, `-g --format=long` and `-ogl`.
- They even retain some information when overridden by another format: `-oCl` (or `-o --format=vertical --format=long`) still hides the group.
My previous solution for handling the behaviour where `-l1` shows the long format did not fit with these additions, so I had to rewrite that as well.
The tests only cover the how many names (author, group and owner) are present in the output, so it can't distinguish between, for example, author & group and group & owner.
2021-03-21 15:18:06 +00:00
|
|
|
let inode_short = re_short
|
2021-04-07 09:48:01 +00:00
|
|
|
.captures(result.stdout_str())
|
ls: long format author, group and owner (#1850)
This PR adds the options to customize what information is shown in long format regarding author, group & owner. Specifically it adds:
- `--author`: shows the author, which is always the same as the owner. GNU has this feature because GNU/Hurd supports a difference between author and owner, but I don't think Rust supports GNU/Hurd, so I just used the owner.
- `-G` & `--no-group`: hide the group information.
- `-o`: hide the group and use long format (equivalent to `-lG`).
- `-g`: hide the owner and use long format.
The `-o` and `-g` options have some interesting behaviour that I had to account for. Some examples:
- `-og` hides both group and owner.
- `-ol` still hides the group. Same behaviour with variations such as `-o --format=long`, `-gl`, `-g --format=long` and `-ogl`.
- They even retain some information when overridden by another format: `-oCl` (or `-o --format=vertical --format=long`) still hides the group.
My previous solution for handling the behaviour where `-l1` shows the long format did not fit with these additions, so I had to rewrite that as well.
The tests only cover the how many names (author, group and owner) are present in the output, so it can't distinguish between, for example, author & group and group & owner.
2021-03-21 15:18:06 +00:00
|
|
|
.unwrap()
|
|
|
|
.get(1)
|
|
|
|
.unwrap()
|
|
|
|
.as_str();
|
|
|
|
|
2021-04-07 09:48:01 +00:00
|
|
|
let result = scene.ucmd().arg("test_inode").succeeds();
|
|
|
|
assert!(!re_short.is_match(result.stdout_str()));
|
|
|
|
assert!(!result.stdout_str().contains(inode_short));
|
ls: long format author, group and owner (#1850)
This PR adds the options to customize what information is shown in long format regarding author, group & owner. Specifically it adds:
- `--author`: shows the author, which is always the same as the owner. GNU has this feature because GNU/Hurd supports a difference between author and owner, but I don't think Rust supports GNU/Hurd, so I just used the owner.
- `-G` & `--no-group`: hide the group information.
- `-o`: hide the group and use long format (equivalent to `-lG`).
- `-g`: hide the owner and use long format.
The `-o` and `-g` options have some interesting behaviour that I had to account for. Some examples:
- `-og` hides both group and owner.
- `-ol` still hides the group. Same behaviour with variations such as `-o --format=long`, `-gl`, `-g --format=long` and `-ogl`.
- They even retain some information when overridden by another format: `-oCl` (or `-o --format=vertical --format=long`) still hides the group.
My previous solution for handling the behaviour where `-l1` shows the long format did not fit with these additions, so I had to rewrite that as well.
The tests only cover the how many names (author, group and owner) are present in the output, so it can't distinguish between, for example, author & group and group & owner.
2021-03-21 15:18:06 +00:00
|
|
|
|
2021-04-07 09:48:01 +00:00
|
|
|
let result = scene.ucmd().arg("-li").arg("test_inode").succeeds();
|
|
|
|
assert!(re_long.is_match(result.stdout_str()));
|
ls: long format author, group and owner (#1850)
This PR adds the options to customize what information is shown in long format regarding author, group & owner. Specifically it adds:
- `--author`: shows the author, which is always the same as the owner. GNU has this feature because GNU/Hurd supports a difference between author and owner, but I don't think Rust supports GNU/Hurd, so I just used the owner.
- `-G` & `--no-group`: hide the group information.
- `-o`: hide the group and use long format (equivalent to `-lG`).
- `-g`: hide the owner and use long format.
The `-o` and `-g` options have some interesting behaviour that I had to account for. Some examples:
- `-og` hides both group and owner.
- `-ol` still hides the group. Same behaviour with variations such as `-o --format=long`, `-gl`, `-g --format=long` and `-ogl`.
- They even retain some information when overridden by another format: `-oCl` (or `-o --format=vertical --format=long`) still hides the group.
My previous solution for handling the behaviour where `-l1` shows the long format did not fit with these additions, so I had to rewrite that as well.
The tests only cover the how many names (author, group and owner) are present in the output, so it can't distinguish between, for example, author & group and group & owner.
2021-03-21 15:18:06 +00:00
|
|
|
let inode_long = re_long
|
2021-04-07 09:48:01 +00:00
|
|
|
.captures(result.stdout_str())
|
ls: long format author, group and owner (#1850)
This PR adds the options to customize what information is shown in long format regarding author, group & owner. Specifically it adds:
- `--author`: shows the author, which is always the same as the owner. GNU has this feature because GNU/Hurd supports a difference between author and owner, but I don't think Rust supports GNU/Hurd, so I just used the owner.
- `-G` & `--no-group`: hide the group information.
- `-o`: hide the group and use long format (equivalent to `-lG`).
- `-g`: hide the owner and use long format.
The `-o` and `-g` options have some interesting behaviour that I had to account for. Some examples:
- `-og` hides both group and owner.
- `-ol` still hides the group. Same behaviour with variations such as `-o --format=long`, `-gl`, `-g --format=long` and `-ogl`.
- They even retain some information when overridden by another format: `-oCl` (or `-o --format=vertical --format=long`) still hides the group.
My previous solution for handling the behaviour where `-l1` shows the long format did not fit with these additions, so I had to rewrite that as well.
The tests only cover the how many names (author, group and owner) are present in the output, so it can't distinguish between, for example, author & group and group & owner.
2021-03-21 15:18:06 +00:00
|
|
|
.unwrap()
|
|
|
|
.get(1)
|
|
|
|
.unwrap()
|
|
|
|
.as_str();
|
|
|
|
|
2021-04-07 09:48:01 +00:00
|
|
|
let result = scene.ucmd().arg("-l").arg("test_inode").succeeds();
|
|
|
|
assert!(!re_long.is_match(result.stdout_str()));
|
|
|
|
assert!(!result.stdout_str().contains(inode_long));
|
ls: long format author, group and owner (#1850)
This PR adds the options to customize what information is shown in long format regarding author, group & owner. Specifically it adds:
- `--author`: shows the author, which is always the same as the owner. GNU has this feature because GNU/Hurd supports a difference between author and owner, but I don't think Rust supports GNU/Hurd, so I just used the owner.
- `-G` & `--no-group`: hide the group information.
- `-o`: hide the group and use long format (equivalent to `-lG`).
- `-g`: hide the owner and use long format.
The `-o` and `-g` options have some interesting behaviour that I had to account for. Some examples:
- `-og` hides both group and owner.
- `-ol` still hides the group. Same behaviour with variations such as `-o --format=long`, `-gl`, `-g --format=long` and `-ogl`.
- They even retain some information when overridden by another format: `-oCl` (or `-o --format=vertical --format=long`) still hides the group.
My previous solution for handling the behaviour where `-l1` shows the long format did not fit with these additions, so I had to rewrite that as well.
The tests only cover the how many names (author, group and owner) are present in the output, so it can't distinguish between, for example, author & group and group & owner.
2021-03-21 15:18:06 +00:00
|
|
|
|
|
|
|
assert_eq!(inode_short, inode_long)
|
|
|
|
}
|
|
|
|
|
2021-03-29 11:10:13 +00:00
|
|
|
#[test]
|
|
|
|
#[cfg(not(windows))]
|
|
|
|
fn test_ls_indicator_style() {
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
|
|
|
|
// Setup: Directory, Symlink, and Pipes.
|
|
|
|
at.mkdir("directory");
|
|
|
|
assert!(at.dir_exists("directory"));
|
|
|
|
|
|
|
|
at.touch(&at.plus_as_string("link-src"));
|
|
|
|
at.symlink_file("link-src", "link-dest.link");
|
|
|
|
assert!(at.is_symlink("link-dest.link"));
|
|
|
|
|
|
|
|
at.mkfifo("named-pipe.fifo");
|
|
|
|
assert!(at.is_fifo("named-pipe.fifo"));
|
|
|
|
|
|
|
|
// Classify, File-Type, and Slash all contain indicators for directories.
|
|
|
|
let options = vec!["classify", "file-type", "slash"];
|
|
|
|
for opt in options {
|
|
|
|
// Verify that classify and file-type both contain indicators for symlinks.
|
2021-04-07 09:48:01 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg(format!("--indicator-style={}", opt))
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains(&"/");
|
2021-03-29 11:10:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Same test as above, but with the alternate flags.
|
|
|
|
let options = vec!["--classify", "--file-type", "-p"];
|
|
|
|
for opt in options {
|
2021-04-07 09:48:01 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
2021-05-29 12:32:35 +00:00
|
|
|
.arg(opt.to_string())
|
2021-04-07 09:48:01 +00:00
|
|
|
.succeeds()
|
|
|
|
.stdout_contains(&"/");
|
2021-03-29 11:10:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Classify and File-Type all contain indicators for pipes and links.
|
|
|
|
let options = vec!["classify", "file-type"];
|
|
|
|
for opt in options {
|
|
|
|
// Verify that classify and file-type both contain indicators for symlinks.
|
2021-04-07 09:48:01 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg(format!("--indicator-style={}", opt))
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains(&"@")
|
|
|
|
.stdout_contains(&"|");
|
2021-03-29 11:10:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Test sockets. Because the canonical way of making sockets to test is with
|
|
|
|
// TempDir, we need a separate test.
|
|
|
|
{
|
|
|
|
use self::unix_socket::UnixListener;
|
|
|
|
|
2021-05-29 12:32:35 +00:00
|
|
|
let dir = tempfile::Builder::new()
|
|
|
|
.prefix("unix_socket")
|
|
|
|
.tempdir()
|
|
|
|
.expect("failed to create dir");
|
2021-03-29 11:10:13 +00:00
|
|
|
let socket_path = dir.path().join("sock");
|
|
|
|
let _listener = UnixListener::bind(&socket_path).expect("failed to create socket");
|
|
|
|
|
|
|
|
new_ucmd!()
|
|
|
|
.args(&[
|
|
|
|
PathBuf::from(dir.path().to_str().unwrap()),
|
|
|
|
PathBuf::from("--indicator-style=classify"),
|
|
|
|
])
|
|
|
|
.succeeds()
|
|
|
|
.stdout_only("sock=\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Essentially the same test as above, but only test symlinks and directories,
|
|
|
|
// not pipes or sockets.
|
|
|
|
#[test]
|
|
|
|
#[cfg(not(unix))]
|
|
|
|
fn test_ls_indicator_style() {
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
|
|
|
|
// Setup: Directory, Symlink.
|
|
|
|
at.mkdir("directory");
|
|
|
|
assert!(at.dir_exists("directory"));
|
|
|
|
|
|
|
|
at.touch(&at.plus_as_string("link-src"));
|
|
|
|
at.symlink_file("link-src", "link-dest.link");
|
|
|
|
assert!(at.is_symlink("link-dest.link"));
|
|
|
|
|
|
|
|
// Classify, File-Type, and Slash all contain indicators for directories.
|
|
|
|
let options = vec!["classify", "file-type", "slash"];
|
|
|
|
for opt in options {
|
|
|
|
// Verify that classify and file-type both contain indicators for symlinks.
|
2021-04-21 15:43:57 +00:00
|
|
|
scene
|
2021-04-07 09:48:01 +00:00
|
|
|
.ucmd()
|
|
|
|
.arg(format!("--indicator-style={}", opt))
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains(&"/");
|
2021-03-29 11:10:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Same test as above, but with the alternate flags.
|
|
|
|
let options = vec!["--classify", "--file-type", "-p"];
|
|
|
|
for opt in options {
|
2021-04-21 15:43:57 +00:00
|
|
|
scene
|
2021-04-07 09:48:01 +00:00
|
|
|
.ucmd()
|
2021-06-06 19:14:35 +00:00
|
|
|
.arg(opt.to_string())
|
2021-04-07 09:48:01 +00:00
|
|
|
.succeeds()
|
|
|
|
.stdout_contains(&"/");
|
2021-03-29 11:10:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Classify and File-Type all contain indicators for pipes and links.
|
|
|
|
let options = vec!["classify", "file-type"];
|
|
|
|
for opt in options {
|
|
|
|
// Verify that classify and file-type both contain indicators for symlinks.
|
2021-04-21 15:43:57 +00:00
|
|
|
scene
|
2021-04-07 09:48:01 +00:00
|
|
|
.ucmd()
|
|
|
|
.arg(format!("--indicator-style={}", opt))
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains(&"@");
|
2021-03-29 11:10:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-18 01:32:34 +00:00
|
|
|
#[cfg(not(any(target_vendor = "apple", target_os = "windows")))] // Truncate not available on mac or win
|
2020-12-15 12:36:12 +00:00
|
|
|
#[test]
|
2021-03-19 14:15:24 +00:00
|
|
|
fn test_ls_human_si() {
|
2020-12-15 12:36:12 +00:00
|
|
|
let scene = TestScenario::new(util_name!());
|
2021-03-19 14:15:24 +00:00
|
|
|
let file1 = "test_human-1";
|
2021-04-07 09:48:01 +00:00
|
|
|
scene
|
2021-03-19 14:15:24 +00:00
|
|
|
.cmd("truncate")
|
|
|
|
.arg("-s")
|
|
|
|
.arg("+1000")
|
|
|
|
.arg(file1)
|
2021-04-07 09:48:01 +00:00
|
|
|
.succeeds();
|
2021-03-19 14:15:24 +00:00
|
|
|
|
2021-04-07 09:48:01 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-hl")
|
|
|
|
.arg(file1)
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains(" 1000 ");
|
2021-03-19 14:15:24 +00:00
|
|
|
|
2021-04-07 09:48:01 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-l")
|
|
|
|
.arg("--si")
|
|
|
|
.arg(file1)
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains(" 1.0k ");
|
2021-03-19 14:15:24 +00:00
|
|
|
|
2020-12-17 19:50:22 +00:00
|
|
|
scene
|
|
|
|
.cmd("truncate")
|
|
|
|
.arg("-s")
|
|
|
|
.arg("+1000k")
|
2021-03-19 14:15:24 +00:00
|
|
|
.arg(file1)
|
|
|
|
.run();
|
|
|
|
|
2021-04-07 09:48:01 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-hl")
|
|
|
|
.arg(file1)
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains(" 1001K ");
|
2021-03-19 14:15:24 +00:00
|
|
|
|
2021-04-07 09:48:01 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-l")
|
|
|
|
.arg("--si")
|
|
|
|
.arg(file1)
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains(" 1.1M ");
|
2021-03-19 14:15:24 +00:00
|
|
|
|
|
|
|
let file2 = "test-human-2";
|
2021-04-07 09:48:01 +00:00
|
|
|
scene
|
2021-03-19 14:15:24 +00:00
|
|
|
.cmd("truncate")
|
|
|
|
.arg("-s")
|
|
|
|
.arg("+12300k")
|
|
|
|
.arg(file2)
|
2021-04-07 09:48:01 +00:00
|
|
|
.succeeds();
|
|
|
|
|
2021-03-19 14:15:24 +00:00
|
|
|
// GNU rounds up, so we must too.
|
2021-04-07 09:48:01 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-hl")
|
|
|
|
.arg(file2)
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains(" 13M ");
|
2021-03-19 14:15:24 +00:00
|
|
|
|
|
|
|
// GNU rounds up, so we must too.
|
2021-04-07 09:48:01 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-l")
|
|
|
|
.arg("--si")
|
|
|
|
.arg(file2)
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains(" 13M ");
|
2021-03-19 14:15:24 +00:00
|
|
|
|
|
|
|
let file3 = "test-human-3";
|
2021-04-07 09:48:01 +00:00
|
|
|
scene
|
2021-03-19 14:15:24 +00:00
|
|
|
.cmd("truncate")
|
|
|
|
.arg("-s")
|
|
|
|
.arg("+9999")
|
|
|
|
.arg(file3)
|
2021-04-07 09:48:01 +00:00
|
|
|
.succeeds();
|
|
|
|
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-hl")
|
|
|
|
.arg(file3)
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains(" 9.8K ");
|
|
|
|
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-l")
|
|
|
|
.arg("--si")
|
|
|
|
.arg(file3)
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains(" 10k ");
|
2020-12-15 12:36:12 +00:00
|
|
|
}
|
2020-12-19 16:54:28 +00:00
|
|
|
|
|
|
|
#[cfg(windows)]
|
|
|
|
#[test]
|
|
|
|
fn test_ls_hidden_windows() {
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
let file = "hiddenWindowsFileNoDot";
|
|
|
|
at.touch(file);
|
|
|
|
// hide the file
|
|
|
|
scene
|
|
|
|
.cmd("attrib")
|
|
|
|
.arg("+h")
|
|
|
|
.arg("+S")
|
|
|
|
.arg("+r")
|
|
|
|
.arg(file)
|
2021-04-07 09:48:01 +00:00
|
|
|
.succeeds();
|
|
|
|
|
|
|
|
let result = scene.ucmd().succeeds();
|
|
|
|
assert!(!result.stdout_str().contains(file));
|
2021-04-21 15:43:57 +00:00
|
|
|
scene.ucmd().arg("-a").succeeds().stdout_contains(file);
|
2020-12-19 16:54:28 +00:00
|
|
|
}
|
2021-03-25 19:24:53 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_ls_version_sort() {
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
for filename in &[
|
|
|
|
"a2",
|
|
|
|
"b1",
|
|
|
|
"b20",
|
|
|
|
"a1.4",
|
|
|
|
"a1.40",
|
|
|
|
"b3",
|
|
|
|
"b11",
|
|
|
|
"b20b",
|
|
|
|
"b20a",
|
|
|
|
"a100",
|
|
|
|
"a1.13",
|
|
|
|
"aa",
|
|
|
|
"a1",
|
|
|
|
"aaa",
|
|
|
|
"a1.00000040",
|
|
|
|
"abab",
|
|
|
|
"ab",
|
|
|
|
"a01.40",
|
|
|
|
"a001.001",
|
|
|
|
"a01.0000001",
|
|
|
|
"a01.001",
|
|
|
|
"a001.01",
|
|
|
|
] {
|
|
|
|
at.touch(filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut expected = vec![
|
|
|
|
"a1",
|
|
|
|
"a001.001",
|
|
|
|
"a001.01",
|
|
|
|
"a01.0000001",
|
|
|
|
"a01.001",
|
|
|
|
"a1.4",
|
|
|
|
"a1.13",
|
|
|
|
"a01.40",
|
|
|
|
"a1.00000040",
|
|
|
|
"a1.40",
|
|
|
|
"a2",
|
|
|
|
"a100",
|
|
|
|
"aa",
|
|
|
|
"aaa",
|
|
|
|
"ab",
|
|
|
|
"abab",
|
|
|
|
"b1",
|
|
|
|
"b3",
|
|
|
|
"b11",
|
|
|
|
"b20",
|
|
|
|
"b20a",
|
|
|
|
"b20b",
|
|
|
|
"", // because of '\n' at the end of the output
|
|
|
|
];
|
|
|
|
|
2021-04-07 09:48:01 +00:00
|
|
|
let result = scene.ucmd().arg("-1v").succeeds();
|
|
|
|
assert_eq!(
|
|
|
|
result.stdout_str().split('\n').collect::<Vec<_>>(),
|
|
|
|
expected
|
|
|
|
);
|
2021-03-25 19:24:53 +00:00
|
|
|
|
2021-04-07 09:48:01 +00:00
|
|
|
let result = scene.ucmd().arg("-1").arg("--sort=version").succeeds();
|
|
|
|
assert_eq!(
|
|
|
|
result.stdout_str().split('\n').collect::<Vec<_>>(),
|
|
|
|
expected
|
|
|
|
);
|
2021-03-25 19:24:53 +00:00
|
|
|
|
2021-04-07 09:48:01 +00:00
|
|
|
let result = scene.ucmd().arg("-a1v").succeeds();
|
2021-03-25 19:24:53 +00:00
|
|
|
expected.insert(0, "..");
|
|
|
|
expected.insert(0, ".");
|
2021-04-07 09:48:01 +00:00
|
|
|
assert_eq!(
|
|
|
|
result.stdout_str().split('\n').collect::<Vec<_>>(),
|
|
|
|
expected,
|
|
|
|
)
|
2021-03-25 19:24:53 +00:00
|
|
|
}
|
2021-04-01 20:50:13 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_ls_quoting_style() {
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
|
|
|
|
at.touch("one two");
|
|
|
|
at.touch("one");
|
|
|
|
|
|
|
|
// It seems that windows doesn't allow \n in filenames.
|
2021-04-21 10:45:21 +00:00
|
|
|
// And it also doesn't like \, of course.
|
2021-04-01 20:50:13 +00:00
|
|
|
#[cfg(unix)]
|
|
|
|
{
|
|
|
|
at.touch("one\ntwo");
|
2021-04-21 10:45:21 +00:00
|
|
|
at.touch("one\\two");
|
2021-04-01 20:50:13 +00:00
|
|
|
// Default is shell-escape
|
2021-04-07 09:48:01 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("one\ntwo")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_only("'one'$'\\n''two'\n");
|
2021-04-01 20:50:13 +00:00
|
|
|
|
|
|
|
for (arg, correct) in &[
|
2021-04-03 11:15:19 +00:00
|
|
|
("--quoting-style=literal", "one?two"),
|
|
|
|
("-N", "one?two"),
|
|
|
|
("--literal", "one?two"),
|
2021-04-01 20:50:13 +00:00
|
|
|
("--quoting-style=c", "\"one\\ntwo\""),
|
|
|
|
("-Q", "\"one\\ntwo\""),
|
|
|
|
("--quote-name", "\"one\\ntwo\""),
|
|
|
|
("--quoting-style=escape", "one\\ntwo"),
|
|
|
|
("-b", "one\\ntwo"),
|
|
|
|
("--escape", "one\\ntwo"),
|
|
|
|
("--quoting-style=shell-escape", "'one'$'\\n''two'"),
|
|
|
|
("--quoting-style=shell-escape-always", "'one'$'\\n''two'"),
|
|
|
|
("--quoting-style=shell", "one?two"),
|
|
|
|
("--quoting-style=shell-always", "'one?two'"),
|
|
|
|
] {
|
2021-04-07 09:48:01 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg(arg)
|
|
|
|
.arg("one\ntwo")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_only(format!("{}\n", correct));
|
2021-04-01 20:50:13 +00:00
|
|
|
}
|
2021-04-03 11:15:19 +00:00
|
|
|
|
2021-04-03 14:42:29 +00:00
|
|
|
for (arg, correct) in &[
|
|
|
|
("--quoting-style=literal", "one?two"),
|
|
|
|
("-N", "one?two"),
|
|
|
|
("--literal", "one?two"),
|
|
|
|
("--quoting-style=shell", "one?two"),
|
|
|
|
("--quoting-style=shell-always", "'one?two'"),
|
|
|
|
] {
|
2021-04-07 09:48:01 +00:00
|
|
|
scene
|
2021-04-03 14:42:29 +00:00
|
|
|
.ucmd()
|
|
|
|
.arg(arg)
|
|
|
|
.arg("--hide-control-chars")
|
|
|
|
.arg("one\ntwo")
|
2021-04-07 09:48:01 +00:00
|
|
|
.succeeds()
|
|
|
|
.stdout_only(format!("{}\n", correct));
|
2021-04-03 14:42:29 +00:00
|
|
|
}
|
|
|
|
|
2021-04-03 11:15:19 +00:00
|
|
|
for (arg, correct) in &[
|
|
|
|
("--quoting-style=literal", "one\ntwo"),
|
|
|
|
("-N", "one\ntwo"),
|
|
|
|
("--literal", "one\ntwo"),
|
|
|
|
("--quoting-style=shell", "one\ntwo"),
|
|
|
|
("--quoting-style=shell-always", "'one\ntwo'"),
|
|
|
|
] {
|
2021-04-07 09:48:01 +00:00
|
|
|
scene
|
2021-04-03 11:15:19 +00:00
|
|
|
.ucmd()
|
|
|
|
.arg(arg)
|
|
|
|
.arg("--show-control-chars")
|
|
|
|
.arg("one\ntwo")
|
2021-04-07 09:48:01 +00:00
|
|
|
.succeeds()
|
|
|
|
.stdout_only(format!("{}\n", correct));
|
2021-04-03 11:15:19 +00:00
|
|
|
}
|
2021-04-21 10:45:21 +00:00
|
|
|
|
|
|
|
for (arg, correct) in &[
|
|
|
|
("--quoting-style=literal", "one\\two"),
|
|
|
|
("-N", "one\\two"),
|
|
|
|
("--quoting-style=c", "\"one\\\\two\""),
|
|
|
|
("-Q", "\"one\\\\two\""),
|
|
|
|
("--quote-name", "\"one\\\\two\""),
|
|
|
|
("--quoting-style=escape", "one\\\\two"),
|
|
|
|
("-b", "one\\\\two"),
|
|
|
|
("--quoting-style=shell-escape", "'one\\two'"),
|
|
|
|
("--quoting-style=shell-escape-always", "'one\\two'"),
|
|
|
|
("--quoting-style=shell", "'one\\two'"),
|
|
|
|
("--quoting-style=shell-always", "'one\\two'"),
|
|
|
|
] {
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg(arg)
|
|
|
|
.arg("one\\two")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_only(format!("{}\n", correct));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tests for a character that forces quotation in shell-style escaping
|
|
|
|
// after a character in a dollar expression
|
|
|
|
at.touch("one\n&two");
|
|
|
|
for (arg, correct) in &[
|
|
|
|
("--quoting-style=shell-escape", "'one'$'\\n''&two'"),
|
|
|
|
("--quoting-style=shell-escape-always", "'one'$'\\n''&two'"),
|
|
|
|
] {
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg(arg)
|
|
|
|
.arg("one\n&two")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_only(format!("{}\n", correct));
|
|
|
|
}
|
2021-04-01 20:50:13 +00:00
|
|
|
}
|
|
|
|
|
2021-04-07 09:48:01 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("one two")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_only("'one two'\n");
|
2021-04-01 20:50:13 +00:00
|
|
|
|
|
|
|
for (arg, correct) in &[
|
|
|
|
("--quoting-style=literal", "one two"),
|
|
|
|
("-N", "one two"),
|
|
|
|
("--literal", "one two"),
|
|
|
|
("--quoting-style=c", "\"one two\""),
|
|
|
|
("-Q", "\"one two\""),
|
|
|
|
("--quote-name", "\"one two\""),
|
|
|
|
("--quoting-style=escape", "one\\ two"),
|
|
|
|
("-b", "one\\ two"),
|
|
|
|
("--escape", "one\\ two"),
|
|
|
|
("--quoting-style=shell-escape", "'one two'"),
|
|
|
|
("--quoting-style=shell-escape-always", "'one two'"),
|
|
|
|
("--quoting-style=shell", "'one two'"),
|
|
|
|
("--quoting-style=shell-always", "'one two'"),
|
|
|
|
] {
|
2021-04-07 09:48:01 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg(arg)
|
|
|
|
.arg("one two")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_only(format!("{}\n", correct));
|
2021-04-01 20:50:13 +00:00
|
|
|
}
|
|
|
|
|
2021-04-07 09:48:01 +00:00
|
|
|
scene.ucmd().arg("one").succeeds().stdout_only("one\n");
|
2021-04-01 20:50:13 +00:00
|
|
|
|
|
|
|
for (arg, correct) in &[
|
|
|
|
("--quoting-style=literal", "one"),
|
|
|
|
("-N", "one"),
|
|
|
|
("--quoting-style=c", "\"one\""),
|
|
|
|
("-Q", "\"one\""),
|
|
|
|
("--quote-name", "\"one\""),
|
|
|
|
("--quoting-style=escape", "one"),
|
|
|
|
("-b", "one"),
|
|
|
|
("--quoting-style=shell-escape", "one"),
|
|
|
|
("--quoting-style=shell-escape-always", "'one'"),
|
|
|
|
("--quoting-style=shell", "one"),
|
|
|
|
("--quoting-style=shell-always", "'one'"),
|
|
|
|
] {
|
2021-04-07 09:48:01 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg(arg)
|
|
|
|
.arg("one")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_only(format!("{}\n", correct));
|
2021-04-01 20:50:13 +00:00
|
|
|
}
|
|
|
|
}
|
2021-04-04 17:19:56 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_ls_ignore_hide() {
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
|
|
|
|
at.touch("README.md");
|
|
|
|
at.touch("CONTRIBUTING.md");
|
|
|
|
at.touch("some_other_file");
|
|
|
|
at.touch("READMECAREFULLY.md");
|
|
|
|
|
2021-04-04 21:14:55 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("--hide")
|
|
|
|
.arg("*")
|
|
|
|
.arg("-1")
|
|
|
|
.succeeds()
|
2021-04-07 09:48:01 +00:00
|
|
|
.stdout_only("");
|
2021-04-04 17:19:56 +00:00
|
|
|
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("--ignore")
|
|
|
|
.arg("*")
|
2021-04-04 21:14:55 +00:00
|
|
|
.arg("-1")
|
2021-04-04 17:19:56 +00:00
|
|
|
.succeeds()
|
2021-04-07 09:48:01 +00:00
|
|
|
.stdout_only("");
|
2021-04-04 17:19:56 +00:00
|
|
|
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("--ignore")
|
|
|
|
.arg("irrelevant pattern")
|
2021-04-04 21:14:55 +00:00
|
|
|
.arg("-1")
|
2021-04-04 17:19:56 +00:00
|
|
|
.succeeds()
|
2021-04-07 09:48:01 +00:00
|
|
|
.stdout_only("CONTRIBUTING.md\nREADME.md\nREADMECAREFULLY.md\nsome_other_file\n");
|
2021-04-04 17:19:56 +00:00
|
|
|
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("--ignore")
|
|
|
|
.arg("README*.md")
|
2021-04-04 21:14:55 +00:00
|
|
|
.arg("-1")
|
2021-04-04 17:19:56 +00:00
|
|
|
.succeeds()
|
2021-04-07 09:48:01 +00:00
|
|
|
.stdout_only("CONTRIBUTING.md\nsome_other_file\n");
|
2021-04-04 17:19:56 +00:00
|
|
|
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("--hide")
|
|
|
|
.arg("README*.md")
|
2021-04-04 21:14:55 +00:00
|
|
|
.arg("-1")
|
2021-04-04 17:19:56 +00:00
|
|
|
.succeeds()
|
2021-04-07 09:48:01 +00:00
|
|
|
.stdout_only("CONTRIBUTING.md\nsome_other_file\n");
|
2021-04-04 17:19:56 +00:00
|
|
|
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("--ignore")
|
|
|
|
.arg("*.md")
|
2021-04-04 21:14:55 +00:00
|
|
|
.arg("-1")
|
2021-04-04 17:19:56 +00:00
|
|
|
.succeeds()
|
2021-04-07 09:48:01 +00:00
|
|
|
.stdout_only("some_other_file\n");
|
2021-04-04 17:19:56 +00:00
|
|
|
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-a")
|
|
|
|
.arg("--ignore")
|
|
|
|
.arg("*.md")
|
2021-04-04 21:14:55 +00:00
|
|
|
.arg("-1")
|
2021-04-04 17:19:56 +00:00
|
|
|
.succeeds()
|
2021-04-07 09:48:01 +00:00
|
|
|
.stdout_only(".\n..\nsome_other_file\n");
|
2021-04-04 17:19:56 +00:00
|
|
|
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-a")
|
|
|
|
.arg("--hide")
|
|
|
|
.arg("*.md")
|
2021-04-04 21:14:55 +00:00
|
|
|
.arg("-1")
|
2021-04-04 17:19:56 +00:00
|
|
|
.succeeds()
|
2021-04-07 09:48:01 +00:00
|
|
|
.stdout_only(".\n..\nCONTRIBUTING.md\nREADME.md\nREADMECAREFULLY.md\nsome_other_file\n");
|
2021-04-04 17:19:56 +00:00
|
|
|
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-A")
|
|
|
|
.arg("--ignore")
|
|
|
|
.arg("*.md")
|
2021-04-04 21:14:55 +00:00
|
|
|
.arg("-1")
|
2021-04-04 17:19:56 +00:00
|
|
|
.succeeds()
|
2021-04-07 09:48:01 +00:00
|
|
|
.stdout_only("some_other_file\n");
|
2021-04-04 17:19:56 +00:00
|
|
|
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-A")
|
|
|
|
.arg("--hide")
|
|
|
|
.arg("*.md")
|
2021-04-04 21:14:55 +00:00
|
|
|
.arg("-1")
|
2021-04-04 17:19:56 +00:00
|
|
|
.succeeds()
|
2021-04-07 09:48:01 +00:00
|
|
|
.stdout_only("CONTRIBUTING.md\nREADME.md\nREADMECAREFULLY.md\nsome_other_file\n");
|
2021-04-04 20:35:22 +00:00
|
|
|
|
|
|
|
// Stacking multiple patterns
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("--ignore")
|
|
|
|
.arg("README*")
|
|
|
|
.arg("--ignore")
|
|
|
|
.arg("CONTRIBUTING*")
|
2021-04-04 21:14:55 +00:00
|
|
|
.arg("-1")
|
2021-04-04 20:35:22 +00:00
|
|
|
.succeeds()
|
2021-04-07 09:48:01 +00:00
|
|
|
.stdout_only("some_other_file\n");
|
2021-04-04 20:35:22 +00:00
|
|
|
|
2021-04-05 10:17:42 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("--hide")
|
|
|
|
.arg("README*")
|
|
|
|
.arg("--ignore")
|
|
|
|
.arg("CONTRIBUTING*")
|
|
|
|
.arg("-1")
|
|
|
|
.succeeds()
|
2021-04-07 09:48:01 +00:00
|
|
|
.stdout_only("some_other_file\n");
|
2021-04-05 10:17:42 +00:00
|
|
|
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("--hide")
|
|
|
|
.arg("README*")
|
|
|
|
.arg("--hide")
|
|
|
|
.arg("CONTRIBUTING*")
|
|
|
|
.arg("-1")
|
|
|
|
.succeeds()
|
2021-04-07 09:48:01 +00:00
|
|
|
.stdout_only("some_other_file\n");
|
2021-04-05 10:17:42 +00:00
|
|
|
|
2021-04-04 20:35:22 +00:00
|
|
|
// Invalid patterns
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("--ignore")
|
|
|
|
.arg("READ[ME")
|
2021-04-04 21:14:55 +00:00
|
|
|
.arg("-1")
|
2021-04-04 20:35:22 +00:00
|
|
|
.succeeds()
|
2021-04-07 09:48:01 +00:00
|
|
|
.stderr_contains(&"Invalid pattern")
|
|
|
|
.stdout_is("CONTRIBUTING.md\nREADME.md\nREADMECAREFULLY.md\nsome_other_file\n");
|
2021-04-04 20:35:22 +00:00
|
|
|
|
|
|
|
scene
|
|
|
|
.ucmd()
|
2021-04-05 10:17:42 +00:00
|
|
|
.arg("--hide")
|
2021-04-04 20:35:22 +00:00
|
|
|
.arg("READ[ME")
|
2021-04-04 21:14:55 +00:00
|
|
|
.arg("-1")
|
2021-04-04 20:35:22 +00:00
|
|
|
.succeeds()
|
2021-04-07 09:48:01 +00:00
|
|
|
.stderr_contains(&"Invalid pattern")
|
|
|
|
.stdout_is("CONTRIBUTING.md\nREADME.md\nREADMECAREFULLY.md\nsome_other_file\n");
|
2021-04-04 17:19:56 +00:00
|
|
|
}
|
2021-04-14 12:12:00 +00:00
|
|
|
|
2021-04-21 10:03:48 +00:00
|
|
|
#[test]
|
|
|
|
fn test_ls_ignore_backups() {
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
|
|
|
|
at.touch("somefile");
|
|
|
|
at.touch("somebackup~");
|
|
|
|
at.touch(".somehiddenfile");
|
|
|
|
at.touch(".somehiddenbackup~");
|
|
|
|
|
|
|
|
scene.ucmd().arg("-B").succeeds().stdout_is("somefile\n");
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("--ignore-backups")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_is("somefile\n");
|
|
|
|
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-aB")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains(".somehiddenfile")
|
|
|
|
.stdout_contains("somefile")
|
|
|
|
.stdout_does_not_contain("somebackup")
|
|
|
|
.stdout_does_not_contain(".somehiddenbackup~");
|
|
|
|
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-a")
|
|
|
|
.arg("--ignore-backups")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains(".somehiddenfile")
|
|
|
|
.stdout_contains("somefile")
|
|
|
|
.stdout_does_not_contain("somebackup")
|
|
|
|
.stdout_does_not_contain(".somehiddenbackup~");
|
|
|
|
}
|
2021-04-21 10:06:54 +00:00
|
|
|
|
2021-04-14 12:12:00 +00:00
|
|
|
#[test]
|
|
|
|
fn test_ls_directory() {
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
|
|
|
|
at.mkdir("some_dir");
|
|
|
|
at.symlink_dir("some_dir", "sym_dir");
|
|
|
|
|
2021-04-16 16:27:36 +00:00
|
|
|
at.touch(Path::new("some_dir").join("nested_file").to_str().unwrap());
|
2021-04-14 12:12:00 +00:00
|
|
|
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("some_dir")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_is("nested_file\n");
|
|
|
|
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("--directory")
|
|
|
|
.arg("some_dir")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_is("some_dir\n");
|
|
|
|
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("sym_dir")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_is("nested_file\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_ls_deref_command_line() {
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
|
|
|
|
at.touch("some_file");
|
|
|
|
at.symlink_file("some_file", "sym_file");
|
|
|
|
|
2021-04-14 12:42:14 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("sym_file")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_is("sym_file\n");
|
|
|
|
|
|
|
|
// -l changes the default to no dereferencing
|
2021-04-14 12:12:00 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-l")
|
|
|
|
.arg("sym_file")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains("sym_file ->");
|
|
|
|
|
2021-04-14 12:42:14 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("--dereference-command-line-symlink-to-dir")
|
|
|
|
.arg("sym_file")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_is("sym_file\n");
|
|
|
|
|
2021-04-14 12:12:00 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-l")
|
|
|
|
.arg("--dereference-command-line-symlink-to-dir")
|
|
|
|
.arg("sym_file")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains("sym_file ->");
|
|
|
|
|
2021-04-14 12:42:14 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("--dereference-command-line")
|
|
|
|
.arg("sym_file")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_is("sym_file\n");
|
|
|
|
|
2021-04-14 12:12:00 +00:00
|
|
|
let result = scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-l")
|
|
|
|
.arg("--dereference-command-line")
|
|
|
|
.arg("sym_file")
|
|
|
|
.succeeds();
|
|
|
|
|
|
|
|
assert!(!result.stdout_str().contains("->"));
|
|
|
|
|
|
|
|
let result = scene.ucmd().arg("-lH").arg("sym_file").succeeds();
|
|
|
|
|
|
|
|
assert!(!result.stdout_str().contains("sym_file ->"));
|
|
|
|
|
|
|
|
// If the symlink is not a command line argument, it must be shown normally
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-l")
|
|
|
|
.arg("--dereference-command-line")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains("sym_file ->");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_ls_deref_command_line_dir() {
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
|
|
|
|
at.mkdir("some_dir");
|
|
|
|
at.symlink_dir("some_dir", "sym_dir");
|
|
|
|
|
2021-04-16 16:27:36 +00:00
|
|
|
at.touch(Path::new("some_dir").join("nested_file").to_str().unwrap());
|
2021-04-14 12:12:00 +00:00
|
|
|
|
2021-04-14 12:42:14 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("sym_dir")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains("nested_file");
|
|
|
|
|
2021-04-14 12:12:00 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-l")
|
|
|
|
.arg("sym_dir")
|
|
|
|
.succeeds()
|
2021-04-14 12:42:14 +00:00
|
|
|
.stdout_contains("sym_dir ->");
|
|
|
|
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("--dereference-command-line-symlink-to-dir")
|
|
|
|
.arg("sym_dir")
|
|
|
|
.succeeds()
|
2021-04-14 12:12:00 +00:00
|
|
|
.stdout_contains("nested_file");
|
|
|
|
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-l")
|
|
|
|
.arg("--dereference-command-line-symlink-to-dir")
|
|
|
|
.arg("sym_dir")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains("nested_file");
|
|
|
|
|
2021-04-14 12:42:14 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("--dereference-command-line")
|
|
|
|
.arg("sym_dir")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains("nested_file");
|
|
|
|
|
2021-04-14 12:12:00 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-l")
|
|
|
|
.arg("--dereference-command-line")
|
|
|
|
.arg("sym_dir")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains("nested_file");
|
|
|
|
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-lH")
|
|
|
|
.arg("sym_dir")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains("nested_file");
|
|
|
|
|
|
|
|
// If the symlink is not a command line argument, it must be shown normally
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-l")
|
|
|
|
.arg("--dereference-command-line")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains("sym_dir ->");
|
|
|
|
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-lH")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains("sym_dir ->");
|
|
|
|
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-l")
|
|
|
|
.arg("--dereference-command-line-symlink-to-dir")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains("sym_dir ->");
|
|
|
|
|
|
|
|
// --directory does not dereference anything by default
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-l")
|
|
|
|
.arg("--directory")
|
|
|
|
.arg("sym_dir")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains("sym_dir ->");
|
|
|
|
|
|
|
|
let result = scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-l")
|
|
|
|
.arg("--directory")
|
|
|
|
.arg("--dereference-command-line-symlink-to-dir")
|
|
|
|
.arg("sym_dir")
|
|
|
|
.succeeds();
|
|
|
|
|
|
|
|
assert!(!result.stdout_str().ends_with("sym_dir"));
|
2021-04-14 12:42:14 +00:00
|
|
|
|
|
|
|
// --classify does not dereference anything by default
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-l")
|
|
|
|
.arg("--directory")
|
|
|
|
.arg("sym_dir")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains("sym_dir ->");
|
|
|
|
|
|
|
|
let result = scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-l")
|
|
|
|
.arg("--directory")
|
|
|
|
.arg("--dereference-command-line-symlink-to-dir")
|
|
|
|
.arg("sym_dir")
|
|
|
|
.succeeds();
|
|
|
|
|
|
|
|
assert!(!result.stdout_str().ends_with("sym_dir"));
|
2021-04-14 12:12:00 +00:00
|
|
|
}
|
2021-03-29 20:26:55 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_ls_sort_extension() {
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
for filename in &[
|
|
|
|
"file1",
|
|
|
|
"file2",
|
|
|
|
"anotherFile",
|
|
|
|
".hidden",
|
|
|
|
".file.1",
|
|
|
|
".file.2",
|
|
|
|
"file.1",
|
|
|
|
"file.2",
|
|
|
|
"anotherFile.1",
|
|
|
|
"anotherFile.2",
|
|
|
|
"file.ext",
|
|
|
|
"file.debug",
|
|
|
|
"anotherFile.ext",
|
|
|
|
"anotherFile.debug",
|
|
|
|
] {
|
|
|
|
at.touch(filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
let expected = vec![
|
|
|
|
".",
|
|
|
|
"..",
|
2021-04-26 12:42:42 +00:00
|
|
|
".hidden",
|
2021-03-29 20:26:55 +00:00
|
|
|
"anotherFile",
|
|
|
|
"file1",
|
|
|
|
"file2",
|
|
|
|
".file.1",
|
|
|
|
"anotherFile.1",
|
|
|
|
"file.1",
|
|
|
|
".file.2",
|
|
|
|
"anotherFile.2",
|
|
|
|
"file.2",
|
|
|
|
"anotherFile.debug",
|
|
|
|
"file.debug",
|
|
|
|
"anotherFile.ext",
|
|
|
|
"file.ext",
|
|
|
|
"", // because of '\n' at the end of the output
|
|
|
|
];
|
|
|
|
|
|
|
|
let result = scene.ucmd().arg("-1aX").run();
|
2021-04-26 12:42:42 +00:00
|
|
|
assert_eq!(
|
|
|
|
result.stdout_str().split('\n').collect::<Vec<_>>(),
|
|
|
|
expected,
|
|
|
|
);
|
2021-03-29 20:26:55 +00:00
|
|
|
|
|
|
|
let result = scene.ucmd().arg("-1a").arg("--sort=extension").run();
|
2021-04-26 12:42:42 +00:00
|
|
|
assert_eq!(
|
|
|
|
result.stdout_str().split('\n').collect::<Vec<_>>(),
|
|
|
|
expected,
|
|
|
|
);
|
2021-04-25 21:33:19 +00:00
|
|
|
}
|
2021-05-18 00:00:16 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_ls_path() {
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
|
|
|
|
let file1 = "file1";
|
|
|
|
let file2 = "file2";
|
|
|
|
let dir = "dir";
|
|
|
|
let path = &format!("{}/{}", dir, file2);
|
|
|
|
|
|
|
|
at.mkdir(dir);
|
|
|
|
at.touch(file1);
|
|
|
|
at.touch(path);
|
|
|
|
|
|
|
|
let expected_stdout = &format!("{}\n", path);
|
|
|
|
scene.ucmd().arg(path).run().stdout_is(expected_stdout);
|
|
|
|
|
|
|
|
let expected_stdout = &format!("./{}\n", path);
|
2021-05-21 16:50:54 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg(format!("./{}", path))
|
|
|
|
.run()
|
|
|
|
.stdout_is(expected_stdout);
|
2021-05-18 00:00:16 +00:00
|
|
|
|
2021-05-21 16:50:54 +00:00
|
|
|
let abs_path = format!("{}/{}", at.as_string(), path);
|
2021-05-22 09:21:50 +00:00
|
|
|
let expected_stdout = if cfg!(windows) {
|
|
|
|
format!("\'{}\'\n", abs_path)
|
|
|
|
} else {
|
|
|
|
format!("{}\n", abs_path)
|
|
|
|
};
|
2021-05-21 16:50:54 +00:00
|
|
|
scene.ucmd().arg(&abs_path).run().stdout_is(expected_stdout);
|
2021-05-18 00:00:16 +00:00
|
|
|
|
2021-08-11 20:03:41 +00:00
|
|
|
let expected_stdout = format!("{}\n{}\n", path, file1);
|
2021-05-18 00:00:16 +00:00
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg(file1)
|
|
|
|
.arg(path)
|
|
|
|
.run()
|
|
|
|
.stdout_is(expected_stdout);
|
|
|
|
}
|
2021-06-20 08:20:38 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_ls_dangling_symlinks() {
|
|
|
|
let scene = TestScenario::new(util_name!());
|
|
|
|
let at = &scene.fixtures;
|
|
|
|
|
|
|
|
at.mkdir("temp_dir");
|
|
|
|
at.symlink_file("does_not_exist", "temp_dir/dangle");
|
|
|
|
|
|
|
|
scene.ucmd().arg("-L").arg("temp_dir/dangle").fails();
|
|
|
|
scene.ucmd().arg("-H").arg("temp_dir/dangle").fails();
|
|
|
|
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("temp_dir/dangle")
|
|
|
|
.succeeds()
|
|
|
|
.stdout_contains("dangle");
|
|
|
|
|
|
|
|
scene
|
|
|
|
.ucmd()
|
|
|
|
.arg("-Li")
|
|
|
|
.arg("temp_dir")
|
|
|
|
.succeeds() // this should fail, though at the moment, ls lacks a way to propagate errors encountered during display
|
2021-06-20 11:28:28 +00:00
|
|
|
.stdout_contains(if cfg!(windows) { "dangle" } else { "? dangle" });
|
2021-06-20 08:20:38 +00:00
|
|
|
}
|