use std::path::Path;
use tokio::fs::DirEntry;
use std::fs::FileType;
pub async fn list_dir_entries(path: &Path) -> Vec<DirEntry> {
let mut entries = match tokio::fs::read_dir(path).await {
Ok(rd) => rd,
Err(_) => return Vec::new(),
};
let mut out = Vec::new();
while let Ok(Some(entry)) = entries.next_entry().await {
out.push(entry);
}
out
}
pub async fn entry_is_dir(entry: &DirEntry) -> bool {
entry
.metadata()
.await
.map(|m| m.is_dir())
.unwrap_or(false)
}
pub async fn entry_file_type(entry: &DirEntry) -> Option<FileType> {
entry.file_type().await.ok()
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn list_dir_entries_empty_dir() {
let tmp = tempfile::tempdir().unwrap();
let entries = list_dir_entries(tmp.path()).await;
assert!(entries.is_empty());
}
#[tokio::test]
async fn list_dir_entries_missing_path_returns_empty() {
let tmp = tempfile::tempdir().unwrap();
let entries = list_dir_entries(&tmp.path().join("does-not-exist")).await;
assert!(entries.is_empty());
}
#[tokio::test]
async fn list_dir_entries_returns_children() {
let tmp = tempfile::tempdir().unwrap();
tokio::fs::create_dir(tmp.path().join("a")).await.unwrap();
tokio::fs::create_dir(tmp.path().join("b")).await.unwrap();
tokio::fs::write(tmp.path().join("c.txt"), b"").await.unwrap();
let mut names: Vec<String> = list_dir_entries(tmp.path())
.await
.into_iter()
.map(|e| e.file_name().to_string_lossy().to_string())
.collect();
names.sort();
assert_eq!(names, vec!["a", "b", "c.txt"]);
}
#[tokio::test]
async fn entry_is_dir_distinguishes_dir_and_file() {
let tmp = tempfile::tempdir().unwrap();
tokio::fs::create_dir(tmp.path().join("d")).await.unwrap();
tokio::fs::write(tmp.path().join("f"), b"x").await.unwrap();
let entries = list_dir_entries(tmp.path()).await;
for entry in entries {
let name = entry.file_name().to_string_lossy().to_string();
let is_dir = entry_is_dir(&entry).await;
match name.as_str() {
"d" => assert!(is_dir),
"f" => assert!(!is_dir),
other => panic!("unexpected entry: {other}"),
}
}
}
}