use super::{ctx, existing, prepared};
use crate::boundary::config::ConfigFile;
use crate::boundary::help;
use crate::boundary::line::{parse, spell};
use crate::boundary::{Action, Gesture, Query};
use crate::fan::Verb;
use crate::start::{BallSpec, Payload};
use std::path::PathBuf;
mod balls;
mod inspector;
mod policy;
mod tools;
pub(super) fn rt(gesture: Gesture) {
let line = spell(&gesture);
assert_eq!(parse(&line, &ctx()), Ok(gesture.clone()), "via {line}");
let verb = line
.split_whitespace()
.next()
.unwrap_or_default()
.trim_start_matches('/');
assert!(help::known(verb), "/{verb} has no help page");
}
#[test]
fn the_attempt_round_trips_with_and_without_skills() {
for skills in [Vec::new(), vec!["bash".to_owned(), "read_file".to_owned()]] {
rt(Gesture::Act(Action::Fork {
workspace: "ws".to_owned(),
parent: "c-1".to_owned(),
attempt: crate::fork::Attempt {
from: "config/strict".to_owned(),
role: "worker".to_owned(),
skills,
},
goal: "try it the other way".to_owned(),
}));
}
}
#[test]
fn every_lernie_action_round_trips() {
rt(Gesture::Act(Action::Message {
workspace: "ws".to_owned(),
agent: "c-1".to_owned(),
content: "ship it".to_owned(),
}));
rt(Gesture::Act(Action::Interrupt {
workspace: "ws".to_owned(),
agent: "c-1".to_owned(),
content: "stop and do this".to_owned(),
}));
for children in [false, true] {
rt(Gesture::Act(Action::Stop {
workspace: "ws".to_owned(),
agent: "c-1".to_owned(),
children,
}));
}
rt(Gesture::Act(Action::Scan {
workspace: "ws".to_owned(),
}));
rt(Gesture::Act(Action::Nudge {
workspace: "ws".to_owned(),
agent: "c-1".to_owned(),
}));
let extra = parse("/nudge again", &ctx()).expect_err("it takes no arguments");
assert!(extra.contains("takes no arguments"), "{extra}");
let unselected = parse("/nudge", &crate::boundary::line::Context::default())
.expect_err("a nudge is fired at a conversation, and none is selected");
assert!(
unselected.contains("no workspace in context"),
"{unselected}"
);
rt(Gesture::Act(Action::Retarget {
workspace: "ws".to_owned(),
agent: "c-1".to_owned(),
}));
}
#[test]
fn every_start_rung_and_the_prompt_round_trip() {
for payload in [
Payload::Bare,
Payload::Path {
dir: PathBuf::from("/tmp/work"),
},
Payload::Ball {
project: "proj".to_owned(),
ball: existing(),
},
Payload::Ball {
project: "proj".to_owned(),
ball: BallSpec::New {
title: "a fresh ball".to_owned(),
body: String::new(),
},
},
Payload::Ball {
project: "proj".to_owned(),
ball: BallSpec::New {
title: "a fresh ball".to_owned(),
body: "with a body".to_owned(),
},
},
] {
rt(Gesture::Act(Action::Prepare {
workspace: "ws".to_owned(),
payload,
}));
}
rt(Gesture::Act(Action::Prompt {
prepared: prepared(),
goal: "do the thing".to_owned(),
seed: None,
}));
}
fn obligation() -> crate::fan::Obligation {
crate::fan::Obligation {
project: "proj".to_owned(),
ball: Some("bl-1".to_owned()),
}
}
#[test]
fn the_fan_family_round_trips() {
for n in [0, 1, 5] {
rt(Gesture::Act(Action::Fan(Verb::Spread {
prepared: prepared(),
obligation: obligation(),
n,
})));
}
rt(Gesture::Act(Action::Fan(Verb::Retire {
obligation: obligation(),
handle: "at-0badcafe".to_owned(),
})));
rt(Gesture::Act(Action::Fan(Verb::Deliver {
obligation: obligation(),
handle: "at-0badcafe".to_owned(),
summary: "take the winner — internal spaces stay".to_owned(),
})));
}
#[test]
fn every_trail_verb_and_query_round_trips() {
rt(Gesture::Act(Action::DeleteWorkspace {
workspace: "ws".to_owned(),
typed: "alba".to_owned(),
}));
for typed in ["", "the goal name"] {
rt(Gesture::Act(Action::DeleteAgent {
workspace: "ws".to_owned(),
agent: "c-1".to_owned(),
typed: typed.to_owned(),
}));
}
rt(Gesture::Act(Action::Ack));
rt(Gesture::Act(Action::MarkSeen {
workspace: "ws".to_owned(),
agent: "c-1".to_owned(),
}));
rt(Gesture::Act(Action::ClearTrail));
}
#[test]
fn the_config_familys_reads_round_trip() {
for file in [
ConfigFile::Brazen {
workspace: "ws".to_owned(),
},
ConfigFile::LernieModels,
ConfigFile::Cadence,
ConfigFile::LernieWorkflow {
name: "review".to_owned(),
},
] {
rt(Gesture::Ask(Query::ReadConfig { file }));
}
for origin in [
crate::config_edit::branch::edit::EditOrigin::Advance,
crate::config_edit::branch::edit::EditOrigin::Orphan,
crate::config_edit::branch::edit::EditOrigin::Fork {
source: "base".to_owned(),
},
] {
rt(Gesture::Ask(Query::ReadConfig {
file: ConfigFile::Branch {
workspace: "ws".to_owned(),
lineage: "strict".to_owned(),
origin,
path: "workflow.yaml".to_owned(),
},
}));
}
rt(Gesture::Ask(Query::Marks {
workspace: "ws".to_owned(),
}));
rt(Gesture::Ask(Query::Providers {
workspace: "ws".to_owned(),
}));
rt(Gesture::Ask(Query::Lineages {
workspace: "ws".to_owned(),
}));
rt(Gesture::Ask(Query::Models {
workspace: "ws".to_owned(),
provider: "acme".to_owned(),
}));
}