refactor: move embedded tests into dedicated test directory
This commit is contained in:
@@ -0,0 +1,325 @@
|
||||
use super::*;
|
||||
struct Fixture(PathBuf);
|
||||
impl Fixture {
|
||||
fn new() -> Self {
|
||||
let path = std::env::temp_dir().join(format!(
|
||||
"vamp-resolver-test-{}-{}",
|
||||
std::process::id(),
|
||||
NEXT.fetch_add(1, Ordering::Relaxed)
|
||||
));
|
||||
fs::create_dir(&path).unwrap();
|
||||
Self(path)
|
||||
}
|
||||
fn jj(&self, args: &[&str]) -> String {
|
||||
let output = Command::new("jj")
|
||||
.current_dir(&self.0)
|
||||
.env("JJ_CONFIG", "/dev/null")
|
||||
.args([
|
||||
"--config=user.name=Resolver",
|
||||
"--config=user.email=resolver@example.test",
|
||||
"--config=debug.commit-timestamp=\"2001-01-01T00:00:00Z\"",
|
||||
"--config=debug.operation-timestamp=\"2001-01-01T00:00:00Z\"",
|
||||
])
|
||||
.args(args)
|
||||
.output()
|
||||
.unwrap();
|
||||
assert!(
|
||||
output.status.success(),
|
||||
"{}",
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
);
|
||||
String::from_utf8(output.stdout).unwrap()
|
||||
}
|
||||
fn conflict(&self) {
|
||||
self.jj(&["git", "init", "--no-colocate", "."]);
|
||||
self.jj(&["config", "set", "--repo", "user.name", "Resolver"]);
|
||||
self.jj(&[
|
||||
"config",
|
||||
"set",
|
||||
"--repo",
|
||||
"user.email",
|
||||
"resolver@example.test",
|
||||
]);
|
||||
self.jj(&[
|
||||
"config",
|
||||
"set",
|
||||
"--repo",
|
||||
"debug.commit-timestamp",
|
||||
"\"2001-01-01T00:00:00Z\"",
|
||||
]);
|
||||
self.jj(&[
|
||||
"config",
|
||||
"set",
|
||||
"--repo",
|
||||
"debug.operation-timestamp",
|
||||
"\"2001-01-01T00:00:00Z\"",
|
||||
]);
|
||||
fs::write(self.0.join("file"), "base\n").unwrap();
|
||||
self.jj(&["bookmark", "create", "base"]);
|
||||
self.jj(&["new", "base"]);
|
||||
fs::write(self.0.join("file"), "left\n").unwrap();
|
||||
self.jj(&["bookmark", "create", "left"]);
|
||||
self.jj(&["new", "base"]);
|
||||
fs::write(self.0.join("file"), "right\n").unwrap();
|
||||
self.jj(&["bookmark", "create", "right"]);
|
||||
self.jj(&["new", "left", "right"]);
|
||||
}
|
||||
}
|
||||
impl Drop for Fixture {
|
||||
fn drop(&mut self) {
|
||||
let _ = fs::remove_dir_all(&self.0);
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn discovery_is_readonly_and_save_uses_jj_authority_and_stale_guards() {
|
||||
let fixture = Fixture::new();
|
||||
fixture.conflict();
|
||||
let operation = fixture.jj(&[
|
||||
"--ignore-working-copy",
|
||||
"op",
|
||||
"log",
|
||||
"--no-graph",
|
||||
"-n",
|
||||
"1",
|
||||
"-T",
|
||||
"id",
|
||||
]);
|
||||
let workspace = load(&fixture.0, &|| false).unwrap();
|
||||
assert_eq!(workspace.files.len(), 1);
|
||||
let file = &workspace.files[0];
|
||||
assert!(file.sources.iter().any(|s| s.base && s.bytes == b"base\n"));
|
||||
assert!(file.sources.iter().any(|s| !s.base && s.bytes == b"left\n"));
|
||||
assert!(
|
||||
file.sources
|
||||
.iter()
|
||||
.any(|s| !s.base && s.bytes == b"right\n")
|
||||
);
|
||||
for bookmark in ["base", "left", "right"] {
|
||||
assert!(
|
||||
file.sources
|
||||
.iter()
|
||||
.any(|s| s.label.contains(&format!("[{bookmark}]")))
|
||||
);
|
||||
}
|
||||
assert_eq!(
|
||||
operation,
|
||||
fixture.jj(&[
|
||||
"--ignore-working-copy",
|
||||
"op",
|
||||
"log",
|
||||
"--no-graph",
|
||||
"-n",
|
||||
"1",
|
||||
"-T",
|
||||
"id"
|
||||
])
|
||||
);
|
||||
let blocks = regions(file.result.as_ref().unwrap());
|
||||
assert_eq!(blocks.len(), 1);
|
||||
for source in &file.sources {
|
||||
assert_eq!(blocks[0].choose(source).unwrap().as_bytes(), source.bytes);
|
||||
}
|
||||
let mut changed = blocks[0].clone();
|
||||
changed.sides.pop();
|
||||
assert!(changed.choose(&file.sources[0]).is_err());
|
||||
fs::write(fixture.0.join("file"), "external\n").unwrap();
|
||||
assert!(
|
||||
save(&workspace, 0, Resolution::Text("lost\n".into()), &|| false)
|
||||
.unwrap_err()
|
||||
.contains("externally")
|
||||
);
|
||||
fs::write(fixture.0.join("file"), file.result.as_ref().unwrap()).unwrap();
|
||||
fixture.jj(&["new", "base"]);
|
||||
let before = fs::read(fixture.0.join("file")).unwrap();
|
||||
assert!(
|
||||
save(
|
||||
&workspace,
|
||||
0,
|
||||
Resolution::Text("wrong checkout\n".into()),
|
||||
&|| false
|
||||
)
|
||||
.unwrap_err()
|
||||
.contains("checkout changed")
|
||||
);
|
||||
assert_eq!(fs::read(fixture.0.join("file")).unwrap(), before);
|
||||
}
|
||||
#[test]
|
||||
fn text_choice_is_confirmed_by_jj() {
|
||||
let fixture = Fixture::new();
|
||||
fixture.conflict();
|
||||
let mut workspace = load(&fixture.0, &|| false).unwrap();
|
||||
let cancelled_after_write =
|
||||
|| fs::read(fixture.0.join("file")).is_ok_and(|bytes| bytes == b"draft\n");
|
||||
let saved = save(
|
||||
&workspace,
|
||||
0,
|
||||
Resolution::Text("draft\n".into()),
|
||||
&cancelled_after_write,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(saved.file.status, Status::Unconfirmed);
|
||||
assert!(saved.confirmation.is_some());
|
||||
assert_eq!(fs::read(fixture.0.join("file")).unwrap(), b"draft\n");
|
||||
assert_eq!(
|
||||
entries(&fixture.0, &workspace.checkout.commit, &|| false).unwrap(),
|
||||
[PathBuf::from("file")]
|
||||
);
|
||||
workspace.checkout = saved.checkout;
|
||||
workspace.files[0] = saved.file;
|
||||
let outcome = save(
|
||||
&workspace,
|
||||
0,
|
||||
Resolution::Text("resolved\n".into()),
|
||||
&|| false,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
outcome.file.status,
|
||||
Status::Resolved,
|
||||
"{:?}",
|
||||
outcome.confirmation
|
||||
);
|
||||
assert_eq!(fs::read(fixture.0.join("file")).unwrap(), b"resolved\n");
|
||||
assert!(
|
||||
entries(&fixture.0, &outcome.checkout.commit, &|| false)
|
||||
.unwrap()
|
||||
.is_empty()
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn all_three_sides_and_bases_are_loaded_and_directory_children_are_protected() {
|
||||
let fixture = Fixture::new();
|
||||
fixture.conflict();
|
||||
fixture.jj(&["new", "base"]);
|
||||
fs::write(fixture.0.join("file"), "third\n").unwrap();
|
||||
fixture.jj(&["bookmark", "create", "third"]);
|
||||
fixture.jj(&["new", "left", "right", "third"]);
|
||||
let workspace = load(&fixture.0, &|| false).unwrap();
|
||||
let file = &workspace.files[0];
|
||||
assert_eq!(file.sources.iter().filter(|s| !s.base).count(), 3);
|
||||
assert_eq!(file.sources.iter().filter(|s| s.base).count(), 2);
|
||||
assert!(file.sources.iter().any(|s| s.bytes == b"third\n"));
|
||||
let blocks = regions(file.result.as_ref().unwrap());
|
||||
for source in &file.sources {
|
||||
assert_eq!(blocks[0].choose(source).unwrap().as_bytes(), source.bytes);
|
||||
}
|
||||
fs::remove_file(fixture.0.join("file")).unwrap();
|
||||
fs::create_dir(fixture.0.join("file")).unwrap();
|
||||
fs::write(fixture.0.join("file/untracked"), b"keep my draft").unwrap();
|
||||
let workspace = load(&fixture.0, &|| false).unwrap();
|
||||
assert!(
|
||||
save(&workspace, 0, Resolution::Source(0), &|| false)
|
||||
.unwrap_err()
|
||||
.contains("untracked or modified children")
|
||||
);
|
||||
assert_eq!(
|
||||
fs::read(fixture.0.join("file/untracked")).unwrap(),
|
||||
b"keep my draft"
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn binary_symlink_and_deleted_file_choices_preserve_types_and_bytes() {
|
||||
let fixture = Fixture::new();
|
||||
fixture.conflict();
|
||||
fixture.jj(&["edit", "left"]);
|
||||
fs::write(fixture.0.join("binary"), b"left\0\xff").unwrap();
|
||||
{
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
fs::set_permissions(fixture.0.join("binary"), fs::Permissions::from_mode(0o755)).unwrap();
|
||||
}
|
||||
std::os::unix::fs::symlink("left-target", fixture.0.join("link")).unwrap();
|
||||
fixture.jj(&["new", "right"]);
|
||||
fs::write(fixture.0.join("binary"), b"right\0\xfe").unwrap();
|
||||
std::os::unix::fs::symlink("right-target", fixture.0.join("link")).unwrap();
|
||||
fixture.jj(&["bookmark", "create", "right-extra"]);
|
||||
fixture.jj(&["new", "left", "right-extra"]);
|
||||
let mut workspace = load(&fixture.0, &|| false).unwrap();
|
||||
for (name, kind, bytes) in [
|
||||
("binary", FileKind::Binary, b"left\0\xff".as_slice()),
|
||||
("link", FileKind::Symlink, b"left-target".as_slice()),
|
||||
] {
|
||||
let file = workspace
|
||||
.files
|
||||
.iter()
|
||||
.position(|f| f.path == Path::new(name))
|
||||
.unwrap();
|
||||
assert!(workspace.files[file].result.is_none());
|
||||
let source = workspace.files[file]
|
||||
.sources
|
||||
.iter()
|
||||
.position(|s| !s.base && s.kind == kind && s.bytes == bytes)
|
||||
.unwrap();
|
||||
assert!(
|
||||
save(
|
||||
&workspace,
|
||||
file,
|
||||
Resolution::Text("not allowed".into()),
|
||||
&|| false
|
||||
)
|
||||
.is_err()
|
||||
);
|
||||
let outcome = save(&workspace, file, Resolution::Source(source), &|| false).unwrap();
|
||||
assert_eq!(
|
||||
outcome.file.status,
|
||||
Status::Resolved,
|
||||
"{:?}",
|
||||
outcome.confirmation
|
||||
);
|
||||
workspace.checkout = outcome.checkout;
|
||||
workspace.files[file] = outcome.file;
|
||||
if kind == FileKind::Symlink {
|
||||
assert_eq!(
|
||||
fs::read_link(fixture.0.join(name)).unwrap(),
|
||||
Path::new("left-target")
|
||||
);
|
||||
} else {
|
||||
assert_eq!(fs::read(fixture.0.join(name)).unwrap(), bytes);
|
||||
}
|
||||
if kind == FileKind::Binary {
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
assert_eq!(
|
||||
fs::metadata(fixture.0.join(name))
|
||||
.unwrap()
|
||||
.permissions()
|
||||
.mode()
|
||||
& 0o111,
|
||||
0o111
|
||||
);
|
||||
}
|
||||
}
|
||||
// add/add conflicts retain an absent base as an explicit deletion choice.
|
||||
let file = workspace
|
||||
.files
|
||||
.iter()
|
||||
.position(|f| f.path == Path::new("binary"))
|
||||
.unwrap();
|
||||
let source = workspace.files[file]
|
||||
.sources
|
||||
.iter()
|
||||
.position(|s| s.kind == FileKind::Deleted)
|
||||
.unwrap();
|
||||
let outcome = save(&workspace, file, Resolution::Source(source), &|| false).unwrap();
|
||||
assert_eq!(
|
||||
outcome.file.status,
|
||||
Status::Resolved,
|
||||
"{:?}",
|
||||
outcome.confirmation
|
||||
);
|
||||
assert!(!fixture.0.join("binary").exists());
|
||||
}
|
||||
#[test]
|
||||
fn marker_styles_widths_multisides_and_missing_eol() {
|
||||
let snapshot = "before\n<<<<<<<<<<< conflict 1 of 1\n+++++++++++ a\nleft\n----------- base\nold\n+++++++++++ b\nright\n----------- base2\nold2\n+++++++++++ c\nthird\n>>>>>>>>>>> conflict 1 of 1 ends\nafter\n";
|
||||
let parsed = regions(snapshot);
|
||||
assert_eq!(parsed[0].lines, 1..13);
|
||||
assert_eq!(parsed[0].sides, ["left\n", "right\n", "third\n"]);
|
||||
assert_eq!(parsed[0].bases, ["old\n", "old2\n"]);
|
||||
let prefixed = format!("<<<<<<< literal marker\n{snapshot}");
|
||||
assert_eq!(regions(&prefixed).len(), 1);
|
||||
assert_eq!(regions(&prefixed)[0].lines, 2..14);
|
||||
let diff = "<<<<<<< conflict 1 of 1\n%%%%%%% diff from: base\n^^^^^^^ to: left\n-old\n+left\n+++++++ right\nright\n>>>>>>> conflict 1 of 1 ends\n";
|
||||
assert_eq!(regions(diff)[0].sides, ["left\n", "right\n"]);
|
||||
let git = "<<<<<<< left\nleft\n||||||| base\nold\n=======\nright\n>>>>>>> right";
|
||||
assert_eq!(regions(git)[0].sides, ["left", "right"]);
|
||||
assert!(regions("<<<<<<< unfinished\nleft\n").is_empty());
|
||||
}
|
||||
Reference in New Issue
Block a user