use std::fs;
use std::path::PathBuf;
#[test]
fn test_file_tree_builds_correctly() {
let tmp_dir = tempfile::tempdir().expect("Failed to create temp dir");
let root = tmp_dir.path().canonicalize().unwrap();
fs::create_dir(root.join("src")).unwrap();
fs::write(root.join("src/main.rs"), "fn main() {}").unwrap();
fs::write(root.join("Cargo.toml"), "[package]").unwrap();
fs::write(root.join("README.md"), "# Hello").unwrap();
use ignore::WalkBuilder;
let walker = WalkBuilder::new(&root)
.hidden(true) .git_ignore(false)
.max_depth(Some(2))
.sort_by_file_name(|a, b| a.cmp(b))
.build();
let entries: Vec<PathBuf> = walker.flatten().map(|e| e.into_path()).collect();
assert!(
entries.len() >= 5,
"Should find at least 5 entries, found {}",
entries.len()
);
let names: Vec<String> = entries
.iter()
.filter_map(|p| p.file_name().map(|n| n.to_string_lossy().to_string()))
.collect();
assert!(
names.contains(&"src".to_string()),
"Should contain 'src' dir"
);
assert!(
names.contains(&"main.rs".to_string()),
"Should contain 'main.rs'"
);
assert!(
names.contains(&"Cargo.toml".to_string()),
"Should contain 'Cargo.toml'"
);
assert!(
names.contains(&"README.md".to_string()),
"Should contain 'README.md'"
);
println!("File tree entries: {:?}", names);
}
#[test]
fn test_terminal_pane_handles_missing_claude() {
use portable_pty::{native_pty_system, CommandBuilder, PtySize};
let pty_system = native_pty_system();
let pty_result = pty_system.openpty(PtySize {
rows: 24,
cols: 80,
pixel_width: 0,
pixel_height: 0,
});
match pty_result {
Ok(pty_pair) => {
let cmd = CommandBuilder::new("this_command_does_not_exist_12345");
let spawn_result = pty_pair.slave.spawn_command(cmd);
assert!(
spawn_result.is_err(),
"Spawning non-existent command should fail"
);
println!(
"Correctly handled missing command: {:?}",
spawn_result.err()
);
}
Err(e) => {
println!("PTY creation failed (expected in non-TTY env): {}", e);
}
}
}
#[tokio::test]
async fn test_file_change_triggers_tree_refresh() {
use ignore::WalkBuilder;
use notify::RecursiveMode;
use notify_debouncer_mini::{new_debouncer, DebounceEventResult, DebouncedEventKind};
use std::time::Duration;
use tokio::sync::mpsc;
let tmp_dir = tempfile::tempdir().expect("Failed to create temp dir");
let root = tmp_dir.path().canonicalize().unwrap();
let initial_entries: Vec<_> = WalkBuilder::new(&root)
.max_depth(Some(1))
.build()
.flatten()
.collect();
let initial_count = initial_entries.len();
let (tx, mut rx) = mpsc::unbounded_channel::<PathBuf>();
let mut debouncer = new_debouncer(
Duration::from_millis(100),
move |result: DebounceEventResult| {
if let Ok(events) = result {
for fs_event in events {
if matches!(
fs_event.kind,
DebouncedEventKind::Any | DebouncedEventKind::AnyContinuous
) {
let _ = tx.send(fs_event.path);
}
}
}
},
)
.unwrap();
debouncer
.watcher()
.watch(&root, RecursiveMode::Recursive)
.unwrap();
fs::write(root.join("new_file.txt"), "created by claude").unwrap();
let event = tokio::time::timeout(Duration::from_secs(3), rx.recv()).await;
assert!(event.is_ok(), "Should detect new file creation");
let refreshed_entries: Vec<_> = WalkBuilder::new(&root)
.max_depth(Some(1))
.build()
.flatten()
.collect();
assert!(
refreshed_entries.len() > initial_count,
"Tree should have more entries after file creation: {} -> {}",
initial_count,
refreshed_entries.len()
);
let has_new_file = refreshed_entries
.iter()
.any(|e| e.file_name().to_string_lossy() == "new_file.txt");
assert!(has_new_file, "Refreshed tree should contain 'new_file.txt'");
println!("File watching + tree refresh integration: OK");
println!(
" Initial entries: {}, After creation: {}",
initial_count,
refreshed_entries.len()
);
}