237 lines
6.8 KiB
Rust
237 lines
6.8 KiB
Rust
//! End-to-end UI tests: drive the egui window headlessly (egui_kittest) the way
|
||
//! a user would — open a dialog, click buttons — and check the pool on disk.
|
||
|
||
use std::fs;
|
||
use std::path::{Path, PathBuf};
|
||
use std::time::{Duration, Instant};
|
||
|
||
use curator::core::file_manager::FileManager;
|
||
use curator::ui::app::CuratorApp;
|
||
use egui_kittest::Harness;
|
||
use egui_kittest::kittest::Queryable;
|
||
|
||
struct Env {
|
||
dir: tempfile::TempDir,
|
||
}
|
||
|
||
impl Env {
|
||
fn new() -> Self {
|
||
Self {
|
||
dir: tempfile::tempdir().unwrap(),
|
||
}
|
||
}
|
||
|
||
fn pool(&self) -> PathBuf {
|
||
self.dir.path().join("pool")
|
||
}
|
||
|
||
fn manager(&self) -> FileManager {
|
||
let mut fm = FileManager::with_config_path(self.dir.path().join("cfg.json"));
|
||
fm.set_pool_dir(&self.pool()).unwrap();
|
||
fm.load_pool_movies().unwrap();
|
||
fm
|
||
}
|
||
|
||
fn source(&self, name: &str) -> PathBuf {
|
||
let p = self.dir.path().join("src").join(name);
|
||
fs::create_dir_all(p.parent().unwrap()).unwrap();
|
||
fs::write(&p, name).unwrap();
|
||
p
|
||
}
|
||
}
|
||
|
||
fn harness(fm: FileManager) -> Harness<'static, CuratorApp> {
|
||
Harness::builder()
|
||
.with_size(egui::vec2(1300.0, 800.0))
|
||
.allow_missing_glyphs()
|
||
.with_accessibility_check(false)
|
||
.build_eframe(|cc| CuratorApp::new(fm, cc.egui_ctx.clone()))
|
||
}
|
||
|
||
/// Step until no background task runs (or time out).
|
||
fn wait_idle(h: &mut Harness<'static, CuratorApp>) {
|
||
let start = Instant::now();
|
||
loop {
|
||
h.step();
|
||
if !h.state().busy() {
|
||
h.run_steps(3);
|
||
return;
|
||
}
|
||
assert!(
|
||
start.elapsed() < Duration::from_secs(20),
|
||
"task did not finish"
|
||
);
|
||
std::thread::sleep(Duration::from_millis(20));
|
||
}
|
||
}
|
||
|
||
fn exists(p: &Path) -> bool {
|
||
p.exists()
|
||
}
|
||
|
||
#[test]
|
||
fn test_import_movie_through_the_dialog() {
|
||
let env = Env::new();
|
||
let src = env.source("Matrix.1999.1080p.mkv");
|
||
let mut h = harness(env.manager());
|
||
h.state_mut().open_import(vec![src.clone()]);
|
||
h.run_steps(3);
|
||
h.get_by_label("OK").click();
|
||
h.run_steps(2);
|
||
wait_idle(&mut h);
|
||
let pooled = env.pool().join("Filmy/Matrix.1999.1080p (1999).mkv");
|
||
assert!(
|
||
exists(&pooled),
|
||
"pool: {:?}",
|
||
fs::read_dir(env.pool().join("Filmy"))
|
||
.unwrap()
|
||
.collect::<Vec<_>>()
|
||
);
|
||
assert!(exists(&src), "copy keeps the source");
|
||
// the summary message is shown and can be dismissed
|
||
h.get_by_label("OK").click();
|
||
h.run_steps(2);
|
||
let fm = h.state().file_manager().unwrap();
|
||
assert_eq!(fm.filelist.len(), 1);
|
||
}
|
||
|
||
#[test]
|
||
fn test_import_requires_a_year() {
|
||
let env = Env::new();
|
||
let src = env.source("Bez roku.mkv");
|
||
let mut h = harness(env.manager());
|
||
h.state_mut().open_import(vec![src]);
|
||
h.run_steps(3);
|
||
h.get_by_label("OK").click();
|
||
h.run_steps(3);
|
||
// a warning appears and nothing is imported
|
||
assert!(h.query_by_label_contains("čtyřmístný rok").is_some());
|
||
assert!(
|
||
fs::read_dir(env.pool().join("Filmy"))
|
||
.unwrap()
|
||
.next()
|
||
.is_none()
|
||
);
|
||
}
|
||
|
||
#[test]
|
||
fn test_import_existing_film_as_a_version() {
|
||
let env = Env::new();
|
||
let mut fm = env.manager();
|
||
let opts = curator::core::file_manager::ImportOptions {
|
||
year: Some("2009".into()),
|
||
tmdb_id: Some("19995".into()),
|
||
..Default::default()
|
||
};
|
||
fm.import_movie(&env.source("a.mkv"), "Avatar", opts)
|
||
.unwrap();
|
||
// a second copy of the same film, named so title/year/id are prefilled
|
||
let src = env.source("Avatar (2009).3D.HSBS.mkv");
|
||
let nfo = src.with_extension("nfo");
|
||
fs::write(
|
||
&nfo,
|
||
"<movie><title>Avatar</title><uniqueid type=\"tmdb\">19995</uniqueid></movie>",
|
||
)
|
||
.unwrap();
|
||
let mut h = harness(fm);
|
||
h.state_mut().open_import(vec![src]);
|
||
h.run_steps(3);
|
||
h.get_by_label("OK").click();
|
||
h.run_steps(3);
|
||
// conflict question → add as a version
|
||
h.get_by_label("Přidat jako verzi").click();
|
||
h.run_steps(3);
|
||
// the popisek prompt is pre-filled from the 3D tag
|
||
h.get_by_label("OK").click();
|
||
h.run_steps(2);
|
||
wait_idle(&mut h);
|
||
let folder = env.pool().join("Filmy/Avatar (2009) [tmdbid-19995]");
|
||
assert!(folder.join("Avatar (2009) [tmdbid-19995].mkv").exists());
|
||
assert!(
|
||
folder
|
||
.join("Avatar (2009) [tmdbid-19995] - 3D HSBS.mkv")
|
||
.exists()
|
||
);
|
||
}
|
||
|
||
fn imported(env: &Env, fm: &mut FileManager, name: &str, title: &str) -> PathBuf {
|
||
fm.import_movie(
|
||
&env.source(name),
|
||
title,
|
||
curator::core::file_manager::ImportOptions::default(),
|
||
)
|
||
.unwrap()
|
||
.unwrap()
|
||
}
|
||
|
||
#[test]
|
||
fn test_edit_movie_renames_with_year_and_id() {
|
||
let env = Env::new();
|
||
let mut fm = env.manager();
|
||
let p = imported(&env, &mut fm, "x.mkv", "Matrix");
|
||
let mut h = harness(fm);
|
||
h.state_mut().select_movies(&[p]);
|
||
h.state_mut().debug_action("edit");
|
||
h.run_steps(3);
|
||
// the editor's year and TMDb fields (hint texts identify them)
|
||
for (label, text) in [("Rok:", "1999"), ("TMDb ID:", "603")] {
|
||
h.get_by_label(label).focus();
|
||
h.run_steps(1);
|
||
h.get_by_label(label).type_text(text);
|
||
h.run_steps(1);
|
||
}
|
||
h.run_steps(2);
|
||
h.get_by_label("OK").click();
|
||
h.run_steps(3);
|
||
assert!(
|
||
env.pool()
|
||
.join("Filmy/Matrix (1999) [tmdbid-603].mkv")
|
||
.exists()
|
||
);
|
||
}
|
||
|
||
#[test]
|
||
fn test_remove_movie_after_confirmation() {
|
||
let env = Env::new();
|
||
let mut fm = env.manager();
|
||
let p = imported(&env, &mut fm, "x.mkv", "Matrix");
|
||
let mut h = harness(fm);
|
||
h.state_mut().select_movies(std::slice::from_ref(&p));
|
||
h.run_steps(2);
|
||
h.key_press(egui::Key::Delete);
|
||
h.run_steps(3);
|
||
h.get_by_label("Ano").click();
|
||
h.run_steps(3);
|
||
assert!(!p.exists());
|
||
assert!(h.state().file_manager().unwrap().filelist.is_empty());
|
||
}
|
||
|
||
#[test]
|
||
fn test_assign_a_new_tag_through_the_dialog() {
|
||
let env = Env::new();
|
||
let mut fm = env.manager();
|
||
let p = imported(&env, &mut fm, "x.mkv", "Matrix");
|
||
let mut h = harness(fm);
|
||
h.state_mut().select_movies(std::slice::from_ref(&p));
|
||
h.state_mut().debug_action("tags");
|
||
h.run_steps(3);
|
||
h.get_by_label("➕ Nový štítek…").click();
|
||
h.run_steps(3);
|
||
// pick the "Žánr" category, then type the tag name
|
||
h.get_all_by_label("Žánr").last().unwrap().click();
|
||
h.run_steps(2);
|
||
h.get_all_by_label("OK").last().unwrap().click();
|
||
h.run_steps(3);
|
||
h.get_all_by_role(egui::accesskit::Role::TextInput)
|
||
.last()
|
||
.unwrap()
|
||
.type_text("Sci-Fi");
|
||
h.run_steps(2);
|
||
h.get_all_by_label("OK").last().unwrap().click();
|
||
h.run_steps(3);
|
||
h.get_by_label("OK").click();
|
||
h.run_steps(3);
|
||
let f = h.state().file_manager().unwrap().file(&p).unwrap().clone();
|
||
assert!(f.tag_paths().contains("Žánr/Sci-Fi"), "{:?}", f.tags);
|
||
}
|