Merge branch 'file-name-refactoring'

This commit is contained in:
Benjamin Sago 2017-05-02 19:34:33 +01:00
commit 609bafef49
23 changed files with 387 additions and 201 deletions

10
Vagrantfile vendored
View File

@ -172,6 +172,16 @@ Vagrant.configure(2) do |config|
echo -ne "#{test_dir}/file-names/invalid-utf8-2: [\\xc3\\x28]" | xargs -0 touch
echo -ne "#{test_dir}/file-names/invalid-utf8-3: [\\xe2\\x82\\x28]" | xargs -0 touch
echo -ne "#{test_dir}/file-names/invalid-utf8-4: [\\xf0\\x28\\x8c\\x28]" | xargs -0 touch
echo -ne "#{test_dir}/file-names/new-line-dir: [\\n]" | xargs -0 mkdir
echo -ne "#{test_dir}/file-names/new-line-dir: [\\n]/subfile" | xargs -0 touch
echo -ne "#{test_dir}/file-names/new-line-dir: [\\n]/another: [\\n]" | xargs -0 touch
echo -ne "#{test_dir}/file-names/new-line-dir: [\\n]/broken" | xargs -0 touch
mkdir "#{test_dir}/file-names/links"
ln -s "#{test_dir}/file-names/new-line-dir"*/* "#{test_dir}/file-names/links"
echo -ne "#{test_dir}/file-names/new-line-dir: [\\n]/broken" | xargs -0 rm
EOF

View File

@ -23,9 +23,12 @@ use std::ffi::OsStr;
use std::io::{stderr, Write, Result as IOResult};
use std::path::{Component, Path};
use ansi_term::{ANSIStrings, Style};
use fs::{Dir, File};
use options::{Options, View};
pub use options::Misfire;
use output::escape;
mod fs;
mod info;
@ -116,7 +119,9 @@ impl<'w, W: Write + 'w> Exa<'w, W> {
}
if !is_only_dir {
writeln!(self.writer, "{}:", dir.path.display())?;
let mut bits = Vec::new();
escape(dir.path.display().to_string(), &mut bits, Style::default(), Style::default());
writeln!(self.writer, "{}:", ANSIStrings(&bits))?;
}
let mut children = Vec::new();

View File

@ -1,7 +1,5 @@
//! Files, and methods and fields to access their metadata.
use std::ascii::AsciiExt;
use std::env::current_dir;
use std::fs;
use std::io::Error as IOError;
use std::io::Result as IOResult;
@ -14,6 +12,7 @@ use fs::fields as f;
#[cfg(any(target_os = "macos", target_os = "linux"))]
use std::os::unix::fs::FileTypeExt;
/// Constant table copied from https://doc.rust-lang.org/src/std/sys/unix/ext/fs.rs.html#11-259
/// which is currently unstable and lacks vision for stabilization,
/// see https://github.com/rust-lang/rust/issues/27712
@ -344,6 +343,8 @@ impl<'dir> File<'dir> {
/// directory, so will not work if this file has just been passed in on
/// the command line.
pub fn git_status(&self) -> f::Git {
use std::env::current_dir;
match self.dir {
None => f::Git { staged: f::GitStatus::NotModified, unstaged: f::GitStatus::NotModified },
Some(d) => {
@ -421,6 +422,8 @@ impl<'a> AsRef<File<'a>> for File<'a> {
/// against a pre-compiled list of extensions which are known to only exist
/// within ASCII, so it's alright.
fn ext(path: &Path) -> Option<String> {
use std::ascii::AsciiExt;
let name = match path.file_name() {
Some(f) => f.to_string_lossy().to_string(),
None => return None,

View File

@ -160,10 +160,21 @@ impl TextCellContents {
ANSIStrings(&self.0)
}
/// Calculates the width that a cell with these contents would take up, by
/// counting the number of characters in each unformatted ANSI string.
pub fn width(&self) -> DisplayWidth {
let foo = self.0.iter().map(|anstr| anstr.chars().count()).sum();
DisplayWidth(foo)
}
/// Promotes these contents to a full cell containing them alongside
/// their calculated width.
pub fn promote(self) -> TextCell {
TextCell {
width: self.width(),
contents: self,
}
}
}

View File

@ -99,9 +99,9 @@ use fs::feature::xattr::{Attribute, FileAttributes};
use options::{FileFilter, RecurseOptions};
use output::colours::Colours;
use output::column::{Alignment, Column, Columns, SizeFormat};
use output::cell::{TextCell, DisplayWidth};
use output::cell::{TextCell, TextCellContents, DisplayWidth};
use output::tree::TreeTrunk;
use super::filename;
use output::file_name::FileName;
/// With the **Details** view, the output gets formatted into columns, with
@ -307,24 +307,10 @@ impl Details {
let mut files = Vec::new();
let mut errors = egg.errors;
let filename = filename(&egg.file, &self.colours, true, self.classify);
let mut width = filename.width();
if egg.file.dir.is_none() {
if let Some(parent) = egg.file.path.parent() {
width = width + 1 + DisplayWidth::from(parent.to_string_lossy().as_ref());
}
}
let name = TextCell {
contents: filename,
width: width,
};
let row = Row {
depth: depth,
cells: Some(egg.cells),
name: name,
name: FileName::new(&egg.file, &self.colours).paint(true, self.classify).promote(),
last: index == num_eggs - 1,
};
@ -457,20 +443,8 @@ impl<'a, U: Users+Groups+'a> Table<'a, U> {
self.rows.push(row);
}
pub fn filename_cell(&self, file: File, links: bool) -> TextCell {
let filename = filename(&file, &self.opts.colours, links, self.opts.classify);
let mut width = filename.width();
if file.dir.is_none() {
if let Some(parent) = file.path.parent() {
width = width + 1 + DisplayWidth::from(parent.to_string_lossy().as_ref());
}
}
TextCell {
contents: filename,
width: width,
}
pub fn filename(&self, file: File, links: bool) -> TextCellContents {
FileName::new(&file, &self.opts.colours).paint(links, self.opts.classify)
}
pub fn add_file_with_cells(&mut self, cells: Vec<TextCell>, name_cell: TextCell, depth: usize, last: bool) {

25
src/output/escape.rs Normal file
View File

@ -0,0 +1,25 @@
use ansi_term::{ANSIString, Style};
pub fn escape<'a>(string: String, bits: &mut Vec<ANSIString<'a>>, good: Style, bad: Style) {
if string.chars().all(|c| c >= 0x20 as char) {
bits.push(good.paint(string));
}
else {
for c in string.chars() {
// The `escape_default` method on `char` is *almost* what we want here, but
// it still escapes non-ASCII UTF-8 characters, which are still printable.
if c >= 0x20 as char {
// TODO: This allocates way too much,
// hence the `all` check above.
let mut s = String::new();
s.push(c);
bits.push(good.paint(s));
} else {
let s = c.escape_default().collect::<String>();
bits.push(bad.paint(s));
}
}
}
}

151
src/output/file_name.rs Normal file
View File

@ -0,0 +1,151 @@
use std::path::Path;
use ansi_term::{ANSIString, Style};
use fs::{File, FileTarget};
use output::Colours;
use output::escape;
use output::cell::TextCellContents;
pub struct FileName<'a, 'dir: 'a> {
file: &'a File<'dir>,
colours: &'a Colours,
}
impl<'a, 'dir> FileName<'a, 'dir> {
pub fn new(file: &'a File<'dir>, colours: &'a Colours) -> FileName<'a, 'dir> {
FileName {
file: file,
colours: colours,
}
}
pub fn paint(&self, links: bool, classify: bool) -> TextCellContents {
let mut bits = Vec::new();
if self.file.dir.is_none() {
if let Some(parent) = self.file.path.parent() {
self.add_parent_bits(&mut bits, parent);
}
}
if !self.file.name.is_empty() {
for bit in self.coloured_file_name() {
bits.push(bit);
}
}
if links && self.file.is_link() {
match self.file.link_target() {
FileTarget::Ok(target) => {
bits.push(Style::default().paint(" "));
bits.push(self.colours.punctuation.paint("->"));
bits.push(Style::default().paint(" "));
if let Some(parent) = target.path.parent() {
self.add_parent_bits(&mut bits, parent);
}
if !target.name.is_empty() {
let target = FileName::new(&target, self.colours);
for bit in target.coloured_file_name() {
bits.push(bit);
}
}
},
FileTarget::Broken(broken_path) => {
bits.push(Style::default().paint(" "));
bits.push(self.colours.broken_arrow.paint("->"));
bits.push(Style::default().paint(" "));
escape(broken_path.display().to_string(), &mut bits, self.colours.broken_filename, self.colours.control_char.underline());
},
FileTarget::Err(_) => {
// Do nothing -- the error gets displayed on the next line
}
}
}
else if classify {
if let Some(class) = self.classify_char() {
bits.push(Style::default().paint(class));
}
}
bits.into()
}
/// Adds the bits of the parent path to the given bits vector.
/// The path gets its characters escaped based on the colours.
fn add_parent_bits(&self, bits: &mut Vec<ANSIString>, parent: &Path) {
let coconut = parent.components().count();
if coconut == 1 && parent.has_root() {
bits.push(self.colours.symlink_path.paint("/"));
}
else if coconut >= 1 {
escape(parent.to_string_lossy().to_string(), bits, self.colours.symlink_path, self.colours.control_char);
bits.push(self.colours.symlink_path.paint("/"));
}
}
/// The character to be displayed after a file when classifying is on, if
/// the files type has one associated with it.
fn classify_char(&self) -> Option<&'static str> {
if self.file.is_executable_file() {
Some("*")
} else if self.file.is_directory() {
Some("/")
} else if self.file.is_pipe() {
Some("|")
} else if self.file.is_link() {
Some("@")
} else if self.file.is_socket() {
Some("=")
} else {
None
}
}
/// Returns at least one ANSI-highlighted string representing this files
/// name using the given set of colours.
///
/// Ordinarily, this will be just one string: the files complete name,
/// coloured according to its file type. If the name contains control
/// characters such as newlines or escapes, though, we cant just print them
/// to the screen directly, because then therell be newlines in weird places.
///
/// So in that situation, those characters will be escaped and highlighted in
/// a different colour.
fn coloured_file_name<'unused>(&self) -> Vec<ANSIString<'unused>> {
let file_style = self.style();
let mut bits = Vec::new();
escape(self.file.name.clone(), &mut bits, file_style, self.colours.control_char);
bits
}
pub fn style(&self) -> Style {
match self.file {
f if f.is_directory() => self.colours.filetypes.directory,
f if f.is_executable_file() => self.colours.filetypes.executable,
f if f.is_link() => self.colours.filetypes.symlink,
f if f.is_pipe() => self.colours.filetypes.pipe,
f if f.is_char_device()
| f.is_block_device() => self.colours.filetypes.device,
f if f.is_socket() => self.colours.filetypes.socket,
f if !f.is_file() => self.colours.filetypes.special,
f if f.is_immediate() => self.colours.filetypes.immediate,
f if f.is_image() => self.colours.filetypes.image,
f if f.is_video() => self.colours.filetypes.video,
f if f.is_music() => self.colours.filetypes.music,
f if f.is_lossless() => self.colours.filetypes.lossless,
f if f.is_crypto() => self.colours.filetypes.crypto,
f if f.is_document() => self.colours.filetypes.document,
f if f.is_compressed() => self.colours.filetypes.compressed,
f if f.is_temp() => self.colours.filetypes.temp,
f if f.is_compiled() => self.colours.filetypes.compiled,
_ => self.colours.filetypes.normal,
}
}
}

View File

@ -3,9 +3,8 @@ use std::io::{Write, Result as IOResult};
use term_grid as grid;
use fs::File;
use output::DisplayWidth;
use output::colours::Colours;
use super::filename;
use output::file_name::FileName;
#[derive(PartialEq, Debug, Copy, Clone)]
@ -29,14 +28,8 @@ impl Grid {
grid.reserve(files.len());
for file in files.iter() {
let filename = filename(file, &self.colours, false, self.classify);
let mut width = filename.width();
if file.dir.is_none() {
if let Some(parent) = file.path.parent() {
width = width + 1 + DisplayWidth::from(parent.to_string_lossy().as_ref());
}
}
let filename = FileName::new(file, &self.colours).paint(false, self.classify);
let width = filename.width();
grid.add(grid::Cell {
contents: filename.strings().to_string(),
@ -50,7 +43,8 @@ impl Grid {
else {
// File names too long for a grid - drop down to just listing them!
for file in files.iter() {
writeln!(w, "{}", filename(file, &self.colours, false, self.classify).strings())?;
let name_cell = FileName::new(file, &self.colours).paint(false, self.classify);
writeln!(w, "{}", name_cell.strings())?;
}
Ok(())
}

View File

@ -45,7 +45,7 @@ impl GridDetails {
.collect::<Vec<_>>();
let file_names = files.into_iter()
.map(|file| first_table.filename_cell(file, false))
.map(|file| first_table.filename(file, false).promote())
.collect::<Vec<_>>();
(cells, file_names)

View File

@ -4,7 +4,7 @@ use ansi_term::ANSIStrings;
use fs::File;
use super::filename;
use output::file_name::FileName;
use super::colours::Colours;
@ -18,7 +18,8 @@ pub struct Lines {
impl Lines {
pub fn view<W: Write>(&self, files: Vec<File>, w: &mut W) -> IOResult<()> {
for file in files {
writeln!(w, "{}", ANSIStrings(&filename(&file, &self.colours, true, self.classify)))?;
let name_cell = FileName::new(&file, &self.colours).paint(true, self.classify);
writeln!(w, "{}", ANSIStrings(&name_cell))?;
}
Ok(())
}

View File

@ -1,13 +1,10 @@
use ansi_term::{ANSIString, Style};
use fs::{File, FileTarget};
pub use self::cell::{TextCell, TextCellContents, DisplayWidth};
pub use self::colours::Colours;
pub use self::details::Details;
pub use self::grid_details::GridDetails;
pub use self::grid::Grid;
pub use self::lines::Lines;
pub use self::escape::escape;
mod grid;
pub mod details;
@ -17,143 +14,5 @@ pub mod column;
mod cell;
mod colours;
mod tree;
pub fn filename(file: &File, colours: &Colours, links: bool, classify: bool) -> TextCellContents {
let mut bits = Vec::new();
// TODO: This long function could do with some splitting up.
if file.dir.is_none() {
if let Some(parent) = file.path.parent() {
let coconut = parent.components().count();
if coconut == 1 && parent.has_root() {
bits.push(colours.symlink_path.paint("/"));
}
else if coconut >= 1 {
bits.push(colours.symlink_path.paint(parent.to_string_lossy().to_string()));
bits.push(colours.symlink_path.paint("/"));
}
}
}
if !file.name.is_empty() {
for bit in coloured_file_name(file, colours) {
bits.push(bit);
}
}
if links && file.is_link() {
match file.link_target() {
FileTarget::Ok(target) => {
bits.push(Style::default().paint(" "));
bits.push(colours.punctuation.paint("->"));
bits.push(Style::default().paint(" "));
if let Some(parent) = target.path.parent() {
let coconut = parent.components().count();
if coconut == 1 && parent.has_root() {
bits.push(colours.symlink_path.paint("/"));
}
else if coconut >= 1 {
bits.push(colours.symlink_path.paint(parent.to_string_lossy().to_string()));
bits.push(colours.symlink_path.paint("/"));
}
}
if !target.name.is_empty() {
bits.push(file_colour(colours, &target).paint(target.name));
}
},
FileTarget::Broken(broken_path) => {
bits.push(Style::default().paint(" "));
bits.push(colours.broken_arrow.paint("->"));
bits.push(Style::default().paint(" "));
bits.push(colours.broken_filename.paint(broken_path.display().to_string()));
},
FileTarget::Err(_) => {
// Do nothing -- the error gets displayed on the next line
}
}
} else if classify {
if file.is_executable_file() {
bits.push(Style::default().paint("*"));
} else if file.is_directory() {
bits.push(Style::default().paint("/"));
} else if file.is_pipe() {
bits.push(Style::default().paint("|"));
} else if file.is_link() {
bits.push(Style::default().paint("@"));
} else if file.is_socket() {
bits.push(Style::default().paint("="));
}
}
bits.into()
}
/// Returns at least one ANSI-highlighted string representing this files
/// name using the given set of colours.
///
/// Ordinarily, this will be just one string: the files complete name,
/// coloured according to its file type. If the name contains control
/// characters such as newlines or escapes, though, we cant just print them
/// to the screen directly, because then therell be newlines in weird places.
///
/// So in that situation, those characters will be escaped and highlighted in
/// a different colour.
fn coloured_file_name<'a>(file: &File, colours: &Colours) -> Vec<ANSIString<'a>> {
let colour = file_colour(colours, file);
let mut bits = Vec::new();
if file.name.chars().all(|c| c >= 0x20 as char) {
bits.push(colour.paint(file.name.clone()));
}
else {
for c in file.name.chars() {
// The `escape_default` method on `char` is *almost* what we want here, but
// it still escapes non-ASCII UTF-8 characters, which are still printable.
if c >= 0x20 as char {
// TODO: This allocates way too much,
// hence the `all` check above.
let mut s = String::new();
s.push(c);
bits.push(colour.paint(s));
} else {
let s = c.escape_default().collect::<String>();
bits.push(colours.control_char.paint(s));
}
}
}
bits
}
pub fn file_colour(colours: &Colours, file: &File) -> Style {
match file {
f if f.is_directory() => colours.filetypes.directory,
f if f.is_executable_file() => colours.filetypes.executable,
f if f.is_link() => colours.filetypes.symlink,
f if f.is_pipe() => colours.filetypes.pipe,
f if f.is_char_device()
| f.is_block_device() => colours.filetypes.device,
f if f.is_socket() => colours.filetypes.socket,
f if !f.is_file() => colours.filetypes.special,
f if f.is_immediate() => colours.filetypes.immediate,
f if f.is_image() => colours.filetypes.image,
f if f.is_video() => colours.filetypes.video,
f if f.is_music() => colours.filetypes.music,
f if f.is_lossless() => colours.filetypes.lossless,
f if f.is_crypto() => colours.filetypes.crypto,
f if f.is_document() => colours.filetypes.document,
f if f.is_compressed() => colours.filetypes.compressed,
f if f.is_temp() => colours.filetypes.temp,
f if f.is_compiled() => colours.filetypes.compiled,
_ => colours.filetypes.normal,
}
}
pub mod file_name;
mod escape;

View File

@ -1,6 +1,6 @@
ansi: [\u{1b}[34mblue\u{1b}[0m] form-feed: [\u{c}] return: [\r]
ascii: hello invalid-utf8-1: [<5B>] tab: [\t]
backspace: [\u{8}] invalid-utf8-2: [<5B>(] utf-8: pâté
bell: [\u{7}] invalid-utf8-3: [<5B>(] vertical-tab: [\u{b}]
emoji: [🆒] invalid-utf8-4: [<5B>(<28>(]
escape: [\u{1b}] new-line: [\n]
ansi: [\u{1b}[34mblue\u{1b}[0m] form-feed: [\u{c}] new-line-dir: [\n]
ascii: hello invalid-utf8-1: [<5B>] new-line: [\n]
backspace: [\u{8}] invalid-utf8-2: [<5B>(] return: [\r]
bell: [\u{7}] invalid-utf8-3: [<5B>(] tab: [\t]
emoji: [🆒] invalid-utf8-4: [<5B>(<28>(] utf-8: pâté
escape: [\u{1b}] links vertical-tab: [\u{b}]

View File

@ -9,6 +9,8 @@ invalid-utf8-1: [<5B>]
invalid-utf8-2: [<5B>(]
invalid-utf8-3: [<5B>(]
invalid-utf8-4: [<5B>(<28>(]
links
new-line-dir: [\n]
new-line: [\n]
return: [\r]
tab: [\t]

12
xtests/file_names_R Normal file
View File

@ -0,0 +1,12 @@
ansi: [\u{1b}[34mblue\u{1b}[0m] form-feed: [\u{c}] new-line-dir: [\n]
ascii: hello invalid-utf8-1: [<5B>] new-line: [\n]
backspace: [\u{8}] invalid-utf8-2: [<5B>(] return: [\r]
bell: [\u{7}] invalid-utf8-3: [<5B>(] tab: [\t]
emoji: [🆒] invalid-utf8-4: [<5B>(<28>(] utf-8: pâté
escape: [\u{1b}] links vertical-tab: [\u{b}]
/testcases/file-names/links:
another: [\n] broken subfile
/testcases/file-names/new-line-dir: [\n]:
another: [\n] subfile

29
xtests/file_names_T Normal file
View File

@ -0,0 +1,29 @@
/testcases/file-names
├── ansi: [\u{1b}[34mblue\u{1b}[0m]
├── ascii: hello
├── backspace: [\u{8}]
├── bell: [\u{7}]
├── emoji: [🆒]
├── escape: [\u{1b}]
├── form-feed: [\u{c}]
├── invalid-utf8-1: [<5B>]
│ └── <Error: path somehow contained a NUL?>
├── invalid-utf8-2: [<5B>(]
│ └── <Error: path somehow contained a NUL?>
├── invalid-utf8-3: [<5B>(]
│ └── <Error: path somehow contained a NUL?>
├── invalid-utf8-4: [<5B>(<28>(]
│ └── <Error: path somehow contained a NUL?>
├── links
│ ├── another: [\n] -> /testcases/file-names/new-line-dir: [\n]/another: [\n]
│ ├── broken -> /testcases/file-names/new-line-dir: [\n]/broken
│ │ └── <No such file or directory (os error 2)>
│ └── subfile -> /testcases/file-names/new-line-dir: [\n]/subfile
├── new-line-dir: [\n]
│ ├── another: [\n]
│ └── subfile
├── new-line: [\n]
├── return: [\r]
├── tab: [\t]
├── utf-8: pâté
└── vertical-tab: [\u{b}]

View File

@ -1,6 +1,6 @@
ansi: [\u{1b}[34mblue\u{1b}[0m] ascii: hello backspace: [\u{8}]
bell: [\u{7}] emoji: [🆒] escape: [\u{1b}]
form-feed: [\u{c}] invalid-utf8-1: [<5B>] invalid-utf8-2: [<5B>(]
invalid-utf8-3: [<5B>(] invalid-utf8-4: [<5B>(<28>(] new-line: [\n]
return: [\r] tab: [\t] utf-8: pâté
vertical-tab: [\u{b}]
invalid-utf8-3: [<5B>(] invalid-utf8-4: [<5B>(<28>(] links
new-line-dir: [\n] new-line: [\n] return: [\r]
tab: [\t] utf-8: pâté vertical-tab: [\u{b}]

13
xtests/files_star_100 Normal file
View File

@ -0,0 +1,13 @@
/testcases/files/10_bytes /testcases/files/1_KiB /testcases/files/5_MiB
/testcases/files/10_KiB /testcases/files/1_MiB /testcases/files/6_bytes
/testcases/files/10_MiB /testcases/files/2_bytes /testcases/files/6_KiB
/testcases/files/11_bytes /testcases/files/2_KiB /testcases/files/6_MiB
/testcases/files/11_KiB /testcases/files/2_MiB /testcases/files/7_bytes
/testcases/files/11_MiB /testcases/files/3_bytes /testcases/files/7_KiB
/testcases/files/12_bytes /testcases/files/3_KiB /testcases/files/7_MiB
/testcases/files/12_KiB /testcases/files/3_MiB /testcases/files/8_bytes
/testcases/files/12_MiB /testcases/files/4_bytes /testcases/files/8_KiB
/testcases/files/13_bytes /testcases/files/4_KiB /testcases/files/8_MiB
/testcases/files/13_KiB /testcases/files/4_MiB /testcases/files/9_bytes
/testcases/files/13_MiB /testcases/files/5_bytes /testcases/files/9_KiB
/testcases/files/1_bytes /testcases/files/5_KiB /testcases/files/9_MiB

8
xtests/files_star_150 Normal file
View File

@ -0,0 +1,8 @@
/testcases/files/10_bytes /testcases/files/12_MiB /testcases/files/2_KiB /testcases/files/5_bytes /testcases/files/7_MiB
/testcases/files/10_KiB /testcases/files/13_bytes /testcases/files/2_MiB /testcases/files/5_KiB /testcases/files/8_bytes
/testcases/files/10_MiB /testcases/files/13_KiB /testcases/files/3_bytes /testcases/files/5_MiB /testcases/files/8_KiB
/testcases/files/11_bytes /testcases/files/13_MiB /testcases/files/3_KiB /testcases/files/6_bytes /testcases/files/8_MiB
/testcases/files/11_KiB /testcases/files/1_bytes /testcases/files/3_MiB /testcases/files/6_KiB /testcases/files/9_bytes
/testcases/files/11_MiB /testcases/files/1_KiB /testcases/files/4_bytes /testcases/files/6_MiB /testcases/files/9_KiB
/testcases/files/12_bytes /testcases/files/1_MiB /testcases/files/4_KiB /testcases/files/7_bytes /testcases/files/9_MiB
/testcases/files/12_KiB /testcases/files/2_bytes /testcases/files/4_MiB /testcases/files/7_KiB

6
xtests/files_star_200 Normal file
View File

@ -0,0 +1,6 @@
/testcases/files/10_bytes /testcases/files/12_bytes /testcases/files/1_bytes /testcases/files/3_bytes /testcases/files/5_bytes /testcases/files/7_bytes /testcases/files/9_bytes
/testcases/files/10_KiB /testcases/files/12_KiB /testcases/files/1_KiB /testcases/files/3_KiB /testcases/files/5_KiB /testcases/files/7_KiB /testcases/files/9_KiB
/testcases/files/10_MiB /testcases/files/12_MiB /testcases/files/1_MiB /testcases/files/3_MiB /testcases/files/5_MiB /testcases/files/7_MiB /testcases/files/9_MiB
/testcases/files/11_bytes /testcases/files/13_bytes /testcases/files/2_bytes /testcases/files/4_bytes /testcases/files/6_bytes /testcases/files/8_bytes
/testcases/files/11_KiB /testcases/files/13_KiB /testcases/files/2_KiB /testcases/files/4_KiB /testcases/files/6_KiB /testcases/files/8_KiB
/testcases/files/11_MiB /testcases/files/13_MiB /testcases/files/2_MiB /testcases/files/4_MiB /testcases/files/6_MiB /testcases/files/8_MiB

39
xtests/files_star_lG_100 Normal file
View File

@ -0,0 +1,39 @@
.rw-r--r-- 10 cassowary  1 Jan 12:34 /testcases/files/10_bytes
.rw-r--r-- 10k cassowary  1 Jan 12:34 /testcases/files/10_KiB
.rw-r--r-- 10M cassowary  1 Jan 12:34 /testcases/files/10_MiB
.rw-r--r-- 11 cassowary  1 Jan 12:34 /testcases/files/11_bytes
.rw-r--r-- 11k cassowary  1 Jan 12:34 /testcases/files/11_KiB
.rw-r--r-- 11M cassowary  1 Jan 12:34 /testcases/files/11_MiB
.rw-r--r-- 12 cassowary  1 Jan 12:34 /testcases/files/12_bytes
.rw-r--r-- 12k cassowary  1 Jan 12:34 /testcases/files/12_KiB
.rw-r--r-- 12M cassowary  1 Jan 12:34 /testcases/files/12_MiB
.rw-r--r-- 13 cassowary  1 Jan 12:34 /testcases/files/13_bytes
.rw-r--r-- 13k cassowary  1 Jan 12:34 /testcases/files/13_KiB
.rw-r--r-- 13M cassowary  1 Jan 12:34 /testcases/files/13_MiB
.rw-r--r-- 1 cassowary  1 Jan 12:34 /testcases/files/1_bytes
.rw-r--r-- 1.0k cassowary  1 Jan 12:34 /testcases/files/1_KiB
.rw-r--r-- 1.0M cassowary  1 Jan 12:34 /testcases/files/1_MiB
.rw-r--r-- 2 cassowary  1 Jan 12:34 /testcases/files/2_bytes
.rw-r--r-- 2.0k cassowary  1 Jan 12:34 /testcases/files/2_KiB
.rw-r--r-- 2.1M cassowary  1 Jan 12:34 /testcases/files/2_MiB
.rw-r--r-- 3 cassowary  1 Jan 12:34 /testcases/files/3_bytes
.rw-r--r-- 3.1k cassowary  1 Jan 12:34 /testcases/files/3_KiB
.rw-r--r-- 3.1M cassowary  1 Jan 12:34 /testcases/files/3_MiB
.rw-r--r-- 4 cassowary  1 Jan 12:34 /testcases/files/4_bytes
.rw-r--r-- 4.1k cassowary  1 Jan 12:34 /testcases/files/4_KiB
.rw-r--r-- 4.2M cassowary  1 Jan 12:34 /testcases/files/4_MiB
.rw-r--r-- 5 cassowary  1 Jan 12:34 /testcases/files/5_bytes
.rw-r--r-- 5.1k cassowary  1 Jan 12:34 /testcases/files/5_KiB
.rw-r--r-- 5.2M cassowary  1 Jan 12:34 /testcases/files/5_MiB
.rw-r--r-- 6 cassowary  1 Jan 12:34 /testcases/files/6_bytes
.rw-r--r-- 6.1k cassowary  1 Jan 12:34 /testcases/files/6_KiB
.rw-r--r-- 6.3M cassowary  1 Jan 12:34 /testcases/files/6_MiB
.rw-r--r-- 7 cassowary  1 Jan 12:34 /testcases/files/7_bytes
.rw-r--r-- 7.2k cassowary  1 Jan 12:34 /testcases/files/7_KiB
.rw-r--r-- 7.3M cassowary  1 Jan 12:34 /testcases/files/7_MiB
.rw-r--r-- 8 cassowary  1 Jan 12:34 /testcases/files/8_bytes
.rw-r--r-- 8.2k cassowary  1 Jan 12:34 /testcases/files/8_KiB
.rw-r--r-- 8.4M cassowary  1 Jan 12:34 /testcases/files/8_MiB
.rw-r--r-- 9 cassowary  1 Jan 12:34 /testcases/files/9_bytes
.rw-r--r-- 9.2k cassowary  1 Jan 12:34 /testcases/files/9_KiB
.rw-r--r-- 9.4M cassowary  1 Jan 12:34 /testcases/files/9_MiB

20
xtests/files_star_lG_150 Normal file
View File

@ -0,0 +1,20 @@
.rw-r--r-- 10 cassowary  1 Jan 12:34 /testcases/files/10_bytes .rw-r--r-- 3.1M cassowary  1 Jan 12:34 /testcases/files/3_MiB
.rw-r--r-- 10k cassowary  1 Jan 12:34 /testcases/files/10_KiB .rw-r--r-- 4 cassowary  1 Jan 12:34 /testcases/files/4_bytes
.rw-r--r-- 10M cassowary  1 Jan 12:34 /testcases/files/10_MiB .rw-r--r-- 4.1k cassowary  1 Jan 12:34 /testcases/files/4_KiB
.rw-r--r-- 11 cassowary  1 Jan 12:34 /testcases/files/11_bytes .rw-r--r-- 4.2M cassowary  1 Jan 12:34 /testcases/files/4_MiB
.rw-r--r-- 11k cassowary  1 Jan 12:34 /testcases/files/11_KiB .rw-r--r-- 5 cassowary  1 Jan 12:34 /testcases/files/5_bytes
.rw-r--r-- 11M cassowary  1 Jan 12:34 /testcases/files/11_MiB .rw-r--r-- 5.1k cassowary  1 Jan 12:34 /testcases/files/5_KiB
.rw-r--r-- 12 cassowary  1 Jan 12:34 /testcases/files/12_bytes .rw-r--r-- 5.2M cassowary  1 Jan 12:34 /testcases/files/5_MiB
.rw-r--r-- 12k cassowary  1 Jan 12:34 /testcases/files/12_KiB .rw-r--r-- 6 cassowary  1 Jan 12:34 /testcases/files/6_bytes
.rw-r--r-- 12M cassowary  1 Jan 12:34 /testcases/files/12_MiB .rw-r--r-- 6.1k cassowary  1 Jan 12:34 /testcases/files/6_KiB
.rw-r--r-- 13 cassowary  1 Jan 12:34 /testcases/files/13_bytes .rw-r--r-- 6.3M cassowary  1 Jan 12:34 /testcases/files/6_MiB
.rw-r--r-- 13k cassowary  1 Jan 12:34 /testcases/files/13_KiB .rw-r--r-- 7 cassowary  1 Jan 12:34 /testcases/files/7_bytes
.rw-r--r-- 13M cassowary  1 Jan 12:34 /testcases/files/13_MiB .rw-r--r-- 7.2k cassowary  1 Jan 12:34 /testcases/files/7_KiB
.rw-r--r-- 1 cassowary  1 Jan 12:34 /testcases/files/1_bytes .rw-r--r-- 7.3M cassowary  1 Jan 12:34 /testcases/files/7_MiB
.rw-r--r-- 1.0k cassowary  1 Jan 12:34 /testcases/files/1_KiB .rw-r--r-- 8 cassowary  1 Jan 12:34 /testcases/files/8_bytes
.rw-r--r-- 1.0M cassowary  1 Jan 12:34 /testcases/files/1_MiB .rw-r--r-- 8.2k cassowary  1 Jan 12:34 /testcases/files/8_KiB
.rw-r--r-- 2 cassowary  1 Jan 12:34 /testcases/files/2_bytes .rw-r--r-- 8.4M cassowary  1 Jan 12:34 /testcases/files/8_MiB
.rw-r--r-- 2.0k cassowary  1 Jan 12:34 /testcases/files/2_KiB .rw-r--r-- 9 cassowary  1 Jan 12:34 /testcases/files/9_bytes
.rw-r--r-- 2.1M cassowary  1 Jan 12:34 /testcases/files/2_MiB .rw-r--r-- 9.2k cassowary  1 Jan 12:34 /testcases/files/9_KiB
.rw-r--r-- 3 cassowary  1 Jan 12:34 /testcases/files/3_bytes .rw-r--r-- 9.4M cassowary  1 Jan 12:34 /testcases/files/9_MiB
.rw-r--r-- 3.1k cassowary  1 Jan 12:34 /testcases/files/3_KiB

13
xtests/files_star_lG_200 Normal file
View File

@ -0,0 +1,13 @@
.rw-r--r-- 10 cassowary  1 Jan 12:34 /testcases/files/10_bytes .rw-r--r-- 1.0k cassowary  1 Jan 12:34 /testcases/files/1_KiB .rw-r--r-- 5.2M cassowary  1 Jan 12:34 /testcases/files/5_MiB
.rw-r--r-- 10k cassowary  1 Jan 12:34 /testcases/files/10_KiB .rw-r--r-- 1.0M cassowary  1 Jan 12:34 /testcases/files/1_MiB .rw-r--r-- 6 cassowary  1 Jan 12:34 /testcases/files/6_bytes
.rw-r--r-- 10M cassowary  1 Jan 12:34 /testcases/files/10_MiB .rw-r--r-- 2 cassowary  1 Jan 12:34 /testcases/files/2_bytes .rw-r--r-- 6.1k cassowary  1 Jan 12:34 /testcases/files/6_KiB
.rw-r--r-- 11 cassowary  1 Jan 12:34 /testcases/files/11_bytes .rw-r--r-- 2.0k cassowary  1 Jan 12:34 /testcases/files/2_KiB .rw-r--r-- 6.3M cassowary  1 Jan 12:34 /testcases/files/6_MiB
.rw-r--r-- 11k cassowary  1 Jan 12:34 /testcases/files/11_KiB .rw-r--r-- 2.1M cassowary  1 Jan 12:34 /testcases/files/2_MiB .rw-r--r-- 7 cassowary  1 Jan 12:34 /testcases/files/7_bytes
.rw-r--r-- 11M cassowary  1 Jan 12:34 /testcases/files/11_MiB .rw-r--r-- 3 cassowary  1 Jan 12:34 /testcases/files/3_bytes .rw-r--r-- 7.2k cassowary  1 Jan 12:34 /testcases/files/7_KiB
.rw-r--r-- 12 cassowary  1 Jan 12:34 /testcases/files/12_bytes .rw-r--r-- 3.1k cassowary  1 Jan 12:34 /testcases/files/3_KiB .rw-r--r-- 7.3M cassowary  1 Jan 12:34 /testcases/files/7_MiB
.rw-r--r-- 12k cassowary  1 Jan 12:34 /testcases/files/12_KiB .rw-r--r-- 3.1M cassowary  1 Jan 12:34 /testcases/files/3_MiB .rw-r--r-- 8 cassowary  1 Jan 12:34 /testcases/files/8_bytes
.rw-r--r-- 12M cassowary  1 Jan 12:34 /testcases/files/12_MiB .rw-r--r-- 4 cassowary  1 Jan 12:34 /testcases/files/4_bytes .rw-r--r-- 8.2k cassowary  1 Jan 12:34 /testcases/files/8_KiB
.rw-r--r-- 13 cassowary  1 Jan 12:34 /testcases/files/13_bytes .rw-r--r-- 4.1k cassowary  1 Jan 12:34 /testcases/files/4_KiB .rw-r--r-- 8.4M cassowary  1 Jan 12:34 /testcases/files/8_MiB
.rw-r--r-- 13k cassowary  1 Jan 12:34 /testcases/files/13_KiB .rw-r--r-- 4.2M cassowary  1 Jan 12:34 /testcases/files/4_MiB .rw-r--r-- 9 cassowary  1 Jan 12:34 /testcases/files/9_bytes
.rw-r--r-- 13M cassowary  1 Jan 12:34 /testcases/files/13_MiB .rw-r--r-- 5 cassowary  1 Jan 12:34 /testcases/files/5_bytes .rw-r--r-- 9.2k cassowary  1 Jan 12:34 /testcases/files/9_KiB
.rw-r--r-- 1 cassowary  1 Jan 12:34 /testcases/files/1_bytes .rw-r--r-- 5.1k cassowary  1 Jan 12:34 /testcases/files/5_KiB .rw-r--r-- 9.4M cassowary  1 Jan 12:34 /testcases/files/9_MiB

View File

@ -33,6 +33,10 @@ COLUMNS=120 $exa $testcases/files | diff -q - $results/files_120 || exit 1
COLUMNS=160 $exa $testcases/files | diff -q - $results/files_160 || exit 1
COLUMNS=200 $exa $testcases/files | diff -q - $results/files_200 || exit 1
COLUMNS=100 $exa $testcases/files/* | diff -q - $results/files_star_100 || exit 1
COLUMNS=150 $exa $testcases/files/* | diff -q - $results/files_star_150 || exit 1
COLUMNS=200 $exa $testcases/files/* | diff -q - $results/files_star_200 || exit 1
# Long grid view tests
COLUMNS=40 $exa $testcases/files -lG | diff -q - $results/files_lG_40 || exit 1
@ -41,6 +45,10 @@ COLUMNS=120 $exa $testcases/files -lG | diff -q - $results/files_lG_120 || exit
COLUMNS=160 $exa $testcases/files -lG | diff -q - $results/files_lG_160 || exit 1
COLUMNS=200 $exa $testcases/files -lG | diff -q - $results/files_lG_200 || exit 1
COLUMNS=100 $exa $testcases/files/* -lG | diff -q - $results/files_star_lG_100 || exit 1
COLUMNS=150 $exa $testcases/files/* -lG | diff -q - $results/files_star_lG_150 || exit 1
COLUMNS=200 $exa $testcases/files/* -lG | diff -q - $results/files_star_lG_200 || exit 1
# Attributes
$exa $testcases/attributes -l@T | diff -q - $results/attributes || exit 1
@ -55,9 +63,12 @@ sudo -u cassowary $exa $testcases/permissions -lghR 2>&1 | diff -q - $results/pe
$exa $testcases/permissions -lghR 2>&1 | diff -q - $results/permissions || exit 1
# File names
# (Mostly escaping control characters in file names)
COLUMNS=80 $exa $testcases/file-names 2>&1 | diff -q - $results/file_names || exit 1
COLUMNS=80 $exa $testcases/file-names -x 2>&1 | diff -q - $results/file_names_x || exit 1
COLUMNS=80 $exa $testcases/file-names -R 2>&1 | diff -q - $results/file_names_R || exit 1
$exa $testcases/file-names -1 2>&1 | diff -q - $results/file_names_1 || exit 1
$exa $testcases/file-names -T 2>&1 | diff -q - $results/file_names_T || exit 1
# File types
$exa $testcases/file-names-exts -1 2>&1 | diff -q - $results/file-names-exts || exit 1