use serde::Serialize;
use crate::entry::{Entry, EntryKind};
#[derive(Debug, Serialize)]
pub(crate) struct WireEntry {
pub(crate) name: String,
pub(crate) size: u64,
pub(crate) is_dir: bool,
pub(crate) category: crate::classify::Category,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) modified_days_ago: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub(crate) children: Option<Vec<WireEntry>>,
}
impl WireEntry {
pub(crate) fn from_entry(entry: &Entry) -> Self {
let children = match &entry.kind {
EntryKind::Dir(c) => Some(c.iter().map(WireEntry::from_entry).collect()),
EntryKind::File => None,
};
Self {
name: entry.name.clone(),
size: entry.size,
is_dir: entry.is_dir(),
category: entry.category,
modified_days_ago: entry.modified_days_ago,
children,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::classify::Category;
fn leaf(name: &str, size: u64) -> Entry {
Entry::file(name.to_string(), size, Category::Other, None)
}
fn dir_with(name: &str, children: Vec<Entry>) -> Entry {
Entry::dir(name.to_string(), Category::Other, None, children)
}
#[test]
fn wire_shape_matches_v0_1_0_format() {
let root = dir_with("root", vec![leaf("a.txt", 10)]);
let wire = WireEntry::from_entry(&root);
let json = serde_json::to_string(&wire).unwrap();
assert!(json.contains("\"is_dir\":true"));
assert!(json.contains("\"children\":["));
assert!(json.contains("\"is_dir\":false"));
assert!(!json.contains("modified_days_ago"));
}
#[test]
fn empty_directory_serializes_with_an_empty_children_array() {
let empty_dir = dir_with("empty", vec![]);
let wire = WireEntry::from_entry(&empty_dir);
let json = serde_json::to_string(&wire).unwrap();
assert!(json.contains("\"children\":[]"));
}
#[test]
fn modified_days_ago_is_emitted_when_present() {
let dated = Entry::file("a.txt".to_string(), 5, Category::Other, Some(7));
let wire = WireEntry::from_entry(&dated);
let json = serde_json::to_string(&wire).unwrap();
assert!(json.contains("\"modified_days_ago\":7"));
}
}