mod declines;
use std::path::{Path, PathBuf};
use super::{MAIN, Project, ball, close_gate, read0, snap};
use crate::files_view::Preview;
use crate::workdiff::{Attempt, Change, Churn, WorkFile, patch};
pub(super) const WS: &str = "/data/workspaces/storeroom";
pub(super) const NAME: &str = "storeroom";
pub(super) fn only(attempts: Vec<Attempt>) -> Attempt {
assert_eq!(attempts.len(), 1, "{attempts:?}");
attempts.into_iter().next().unwrap()
}
pub(super) fn worked() -> Project {
let project = Project::new();
project.switch("work/bl-1");
project.commit("src/a.rs", "fn a() {}\n");
project.commit("docs/b.md", "b\n");
project.checkout(MAIN);
project
}
#[test]
fn the_diff_is_target_dot_dot_source_of_the_bound_claim() {
let project = worked();
let snap = snap(
Path::new(WS),
NAME,
&project.path,
vec![ball("bl-1", Some(NAME), None)],
);
let attempt = only(read0(&snap, Path::new(WS)));
assert_eq!(attempt.ball_id, "bl-1");
assert_eq!(attempt.project, snap.project_name(&project.path));
assert!(!attempt.project.contains(std::path::MAIN_SEPARATOR));
assert_eq!(
snap.project_path(&attempt.project),
Ok(project.path.clone())
);
assert_eq!(attempt.range().as_deref(), Some("main..work/bl-1"));
let Change::Diff {
target,
source,
target_oid,
source_oid,
files,
truncated,
} = &attempt.change
else {
panic!("a worked branch diffs: {attempt:?}");
};
assert_eq!((target.as_str(), source.as_str()), (MAIN, "work/bl-1"));
assert_ne!(target_oid, source_oid);
assert_eq!(target_oid.len(), 40, "a full oid: {target_oid}");
assert!(!truncated);
let paths: Vec<&str> = files.iter().map(|f| f.path.as_str()).collect();
assert_eq!(paths, vec!["docs/b.md", "src/a.rs"]);
assert_eq!(
files[1].churn,
Churn::Text {
added: 1,
removed: 0
}
);
}
#[test]
fn a_close_gated_child_reads_against_its_parents_branch() {
let project = Project::new();
project.switch("work/bl-parent");
project.commit("parent.txt", "parent work\n");
project.switch("work/bl-kid");
project.commit("kid.txt", "kid work\n");
let snap = snap(
Path::new(WS),
NAME,
&project.path,
vec![
close_gate(ball("bl-parent", None, None), "bl-kid"),
ball("bl-kid", Some(NAME), Some("bl-parent")),
],
);
let attempt = only(read0(&snap, Path::new(WS)));
assert_eq!(
attempt.range().as_deref(),
Some("work/bl-parent..work/bl-kid")
);
let Change::Diff { files, .. } = &attempt.change else {
panic!("{attempt:?}");
};
let paths: Vec<&str> = files.iter().map(|f| f.path.as_str()).collect();
assert_eq!(
paths,
vec!["kid.txt"],
"the parent's own work is not the kid's"
);
}
#[test]
fn a_branch_with_no_work_diffs_to_nothing() {
let project = Project::new();
project.switch("work/bl-1");
project.checkout(MAIN);
let snap = snap(
Path::new(WS),
NAME,
&project.path,
vec![ball("bl-1", Some(NAME), None)],
);
let Change::Diff { files, .. } = only(read0(&snap, Path::new(WS))).change else {
panic!("both ends resolve");
};
assert!(files.is_empty());
}
#[test]
fn a_picked_file_reads_its_patch() {
let project = worked();
let snap = snap(
Path::new(WS),
NAME,
&project.path,
vec![ball("bl-1", Some(NAME), None)],
);
let attempts = read0(&snap, Path::new(WS));
let file = |ball: &str, path: &str| WorkFile {
ball: ball.to_owned(),
handle: None,
path: path.to_owned(),
};
let Some(Preview::Text(text)) = patch(&snap, &attempts, &file("bl-1", "src/a.rs")) else {
panic!("a changed file has a patch");
};
assert!(text.contains("+fn a() {}"), "{text}");
assert!(text.contains("src/a.rs"), "{text}");
assert!(patch(&snap, &attempts, &file("bl-other", "src/a.rs")).is_none());
}
#[test]
fn a_workspace_with_no_claim_has_no_attempt() {
let project = Project::new();
let ws = PathBuf::from(WS);
let unclaimed = snap(&ws, NAME, &project.path, vec![ball("bl-1", None, None)]);
assert!(read0(&unclaimed, &ws).is_empty());
assert!(read0(&unclaimed, Path::new("/data/workspaces/other")).is_empty());
}