use super::{Harness, Rig};
use crate::app::Worker;
use crate::test_support::FakeClock;
use crate::ui_state::SystemClock;
use crate::watch::Mark;
use std::sync::Arc;
use std::time::{Duration, Instant};
fn wait_until(timeout: Duration, mut probe: impl FnMut() -> bool) -> bool {
let deadline = Instant::now() + timeout;
while Instant::now() < deadline {
if probe() {
return true;
}
std::thread::sleep(Duration::from_millis(10));
}
probe()
}
#[test]
fn wait_until_gives_up_and_reports_the_last_reading() {
assert!(!wait_until(Duration::from_millis(20), || false));
}
#[test]
fn the_worker_thread_derives_a_marked_root_and_publishes_it() {
let h = Harness::new();
let (model, deriver) = crate::AppModel::boot(
h.roots.clone(),
Arc::new(SystemClock),
Box::new(super::harness::no_balls()),
Some("me".to_string()),
);
let cell = model.snapshot_cell();
let dirty = deriver.dirty_handle();
let worker = Worker::spawn(deriver);
h.build_more("c-2", "yo");
dirty.mark_all([(h.ws.clone(), Mark::Watch)]);
assert!(
wait_until(Duration::from_secs(5), || {
crate::state::latest_snapshot(&cell)
.trees
.get(&h.ws)
.is_some_and(|t| t.agents.len() == 2)
}),
"the worker published a snapshot carrying the new agent"
);
drop(worker); }
fn late_rows(rig: &Rig) -> Vec<String> {
rig.snap
.ops
.iter()
.filter(|r| r.drift())
.map(|r| r.argv.clone())
.filter(|argv| argv.ends_with("late"))
.collect()
}
#[test]
fn a_pass_that_outruns_its_cadence_names_itself_once_however_long_it_lasts() {
let h = Harness::new();
let clock = FakeClock::lurching(Duration::from_secs(1));
let (model, deriver) = crate::AppModel::boot(
h.roots.clone(),
clock.arc(),
Box::new(super::harness::no_balls()),
Some("me".to_string()),
);
let mut rig = Rig { model, deriver };
rig.tick();
assert_eq!(late_rows(&rig).len(), 1, "one late-pass line");
rig.tick();
rig.tick();
let late = late_rows(&rig);
assert_eq!(
late.len(),
1,
"a derivation that never keeps cadence is ONE event: {late:?}"
);
}
#[test]
fn the_ops_surface_says_how_stale_the_rendered_derivation_is() {
let h = Harness::new();
let (clock, model) = h.model();
assert_eq!(
crate::test_support::chrome::notes(&model).0,
None,
"a snapshot the worker just published is not stale"
);
clock.advance(Duration::from_secs(40));
assert_eq!(
crate::test_support::chrome::notes(&model).0.as_deref(),
Some("derivation 40 s behind"),
"the age of what is on screen, not a claim about what it should be"
);
}
#[test]
fn a_conversation_whose_descent_grows_is_named_on_the_ops_surface() {
let h = Harness::new();
let (clock, mut model) = h.model();
assert_eq!(
crate::test_support::chrome::notes(&model).1,
None,
"a quiet workspace says nothing"
);
h.build_more("c-1-kid-1", "sub one");
h.build_more("c-1-kid-2", "sub two");
model.dirty_handle().mark_all([(h.ws.clone(), Mark::Watch)]);
super::derive::settle(&mut model, &clock);
assert_eq!(
crate::test_support::chrome::notes(&model).1.as_deref(),
Some("hello +2 branches"),
"named by the §3.3 display name the roster shows"
);
}