|
|
@@ -1,25 +1,22 @@
|
|
|
-use std::env::var_os;
|
|
|
-
|
|
|
use output::Colours;
|
|
|
use output::{View, Mode, grid, details};
|
|
|
-use output::table::{TimeTypes, Environment, SizeFormat, Options as TableOptions};
|
|
|
+use output::table::{TimeTypes, Environment, SizeFormat, Columns, Options as TableOptions};
|
|
|
use output::file_name::{Classify, FileStyle};
|
|
|
use output::time::TimeFormat;
|
|
|
|
|
|
-use options::{flags, Misfire};
|
|
|
+use options::{flags, Misfire, Vars};
|
|
|
use options::parser::MatchedFlags;
|
|
|
|
|
|
use fs::feature::xattr;
|
|
|
use info::filetype::FileExtensions;
|
|
|
|
|
|
-
|
|
|
impl View {
|
|
|
|
|
|
/// Determine which view to use and all of that view’s arguments.
|
|
|
- pub fn deduce(matches: &MatchedFlags) -> Result<View, Misfire> {
|
|
|
- let mode = Mode::deduce(matches)?;
|
|
|
+ pub fn deduce<V: Vars>(matches: &MatchedFlags, vars: V) -> Result<View, Misfire> {
|
|
|
+ let mode = Mode::deduce(matches, vars)?;
|
|
|
let colours = Colours::deduce(matches)?;
|
|
|
- let style = FileStyle::deduce(matches);
|
|
|
+ let style = FileStyle::deduce(matches)?;
|
|
|
Ok(View { mode, colours, style })
|
|
|
}
|
|
|
}
|
|
|
@@ -28,21 +25,21 @@ impl View {
|
|
|
impl Mode {
|
|
|
|
|
|
/// Determine the mode from the command-line arguments.
|
|
|
- pub fn deduce(matches: &MatchedFlags) -> Result<Mode, Misfire> {
|
|
|
+ pub fn deduce<V: Vars>(matches: &MatchedFlags, vars: V) -> Result<Mode, Misfire> {
|
|
|
use options::misfire::Misfire::*;
|
|
|
|
|
|
let long = || {
|
|
|
- if matches.has(&flags::ACROSS) && !matches.has(&flags::GRID) {
|
|
|
+ if matches.has(&flags::ACROSS)? && !matches.has(&flags::GRID)? {
|
|
|
Err(Useless(&flags::ACROSS, true, &flags::LONG))
|
|
|
}
|
|
|
- else if matches.has(&flags::ONE_LINE) {
|
|
|
+ else if matches.has(&flags::ONE_LINE)? {
|
|
|
Err(Useless(&flags::ONE_LINE, true, &flags::LONG))
|
|
|
}
|
|
|
else {
|
|
|
Ok(details::Options {
|
|
|
table: Some(TableOptions::deduce(matches)?),
|
|
|
- header: matches.has(&flags::HEADER),
|
|
|
- xattr: xattr::ENABLED && matches.has(&flags::EXTENDED),
|
|
|
+ header: matches.has(&flags::HEADER)?,
|
|
|
+ xattr: xattr::ENABLED && matches.has(&flags::EXTENDED)?,
|
|
|
})
|
|
|
}
|
|
|
};
|
|
|
@@ -50,15 +47,15 @@ impl Mode {
|
|
|
let long_options_scan = || {
|
|
|
for option in &[ &flags::BINARY, &flags::BYTES, &flags::INODE, &flags::LINKS,
|
|
|
&flags::HEADER, &flags::BLOCKS, &flags::TIME, &flags::GROUP ] {
|
|
|
- if matches.has(option) {
|
|
|
+ if matches.is_strict() && matches.has(option)? {
|
|
|
return Err(Useless(*option, false, &flags::LONG));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if cfg!(feature="git") && matches.has(&flags::GIT) {
|
|
|
+ if cfg!(feature="git") && matches.has(&flags::GIT)? {
|
|
|
Err(Useless(&flags::GIT, false, &flags::LONG))
|
|
|
}
|
|
|
- else if matches.has(&flags::LEVEL) && !matches.has(&flags::RECURSE) && !matches.has(&flags::TREE) {
|
|
|
+ else if matches.has(&flags::LEVEL)? && !matches.has(&flags::RECURSE)? && !matches.has(&flags::TREE)? {
|
|
|
Err(Useless2(&flags::LEVEL, &flags::RECURSE, &flags::TREE))
|
|
|
}
|
|
|
else {
|
|
|
@@ -67,27 +64,27 @@ impl Mode {
|
|
|
};
|
|
|
|
|
|
let other_options_scan = || {
|
|
|
- if let Some(width) = TerminalWidth::deduce()?.width() {
|
|
|
- if matches.has(&flags::ONE_LINE) {
|
|
|
- if matches.has(&flags::ACROSS) {
|
|
|
+ if let Some(width) = TerminalWidth::deduce(vars)?.width() {
|
|
|
+ if matches.has(&flags::ONE_LINE)? {
|
|
|
+ if matches.has(&flags::ACROSS)? {
|
|
|
Err(Useless(&flags::ACROSS, true, &flags::ONE_LINE))
|
|
|
}
|
|
|
else {
|
|
|
Ok(Mode::Lines)
|
|
|
}
|
|
|
}
|
|
|
- else if matches.has(&flags::TREE) {
|
|
|
+ else if matches.has(&flags::TREE)? {
|
|
|
let details = details::Options {
|
|
|
table: None,
|
|
|
header: false,
|
|
|
- xattr: xattr::ENABLED && matches.has(&flags::EXTENDED),
|
|
|
+ xattr: xattr::ENABLED && matches.has(&flags::EXTENDED)?,
|
|
|
};
|
|
|
|
|
|
Ok(Mode::Details(details))
|
|
|
}
|
|
|
else {
|
|
|
let grid = grid::Options {
|
|
|
- across: matches.has(&flags::ACROSS),
|
|
|
+ across: matches.has(&flags::ACROSS)?,
|
|
|
console_width: width,
|
|
|
};
|
|
|
|
|
|
@@ -99,11 +96,11 @@ impl Mode {
|
|
|
// as the program’s stdout being connected to a file, then
|
|
|
// fallback to the lines view.
|
|
|
|
|
|
- if matches.has(&flags::TREE) {
|
|
|
+ if matches.has(&flags::TREE)? {
|
|
|
let details = details::Options {
|
|
|
table: None,
|
|
|
header: false,
|
|
|
- xattr: xattr::ENABLED && matches.has(&flags::EXTENDED),
|
|
|
+ xattr: xattr::ENABLED && matches.has(&flags::EXTENDED)?,
|
|
|
};
|
|
|
|
|
|
Ok(Mode::Details(details))
|
|
|
@@ -114,9 +111,9 @@ impl Mode {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
- if matches.has(&flags::LONG) {
|
|
|
+ if matches.has(&flags::LONG)? {
|
|
|
let details = long()?;
|
|
|
- if matches.has(&flags::GRID) {
|
|
|
+ if matches.has(&flags::GRID)? {
|
|
|
match other_options_scan()? {
|
|
|
Mode::Grid(grid) => return Ok(Mode::GridDetails(grid, details)),
|
|
|
others => return Ok(others),
|
|
|
@@ -153,8 +150,8 @@ impl TerminalWidth {
|
|
|
/// Determine a requested terminal width from the command-line arguments.
|
|
|
///
|
|
|
/// Returns an error if a requested width doesn’t parse to an integer.
|
|
|
- fn deduce() -> Result<TerminalWidth, Misfire> {
|
|
|
- if let Some(columns) = var_os("COLUMNS").and_then(|s| s.into_string().ok()) {
|
|
|
+ fn deduce<V: Vars>(vars: V) -> Result<TerminalWidth, Misfire> {
|
|
|
+ if let Some(columns) = vars.get("COLUMNS").and_then(|s| s.into_string().ok()) {
|
|
|
match columns.parse() {
|
|
|
Ok(width) => Ok(TerminalWidth::Set(width)),
|
|
|
Err(e) => Err(Misfire::FailedParse(e)),
|
|
|
@@ -180,17 +177,26 @@ impl TerminalWidth {
|
|
|
|
|
|
impl TableOptions {
|
|
|
fn deduce(matches: &MatchedFlags) -> Result<Self, Misfire> {
|
|
|
- Ok(TableOptions {
|
|
|
- env: Environment::load_all(),
|
|
|
- time_format: TimeFormat::deduce(matches)?,
|
|
|
- size_format: SizeFormat::deduce(matches)?,
|
|
|
- time_types: TimeTypes::deduce(matches)?,
|
|
|
- inode: matches.has(&flags::INODE),
|
|
|
- links: matches.has(&flags::LINKS),
|
|
|
- blocks: matches.has(&flags::BLOCKS),
|
|
|
- group: matches.has(&flags::GROUP),
|
|
|
- git: cfg!(feature="git") && matches.has(&flags::GIT),
|
|
|
- })
|
|
|
+ let env = Environment::load_all();
|
|
|
+ let time_format = TimeFormat::deduce(matches)?;
|
|
|
+ let size_format = SizeFormat::deduce(matches)?;
|
|
|
+ let extra_columns = Columns::deduce(matches)?;
|
|
|
+ Ok(TableOptions { env, time_format, size_format, extra_columns })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+impl Columns {
|
|
|
+ fn deduce(matches: &MatchedFlags) -> Result<Self, Misfire> {
|
|
|
+ let time_types = TimeTypes::deduce(matches)?;
|
|
|
+ let git = cfg!(feature="git") && matches.has(&flags::GIT)?;
|
|
|
+
|
|
|
+ let blocks = matches.has(&flags::BLOCKS)?;
|
|
|
+ let group = matches.has(&flags::GROUP)?;
|
|
|
+ let inode = matches.has(&flags::INODE)?;
|
|
|
+ let links = matches.has(&flags::LINKS)?;
|
|
|
+
|
|
|
+ Ok(Columns { time_types, git, blocks, group, inode, links })
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -206,27 +212,26 @@ impl SizeFormat {
|
|
|
/// involves the `--binary` or `--bytes` flags, and these conflict with
|
|
|
/// each other.
|
|
|
fn deduce(matches: &MatchedFlags) -> Result<SizeFormat, Misfire> {
|
|
|
- let binary = matches.has(&flags::BINARY);
|
|
|
- let bytes = matches.has(&flags::BYTES);
|
|
|
-
|
|
|
- match (binary, bytes) {
|
|
|
- (true, true ) => Err(Misfire::Conflict(&flags::BINARY, &flags::BYTES)),
|
|
|
- (true, false) => Ok(SizeFormat::BinaryBytes),
|
|
|
- (false, true ) => Ok(SizeFormat::JustBytes),
|
|
|
- (false, false) => Ok(SizeFormat::DecimalBytes),
|
|
|
- }
|
|
|
+ let flag = matches.has_where(|f| f.matches(&flags::BINARY) || f.matches(&flags::BYTES))?;
|
|
|
+
|
|
|
+ Ok(match flag {
|
|
|
+ Some(f) if f.matches(&flags::BINARY) => SizeFormat::BinaryBytes,
|
|
|
+ Some(f) if f.matches(&flags::BYTES) => SizeFormat::JustBytes,
|
|
|
+ _ => SizeFormat::DecimalBytes,
|
|
|
+ })
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
+const TIME_STYLES: &[&str] = &["default", "long-iso", "full-iso", "iso"];
|
|
|
+
|
|
|
impl TimeFormat {
|
|
|
|
|
|
/// Determine how time should be formatted in timestamp columns.
|
|
|
fn deduce(matches: &MatchedFlags) -> Result<TimeFormat, Misfire> {
|
|
|
pub use output::time::{DefaultFormat, ISOFormat};
|
|
|
- const STYLES: &[&str] = &["default", "long-iso", "full-iso", "iso"];
|
|
|
|
|
|
- let word = match matches.get(&flags::TIME_STYLE) {
|
|
|
+ let word = match matches.get(&flags::TIME_STYLE)? {
|
|
|
Some(w) => w,
|
|
|
None => return Ok(TimeFormat::DefaultFormat(DefaultFormat::new())),
|
|
|
};
|
|
|
@@ -244,7 +249,7 @@ impl TimeFormat {
|
|
|
Ok(TimeFormat::FullISO)
|
|
|
}
|
|
|
else {
|
|
|
- Err(Misfire::bad_argument(&flags::TIME_STYLE, word, STYLES))
|
|
|
+ Err(Misfire::bad_argument(&flags::TIME_STYLE, word, TIME_STYLES))
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -265,10 +270,10 @@ impl TimeTypes {
|
|
|
/// option, but passing *no* options means that the user just wants to
|
|
|
/// see the default set.
|
|
|
fn deduce(matches: &MatchedFlags) -> Result<TimeTypes, Misfire> {
|
|
|
- let possible_word = matches.get(&flags::TIME);
|
|
|
- let modified = matches.has(&flags::MODIFIED);
|
|
|
- let created = matches.has(&flags::CREATED);
|
|
|
- let accessed = matches.has(&flags::ACCESSED);
|
|
|
+ let possible_word = matches.get(&flags::TIME)?;
|
|
|
+ let modified = matches.has(&flags::MODIFIED)?;
|
|
|
+ let created = matches.has(&flags::CREATED)?;
|
|
|
+ let accessed = matches.has(&flags::ACCESSED)?;
|
|
|
|
|
|
if let Some(word) = possible_word {
|
|
|
if modified {
|
|
|
@@ -329,13 +334,14 @@ impl Default for TerminalColours {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+const COLOURS: &[&str] = &["always", "auto", "never"];
|
|
|
+
|
|
|
impl TerminalColours {
|
|
|
|
|
|
/// Determine which terminal colour conditions to use.
|
|
|
fn deduce(matches: &MatchedFlags) -> Result<TerminalColours, Misfire> {
|
|
|
- const COLOURS: &[&str] = &["always", "auto", "never"];
|
|
|
|
|
|
- let word = match matches.get(&flags::COLOR).or_else(|| matches.get(&flags::COLOUR)) {
|
|
|
+ let word = match matches.get_where(|f| f.matches(&flags::COLOR) || f.matches(&flags::COLOUR))? {
|
|
|
Some(w) => w,
|
|
|
None => return Ok(TerminalColours::default()),
|
|
|
};
|
|
|
@@ -362,7 +368,7 @@ impl Colours {
|
|
|
|
|
|
let tc = TerminalColours::deduce(matches)?;
|
|
|
if tc == Always || (tc == Automatic && TERM_WIDTH.is_some()) {
|
|
|
- let scale = matches.has(&flags::COLOR_SCALE) || matches.has(&flags::COLOUR_SCALE);
|
|
|
+ let scale = matches.has(&flags::COLOR_SCALE)? || matches.has(&flags::COLOUR_SCALE)?;
|
|
|
Ok(Colours::colourful(scale))
|
|
|
}
|
|
|
else {
|
|
|
@@ -374,17 +380,19 @@ impl Colours {
|
|
|
|
|
|
|
|
|
impl FileStyle {
|
|
|
- fn deduce(matches: &MatchedFlags) -> FileStyle {
|
|
|
- let classify = Classify::deduce(matches);
|
|
|
+ fn deduce(matches: &MatchedFlags) -> Result<FileStyle, Misfire> {
|
|
|
+ let classify = Classify::deduce(matches)?;
|
|
|
let exts = FileExtensions;
|
|
|
- FileStyle { classify, exts }
|
|
|
+ Ok(FileStyle { classify, exts })
|
|
|
}
|
|
|
}
|
|
|
|
|
|
impl Classify {
|
|
|
- fn deduce(matches: &MatchedFlags) -> Classify {
|
|
|
- if matches.has(&flags::CLASSIFY) { Classify::AddFileIndicators }
|
|
|
- else { Classify::JustFilenames }
|
|
|
+ fn deduce(matches: &MatchedFlags) -> Result<Classify, Misfire> {
|
|
|
+ let flagged = matches.has(&flags::CLASSIFY)?;
|
|
|
+
|
|
|
+ Ok(if flagged { Classify::AddFileIndicators }
|
|
|
+ else { Classify::JustFilenames })
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -409,6 +417,10 @@ mod test {
|
|
|
use super::*;
|
|
|
use std::ffi::OsString;
|
|
|
use options::flags;
|
|
|
+ use options::parser::{Flag, Arg};
|
|
|
+
|
|
|
+ use options::test::parse_for_test;
|
|
|
+ use options::test::Strictnesses::*;
|
|
|
|
|
|
pub fn os(input: &'static str) -> OsString {
|
|
|
let mut os = OsString::new();
|
|
|
@@ -416,19 +428,74 @@ mod test {
|
|
|
os
|
|
|
}
|
|
|
|
|
|
+ static TEST_ARGS: &[&Arg] = &[ &flags::BINARY, &flags::BYTES, &flags::TIME_STYLE,
|
|
|
+ &flags::TIME, &flags::MODIFIED, &flags::CREATED, &flags::ACCESSED,
|
|
|
+ &flags::COLOR, &flags::COLOUR,
|
|
|
+ &flags::HEADER, &flags::GROUP, &flags::INODE,
|
|
|
+ &flags::LINKS, &flags::BLOCKS, &flags::LONG,
|
|
|
+ &flags::GRID, &flags::ACROSS, &flags::ONE_LINE ];
|
|
|
+
|
|
|
macro_rules! test {
|
|
|
- ($name:ident: $type:ident <- $inputs:expr => $result:expr) => {
|
|
|
+
|
|
|
+ ($name:ident: $type:ident <- $inputs:expr; $stricts:expr => $result:expr) => {
|
|
|
+ /// Macro that writes a test.
|
|
|
+ /// If testing both strictnesses, they’ll both be done in the same function.
|
|
|
#[test]
|
|
|
fn $name() {
|
|
|
- use options::parser::{Args, Arg};
|
|
|
- use std::ffi::OsString;
|
|
|
+ for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf)) {
|
|
|
+ assert_eq!(result, $result);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
|
|
|
- static TEST_ARGS: &[&Arg] = &[ &flags::BINARY, &flags::BYTES,
|
|
|
- &flags::TIME, &flags::MODIFIED, &flags::CREATED, &flags::ACCESSED ];
|
|
|
+ ($name:ident: $type:ident <- $inputs:expr; $stricts:expr => err $result:expr) => {
|
|
|
+ /// Special macro for testing Err results.
|
|
|
+ /// This is needed because sometimes the Ok type doesn’t implement PartialEq.
|
|
|
+ #[test]
|
|
|
+ fn $name() {
|
|
|
+ for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf)) {
|
|
|
+ assert_eq!(result.unwrap_err(), $result);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
|
|
|
- let bits = $inputs.as_ref().into_iter().map(|&o| os(o)).collect::<Vec<OsString>>();
|
|
|
- let results = Args(TEST_ARGS).parse(bits.iter());
|
|
|
- assert_eq!($type::deduce(&results.unwrap().flags), $result);
|
|
|
+ ($name:ident: $type:ident <- $inputs:expr; $stricts:expr => like $pat:pat) => {
|
|
|
+ /// More general macro for testing against a pattern.
|
|
|
+ /// Instead of using PartialEq, this just tests if it matches a pat.
|
|
|
+ #[test]
|
|
|
+ fn $name() {
|
|
|
+ for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf)) {
|
|
|
+ println!("Testing {:?}", result);
|
|
|
+ match result {
|
|
|
+ $pat => assert!(true),
|
|
|
+ _ => assert!(false),
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+
|
|
|
+ ($name:ident: $type:ident <- $inputs:expr, $vars:expr; $stricts:expr => err $result:expr) => {
|
|
|
+ /// Like above, but with $vars.
|
|
|
+ #[test]
|
|
|
+ fn $name() {
|
|
|
+ for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf, $vars)) {
|
|
|
+ assert_eq!(result.unwrap_err(), $result);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ ($name:ident: $type:ident <- $inputs:expr, $vars:expr; $stricts:expr => like $pat:pat) => {
|
|
|
+ /// Like further above, but with $vars.
|
|
|
+ #[test]
|
|
|
+ fn $name() {
|
|
|
+ for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf, $vars)) {
|
|
|
+ println!("Testing {:?}", result);
|
|
|
+ match result {
|
|
|
+ $pat => assert!(true),
|
|
|
+ _ => assert!(false),
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
};
|
|
|
}
|
|
|
@@ -437,10 +504,51 @@ mod test {
|
|
|
mod size_formats {
|
|
|
use super::*;
|
|
|
|
|
|
- test!(empty: SizeFormat <- [] => Ok(SizeFormat::DecimalBytes));
|
|
|
- test!(binary: SizeFormat <- ["--binary"] => Ok(SizeFormat::BinaryBytes));
|
|
|
- test!(bytes: SizeFormat <- ["--bytes"] => Ok(SizeFormat::JustBytes));
|
|
|
- test!(both: SizeFormat <- ["--binary", "--bytes"] => Err(Misfire::Conflict(&flags::BINARY, &flags::BYTES)));
|
|
|
+ // Default behaviour
|
|
|
+ test!(empty: SizeFormat <- []; Both => Ok(SizeFormat::DecimalBytes));
|
|
|
+
|
|
|
+ // Individual flags
|
|
|
+ test!(binary: SizeFormat <- ["--binary"]; Both => Ok(SizeFormat::BinaryBytes));
|
|
|
+ test!(bytes: SizeFormat <- ["--bytes"]; Both => Ok(SizeFormat::JustBytes));
|
|
|
+
|
|
|
+ // Overriding
|
|
|
+ test!(both_1: SizeFormat <- ["--binary", "--binary"]; Last => Ok(SizeFormat::BinaryBytes));
|
|
|
+ test!(both_2: SizeFormat <- ["--bytes", "--binary"]; Last => Ok(SizeFormat::BinaryBytes));
|
|
|
+ test!(both_3: SizeFormat <- ["--binary", "--bytes"]; Last => Ok(SizeFormat::JustBytes));
|
|
|
+ test!(both_4: SizeFormat <- ["--bytes", "--bytes"]; Last => Ok(SizeFormat::JustBytes));
|
|
|
+
|
|
|
+ test!(both_5: SizeFormat <- ["--binary", "--binary"]; Complain => err Misfire::Duplicate(Flag::Long("binary"), Flag::Long("binary")));
|
|
|
+ test!(both_6: SizeFormat <- ["--bytes", "--binary"]; Complain => err Misfire::Duplicate(Flag::Long("bytes"), Flag::Long("binary")));
|
|
|
+ test!(both_7: SizeFormat <- ["--binary", "--bytes"]; Complain => err Misfire::Duplicate(Flag::Long("binary"), Flag::Long("bytes")));
|
|
|
+ test!(both_8: SizeFormat <- ["--bytes", "--bytes"]; Complain => err Misfire::Duplicate(Flag::Long("bytes"), Flag::Long("bytes")));
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ mod time_formats {
|
|
|
+ use super::*;
|
|
|
+ use std::ffi::OsStr;
|
|
|
+
|
|
|
+ // These tests use pattern matching because TimeFormat doesn’t
|
|
|
+ // implement PartialEq.
|
|
|
+
|
|
|
+ // Default behaviour
|
|
|
+ test!(empty: TimeFormat <- []; Both => like Ok(TimeFormat::DefaultFormat(_)));
|
|
|
+
|
|
|
+ // Individual settings
|
|
|
+ test!(default: TimeFormat <- ["--time-style=default"]; Both => like Ok(TimeFormat::DefaultFormat(_)));
|
|
|
+ test!(iso: TimeFormat <- ["--time-style", "iso"]; Both => like Ok(TimeFormat::ISOFormat(_)));
|
|
|
+ test!(long_iso: TimeFormat <- ["--time-style=long-iso"]; Both => like Ok(TimeFormat::LongISO));
|
|
|
+ test!(full_iso: TimeFormat <- ["--time-style", "full-iso"]; Both => like Ok(TimeFormat::FullISO));
|
|
|
+
|
|
|
+ // Overriding
|
|
|
+ test!(actually: TimeFormat <- ["--time-style=default", "--time-style", "iso"]; Last => like Ok(TimeFormat::ISOFormat(_)));
|
|
|
+ test!(actual_2: TimeFormat <- ["--time-style=default", "--time-style", "iso"]; Complain => err Misfire::Duplicate(Flag::Long("time-style"), Flag::Long("time-style")));
|
|
|
+
|
|
|
+ test!(nevermind: TimeFormat <- ["--time-style", "long-iso", "--time-style=full-iso"]; Last => like Ok(TimeFormat::FullISO));
|
|
|
+ test!(nevermore: TimeFormat <- ["--time-style", "long-iso", "--time-style=full-iso"]; Complain => err Misfire::Duplicate(Flag::Long("time-style"), Flag::Long("time-style")));
|
|
|
+
|
|
|
+ // Errors
|
|
|
+ test!(daily: TimeFormat <- ["--time-style=24-hour"]; Both => err Misfire::bad_argument(&flags::TIME_STYLE, OsStr::new("24-hour"), TIME_STYLES));
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -448,30 +556,113 @@ mod test {
|
|
|
use super::*;
|
|
|
|
|
|
// Default behaviour
|
|
|
- test!(empty: TimeTypes <- [] => Ok(TimeTypes::default()));
|
|
|
- test!(modified: TimeTypes <- ["--modified"] => Ok(TimeTypes { accessed: false, modified: true, created: false }));
|
|
|
- test!(m: TimeTypes <- ["-m"] => Ok(TimeTypes { accessed: false, modified: true, created: false }));
|
|
|
- test!(time_mod: TimeTypes <- ["--time=modified"] => Ok(TimeTypes { accessed: false, modified: true, created: false }));
|
|
|
- test!(time_m: TimeTypes <- ["-tmod"] => Ok(TimeTypes { accessed: false, modified: true, created: false }));
|
|
|
-
|
|
|
- test!(acc: TimeTypes <- ["--accessed"] => Ok(TimeTypes { accessed: true, modified: false, created: false }));
|
|
|
- test!(a: TimeTypes <- ["-u"] => Ok(TimeTypes { accessed: true, modified: false, created: false }));
|
|
|
- test!(time_acc: TimeTypes <- ["--time", "accessed"] => Ok(TimeTypes { accessed: true, modified: false, created: false }));
|
|
|
- test!(time_a: TimeTypes <- ["-t", "acc"] => Ok(TimeTypes { accessed: true, modified: false, created: false }));
|
|
|
-
|
|
|
- test!(cr: TimeTypes <- ["--created"] => Ok(TimeTypes { accessed: false, modified: false, created: true }));
|
|
|
- test!(c: TimeTypes <- ["-U"] => Ok(TimeTypes { accessed: false, modified: false, created: true }));
|
|
|
- test!(time_cr: TimeTypes <- ["--time=created"] => Ok(TimeTypes { accessed: false, modified: false, created: true }));
|
|
|
- test!(time_c: TimeTypes <- ["-tcr"] => Ok(TimeTypes { accessed: false, modified: false, created: true }));
|
|
|
+ test!(empty: TimeTypes <- []; Both => Ok(TimeTypes::default()));
|
|
|
+
|
|
|
+ // Modified
|
|
|
+ test!(modified: TimeTypes <- ["--modified"]; Both => Ok(TimeTypes { accessed: false, modified: true, created: false }));
|
|
|
+ test!(m: TimeTypes <- ["-m"]; Both => Ok(TimeTypes { accessed: false, modified: true, created: false }));
|
|
|
+ test!(time_mod: TimeTypes <- ["--time=modified"]; Both => Ok(TimeTypes { accessed: false, modified: true, created: false }));
|
|
|
+ test!(time_m: TimeTypes <- ["-tmod"]; Both => Ok(TimeTypes { accessed: false, modified: true, created: false }));
|
|
|
+
|
|
|
+ // Accessed
|
|
|
+ test!(acc: TimeTypes <- ["--accessed"]; Both => Ok(TimeTypes { accessed: true, modified: false, created: false }));
|
|
|
+ test!(a: TimeTypes <- ["-u"]; Both => Ok(TimeTypes { accessed: true, modified: false, created: false }));
|
|
|
+ test!(time_acc: TimeTypes <- ["--time", "accessed"]; Both => Ok(TimeTypes { accessed: true, modified: false, created: false }));
|
|
|
+ test!(time_a: TimeTypes <- ["-t", "acc"]; Both => Ok(TimeTypes { accessed: true, modified: false, created: false }));
|
|
|
+
|
|
|
+ // Created
|
|
|
+ test!(cr: TimeTypes <- ["--created"]; Both => Ok(TimeTypes { accessed: false, modified: false, created: true }));
|
|
|
+ test!(c: TimeTypes <- ["-U"]; Both => Ok(TimeTypes { accessed: false, modified: false, created: true }));
|
|
|
+ test!(time_cr: TimeTypes <- ["--time=created"]; Both => Ok(TimeTypes { accessed: false, modified: false, created: true }));
|
|
|
+ test!(time_c: TimeTypes <- ["-tcr"]; Both => Ok(TimeTypes { accessed: false, modified: false, created: true }));
|
|
|
|
|
|
// Multiples
|
|
|
- test!(time_uu: TimeTypes <- ["-uU"] => Ok(TimeTypes { accessed: true, modified: false, created: true }));
|
|
|
+ test!(time_uu: TimeTypes <- ["-uU"]; Both => Ok(TimeTypes { accessed: true, modified: false, created: true }));
|
|
|
+
|
|
|
+ // Errors
|
|
|
+ test!(time_tea: TimeTypes <- ["--time=tea"]; Both => err Misfire::bad_argument(&flags::TIME, &os("tea"), super::TIMES));
|
|
|
+ test!(time_ea: TimeTypes <- ["-tea"]; Both => err Misfire::bad_argument(&flags::TIME, &os("ea"), super::TIMES));
|
|
|
|
|
|
// Overriding
|
|
|
- test!(time_mc: TimeTypes <- ["-tcr", "-tmod"] => Ok(TimeTypes { accessed: false, modified: true, created: false }));
|
|
|
+ test!(overridden: TimeTypes <- ["-tcr", "-tmod"]; Last => Ok(TimeTypes { accessed: false, modified: true, created: false }));
|
|
|
+ test!(overridden_2: TimeTypes <- ["-tcr", "-tmod"]; Complain => err Misfire::Duplicate(Flag::Short(b't'), Flag::Short(b't')));
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ mod colourses {
|
|
|
+ use super::*;
|
|
|
+
|
|
|
+ // Default
|
|
|
+ test!(empty: TerminalColours <- []; Both => Ok(TerminalColours::default()));
|
|
|
+
|
|
|
+ // --colour
|
|
|
+ test!(u_always: TerminalColours <- ["--colour=always"]; Both => Ok(TerminalColours::Always));
|
|
|
+ test!(u_auto: TerminalColours <- ["--colour", "auto"]; Both => Ok(TerminalColours::Automatic));
|
|
|
+ test!(u_never: TerminalColours <- ["--colour=never"]; Both => Ok(TerminalColours::Never));
|
|
|
+
|
|
|
+ // --color
|
|
|
+ test!(no_u_always: TerminalColours <- ["--color", "always"]; Both => Ok(TerminalColours::Always));
|
|
|
+ test!(no_u_auto: TerminalColours <- ["--color=auto"]; Both => Ok(TerminalColours::Automatic));
|
|
|
+ test!(no_u_never: TerminalColours <- ["--color", "never"]; Both => Ok(TerminalColours::Never));
|
|
|
|
|
|
// Errors
|
|
|
- test!(time_tea: TimeTypes <- ["--time=tea"] => Err(Misfire::bad_argument(&flags::TIME, &os("tea"), super::TIMES)));
|
|
|
- test!(time_ea: TimeTypes <- ["-tea"] => Err(Misfire::bad_argument(&flags::TIME, &os("ea"), super::TIMES)));
|
|
|
+ test!(no_u_error: TerminalColours <- ["--color=upstream"]; Both => err Misfire::bad_argument(&flags::COLOR, &os("upstream"), super::COLOURS)); // the error is for --color
|
|
|
+ test!(u_error: TerminalColours <- ["--colour=lovers"]; Both => err Misfire::bad_argument(&flags::COLOR, &os("lovers"), super::COLOURS)); // and so is this one!
|
|
|
+
|
|
|
+ // Overriding
|
|
|
+ test!(overridden_1: TerminalColours <- ["--colour=auto", "--colour=never"]; Last => Ok(TerminalColours::Never));
|
|
|
+ test!(overridden_2: TerminalColours <- ["--color=auto", "--colour=never"]; Last => Ok(TerminalColours::Never));
|
|
|
+ test!(overridden_3: TerminalColours <- ["--colour=auto", "--color=never"]; Last => Ok(TerminalColours::Never));
|
|
|
+ test!(overridden_4: TerminalColours <- ["--color=auto", "--color=never"]; Last => Ok(TerminalColours::Never));
|
|
|
+
|
|
|
+ test!(overridden_5: TerminalColours <- ["--colour=auto", "--colour=never"]; Complain => err Misfire::Duplicate(Flag::Long("colour"), Flag::Long("colour")));
|
|
|
+ test!(overridden_6: TerminalColours <- ["--color=auto", "--colour=never"]; Complain => err Misfire::Duplicate(Flag::Long("color"), Flag::Long("colour")));
|
|
|
+ test!(overridden_7: TerminalColours <- ["--colour=auto", "--color=never"]; Complain => err Misfire::Duplicate(Flag::Long("colour"), Flag::Long("color")));
|
|
|
+ test!(overridden_8: TerminalColours <- ["--color=auto", "--color=never"]; Complain => err Misfire::Duplicate(Flag::Long("color"), Flag::Long("color")));
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ mod views {
|
|
|
+ use super::*;
|
|
|
+ use output::grid::Options as GridOptions;
|
|
|
+
|
|
|
+ // Default
|
|
|
+ test!(empty: Mode <- [], None; Both => like Ok(Mode::Grid(_)));
|
|
|
+
|
|
|
+ // Grid views
|
|
|
+ test!(original_g: Mode <- ["-G"], None; Both => like Ok(Mode::Grid(GridOptions { across: false, console_width: _ })));
|
|
|
+ test!(grid: Mode <- ["--grid"], None; Both => like Ok(Mode::Grid(GridOptions { across: false, console_width: _ })));
|
|
|
+ test!(across: Mode <- ["--across"], None; Both => like Ok(Mode::Grid(GridOptions { across: true, console_width: _ })));
|
|
|
+ test!(gracross: Mode <- ["-xG"], None; Both => like Ok(Mode::Grid(GridOptions { across: true, console_width: _ })));
|
|
|
+
|
|
|
+ // Lines views
|
|
|
+ test!(lines: Mode <- ["--oneline"], None; Both => like Ok(Mode::Lines));
|
|
|
+ test!(prima: Mode <- ["-1"], None; Both => like Ok(Mode::Lines));
|
|
|
+
|
|
|
+ // Details views
|
|
|
+ test!(long: Mode <- ["--long"], None; Both => like Ok(Mode::Details(_)));
|
|
|
+ test!(ell: Mode <- ["-l"], None; Both => like Ok(Mode::Details(_)));
|
|
|
+
|
|
|
+ // Grid-details views
|
|
|
+ test!(lid: Mode <- ["--long", "--grid"], None; Both => like Ok(Mode::GridDetails(_, _)));
|
|
|
+ test!(leg: Mode <- ["-lG"], None; Both => like Ok(Mode::GridDetails(_, _)));
|
|
|
+
|
|
|
+
|
|
|
+ // Options that do nothing without --long
|
|
|
+ test!(just_header: Mode <- ["--header"], None; Last => like Ok(Mode::Grid(_)));
|
|
|
+ test!(just_group: Mode <- ["--group"], None; Last => like Ok(Mode::Grid(_)));
|
|
|
+ test!(just_inode: Mode <- ["--inode"], None; Last => like Ok(Mode::Grid(_)));
|
|
|
+ test!(just_links: Mode <- ["--links"], None; Last => like Ok(Mode::Grid(_)));
|
|
|
+ test!(just_blocks: Mode <- ["--blocks"], None; Last => like Ok(Mode::Grid(_)));
|
|
|
+ test!(just_binary: Mode <- ["--binary"], None; Last => like Ok(Mode::Grid(_)));
|
|
|
+ test!(just_bytes: Mode <- ["--bytes"], None; Last => like Ok(Mode::Grid(_)));
|
|
|
+
|
|
|
+ test!(just_header_2: Mode <- ["--header"], None; Complain => err Misfire::Useless(&flags::HEADER, false, &flags::LONG));
|
|
|
+ test!(just_group_2: Mode <- ["--group"], None; Complain => err Misfire::Useless(&flags::GROUP, false, &flags::LONG));
|
|
|
+ test!(just_inode_2: Mode <- ["--inode"], None; Complain => err Misfire::Useless(&flags::INODE, false, &flags::LONG));
|
|
|
+ test!(just_links_2: Mode <- ["--links"], None; Complain => err Misfire::Useless(&flags::LINKS, false, &flags::LONG));
|
|
|
+ test!(just_blocks_2: Mode <- ["--blocks"], None; Complain => err Misfire::Useless(&flags::BLOCKS, false, &flags::LONG));
|
|
|
+ test!(just_binary_2: Mode <- ["--binary"], None; Complain => err Misfire::Useless(&flags::BINARY, false, &flags::LONG));
|
|
|
+ test!(just_bytes_2: Mode <- ["--bytes"], None; Complain => err Misfire::Useless(&flags::BYTES, false, &flags::LONG));
|
|
|
}
|
|
|
}
|