use std::fs;
use eck::frontend::tui::browse::{
browse_files, browse_files_then_folders, browse_folders, launch_browser,
};
use eck::frontend::tui::launch_ui;
use eck::frontend::tui::parameters::launch_params;
use crate::mocks::helpers::{TestConfigGuard, encrypted_path_for};
use crate::mocks::tui_input::MockTuiInput;
fn read_config(path: &std::path::Path) -> serde_json::Value {
let raw = fs::read_to_string(path).expect("read config");
serde_json::from_str(&raw).expect("parse config")
}
fn guard_password() -> TestConfigGuard {
TestConfigGuard::with_parallelism("PassWord", "Zstd", serde_json::json!("Single"))
}
#[cfg(test)]
mod tests {
use super::*;
use eck::frontend::tui::treatment::treat_objects_encryption;
use tempfile::{NamedTempFile, tempdir};
#[test]
fn params_menu_changes_compression_and_preserves_parallelism() {
let guard = guard_password();
let input = MockTuiInput::new()
.with_select("Change compression type")
.with_select("Lz4 (fastest)")
.with_select("Back to main menu");
launch_params(&input).unwrap();
let cfg = read_config(guard.path());
assert_eq!(cfg["compression"], "Lz4");
assert_eq!(cfg["key_params"], "PassWord");
assert_eq!(cfg["parallelism"], "Single");
assert_eq!(input.pending_selects(), 0);
}
#[test]
fn params_menu_changes_key_type() {
let guard = guard_password();
let input = MockTuiInput::new()
.with_select("Change key type")
.with_select("OS Keyring")
.with_select("Back to main menu");
launch_params(&input).unwrap();
let cfg = read_config(guard.path());
assert_eq!(cfg["key_params"], "Os");
assert_eq!(cfg["compression"], "Zstd");
assert_eq!(cfg["parallelism"], "Single");
}
#[test]
fn params_menu_sets_multithread_parallelism_with_count() {
let guard = guard_password();
let input = MockTuiInput::new()
.with_select("Change parallelism type")
.with_select("MultiThread")
.with_counter(6)
.with_select("Back to main menu");
launch_params(&input).unwrap();
let cfg = read_config(guard.path());
assert_eq!(cfg["parallelism"], serde_json::json!({"MultiThread": 6}));
assert_eq!(input.pending_selects(), 0);
}
#[test]
fn params_menu_sets_single_parallelism_from_multithread() {
let guard = TestConfigGuard::with_parallelism(
"PassWord",
"Zstd",
serde_json::json!({"MultiThread": 8}),
);
let input = MockTuiInput::new()
.with_select("Change parallelism type")
.with_select("Single")
.with_select("Back to main menu");
launch_params(&input).unwrap();
let cfg = read_config(guard.path());
assert_eq!(cfg["parallelism"], "Single");
}
#[test]
fn browse_files_encrypts_the_chosen_file() {
let _guard = guard_password();
let original = NamedTempFile::new().unwrap();
fs::write(&original, b"browse me").unwrap();
let input = MockTuiInput::new()
.with_files(vec![original.path().to_str().unwrap()])
.with_select("Encrypt/Decrypt")
.with_select("Go Back");
browse_files(&input, Some("pwd".into())).unwrap();
assert!(
encrypted_path_for(original.path()).exists(),
"chosen file should have been encrypted"
);
assert_eq!(input.pending_files(), 0);
assert_eq!(input.pending_selects(), 0);
}
#[test]
fn browse_folders_encrypts_the_chosen_folder() {
let _guard = guard_password();
let dir = tempdir().unwrap();
fs::write(dir.path().join("inside.txt"), b"nested").unwrap();
let input = MockTuiInput::new()
.with_folders(vec![dir.path().to_str().unwrap()])
.with_select("Encrypt/Decrypt")
.with_select("Go Back");
browse_folders(&input, Some("pwd".into())).unwrap();
let archive = format!("{}.encky", dir.path().display());
assert!(std::path::Path::new(&archive).exists());
assert_eq!(input.pending_folders(), 0);
assert_eq!(input.pending_selects(), 0);
}
#[test]
fn browse_both_merges_files_and_folders() {
let _guard = guard_password();
let file = NamedTempFile::new().unwrap();
fs::write(&file, b"file side").unwrap();
let dir = tempdir().unwrap();
fs::write(dir.path().join("inside.txt"), b"dir side").unwrap();
let input = MockTuiInput::new()
.with_files(vec![file.path().to_str().unwrap()])
.with_folders(vec![dir.path().to_str().unwrap()])
.with_select("Encrypt/Decrypt")
.with_select("Go Back");
browse_files_then_folders(&input, Some("pwd".into())).unwrap();
assert!(encrypted_path_for(file.path()).exists());
let archive = format!("{}.encky", dir.path().display());
assert!(std::path::Path::new(&archive).exists());
assert_eq!(input.pending_files(), 0, "files pick should be consumed");
assert_eq!(
input.pending_folders(),
0,
"folders pick should be consumed"
);
assert_eq!(
input.pending_selects(),
0,
"treatment menu should be drained"
);
}
#[test]
fn browse_both_works_with_only_files() {
let _guard = guard_password();
let file = NamedTempFile::new().unwrap();
fs::write(&file, b"only file").unwrap();
let input = MockTuiInput::new()
.with_files(vec![file.path().to_str().unwrap()])
.with_folders(vec![])
.with_select("Encrypt/Decrypt")
.with_select("Go Back");
browse_files_then_folders(&input, Some("pwd".into())).unwrap();
assert!(encrypted_path_for(file.path()).exists());
assert_eq!(input.pending_selects(), 0);
}
#[test]
fn launch_browser_exits_on_back_to_main_menu() {
let input = MockTuiInput::new().with_select("Back to main menu");
launch_browser(&input).unwrap();
assert_eq!(input.pending_selects(), 0);
}
#[test]
fn browse_then_inspect_prints_report() {
let _guard = guard_password();
let original = NamedTempFile::new().unwrap();
fs::write(&original, b"inspect me").unwrap();
let input = MockTuiInput::new()
.with_files(vec![original.path().to_str().unwrap()])
.with_select("Inspect")
.with_select("Go Back");
browse_files(&input, None).unwrap();
assert_eq!(input.pending_files(), 0, "file pick should be consumed");
assert_eq!(
input.pending_selects(),
0,
"treatment menu should be drained"
);
assert!(
!encrypted_path_for(original.path()).exists(),
"inspection must not encrypt the object"
);
}
#[test]
fn browse_then_inspect_encrypted_archive() {
let _guard = guard_password();
let original = NamedTempFile::new().unwrap();
fs::write(&original, b"inspect the archive").unwrap();
let encrypt_input = MockTuiInput::new()
.with_files(vec![original.path().to_str().unwrap()])
.with_select("Encrypt/Decrypt")
.with_select("Go Back");
browse_files(&encrypt_input, Some("pwd".into())).unwrap();
let encrypted = encrypted_path_for(original.path());
assert!(encrypted.exists(), "setup: file should be encrypted first");
let inspect_input = MockTuiInput::new()
.with_files(vec![encrypted.to_str().unwrap()])
.with_select("Inspect")
.with_select("Go Back");
browse_files(&inspect_input, None).unwrap();
assert_eq!(inspect_input.pending_files(), 0);
assert_eq!(inspect_input.pending_selects(), 0);
}
#[test]
fn launch_treatment_go_back_does_not_encrypt() {
let _guard = guard_password();
let original = NamedTempFile::new().unwrap();
fs::write(&original, b"no treatment").unwrap();
let input = MockTuiInput::new()
.with_files(vec![original.path().to_str().unwrap()])
.with_select("Go Back");
browse_files(&input, Some("pwd".into())).unwrap();
assert!(!encrypted_path_for(original.path()).exists());
assert_eq!(input.pending_files(), 0);
assert_eq!(input.pending_selects(), 0);
}
#[test]
fn tui_treatment_encrypts_then_decrypts_real_file() {
let _guard = guard_password();
let original = NamedTempFile::new().unwrap();
let content = b"round trip through the Tui treatment path";
fs::write(&original, content).unwrap();
let plain = original.path().to_str().unwrap().to_string();
let encrypted = encrypted_path_for(original.path())
.to_str()
.unwrap()
.to_string();
let enc = MockTuiInput::new()
.with_files(vec![plain.as_str()])
.with_select("Encrypt/Decrypt")
.with_select("Go Back");
browse_files(&enc, Some("pwd".into())).unwrap();
assert!(std::path::Path::new(&encrypted).exists());
assert_eq!(enc.pending_files(), 0);
assert_eq!(enc.pending_selects(), 0, "treatment menu should be drained");
let dec = MockTuiInput::new()
.with_files(vec![encrypted.as_str()])
.with_select("Encrypt/Decrypt")
.with_select("Go Back");
browse_files(&dec, Some("pwd".into())).unwrap();
assert_eq!(dec.pending_selects(), 0);
let restored = fs::read(original.path()).unwrap();
assert_eq!(restored, content);
}
#[test]
fn tui_treatment_roundtrip_across_compressions() {
for comp in ["Zstd", "Lz4", "Xz", "NoComp"] {
let guard =
TestConfigGuard::with_parallelism("PassWord", comp, serde_json::json!("Single"));
let dir = tempdir().unwrap();
let plain = dir.path().join("data.bin");
fs::write(&plain, b"compression aware content").unwrap();
let encrypted_path = format!("{}.encky", plain.display());
let encrypted = std::path::PathBuf::from(&encrypted_path);
let plain_s = plain.to_str().unwrap().to_string();
let enc_s = encrypted.to_str().unwrap().to_string();
let password = Some("pwd".into());
treat_objects_encryption(&vec![plain_s], &password).unwrap();
assert!(encrypted.exists(), "encrypt with {comp}");
treat_objects_encryption(&vec![enc_s], &password).unwrap();
assert_eq!(fs::read(&plain).unwrap(), b"compression aware content");
drop(guard);
}
}
#[test]
fn launch_ui_help_then_exit() {
let input = MockTuiInput::new().with_select("Help").with_select("Exit");
launch_ui(&input);
assert_eq!(
input.pending_selects(),
0,
"menu should fully drain before exit"
);
}
#[test]
fn launch_ui_browse_then_exit() {
let input = MockTuiInput::new()
.with_select("Browse")
.with_select("Back to main menu")
.with_select("Exit");
launch_ui(&input);
assert_eq!(input.pending_selects(), 0);
}
#[test]
fn launch_ui_browse_then_inspect() {
let _guard = guard_password();
let original = NamedTempFile::new().unwrap();
fs::write(&original, b"full ui flow").unwrap();
let path = original.path().to_str().unwrap().to_string();
let input = MockTuiInput::new()
.with_select("Browse")
.with_select("Browse Files")
.with_files(vec![path.as_str()])
.with_select("Inspect")
.with_select("Go Back")
.with_select("Back to main menu")
.with_select("Exit");
launch_ui(&input);
assert!(
!encrypted_path_for(original.path()).exists(),
"inspection must not encrypt the object"
);
assert_eq!(input.pending_selects(), 0, "whole menu stack should drain");
}
}