use super::*;
use crate::app::Roots;
use crate::app::tests::Rig;
use crate::opslog;
use crate::projects::balls::{Ball, parse_list};
use crate::projects::runner::BlRunner;
use crate::test_support::FakeClock;
use std::collections::{HashMap, HashSet};
use std::fs;
use std::sync::{Arc, Mutex};
use tempfile::{TempDir, tempdir};
#[derive(Clone)]
pub(crate) struct FakeBl {
pub(crate) live: Arc<Mutex<HashMap<PathBuf, String>>>,
pub(crate) closed: Arc<Mutex<HashMap<PathBuf, String>>>,
pub(crate) fail: Arc<Mutex<HashSet<PathBuf>>>,
}
impl BlRunner for FakeBl {
fn live(&self, project: &Path) -> std::io::Result<Vec<Ball>> {
if self.fail.lock().unwrap().contains(project) {
return Err(std::io::Error::other("store unreadable"));
}
Ok(canned(&self.live, project))
}
fn closed(&self, project: &Path) -> std::io::Result<Vec<Ball>> {
Ok(canned(&self.closed, project))
}
fn detail(&self, project: &Path, id: &str) -> Option<Ball> {
canned(&self.live, project).into_iter().find(|b| b.id == id)
}
}
pub(crate) fn canned(src: &Arc<Mutex<HashMap<PathBuf, String>>>, project: &Path) -> Vec<Ball> {
parse_list(
src.lock()
.unwrap()
.get(project)
.map_or("[]", String::as_str),
)
}
pub(crate) struct World {
pub(crate) _root: TempDir,
pub(crate) roots: Roots,
pub(crate) project: PathBuf,
pub(crate) ws_cobalt: PathBuf,
pub(crate) ws_spare: PathBuf,
pub(crate) live: Arc<Mutex<HashMap<PathBuf, String>>>,
pub(crate) closed: Arc<Mutex<HashMap<PathBuf, String>>>,
pub(crate) fail: Arc<Mutex<HashSet<PathBuf>>>,
}
const LIST: &str = r#"[{"id":"bl-work","title":"Work","claimant":"cobalt"},
{"id":"bl-boss","title":"Boss","claimant":"boss"}]"#;
pub(crate) fn world() -> World {
let root = tempdir().unwrap();
let roots = Roots {
yog_data: root.path().join("yog"),
litany_data: root.path().join("litany"),
yog_state: root.path().join("state"),
balls_clones: root.path().join("clones"),
home: root.path().join("home"),
world: crate::test_support::no_world(),
};
fs::create_dir_all(roots.balls_clones.join("%2Fproj%2Fa")).unwrap();
fs::create_dir_all(&roots.yog_state).unwrap();
let project = PathBuf::from("/proj/a");
let ws = |name: &str| {
let p = roots.yog_data.join("workspaces").join(name);
fs::create_dir_all(p.join("repo.git")).unwrap();
p
};
let ws_cobalt = ws("cobalt");
let ws_spare = ws("spare");
let live = Arc::new(Mutex::new(HashMap::from([(
project.clone(),
LIST.to_string(),
)])));
let closed = Arc::new(Mutex::new(HashMap::new()));
let fail = Arc::new(Mutex::new(HashSet::new()));
World {
_root: root,
roots,
project,
ws_cobalt,
ws_spare,
live,
closed,
fail,
}
}
pub(crate) fn model(w: &World) -> (FakeClock, Rig) {
let clock = FakeClock::new();
let (model, deriver) = AppModel::boot(
w.roots.clone(),
clock.arc(),
Box::new(FakeBl {
live: w.live.clone(),
closed: w.closed.clone(),
fail: w.fail.clone(),
}),
Some("me".to_string()),
);
(clock, Rig { model, deriver })
}
pub(crate) fn set_list(w: &World, json: &str) {
w.live
.lock()
.unwrap()
.insert(w.project.clone(), json.to_string());
}
pub(crate) fn set_closed(w: &World, json: &str) {
w.closed
.lock()
.unwrap()
.insert(w.project.clone(), json.to_string());
}
pub(crate) fn append_op(m: &AppModel) {
opslog::append(
m.state_root(),
&opslog::OpEntry {
ts: "TS".into(),
argv: vec!["bl".into(), "close".into(), "bl-work".into()],
cwd: "/proj/a".into(),
exit: 0,
stdout: String::new(),
stderr: String::new(),
origin: opslog::Origin::Balls,
},
)
.unwrap();
}