Document and test time formats

This commit is contained in:
Benjamin Sago 2017-08-09 17:14:16 +01:00
parent 0b87392fd4
commit b2947ed590
2 changed files with 90 additions and 9 deletions

View File

@ -413,7 +413,10 @@ mod test {
use super::*;
use std::ffi::OsString;
use options::flags;
use options::parser::Flag;
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();
@ -421,36 +424,77 @@ 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 ];
macro_rules! test {
($name:ident: $type:ident <- $inputs:expr; $stricts:expr => $result:expr) => {
#[test]
fn $name() {
use options::parser::Arg;
use options::test::parse_for_test;
use options::test::Strictnesses::*;
static TEST_ARGS: &[&Arg] = &[ &flags::BINARY, &flags::BYTES,
&flags::TIME, &flags::MODIFIED, &flags::CREATED, &flags::ACCESSED,
&flags::COLOR, &flags::COLOUR ];
for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf)) {
assert_eq!(result, $result);
}
}
};
($name:ident: $type:ident <- $inputs:expr; $stricts:expr => like $pat: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),
}
}
}
};
}
mod size_formats {
use super::*;
// 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));
// Errors
test!(both: SizeFormat <- ["--binary", "--bytes"]; Both => Err(Misfire::Conflict(&flags::BINARY, &flags::BYTES)));
}
mod time_formats {
use super::*;
// These tests use pattern matching because TimeFormat doesnt
// 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 => like 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 => like Err(Misfire::Duplicate(Flag::Long("time-style"), Flag::Long("time-style"))));
// Errors
test!(daily: TimeFormat <- ["--time-style=24-hour"]; Both => like Err(Misfire::BadArgument(_, _, _)));
}
mod time_types {
use super::*;

View File

@ -1,3 +1,5 @@
//! Timestamp formatting.
use datetime::{LocalDateTime, TimeZone, DatePiece, TimePiece};
use datetime::fmt::DateFormat;
use locale;
@ -6,13 +8,48 @@ use std::cmp;
use fs::fields::Time;
/// Every timestamp in exa needs to be rendered by a **time format**.
/// Formatting times is tricky, because how a timestamp is rendered can
/// depend on one or more of the following:
///
/// - The users locale, for printing the month name as “Feb”, or as “fév”,
/// or as “2月”;
/// - The current year, because certain formats will be less precise when
/// dealing with dates far in the past;
/// - The formatting style that the user asked for on the command-line.
///
/// Because not all formatting styles need the same data, they all have their
/// own enum variants. Its not worth looking the locale up if the formatter
/// prints month names as numbers.
///
/// Currently exa does not support *custom* styles, where the user enters a
/// format string in an environment variable or something. Just these four.
#[derive(Debug)]
pub enum TimeFormat {
/// The **default format** uses the users locale to print month names,
/// and specifies the timestamp down to the minute for recent times, and
/// day for older times.
DefaultFormat(DefaultFormat),
/// Use the **ISO format**, which specifies the timestamp down to the
/// minute for recent times, and day for older times. It uses a number
/// for the month so it doesnt need a locale.
ISOFormat(ISOFormat),
/// Use the **long ISO format**, which specifies the timestamp down to the
/// minute using only numbers, without needing the locale or year.
LongISO,
/// Use the **full ISO format**, which specifies the timestamp down to the
/// millisecond and includes its offset down to the minute. This too uses
/// only numbers so doesnt require any special consideration.
FullISO,
}
// There are two different formatting functions because local and zoned
// timestamps are separate types.
impl TimeFormat {
pub fn format_local(&self, time: Time) -> String {
match *self {