use super::*;
use crate::actions::verbs::edit::{Create as BallCreate, Update as BallUpdate};
use crate::cli_outbound::Cli;
use crate::opslog;
use crate::xdg::Env;
use std::path::PathBuf;
use tempfile::{TempDir, tempdir};
mod bound;
mod dispatch;
mod edit;
fn recorder(dir: &Path, name: &str, body: &str) -> PathBuf {
let path = dir.join(name);
crate::test_support::write_exec(&path, body);
path
}
const OK_BODY: &str = "#!/bin/sh\nprintf 'OUT\\n'\nprintf 'ERR\\n' 1>&2\nexit 0\n";
struct World {
_dir: TempDir,
state: TempDir,
cli: Cli,
cwd: PathBuf,
}
impl World {
fn new(name: &str, body: &str) -> Self {
let dir = tempdir().unwrap();
let bin = recorder(dir.path(), name, body);
let cwd = dir.path().to_path_buf();
Self {
_dir: dir,
state: tempdir().unwrap(),
cli: Cli::new(bin),
cwd,
}
}
fn bound(&self) -> Bound {
Bound::at(
&self.cli,
&Env::from_pairs([("XDG_DATA_HOME", self.state.path().display().to_string())]),
&self.cwd,
)
}
fn logged(&self) -> crate::opslog::OpEntry {
let mut entries = opslog::tail(self.state.path(), 8);
assert_eq!(entries.len(), 1, "exactly one op logged");
entries.pop().unwrap()
}
}
fn args_of(e: &crate::opslog::OpEntry) -> Vec<String> {
e.argv[1..].to_vec()
}
#[test]
fn message_builds_argv_and_runs_in_the_workspace() {
let w = World::new("litany", OK_BODY);
let ws = &w.cwd;
message(&w.bound(), w.state.path(), "TS", "a-1", "hi there").unwrap();
let e = w.logged();
assert_eq!(
args_of(&e),
vec!["message", &ws.display().to_string(), "a-1", "hi there"]
);
assert_eq!(e.cwd, ws.display().to_string());
}
#[test]
fn stop_omits_and_includes_the_children_flag() {
let w = World::new("litany", OK_BODY);
let ws = w.cwd.clone();
stop(&w.bound(), w.state.path(), "TS", "a-1", false).unwrap();
assert_eq!(
args_of(&w.logged()),
vec!["stop", &ws.display().to_string(), "a-1"]
);
stop(&w.bound(), w.state.path(), "TS", "a-1", true).unwrap();
let e = opslog::tail(w.state.path(), 8).pop().unwrap();
assert_eq!(
args_of(&e),
vec!["stop", &ws.display().to_string(), "a-1", "--stop-children"]
);
}
#[test]
fn scan_builds_argv() {
let w = World::new("litany", OK_BODY);
let ws = &w.cwd;
scan(&w.bound(), w.state.path(), "TS").unwrap();
assert_eq!(
args_of(&w.logged()),
vec!["scan", &ws.display().to_string()]
);
}
#[test]
fn retarget_builds_argv_for_one_conversation_with_no_config_flag() {
let w = World::new("litany", OK_BODY);
let ws = &w.cwd;
retarget(&w.bound(), w.state.path(), "TS", "a-1").unwrap();
let e = w.logged();
assert_eq!(
args_of(&e),
vec!["retarget", &ws.display().to_string(), "a-1"]
);
assert_eq!(e.cwd, ws.display().to_string());
}
#[test]
fn close_and_unclaim_build_argv_in_the_project() {
let w = World::new("bl", OK_BODY);
let proj = &w.cwd;
close(&w.cli, w.state.path(), "TS", proj, "bl-7", "filtered").unwrap();
let e = w.logged();
assert_eq!(args_of(&e), vec!["close", "bl-7", "--as", "filtered"]);
assert_eq!(e.cwd, proj.display().to_string());
unclaim(&w.cli, w.state.path(), "TS", proj, "bl-7", "filtered").unwrap();
let e = opslog::tail(w.state.path(), 8).pop().unwrap();
assert_eq!(args_of(&e), vec!["unclaim", "bl-7", "--as", "filtered"]);
}
#[test]
fn assign_claims_the_ball_for_the_target_workspace() {
let w = World::new("bl", OK_BODY);
let proj = &w.cwd;
assign(&w.cli, w.state.path(), "TS", proj, "bl-7", "cobalt-gecko").unwrap();
let e = w.logged();
assert_eq!(args_of(&e), vec!["claim", "bl-7", "--as", "cobalt-gecko"]);
assert_eq!(e.cwd, proj.display().to_string());
}
#[test]
fn every_verb_stamps_the_origin_of_its_own_subject() {
let w = World::new("litany", OK_BODY);
message(&w.bound(), w.state.path(), "TS", "a-1", "hi").unwrap();
stop(&w.bound(), w.state.path(), "TS", "a-1", false).unwrap();
scan(&w.bound(), w.state.path(), "TS").unwrap();
for e in opslog::tail(w.state.path(), 8) {
assert_eq!(e.origin, opslog::Origin::Conversation, "{:?}", e.argv);
}
let w = World::new("bl", "#!/bin/sh\nprintf 'bl-9zzz\\n'\nexit 0\n");
let proj = w.cwd.clone();
close(&w.cli, w.state.path(), "TS", &proj, "bl-7", "amber").unwrap();
unclaim(&w.cli, w.state.path(), "TS", &proj, "bl-7", "amber").unwrap();
assign(&w.cli, w.state.path(), "TS", &proj, "bl-7", "cobalt").unwrap();
create(
&w.cli,
w.state.path(),
"TS",
&proj,
"amber",
&BallCreate {
title: "t".into(),
..BallCreate::default()
},
)
.unwrap();
update(
&w.cli,
w.state.path(),
"TS",
&proj,
"bl-7",
"amber",
&BallUpdate::default(),
)
.unwrap();
let ops = opslog::tail(w.state.path(), 16);
assert_eq!(ops.len(), 5, "one row per bl verb");
for e in ops {
assert_eq!(e.origin, opslog::Origin::Balls, "{:?}", e.argv);
}
}