use super::{World, fake_fail, fake_litany};
use crate::binding::workspace_path;
use crate::cli_outbound::Cli;
use crate::opslog::{Origin, YOG_STEP};
use crate::start::{Deps, StartError, execute_ensure_workspace};
use crate::world::{Layout, layout_under};
use std::path::PathBuf;
fn layout(w: &World) -> Layout {
layout_under(w.yog.path())
}
fn deps(w: &World, litany: &Cli) -> Deps {
Deps {
bl: Cli::new("/no/bl"),
litany: litany.clone(),
state_root: w.state.path().to_path_buf(),
yog_binary: PathBuf::from("/no/yog"),
}
}
#[test]
fn ensure_skips_when_the_workspace_already_exists() {
let w = World::new();
let ws = workspace_path(w.yog.path(), "n");
std::fs::create_dir_all(ws.join("repo.git")).unwrap();
let litany = Cli::new("/definitely/not/a/real/litany");
let created = execute_ensure_workspace(
&deps(&w, &litany),
"TS",
&ws,
"default",
&layout(&w),
Origin::Balls,
)
.unwrap();
assert!(!created, "existing workspace skipped");
assert!(w.ops().is_empty(), "skip runs and logs nothing");
}
#[test]
fn ensure_creates_the_workspace_and_logs() {
let w = World::new();
let ws = workspace_path(w.yog.path(), "cobalt-gecko");
let litany = Cli::new(fake_litany(w.bin.path()));
assert!(
execute_ensure_workspace(
&deps(&w, &litany),
"TS",
&ws,
"default",
&layout(&w),
Origin::Balls
)
.unwrap()
);
assert!(ws.parent().unwrap().is_dir(), "parent chain mkdir -p'd");
assert!(ws.join("repo.git").is_dir(), "the birth landed at the name");
let born = &w.ops()[0].argv[2];
assert_eq!(
std::path::Path::new(born).parent(),
ws.parent(),
"born beside its destination, so the landing is a same-dir rename: {born}"
);
assert!(
crate::scratch::is_temp(
&std::path::Path::new(born)
.file_name()
.unwrap()
.to_string_lossy()
),
"{born}"
);
assert!(
!ws.parent().unwrap().join(born).exists(),
"the temp is gone"
);
}
#[test]
fn a_failed_birth_leaves_no_workspace_and_wedges_no_name() {
let w = World::new();
let ws = workspace_path(w.yog.path(), "n");
let half = super::write_exec(
w.bin.path(),
"litany",
"#!/bin/sh\nnew_half() { mkdir -p \"$1/repo.git\"; }\n\
case \"$1\" in new) new_half \"$2\"; exit 1 ;; esac\nexit 0\n",
);
let err = execute_ensure_workspace(
&deps(&w, &Cli::new(half)),
"TS",
&ws,
"default",
&layout(&w),
Origin::Balls,
)
.unwrap_err();
assert!(matches!(err, StartError::VerbFailed { verb: "new", .. }));
assert!(!ws.exists(), "the name is free: {}", ws.display());
assert!(
crate::binding::workspaces(w.yog.path(), w.yog.path()).is_empty(),
"and nothing enumerates the debris"
);
let litany = Cli::new(fake_litany(w.bin.path()));
assert!(
execute_ensure_workspace(
&deps(&w, &litany),
"TS",
&ws,
"default",
&layout(&w),
Origin::Balls
)
.unwrap()
);
assert!(ws.join("repo.git").is_dir());
}
#[test]
fn a_birth_that_cannot_land_logs_its_step_and_leaves_nothing() {
let w = World::new();
let ws = workspace_path(w.yog.path(), "n");
std::fs::create_dir_all(&ws).unwrap();
std::fs::write(ws.join("squatter"), b"x").unwrap();
let litany = Cli::new(fake_litany(w.bin.path()));
let err = execute_ensure_workspace(
&deps(&w, &litany),
"TS",
&ws,
"default",
&layout(&w),
Origin::Balls,
)
.unwrap_err();
assert!(matches!(err, StartError::Io(_)), "{err:?}");
assert!(!ws.join("repo.git").exists(), "nothing landed");
let step = w.ops().into_iter().find(|o| o.argv[0] == YOG_STEP);
assert_eq!(step.expect("a birth step row").argv[1], "birth");
}
#[test]
fn ensure_errors_and_logs_on_a_nonzero_new() {
let w = World::new();
let ws = workspace_path(w.yog.path(), "n");
let litany = Cli::new(fake_fail(w.bin.path(), "litany", "disk full"));
let err = execute_ensure_workspace(
&deps(&w, &litany),
"TS",
&ws,
"default",
&layout(&w),
Origin::Balls,
)
.unwrap_err();
assert!(matches!(err, StartError::VerbFailed { verb: "new", .. }));
}
#[test]
fn a_new_that_died_for_want_of_a_git_identity_names_the_prerequisite() {
let w = World::new();
let ws = workspace_path(w.yog.path(), "n");
let litany = Cli::new(fake_fail(
w.bin.path(),
"litany",
"Author identity unknown *** Please tell me who you are. Run git config --global user.email you@example.com",
));
let err = execute_ensure_workspace(
&deps(&w, &litany),
"TS",
&ws,
"default",
&layout(&w),
Origin::Balls,
)
.unwrap_err();
let said = err.to_string();
assert!(
said.starts_with("git has no identity on this box"),
"{said}"
);
assert!(!said.contains("Please tell me who you are"), "{said}");
let ops = w.ops();
assert_eq!(ops[0].argv[1], "new");
assert_eq!(std::path::Path::new(&ops[0].argv[2]).parent(), ws.parent());
}
#[test]
fn ensure_logs_a_mkdir_step_failure() {
let w = World::new();
let blocker = w.yog.path().join("blocked");
std::fs::write(&blocker, b"x").unwrap();
let ws = blocker.join("workspaces").join("n");
let litany = Cli::new("/definitely/not/a/real/litany");
let err = execute_ensure_workspace(
&deps(&w, &litany),
"TS",
&ws,
"default",
&layout(&w),
Origin::Balls,
)
.unwrap_err();
assert!(matches!(err, StartError::Io(_)));
assert_eq!(w.ops()[0].argv, [YOG_STEP, "mkdir"]);
}
#[test]
fn ensure_creates_whatever_the_birth_template_names() {
let w = World::new();
let tmpl = layout(&w).litany.join("template");
std::fs::create_dir_all(&tmpl).unwrap();
std::fs::write(
tmpl.join("providers.yaml"),
"roles:\n worker:\n provider: codex\n model: gpt-5.4\n",
)
.unwrap();
let ws = workspace_path(w.yog.path(), "n");
let litany = Cli::new(fake_litany(w.bin.path()));
assert!(
execute_ensure_workspace(
&deps(&w, &litany),
"TS",
&ws,
"default",
&layout(&w),
Origin::Balls
)
.unwrap()
);
assert!(
!w.ops().iter().any(|e| e.argv == [YOG_STEP, "template"]),
"no birth-time provider step remains"
);
}