use crate::boundary::config::Read;
use crate::boundary::{Gesture, Query, codec::decode};
pub(super) fn surface() -> Vec<Gesture> {
let mut out = vec![
Gesture::Ask(Query::Workspaces),
Gesture::Ask(Query::Conversations {
workspace: "ws".into(),
}),
Gesture::Ask(Query::Balls),
Gesture::Ask(Query::Board),
Gesture::Ask(Query::Attention),
Gesture::Ask(Query::Ops { max: 32 }),
Gesture::Ask(Query::Search {
text: "tekeli-li".into(),
}),
];
for file in [
None,
Some(crate::workdiff::WorkFile {
ball: "bl-1".into(),
handle: None,
path: "src/a.rs".into(),
}),
Some(crate::workdiff::WorkFile {
ball: "bl-1".into(),
handle: Some("at-1a2b3c4d".into()),
path: "src/a.rs".into(),
}),
] {
out.push(Gesture::Ask(Query::WorkDiff {
workspace: "ws".into(),
file,
}));
}
out.push(Gesture::Ask(Query::Science {
workspace: "ws".into(),
}));
out.push(Gesture::Ask(Query::Config(Read::Lineages {
workspace: "ws".into(),
})));
out.push(Gesture::Ask(Query::Config(Read::Models {
workspace: "ws".into(),
provider: "acme".into(),
})));
out.push(Gesture::Ask(Query::Clients {
workspace: "ws".into(),
}));
for workspace in [None, Some("ws".to_owned())] {
out.push(Gesture::Ask(Query::Doctor { workspace }));
}
out.push(Gesture::Ask(Query::LoginTail {
workspace: "ws".into(),
provider: "acme".into(),
}));
out.push(Gesture::Ask(Query::WorkspaceBalls {
workspace: "ws".into(),
}));
for verb in [None, Some("scan".to_owned())] {
out.push(Gesture::Ask(Query::Help { verb }));
}
out.push(Gesture::Ask(Query::Invocations));
out.push(Gesture::Ask(Query::Capture {
invocation: "inv-1".into(),
}));
out.extend(inspector_family());
out
}
fn inspector_family() -> Vec<Gesture> {
let mut out = Vec::new();
let (workspace, agent) = ("ws".to_owned(), "c-1".to_owned());
for query in [
Query::Transcript {
workspace: workspace.clone(),
agent: agent.clone(),
},
Query::Follow {
workspace: workspace.clone(),
agent: agent.clone(),
},
Query::Steps {
workspace: workspace.clone(),
agent: agent.clone(),
},
Query::Rail {
workspace: workspace.clone(),
agent: agent.clone(),
},
Query::Inbox {
workspace: workspace.clone(),
agent: agent.clone(),
},
Query::Step {
workspace: workspace.clone(),
agent: agent.clone(),
seq: "003".to_owned(),
},
Query::Agent {
workspace: workspace.clone(),
agent: agent.clone(),
},
] {
out.push(Gesture::Ask(query));
}
for path in [None, Some("src/a.rs".to_owned())] {
for at in [None, Some("abcdef1234".to_owned())] {
out.push(Gesture::Ask(Query::Files {
workspace: workspace.clone(),
agent: agent.clone(),
path: path.clone(),
at,
}));
}
}
for at in [None, Some("abcdef1234".to_owned())] {
out.push(Gesture::Ask(Query::Governing {
workspace: workspace.clone(),
agent: agent.clone(),
at,
}));
}
out
}
#[test]
fn an_inspector_envelope_missing_half_its_address_is_refused() {
for op in [
"transcript",
"steps",
"step",
"files",
"governing",
"rail",
"inbox",
] {
assert!(
decode(&serde_json::json!({ "op": op, "workspace": "/ws" })).is_err(),
"{op} without an agent"
);
assert!(
decode(&serde_json::json!({ "op": op, "agent": "c-1" })).is_err(),
"{op} without a workspace"
);
}
assert!(
decode(&serde_json::json!({ "op": "step", "workspace": "/ws", "agent": "c-1" })).is_err()
);
}
#[test]
fn a_roster_envelope_without_its_provider_is_refused() {
assert!(decode(&serde_json::json!({ "op": "models", "workspace": "/ws" })).is_err());
assert!(decode(&serde_json::json!({ "op": "models", "provider": "acme" })).is_err());
assert!(decode(&serde_json::json!({ "op": "lineages" })).is_err());
}
#[test]
fn a_half_named_work_file_is_refused() {
let envelope = |file: serde_json::Value| serde_json::json!({ "op": "work-diff", "workspace": "/ws", "file": file });
assert!(decode(&envelope(serde_json::json!({ "ball": "bl-1" }))).is_err());
assert!(decode(&envelope(serde_json::json!({ "path": "a.rs" }))).is_err());
assert_eq!(
decode(&envelope(serde_json::json!("src/a.rs"))),
Err("file: not a JSON object".to_owned())
);
}