use super::{append_op, model, set_closed, set_list, world};
use crate::projects::join::JoinState;
use crate::watch::Mark;
use std::time::Duration;
#[test]
fn balls_section_carries_the_delivered_badge_after_a_close() {
let w = world();
let (_c, mut m) = model(&w);
set_list(&w, r#"[{"id":"bl-boss","claimant":"boss"}]"#);
set_closed(&w, r#"[{"id":"bl-work","claimant":"cobalt"}]"#);
m.after_bl_verb(&w.project);
m.tick(); let rows = crate::test_support::chrome::ws_balls(&m, &w.ws_cobalt);
assert_eq!(
rows,
vec![crate::nav::BoundBall {
id: "bl-work".to_string(),
badge: Some("delivered".to_string()),
project: crate::naming::leaf(&w.project),
owner: "cobalt".to_string(),
state: JoinState::Delivered,
spend: crate::spend::Figure {
tokens: crate::budgets::BudgetSpend::default(),
cost: None,
attribution: crate::spend::Attribution::Workspace,
},
}],
"the §11 balls section groups the delivered ball under cobalt"
);
assert_eq!(crate::nav::balls::roster(&rows), rows);
}
#[test]
fn after_bl_verb_reflects_a_closed_ball_as_delivered() {
let w = world();
let (_c, mut m) = model(&w);
append_op(&m);
set_list(&w, r#"[{"id":"bl-boss","claimant":"boss"}]"#);
set_closed(&w, r#"[{"id":"bl-work","claimant":"cobalt"}]"#);
m.after_bl_verb(&w.project);
m.tick();
let delivered = crate::test_support::chrome::ws_balls(&m, &w.ws_cobalt);
assert_eq!(delivered.len(), 1);
assert_eq!(delivered[0].badge, Some("delivered".to_string()));
assert_eq!(m.snap.ops.len(), 1);
assert_eq!(m.snap.ops[0].argv, "bl close bl-work");
}
#[test]
fn after_litany_verb_refreshes_only_the_ops_tail() {
let w = world();
let (_c, mut m) = model(&w);
assert!(m.snap.ops.is_empty());
assert_eq!(m.activity().total, 0, "the §11 chip reads the same cache");
append_op(&m);
m.after_litany_verb();
m.tick();
assert_eq!(m.snap.ops.len(), 1);
assert_eq!(m.activity().total, 1);
}
#[test]
fn full_sweep_refetches_balls_and_ops() {
let w = world();
let (clock, mut m) = model(&w);
append_op(&m);
set_list(&w, r#"[{"id":"bl-boss","claimant":"boss"}]"#); clock.advance(Duration::from_secs(20)); m.tick();
assert_eq!(
super::row_for(&m, &w.ws_cobalt).unwrap().state,
JoinState::UnassignedWorkspace
);
assert_eq!(m.snap.ops.len(), 1, "ops re-read on the full sweep");
}
#[test]
fn clones_dirtiness_refetches_balls() {
let w = world();
let (_c, mut m) = model(&w);
set_list(&w, "[]"); m.dirty_handle()
.mark_all([(w.roots.balls_clones.clone(), Mark::Watch)]);
m.tick();
assert_eq!(
super::row_for(&m, &w.ws_cobalt).unwrap().state,
JoinState::UnassignedWorkspace
);
}
#[test]
fn yog_state_dirtiness_refreshes_the_ops_tail() {
let w = world();
let (_c, mut m) = model(&w);
append_op(&m);
m.dirty_handle()
.mark_all([(w.roots.yog_state.clone(), Mark::Watch)]);
m.tick();
assert_eq!(m.snap.ops.len(), 1);
}
#[test]
fn a_names_root_reconcile_rebinds_a_ball_to_a_fresh_workspace() {
let w = world();
set_list(&w, r#"[{"id":"bl-new","title":"Go","claimant":"newname"}]"#);
let (_c, mut m) = model(&w);
let names = w.roots.yog_data.join("workspaces");
let newname = names.join("newname");
assert!(
super::row_for(&m, &newname).is_none(),
"no workspace named the claimant yet"
);
std::fs::create_dir_all(newname.join("repo.git")).unwrap();
m.dirty_handle().mark_all([(names, Mark::Watch)]);
m.tick();
let row = super::row_for(&m, &newname).unwrap();
assert_eq!(
row.state,
JoinState::Bound,
"rebound on reconcile, no re-fetch"
);
assert_eq!(row.ball_id, "bl-new");
}