use super::super::*;
use std::cell::RefCell;
use std::collections::HashMap;
use tempfile::TempDir;
pub(super) struct StubEnv(pub(super) HashMap<&'static str, OsString>);
impl EnvLookup for StubEnv {
fn get(&self, key: &str) -> Option<OsString> {
self.0.get(key).cloned()
}
}
pub(super) fn env(repo: &Path, branch: &str) -> StubEnv {
let mut m = HashMap::new();
m.insert(
crate::prompt::tool::ENV_CONV_REPO,
repo.as_os_str().to_owned(),
);
m.insert(crate::prompt::tool::ENV_CONV_BRANCH, OsString::from(branch));
StubEnv(m)
}
pub(super) struct StubSpawner {
pub(super) out: DispatchOutput,
pub(super) invocations: RefCell<Vec<(String, PathBuf, String, String)>>,
}
impl StubSpawner {
pub(super) fn ok(handle: &str) -> Self {
Self {
out: DispatchOutput {
stdout: format!("{handle}\n"),
stderr: String::new(),
exit: 0,
},
invocations: RefCell::new(Vec::new()),
}
}
pub(super) fn failing(stderr: &str, exit: i32) -> Self {
Self {
out: DispatchOutput {
stdout: String::new(),
stderr: stderr.to_string(),
exit,
},
invocations: RefCell::new(Vec::new()),
}
}
pub(super) fn empty_stdout() -> Self {
Self {
out: DispatchOutput {
stdout: String::new(),
stderr: String::new(),
exit: 0,
},
invocations: RefCell::new(Vec::new()),
}
}
}
impl Spawner for StubSpawner {
fn dispatch(
&self,
role: &str,
repo: &Path,
branch: &str,
goal: &str,
) -> Result<DispatchOutput, io::Error> {
self.invocations.borrow_mut().push((
role.to_string(),
repo.to_path_buf(),
branch.to_string(),
goal.to_string(),
));
Ok(DispatchOutput {
stdout: self.out.stdout.clone(),
stderr: self.out.stderr.clone(),
exit: self.out.exit,
})
}
}
pub(super) struct ErrSpawner;
impl Spawner for ErrSpawner {
fn dispatch(
&self,
_role: &str,
_repo: &Path,
_branch: &str,
_goal: &str,
) -> Result<DispatchOutput, io::Error> {
Err(io::Error::new(io::ErrorKind::NotFound, "no lernie binary"))
}
}
pub(super) fn fake_repo(role: &str) -> (TempDir, PathBuf) {
let (holder, ws) = crate::workspace::fixture::workspace();
let yaml = format!("roles:\n {role}:\n provider: anthropic\n model: sonnet\n",);
let soul_rel = format!("souls/{role}.md");
crate::workspace::fixture::amend_config(
&ws,
&[
("providers.yaml", yaml.as_str()),
(&soul_rel, "soul body\n"),
],
);
for parent in ["p1", "p1-conv"] {
crate::workspace::fixture::spawn_root(&ws, parent);
}
(holder, ws)
}
pub(super) fn input_for(role: &str, goal: &str) -> Vec<u8> {
serde_json::json!({ "role": role, "goal": goal })
.to_string()
.into_bytes()
}