use super::*; fn notice(id: Option<&str>, title: &str, body: &str) -> Notice { Notice { id: id.map(String::from), title: title.into(), body: body.into(), focus: true, report: false, close: false, expire: None, } } #[test] fn a_session_posts_once_in_3_seconds_its_own_under_one_tag() { let mut notices = Notices::default(); let start = Instant::now(); let first = notices.turn(7, None, start).expect("the first post"); assert_eq!((&*first.tag, first.focus, first.report), ("7", true, false)); assert_eq!(notices.turn(7, None, start + Duration::from_secs(2)), None); let again = notices.turn(7, None, start + GAP).expect("past the gap"); assert_eq!(&*again.tag, "7"); assert_eq!(notices.posted.len(), 1, "the last takes its place"); } #[test] fn a_program_s_notifications_go_by_their_id_and_live_until_taken() { let mut notices = Notices::default(); let start = Instant::now(); let mut asked = notice(Some("build"), "T", ""); asked.report = true; asked.focus = false; let posted = notices.turn(7, Some(&asked), start).expect("a post"); assert_eq!( (&*posted.tag, posted.focus, posted.report), ("7:build", false, true) ); let untagged = notices .turn(7, Some(¬ice(None, "T", "")), start + GAP) .expect("a post"); assert!(untagged.tag.starts_with("7#"), "{}", untagged.tag); assert_eq!(notices.alive(), ["build"]); let update = notices .turn(7, Some(&asked), start + GAP * 2) .expect("an update"); assert!( notices.replaced(&posted.tag, posted.count), "a later post holds the tag" ); assert!(!notices.replaced(&update.tag, update.count)); assert_eq!( notices.take("7:build", Some(posted.count)), None, "an expiry takes its own post only" ); assert_eq!(notices.take("7:build", Some(update.count)), Some(update)); assert!(notices.alive().is_empty()); } #[test] fn a_session_keeps_its_last_64_notifications() { let mut notices = Notices::default(); let start = Instant::now(); for at in 0..=POSTED as u32 { let asked = notice(Some(format!("n{at}").as_str()), "T", ""); notices .turn(7, Some(&asked), start + GAP * at) .expect("a post"); } assert_eq!(notices.posted.len(), POSTED); assert!(!notices.alive().contains(&"n0"), "the oldest went"); assert!(notices.alive().contains(&"n64")); } #[test] fn a_notification_says_its_text_as_text() { let asked = notice(None, "Build\u{202e} done", "Line 1\n\nLine 2\u{200b}"); assert_eq!(said(&asked), "Build done\nLine 1\nLine 2"); assert_eq!(finished(Some(0)), "Command finished"); assert_eq!(finished(None), "Command finished"); assert_eq!(finished(Some(2)), "Command exited with 2"); } #[test] fn a_session_posts_unless_it_is_the_one_shown_in_an_active_window() { assert!(!unseen(true, true)); assert!(unseen(true, false), "the window inactive"); assert!(unseen(false, true), "the session hidden"); assert!(unseen(false, false)); } #[test] fn waiting_done_and_error_post_and_work_and_rest_do_not() { for (state, posts) in [ (State::Blocked, true), (State::Done, true), (State::Error, true), (State::Working, false), (State::Idle, false), ] { assert_eq!(tells(state), posts, "{state:?}"); } } #[test] fn a_tag_names_the_session_that_posted_it() { for tag in ["12", "12:build", "12#3"] { assert!(owns(12, tag), "{tag}"); } for tag in ["123", "1", "123:build", "13#3", ""] { assert!(!owns(12, tag), "{tag}"); } } #[test] fn a_body_goes_as_markup_s_text() { assert_eq!( escape("a & "), "<b>a</b> & <a href=x>" ); assert_eq!(escape("plain"), "plain"); }