use super::*;
use crate::route::code;
use crate::source::{Clone, From};
use crate::ui::page::Page;
fn built(state: &State) -> *const Page {
page(state).page()
}
#[test]
fn only_what_a_page_shows_rebuilds_it() {
let mut state = with_repo();
let before = built(&state);
update(&mut state, Msg::RateLimits(RateLimits::default()));
update(&mut state, Msg::Notice(Notice::Info("hi".into())));
update(&mut state, Msg::Problem(Problem::Drafts, None));
let other = DataKey::Issue(ghtui(), 9);
fetched(
&mut state,
other,
Data::Issue(Some(Box::new(fixtures::issue()))),
);
update(&mut state, Msg::Offline(crate::offline::Msg::Probed(false)));
update(&mut state, Msg::Timer(Timer::Minute));
assert!(std::ptr::eq(built(&state), before));
let overview = Data::Repo(Box::new(fixtures::overview()));
fetched(&mut state, DataKey::Repo(ghtui()), overview);
assert!(!std::ptr::eq(built(&state), before));
let before = built(&state);
update(&mut state, Msg::Viewer(Ok("me".into())));
assert!(!std::ptr::eq(built(&state), before));
}
#[test]
fn a_page_away_is_built_with_what_came_meanwhile() {
let mut state = with_issue();
let key = state.needs(&route(&state)).pop().unwrap();
let _ = act(&mut state, Action::OpenInTab);
let _ = state.push(Route::Code(code::Repo(ghtui())));
let mut issue = fixtures::issue();
issue.title = "Renamed meanwhile".into();
fetched(&mut state, key, Data::Issue(Some(Box::new(issue))));
assert!(!page_text(&state).contains("Renamed meanwhile"));
press(&mut state, "<C-PageUp>");
assert!(page_text(&state).contains("Renamed meanwhile"));
}
#[test]
fn a_page_is_built_again_once_its_times_move_on() {
let mut state = with_issue();
let before = built(&state);
update(&mut state, Msg::Timer(Timer::Minute));
assert!(std::ptr::eq(built(&state), before));
state.clock = || NOW + 400 * 86_400;
update(&mut state, Msg::Timer(Timer::Minute));
assert!(!std::ptr::eq(built(&state), before));
let before = built(&state);
update(&mut state, Msg::Timer(Timer::Minute));
assert!(std::ptr::eq(built(&state), before));
}
#[test]
fn recent_times_build_a_page_at_most_once_a_minute() {
use std::sync::atomic::{AtomicU64, Ordering};
use crate::api::browse::Comment;
use crate::api::model::Capped;
use crate::api::timeline::Item;
static CLOCK: AtomicU64 = AtomicU64::new(NOW);
let mut state = with_pr();
state.clock = || CLOCK.load(Ordering::Relaxed);
let pr = PrRef::parse("gold-silver-copper/ghtui#12").unwrap();
let items = [130, 347, 615, 1801]
.map(|ago| {
Item::Comment(Comment {
id: Some(ago),
author: "octocat".into(),
body: "Looks right".into(),
created_at: crate::ui::time::iso8601(NOW - ago),
..Default::default()
})
})
.into();
let mut activity = fixtures::activity();
activity.timeline = Capped::new(items, 4);
fetched(
&mut state,
DataKey::PrActivity(pr),
Data::PrActivity(Box::new(activity)),
);
let mut builds = 0;
for second in 1..=300 {
CLOCK.store(NOW + second, Ordering::Relaxed);
let before = built(&state);
update(&mut state, Msg::Timer(Timer::Watch(0)));
assert!(std::ptr::eq(built(&state), before), "at {second}s");
if second % 60 == 0 {
update(&mut state, Msg::Timer(Timer::Minute));
builds += usize::from(!std::ptr::eq(built(&state), before));
}
}
assert_eq!(builds, 5);
}
#[test]
fn a_file_says_where_git_read_it() {
let mut state = with_repo();
let route = blob("main", "src/main.rs");
let _ = state.push(route.clone());
let key = state.needs(&route).pop().unwrap();
let source = From::Git {
clone: Clone::Cache,
at: None,
listed: None,
};
update(
&mut state,
Msg::Fetched {
key,
result: Ok(Data::Blob(Box::new(fixtures::blob()))),
cached_at: None,
source: Some(source),
},
);
assert!(page_text(&state).contains("Read by git from ghtui's clone"));
}
#[test]
#[ignore = "timing; run in release"]
#[expect(clippy::print_stderr, reason = "reports the timings")]
fn idle_hour_timing_on_a_long_conversation() {
use std::sync::atomic::{AtomicU64, Ordering};
use crate::api::browse::Comment;
use crate::api::model::Capped;
use crate::api::timeline::Item;
static CLOCK: AtomicU64 = AtomicU64::new(NOW);
let mut state = with_pr();
state.clock = || CLOCK.load(Ordering::Relaxed);
let pr = PrRef::parse("gold-silver-copper/ghtui#12").unwrap();
let body = "Looks right, but:\n\n```rust\nfn main() {\n let x = compute(1);\n println!(\"{x}\");\n}\n```\n";
let items: Vec<Item> = (0..300u64)
.map(|i| {
Item::Comment(Comment {
id: Some(i),
author: "octocat".into(),
body: body.repeat(3),
created_at: crate::ui::time::iso8601(NOW - 7200 - (299 - i) * 600),
..Default::default()
})
})
.collect();
let mut activity = fixtures::activity();
activity.timeline = Capped::new(items, 300);
fetched(
&mut state,
DataKey::PrActivity(pr),
Data::PrActivity(Box::new(activity)),
);
let (mut builds, mut spent) = (0u32, std::time::Duration::ZERO);
let mut step = |state: &mut State, msg: Msg| {
let before = built(state);
let start = std::time::Instant::now();
update(state, msg);
if !std::ptr::eq(built(state), before) {
builds += 1;
spent += start.elapsed();
}
};
for minute in 1..=60 {
CLOCK.store(NOW + minute * 60, Ordering::Relaxed);
for _ in 0..6 {
step(&mut state, Msg::RateLimits(RateLimits::default()));
}
step(&mut state, Msg::Timer(Timer::Minute));
}
eprintln!(
"builds in an idle hour: {builds}, {:?} each",
spent.checked_div(builds).unwrap_or_default()
);
}