mod common;
use std::collections::HashSet;
use dioxus_swdir_tree_core::{DirectoryTree, scan};
use common::fixture;
#[test]
fn s8_1_disabled_by_default() {
let fx = fixture();
let mut tree = DirectoryTree::new(&fx.root);
let req = tree.on_toggled(&fx.root).expect("root scan");
let payload = scan::run(&req);
let outcome = tree.on_loaded(payload);
assert!(outcome.accepted);
assert!(
outcome.prefetch_requests.is_empty(),
"no prefetch when prefetch_per_parent = 0"
);
assert!(tree.prefetching_paths().is_empty());
}
#[test]
fn s8_2_one_wave_per_user_scan() {
let fx = fixture();
let mut tree = DirectoryTree::new(&fx.root).with_prefetch_limit(2);
let req = tree.on_toggled(&fx.root).expect("root scan");
let payload = scan::run(&req);
let outcome = tree.on_loaded(payload);
assert!(outcome.accepted);
assert_eq!(
outcome.prefetch_requests.len(),
2,
"should issue 2 prefetch requests (alpha, beta)"
);
let wave_gen = outcome.prefetch_requests[0].generation;
assert!(
outcome
.prefetch_requests
.iter()
.all(|r| r.generation == wave_gen),
"all requests in a wave share the same generation"
);
assert_ne!(
wave_gen, req.generation,
"wave generation must differ from root scan generation"
);
let paths: HashSet<_> = outcome.prefetch_requests.iter().map(|r| &r.path).collect();
assert!(paths.contains(&fx.path("alpha")));
assert!(paths.contains(&fx.path("beta")));
assert_eq!(tree.prefetching_paths().len(), 2);
}
#[test]
fn s8_2_limit_1_issues_at_most_one_request() {
let fx = fixture();
let mut tree = DirectoryTree::new(&fx.root).with_prefetch_limit(1);
let req = tree.on_toggled(&fx.root).expect("root scan");
let outcome = tree.on_loaded(scan::run(&req));
assert_eq!(outcome.prefetch_requests.len(), 1);
}
#[test]
fn s8_3_prefetch_completion_does_not_cascade() {
let fx = fixture();
let mut tree = DirectoryTree::new(&fx.root).with_prefetch_limit(3);
let root_req = tree.on_toggled(&fx.root).expect("root scan");
let root_outcome = tree.on_loaded(scan::run(&root_req));
assert!(!root_outcome.prefetch_requests.is_empty());
let alpha_prefetch_req = root_outcome
.prefetch_requests
.iter()
.find(|r| r.path == fx.path("alpha"))
.expect("alpha prefetch request")
.clone();
assert!(tree.prefetching_paths().contains(&fx.path("alpha")));
let alpha_payload = scan::run(&alpha_prefetch_req);
let alpha_outcome = tree.on_loaded(alpha_payload);
assert!(alpha_outcome.accepted, "prefetch payload accepted");
assert!(
alpha_outcome.prefetch_requests.is_empty(),
"prefetch completion must NOT trigger another wave (S8.3)"
);
assert!(
!tree.prefetching_paths().contains(&fx.path("alpha")),
"alpha removed from registry after completion"
);
}
#[test]
fn s8_4_prefetch_loads_not_expands() {
let fx = fixture();
let mut tree = DirectoryTree::new(&fx.root).with_prefetch_limit(2);
let root_req = tree.on_toggled(&fx.root).expect("root scan");
let root_outcome = tree.on_loaded(scan::run(&root_req));
let alpha_req = root_outcome
.prefetch_requests
.iter()
.find(|r| r.path == fx.path("alpha"))
.expect("alpha prefetch")
.clone();
tree.on_loaded(scan::run(&alpha_req));
let alpha = tree.find(&fx.path("alpha")).expect("alpha node");
assert!(alpha.is_loaded, "is_loaded set by prefetch");
assert!(!alpha.is_expanded, "is_expanded NOT set by prefetch (S8.4)");
assert!(
!alpha.children.is_empty(),
"children populated (at least inner/)"
);
assert!(
tree.on_toggled(&fx.path("alpha")).is_none(),
"expand after prefetch must be instant (no scan request)"
);
assert!(tree.find(&fx.path("alpha")).unwrap().is_expanded);
}
#[test]
fn s8_5_skip_list_excludes_known_dirs() {
let fx = fixture();
let mut tree = DirectoryTree::new(&fx.root)
.with_prefetch_limit(5)
.with_prefetch_skip(["alpha", "beta", "zeta.txt"]);
let req = tree.on_toggled(&fx.root).expect("root scan");
let outcome = tree.on_loaded(scan::run(&req));
assert!(
outcome.prefetch_requests.is_empty(),
"all folder-children are in the custom skip list"
);
}
#[test]
fn s8_5_skip_list_is_case_insensitive() {
let fx = fixture();
let mut tree = DirectoryTree::new(&fx.root)
.with_prefetch_limit(5)
.with_prefetch_skip(["ALPHA", "BETA"]);
let req = tree.on_toggled(&fx.root).expect("root scan");
let outcome = tree.on_loaded(scan::run(&req));
assert!(
outcome.prefetch_requests.is_empty(),
"case-insensitive skip must exclude alpha and beta"
);
}
#[test]
fn s8_6_max_depth_applies_to_prefetch() {
let fx = fixture();
let mut tree = DirectoryTree::new(&fx.root)
.with_max_depth(0)
.with_prefetch_limit(5);
let req = tree.on_toggled(&fx.root).expect("root scan");
let outcome = tree.on_loaded(scan::run(&req));
assert!(
outcome.prefetch_requests.is_empty(),
"children at depth > max_depth must not be prefetched"
);
}
#[test]
fn s8_7_user_wins_over_in_flight_prefetch() {
let fx = fixture();
let mut tree = DirectoryTree::new(&fx.root).with_prefetch_limit(2);
let root_req = tree.on_toggled(&fx.root).expect("root scan");
let root_outcome = tree.on_loaded(scan::run(&root_req));
let alpha_prefetch_req = root_outcome
.prefetch_requests
.iter()
.find(|r| r.path == fx.path("alpha"))
.expect("alpha prefetch")
.clone();
assert!(tree.prefetching_paths().contains(&fx.path("alpha")));
let user_req = tree
.on_toggled(&fx.path("alpha"))
.expect("user-initiated expand must yield a scan request");
assert!(
!tree.prefetching_paths().contains(&fx.path("alpha")),
"alpha removed from prefetching_paths when user takes over"
);
assert_ne!(
user_req.generation, alpha_prefetch_req.generation,
"user request has a newer generation"
);
let stale_payload = scan::run(&alpha_prefetch_req);
let stale_outcome = tree.on_loaded(stale_payload);
assert!(!stale_outcome.accepted, "stale prefetch payload discarded");
let user_payload = scan::run(&user_req);
let user_outcome = tree.on_loaded(user_payload);
assert!(user_outcome.accepted, "user payload accepted");
assert!(
!user_outcome.prefetch_requests.is_empty(),
"user-initiated merge triggers its own prefetch wave"
);
}