use super::*;
#[test]
fn a_workspace_with_no_derivation_yet_contributes_no_drones_and_no_spend() {
let w = world(
vec![ball("bl-new", Some("alfa"), vec![])],
vec![join("bl-new", JoinState::Bound, Some(WS_A), Some("alfa"))],
vec![],
);
let row = w.board().rows.into_iter().next().unwrap();
assert_eq!(row.column, Column::Claimed);
assert!(row.drones.is_empty());
let figure = row.spend.unwrap();
assert_eq!(figure.tokens.total_tokens(), 0);
assert_eq!(
figure.attribution,
crate::spend::Attribution::Workspace,
"nothing stamps it here, so the figure widens and says so"
);
}
#[test]
fn an_epic_rolls_up_its_live_subtree_across_workspaces_billing_each_once() {
let mut epic = ball("bl-epic", None, vec![]);
epic.priority = 1;
let mut kid_a = ball("bl-kida", Some("alfa"), vec![]);
kid_a.parent = Some("bl-epic".to_owned());
let mut kid_b = ball("bl-kidb", Some("bravo"), vec![]);
kid_b.parent = Some("bl-epic".to_owned());
let mut grandkid = ball("bl-gkid", Some("bravo"), vec![]);
grandkid.parent = Some("bl-kidb".to_owned());
let w = world(
vec![epic, kid_a, kid_b, grandkid],
vec![
join("bl-epic", JoinState::ReadyStartable, None, None),
join("bl-kida", JoinState::Bound, Some(WS_A), Some("alfa")),
join("bl-kidb", JoinState::Bound, Some(WS_B), Some("bravo")),
join("bl-gkid", JoinState::Bound, Some(WS_B), Some("bravo")),
],
vec![
(WS_A, vec![agent("conv1", Some("bl-kida"), None)]),
(
WS_B,
vec![
agent("conv2", Some("bl-kidb"), None),
agent("conv3", Some("bl-gkid"), None),
],
),
],
);
let board = w.board();
let row = |id: &str| board.rows.iter().find(|r| r.id == id).unwrap();
assert_eq!(
descendants(
"bl-epic",
&HashMap::from([
("bl-kida", &ball("bl-kida", None, vec![])),
("bl-nope", &ball("bl-nope", None, vec![])),
])
),
Vec::<String>::new(),
"descent follows the stored parent pointer and nothing else"
);
let rollup = row("bl-epic").rollup.as_ref().unwrap();
assert_eq!(rollup.cost.unwrap().usd(), "$3.00");
assert_eq!(
rollup.attribution,
crate::spend::Attribution::Conversations(3)
);
assert!(
row("bl-kida").rollup.is_none(),
"a leaf's rollup is its own figure; a second copy is not a fact"
);
let sub = row("bl-kidb").rollup.as_ref().unwrap();
assert_eq!(sub.cost.unwrap().usd(), "$2.00", "kidb + its grandkid");
}
#[test]
fn a_whole_workspace_slice_absorbs_the_tree_slices_inside_it() {
let mut epic = ball("bl-epic", None, vec![]);
epic.priority = 1;
let mut stamped = ball("bl-stmp", Some("alfa"), vec![]);
stamped.parent = Some("bl-epic".to_owned());
let mut picked = ball("bl-pick", Some("alfa"), vec![]);
picked.parent = Some("bl-epic".to_owned());
let w = world(
vec![epic, stamped, picked],
vec![
join("bl-epic", JoinState::ReadyStartable, None, None),
join("bl-stmp", JoinState::Bound, Some(WS_A), Some("alfa")),
join("bl-pick", JoinState::Bound, Some(WS_A), Some("alfa")),
],
vec![(
WS_A,
vec![
agent("conv1", Some("bl-stmp"), None),
agent("conv2", None, None),
],
)],
);
let board = w.board();
let rollup = board
.rows
.iter()
.find(|r| r.id == "bl-epic")
.unwrap()
.rollup
.as_ref()
.unwrap();
assert_eq!(
rollup.attribution,
crate::spend::Attribution::Workspace,
"an unstamped member widens the whole rollup, and it says so"
);
assert_eq!(
rollup.cost.unwrap().usd(),
"$2.00",
"the workspace's two conversations, counted once — not three"
);
}
#[test]
fn an_unbound_subtree_has_no_rollup_rather_than_a_zero_one() {
let mut epic = ball("bl-epic", None, vec![]);
epic.priority = 1;
let mut kid = ball("bl-kid", None, vec![]);
kid.parent = Some("bl-epic".to_owned());
let w = world(
vec![epic, kid],
vec![
join("bl-epic", JoinState::ReadyStartable, None, None),
join("bl-kid", JoinState::ReadyStartable, None, None),
],
vec![],
);
let board = w.board();
assert!(
board
.rows
.iter()
.find(|r| r.id == "bl-epic")
.unwrap()
.rollup
.is_none()
);
}