mod common;
use common::TmpDir;
use std::fs;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use iced_swdir_tree::{
DirectoryFilter, DirectoryTree, DirectoryTreeEvent, IconRole, IconSpec, IconTheme, UnicodeTheme,
};
#[derive(Debug, Default)]
struct CountingTheme {
folder_closed: AtomicUsize,
folder_open: AtomicUsize,
file: AtomicUsize,
caret_right: AtomicUsize,
caret_down: AtomicUsize,
error: AtomicUsize,
}
impl IconTheme for CountingTheme {
fn glyph(&self, role: IconRole) -> IconSpec {
let counter = match role {
IconRole::FolderClosed => &self.folder_closed,
IconRole::FolderOpen => &self.folder_open,
IconRole::File => &self.file,
IconRole::CaretRight => &self.caret_right,
IconRole::CaretDown => &self.caret_down,
IconRole::Error => &self.error,
_ => return IconSpec::new("?"),
};
counter.fetch_add(1, Ordering::Relaxed);
IconSpec::new("*")
}
}
#[test]
fn new_tree_has_default_theme_installed() {
let _tree = DirectoryTree::new(std::path::PathBuf::from("/tmp"));
let spec = UnicodeTheme.glyph(IconRole::FolderClosed);
assert!(!spec.glyph.as_ref().is_empty());
}
#[test]
fn with_icon_theme_accepts_arc_dyn() {
let theme: Arc<dyn IconTheme> = Arc::new(UnicodeTheme);
let _tree = DirectoryTree::new(std::path::PathBuf::from("/tmp"))
.with_filter(DirectoryFilter::FilesAndFolders)
.with_icon_theme(theme);
}
#[test]
fn view_calls_the_installed_theme() {
let td = TmpDir::new("icon-theme-view");
fs::create_dir(td.path().join("subdir")).unwrap();
fs::write(td.path().join("file.txt"), b"").unwrap();
let counting = Arc::new(CountingTheme::default());
let mut tree = DirectoryTree::new(td.path().to_path_buf())
.with_filter(DirectoryFilter::FilesAndFolders)
.with_icon_theme(counting.clone());
tree.__test_expand_blocking(td.path().to_path_buf());
let _: iced::Element<'_, DirectoryTreeEvent> = tree.view(|e| e);
let total = counting.folder_closed.load(Ordering::Relaxed)
+ counting.folder_open.load(Ordering::Relaxed)
+ counting.file.load(Ordering::Relaxed)
+ counting.caret_right.load(Ordering::Relaxed)
+ counting.caret_down.load(Ordering::Relaxed)
+ counting.error.load(Ordering::Relaxed);
assert!(
total > 0,
"view rendered without consulting the theme at all; \
CountingTheme counts: folder_closed={} folder_open={} file={} \
caret_right={} caret_down={} error={}",
counting.folder_closed.load(Ordering::Relaxed),
counting.folder_open.load(Ordering::Relaxed),
counting.file.load(Ordering::Relaxed),
counting.caret_right.load(Ordering::Relaxed),
counting.caret_down.load(Ordering::Relaxed),
counting.error.load(Ordering::Relaxed)
);
assert!(
counting.folder_open.load(Ordering::Relaxed) >= 1,
"expanded root should have requested FolderOpen at least once"
);
assert!(
counting.folder_closed.load(Ordering::Relaxed) >= 1,
"collapsed subdir should have requested FolderClosed"
);
assert!(
counting.file.load(Ordering::Relaxed) >= 1,
"file row should have requested IconRole::File"
);
}
#[test]
fn theme_survives_filter_change() {
let td = TmpDir::new("icon-theme-filter");
fs::create_dir(td.path().join("folder")).unwrap();
let counting = Arc::new(CountingTheme::default());
let mut tree = DirectoryTree::new(td.path().to_path_buf())
.with_filter(DirectoryFilter::FilesAndFolders)
.with_icon_theme(counting.clone());
tree.__test_expand_blocking(td.path().to_path_buf());
let _: iced::Element<'_, DirectoryTreeEvent> = tree.view(|e| e);
let first = counting.folder_open.load(Ordering::Relaxed);
assert!(first >= 1);
tree.set_filter(DirectoryFilter::FoldersOnly);
let _: iced::Element<'_, DirectoryTreeEvent> = tree.view(|e| e);
let second = counting.folder_open.load(Ordering::Relaxed);
assert!(
second > first,
"post-filter render should also consult the theme"
);
}
#[test]
fn theme_arc_is_cheaply_cloneable() {
let theme: Arc<dyn IconTheme> = Arc::new(UnicodeTheme);
let _c1 = theme.clone();
let _c2 = theme.clone();
let _c3 = Arc::clone(&theme);
assert_eq!(Arc::strong_count(&theme), 4);
}