use polars::prelude::*;
use serde_json::{json, Map, Value as Json};
use taxa_core::treemap::treemap;
use taxa_core::{FrameDataset, FrameSource, TreeNode, TreemapArgs};
fn frame() -> FrameSource {
let df = df![
"path" => ["a/b/c.txt", "a/b/d.txt", "a/e.txt", "f/g.txt"],
"bytes" => [10i64, 20, 5, 7],
]
.unwrap();
FrameSource::new(df)
}
fn ds() -> FrameDataset {
serde_json::from_value(json!({
"source": "fs", "id_column": "path", "label_column": "path",
"axes": [{"id": "tree", "path": {"column": "path", "sep": "/"}}],
"metrics": [{"id": "bytes", "agg": "sum", "column": "bytes", "unit": "count"}],
"default_axis": "tree", "default_size_by": "bytes"
}))
.unwrap()
}
fn m(node: &TreeNode, key: &str) -> f64 {
node.measures.get(key).and_then(Json::as_f64).unwrap()
}
fn child<'a>(node: &'a TreeNode, name: &str) -> &'a TreeNode {
node.children
.iter()
.find(|c| c.name == name)
.unwrap_or_else(|| panic!("no child {name:?}"))
}
fn names(node: &TreeNode) -> Vec<String> {
let mut v: Vec<String> = node.children.iter().map(|c| c.name.clone()).collect();
v.sort();
v
}
fn run(focus: &[&str], depth: i64) -> TreeNode {
let mut a = TreemapArgs::new("tree");
a.focus = focus.iter().map(|s| json!(s)).collect();
a.depth = depth;
a.top_k = 50;
a.filters = Map::new();
treemap(&ds(), &frame(), &a).unwrap()
}
#[test]
fn path_axis_directories_aggregate_and_files_are_leaves() {
let t = run(&[], 2);
assert_eq!(names(&t), ["a", "f"]);
assert_eq!(m(child(&t, "a"), "bytes"), 35.0);
assert_eq!(m(child(&t, "f"), "bytes"), 7.0);
let a = child(&t, "a");
assert_eq!(names(a), ["b", "e.txt"]);
let b = child(a, "b");
assert_eq!(m(b, "bytes"), 30.0);
assert!(b.has_more, "directory `b` has deeper components");
let e = child(a, "e.txt");
assert_eq!(m(e, "bytes"), 5.0);
assert!(!e.has_more, "file `e.txt` is a leaf at depth 2");
assert!(e.children.is_empty(), "file `e.txt` has no children");
let f = child(&t, "f");
assert_eq!(names(f), ["g.txt"]);
let g = child(f, "g.txt");
assert_eq!(m(g, "bytes"), 7.0);
assert!(!g.has_more);
}
#[test]
fn path_axis_descends_to_files_at_deeper_levels() {
let t = run(&[], 3);
let b = child(child(&t, "a"), "b");
assert_eq!(names(b), ["c.txt", "d.txt"]);
let c = child(b, "c.txt");
let d = child(b, "d.txt");
assert_eq!(m(c, "bytes"), 10.0);
assert_eq!(m(d, "bytes"), 20.0);
assert!(
!c.has_more && !d.has_more,
"files are leaves at their own depth"
);
assert!(c.children.is_empty() && d.children.is_empty());
}
#[test]
fn path_axis_focus_zoom() {
let t = run(&["a"], 1);
assert_eq!(m(&t, "bytes"), 35.0);
assert_eq!(names(&t), ["b", "e.txt"]);
assert!(child(&t, "b").has_more);
assert!(!child(&t, "e.txt").has_more);
}