pub mod args;
mod datetime;
pub mod error;
pub mod format;
#[cfg(test)]
mod test_support;
use args::Options;
use error::Error;
use std::path::Path;
#[derive(Debug)]
pub struct Entry {
pub name: String,
pub metadata: Option<std::fs::Metadata>,
}
pub fn list_entries(dir: &Path, options: Options) -> Result<Vec<Entry>, Error> {
let mut entries = vec![];
for entry in std::fs::read_dir(dir)? {
let entry = entry?;
let name = entry.file_name().to_string_lossy().into_owned();
if !options.all && name.starts_with('.') {
continue;
}
let metadata = if options.long {
Some(entry.metadata()?)
} else {
None
};
entries.push(Entry { name, metadata });
}
entries.sort_by(|a, b| a.name.cmp(&b.name));
Ok(entries)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_support::temp_dir;
use std::fs;
fn names_of(entries: &[Entry]) -> Vec<String> {
entries.iter().map(|entry| entry.name.clone()).collect()
}
#[test]
fn empty_directory_lists_nothing() {
let dir = temp_dir("empty");
let entries = list_entries(&dir, Options::default()).expect("list_entries should succeed");
assert_eq!(names_of(&entries), Vec::<String>::new());
fs::remove_dir_all(&dir).expect("failed to clean up temp dir");
}
#[test]
fn entries_are_sorted_alphabetically() {
let dir = temp_dir("sorted");
fs::write(dir.join("b.txt"), b"").expect("failed to create b.txt");
fs::write(dir.join("a.txt"), b"").expect("failed to create a.txt");
fs::write(dir.join("c.txt"), b"").expect("failed to create c.txt");
let entries = list_entries(&dir, Options::default()).expect("list_entries should succeed");
assert_eq!(names_of(&entries), vec!["a.txt", "b.txt", "c.txt"]);
fs::remove_dir_all(&dir).expect("failed to clean up temp dir");
}
#[test]
fn nonexistent_directory_is_an_error() {
let dir = std::env::temp_dir().join("teru-test-this-should-not-exist");
let result = list_entries(&dir, Options::default());
assert!(result.is_err());
}
#[test]
fn hidden_entries_are_skipped_by_default() {
let dir = temp_dir("hidden-default");
fs::write(dir.join("regular.txt"), b"").expect("failed to create regular.txt");
fs::write(dir.join(".hidden"), b"").expect("failed to create .hidden");
let entries = list_entries(&dir, Options::default()).expect("list_entries should succeed");
assert_eq!(names_of(&entries), vec!["regular.txt"]);
fs::remove_dir_all(&dir).expect("failed to clean up temp dir");
}
#[test]
fn hidden_entries_are_included_with_all_option() {
let dir = temp_dir("hidden-all");
fs::write(dir.join("regular.txt"), b"").expect("failed to create regular.txt");
fs::write(dir.join(".hidden"), b"").expect("failed to create .hidden");
let entries = list_entries(
&dir,
Options {
all: true,
..Options::default()
},
)
.expect("list_entries should succeed");
assert_eq!(names_of(&entries), vec![".hidden", "regular.txt"]);
fs::remove_dir_all(&dir).expect("failed to clean up temp dir");
}
#[test]
fn long_option_populates_metadata() {
let dir = temp_dir("long-metadata");
fs::write(dir.join("file.txt"), b"").expect("failed to create file.txt");
let entries = list_entries(
&dir,
Options {
long: true,
..Options::default()
},
)
.expect("list_entries should succeed");
assert!(entries[0].metadata.is_some());
fs::remove_dir_all(&dir).expect("failed to clean up temp dir");
}
#[test]
fn default_option_does_not_populate_metadata() {
let dir = temp_dir("no-metadata");
fs::write(dir.join("file.txt"), b"").expect("failed to create file.txt");
let entries = list_entries(&dir, Options::default()).expect("list_entries should succeed");
assert!(entries[0].metadata.is_none());
fs::remove_dir_all(&dir).expect("failed to clean up temp dir");
}
}