feat: show asynchronously checked episode providers
This commit is contained in:
@@ -824,3 +824,204 @@ fn anilist_unknown_count_allows_explicit_selection_and_provider_local_collection
|
||||
assert!(matches!(browser.screen().content, Content::Catalog { .. }));
|
||||
assert!(!browser.episode_input);
|
||||
}
|
||||
|
||||
fn anilist_browser(directory: &Directory, count: u32) -> Browser {
|
||||
let mut browser = directory.browser(None);
|
||||
browser.provider = Provider::AniList;
|
||||
browser.options.anilist = true;
|
||||
browser.options.miruro = false;
|
||||
browser.state.select_catalog(Provider::AniList);
|
||||
let series = miruro_browser::anilist_series(serde_json::json!({
|
||||
"id":"1", "catalog_provider":"anilist", "title":{"romaji":"Dragon Ball"},
|
||||
"status":"FINISHED", "episode_count":count, "catalog_count":count,
|
||||
"episode_duration_minutes":25, "format":"TV", "season_year":1986
|
||||
}))
|
||||
.unwrap();
|
||||
browser.push(Screen::new(Content::Series {
|
||||
media: series.media,
|
||||
data: Some(series.episodes),
|
||||
}));
|
||||
browser
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn source_candidates_use_rendered_offset_and_three_line_viewport_not_series_size() {
|
||||
use ratatui::{Terminal, backend::TestBackend};
|
||||
let directory = Directory::new();
|
||||
let mut browser = anilist_browser(&directory, 153);
|
||||
let mut terminal = Terminal::new(TestBackend::new(80, 24)).unwrap();
|
||||
terminal
|
||||
.draw(|frame| browser.draw(frame, Duration::ZERO))
|
||||
.unwrap();
|
||||
let initial = browser.source_visible.clone();
|
||||
assert!(initial.len() < 153);
|
||||
assert_eq!(initial.first().unwrap(), "anilist:1:1");
|
||||
let [_, _, content, _, _] = ui::browser_layout(terminal.backend().buffer().area, 1);
|
||||
assert_eq!(
|
||||
initial.len(),
|
||||
usize::from(content.height.saturating_sub(2)) / 3
|
||||
);
|
||||
browser.select(Action::VideoLast);
|
||||
terminal
|
||||
.draw(|frame| browser.draw(frame, Duration::ZERO))
|
||||
.unwrap();
|
||||
let offset = browser.screen().selection.offset();
|
||||
assert!(offset > 0);
|
||||
assert_eq!(
|
||||
browser.source_visible.first().unwrap(),
|
||||
&format!("anilist:1:{}", offset + 1)
|
||||
);
|
||||
assert!(browser.source_visible.contains(&"anilist:1:153".into()));
|
||||
assert!(
|
||||
!browser
|
||||
.source_visible
|
||||
.iter()
|
||||
.any(|key| initial.contains(key))
|
||||
);
|
||||
let selection = browser.screen().selected_key().unwrap().to_owned();
|
||||
let now = Instant::now(); // Inject one fixed clock for every scheduler transition in this test.
|
||||
browser.update_source_checks(now);
|
||||
assert_eq!(
|
||||
browser.source_checks.status(&selection),
|
||||
Some(source_check::Status::Failed)
|
||||
);
|
||||
assert_eq!(browser.screen().selected_key(), Some(selection.as_str()));
|
||||
browser.update_source_checks(now);
|
||||
assert_eq!(browser.screen().selected_key(), Some(selection.as_str()));
|
||||
assert_eq!(browser.screen().len(), 153);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn source_eligibility_pauses_under_popups_loading_and_catalogs_then_resumes_from_frame() {
|
||||
let directory = Directory::new();
|
||||
let mut browser = anilist_browser(&directory, 10);
|
||||
let candidates = |browser: &mut Browser| {
|
||||
browser.update_visible_sources(8);
|
||||
browser.source_visible.clone()
|
||||
};
|
||||
assert_eq!(candidates(&mut browser), ["anilist:1:1", "anilist:1:2"]);
|
||||
browser.help = Some(0);
|
||||
assert!(candidates(&mut browser).is_empty());
|
||||
browser.help = None;
|
||||
browser.preview = Some(PreviewMode::Info);
|
||||
assert!(candidates(&mut browser).is_empty());
|
||||
browser.preview = None;
|
||||
browser.input = Some(String::new());
|
||||
assert!(candidates(&mut browser).is_empty());
|
||||
browser.input = None;
|
||||
browser.removal = Some((CollectionKind::Saved, vec![]));
|
||||
assert!(candidates(&mut browser).is_empty());
|
||||
browser.removal = None;
|
||||
browser.modal = Some(LibraryModal::Categories {
|
||||
names: vec![],
|
||||
checked: BTreeSet::new(),
|
||||
picker: Picker::default(),
|
||||
});
|
||||
assert!(candidates(&mut browser).is_empty());
|
||||
browser.modal = None;
|
||||
browser.request(
|
||||
Request::Episodes {
|
||||
media_id: "1".into(),
|
||||
slug: String::new(),
|
||||
},
|
||||
Intent::Series("1".into()),
|
||||
);
|
||||
assert!(candidates(&mut browser).is_empty());
|
||||
browser.invalidate();
|
||||
assert!(browser.source_visible.is_empty());
|
||||
assert_eq!(candidates(&mut browser).len(), 2);
|
||||
browser.history(false);
|
||||
assert!(candidates(&mut browser).is_empty());
|
||||
browser.history(true);
|
||||
assert_eq!(candidates(&mut browser).len(), 2);
|
||||
browser.provider = Provider::Miruro;
|
||||
assert!(candidates(&mut browser).is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn source_checks_are_session_only_and_collection_rows_keep_selection_checks_and_watch_state() {
|
||||
use ratatui::{Terminal, backend::TestBackend};
|
||||
let directory = Directory::new();
|
||||
let mut browser = anilist_browser(&directory, 10);
|
||||
let video = browser.screen().selected_video().unwrap();
|
||||
browser.save(CollectionKind::Saved);
|
||||
browser.set_watch_status(WatchStatus::Watched);
|
||||
browser.collection(CollectionKind::Saved);
|
||||
browser.screen_mut().toggle_checked();
|
||||
let checks = browser.screen().checked.clone();
|
||||
let saved = fs::read(directory.0.join("saved-videos.toml")).unwrap();
|
||||
let watch = fs::read(directory.0.join("watch-state.toml")).unwrap();
|
||||
let config = fs::read(&browser.config_path).unwrap();
|
||||
let mut terminal = Terminal::new(TestBackend::new(80, 24)).unwrap();
|
||||
terminal
|
||||
.draw(|frame| browser.draw(frame, Duration::ZERO))
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
browser.source_visible.as_slice(),
|
||||
std::slice::from_ref(&video.id)
|
||||
);
|
||||
assert_eq!(browser.rows()[0].height(), 3);
|
||||
let now = Instant::now(); // Fixed injected clock; no elapsed-time dependency.
|
||||
browser.update_source_checks(now);
|
||||
assert_eq!(
|
||||
browser.source_checks.status(&video.id),
|
||||
Some(source_check::Status::Failed)
|
||||
);
|
||||
assert_eq!(browser.screen().selected_key(), Some(video.id.as_str()));
|
||||
assert_eq!(browser.screen().checked, checks);
|
||||
assert!(browser.state.is_watched(&video.id));
|
||||
assert_eq!(
|
||||
fs::read(directory.0.join("saved-videos.toml")).unwrap(),
|
||||
saved
|
||||
);
|
||||
assert_eq!(
|
||||
fs::read(directory.0.join("watch-state.toml")).unwrap(),
|
||||
watch
|
||||
);
|
||||
assert_eq!(fs::read(&browser.config_path).unwrap(), config);
|
||||
browser.refresh();
|
||||
assert_eq!(browser.source_checks.status(&video.id), None);
|
||||
assert_eq!(browser.screen().selected_key(), Some(video.id.as_str()));
|
||||
browser.provider = Provider::Miruro;
|
||||
assert_eq!(browser.rows()[0].height(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn episode_three_lines_align_after_shared_marker_and_leave_metadata_second() {
|
||||
use ratatui::{Terminal, backend::TestBackend};
|
||||
let directory = Directory::new();
|
||||
let mut browser = anilist_browser(&directory, 2);
|
||||
let video = browser.screen().selected_video().unwrap();
|
||||
browser.set_watch_status(WatchStatus::Watched);
|
||||
let mut terminal = Terminal::new(TestBackend::new(100, 30)).unwrap();
|
||||
terminal
|
||||
.draw(|frame| browser.draw(frame, Duration::ZERO))
|
||||
.unwrap();
|
||||
let buffer = terminal.backend().buffer();
|
||||
let find = |needle: &str| {
|
||||
(0..buffer.area.height)
|
||||
.find_map(|y| {
|
||||
let line = (0..buffer.area.width)
|
||||
.map(|x| buffer[(x, y)].symbol())
|
||||
.collect::<String>();
|
||||
line.find(needle)
|
||||
.map(|byte| (line[..byte].chars().count(), y))
|
||||
})
|
||||
.unwrap()
|
||||
};
|
||||
let title = find("Episode 1");
|
||||
let metadata = find("25 min avg");
|
||||
let source = find(browser.source_checks.label(&video.id));
|
||||
assert_eq!(metadata, (title.0, title.1 + 1));
|
||||
assert_eq!(source, (title.0, title.1 + 2));
|
||||
assert_eq!(browser.screen().selected_key(), Some(video.id.as_str()));
|
||||
for metadata in ["25 min avg", "TV", "1986 series"] {
|
||||
assert!(browser.screen().rows[0].details.contains(metadata));
|
||||
}
|
||||
browser.screen_mut().toggle_checked();
|
||||
terminal
|
||||
.draw(|frame| browser.draw(frame, Duration::ZERO))
|
||||
.unwrap();
|
||||
assert!(browser.state.is_watched(&video.id));
|
||||
assert_eq!(browser.screen().checked, [video.id]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user