use super::{Aim, Channel, Chunk, Model, Notice};
use crate::reply::roster::Workspaces;
use crate::reply::{Outcome, Read, Reply, read};
use crate::test_support::window::{own, seated, wall};
use serde_json::json;
#[test]
fn a_channel_says_what_a_gesture_must_carry_or_that_it_cannot_say() {
let flat = Channel {
name: "(this box's own engine)".to_owned(),
named_there: None,
dials: None,
};
assert_eq!(flat.address(&wall("home")), Some("home".to_owned()));
let entry = Channel {
name: "home".to_owned(),
named_there: Some("personal".to_owned()),
dials: None,
};
assert_eq!(entry.address(&wall("personal")), Some("home".to_owned()));
assert_eq!(entry.address(&wall("somebody-elses")), None);
}
#[test]
fn every_frame_becomes_content_or_a_visible_notice() {
let mut model = Model::default();
let flat = own().channel;
model.absorb(
&flat,
read(&json!({"ok": false, "error": "unknown workspace"})),
);
assert_eq!(
model.notice,
Some(Notice::Refused("unknown workspace".to_owned()))
);
model.absorb(
&flat,
read(&json!({"ok": true, "kind": "board", "rows": []})),
);
let Some(Notice::Unreadable(why)) = &model.notice else {
panic!("an unpainted kind is this seat's own sentence");
};
assert!(why.contains("\"board\""), "{why}");
assert!(
model
.notice
.as_ref()
.expect("a notice")
.line()
.contains("this seat")
);
}
#[test]
fn a_roster_answer_replaces_one_channel_and_leaves_the_others() {
let mut model = Model {
roster: vec![own()],
..Model::default()
};
let other = Channel {
name: "elsewhere".to_owned(),
named_there: Some("elsewhere".to_owned()),
dials: None,
};
model.absorb(
&other,
Read::Answer(Reply::Workspaces(Workspaces {
rows: vec![wall("theirs")],
stale: Some("4m behind".to_owned()),
growth: None,
})),
);
assert_eq!(model.roster.len(), 2);
assert_eq!(model.roster[0], own(), "the first channel is untouched");
assert_eq!(model.roster[1].stale.as_deref(), Some("4m behind"));
model.absorb(
&other,
Read::Answer(Reply::Workspaces(Workspaces::default())),
);
assert_eq!(model.roster.len(), 2);
assert!(model.roster[1].walls.is_empty());
assert_eq!(model.roster[1].stale, None);
}
#[test]
fn each_kind_lands_in_the_pane_that_paints_it() {
let mut model = Model::default();
let flat = own().channel;
model.absorb(
&flat,
read(&json!({"ok": true, "kind": "conversations", "rows": [
{"root_id": "a", "display": "one", "state": "live", "uncertain": false, "preview": "",
"age_secs": 0, "attention": 0, "members": 1, "depth": 0, "tone": "live"}]})),
);
assert_eq!(model.convs.len(), 1);
model.absorb(
&flat,
read(&json!({"ok": true, "kind": "transcript", "rows": [
{"name": "001-op.md", "raw": "hi", "kind": "delivered",
"sender": "op", "body": "hi"}]})),
);
assert_eq!(model.transcript.entries.len(), 1);
model.absorb(
&flat,
read(&json!({"ok": true, "kind": "follow", "stream": {"text": "so far"}})),
);
assert_eq!(
model.live.as_ref().and_then(|s| s.text.clone()),
Some("so far".to_owned())
);
}
#[test]
fn a_receipt_either_clears_the_notice_or_carries_the_child_s_own_refusal() {
let mut model = Model {
notice: Some(Notice::Refused("stale".to_owned())),
..Model::default()
};
let flat = own().channel;
model.absorb(&flat, Read::Answer(Reply::Nudged));
assert_eq!(model.notice, None);
model.absorb(
&flat,
Read::Answer(Reply::Outcome(Outcome {
exit: 1,
stdout: String::new(),
stderr: "the gate said no".to_owned(),
})),
);
assert_eq!(
model.notice,
Some(Notice::Refused("the gate said no".to_owned()))
);
model.absorb(
&flat,
Read::Answer(Reply::Outcome(Outcome {
exit: 0,
stdout: "deposited".to_owned(),
stderr: String::new(),
})),
);
assert_eq!(model.notice, None);
}
#[test]
fn a_channel_can_be_held_before_it_has_answered() {
let held = Chunk::of(own().channel);
assert!(held.walls.is_empty());
assert_eq!(held.stale, None);
}
#[test]
fn the_aim_is_a_channel_and_an_address_together() {
let model = Model {
aim: Some(Aim {
channel: "one".to_owned(),
address: "home".to_owned(),
}),
..seated()
};
assert!(model.aimed_at("one", Some(&"home".to_owned())));
assert!(!model.aimed_at("two", Some(&"home".to_owned())));
assert!(!model.aimed_at("one", Some(&"other".to_owned())));
assert!(
!model.aimed_at("one", None),
"an unreachable row is never aimed at"
);
assert!(!Model::default().aimed_at("one", Some(&"home".to_owned())));
}