tests/patch_diff_page_test.rs
Ref: Size: 4.7 KiB History
//! The web view of a patch's *whole* change, not just its head commit.
//!
//! `/{repo}/diff/{oid}` is a single-commit view — it diffs a commit against its
//! first parent — and the patch page linked its head commit there. On a patch
//! of seven commits that renders one commit and one file while `patch diff
//! --stat` reports thirty-three, so the page silently disagreed with the record
//! it was displaying. The oracle here is that CLI: whatever `patch diff --stat`
//! names, the page must show.
mod common;
use common::ServerHarness;
/// A patch whose head commit touches *one* file while the patch touches three,
/// so a single-commit view and a range view cannot produce the same answer.
fn patch_of_three_commits(harness: &ServerHarness) -> String {
let repo = harness.work_repo();
repo.git(&["checkout", "-b", "feature"]);
repo.commit_file("first.rs", "pub fn first() {}\n", "add first");
repo.commit_file("second.rs", "pub fn second() {}\n", "add second");
repo.commit_file("third.rs", "pub fn third() {}\n", "add third");
let out = repo.run_ok(&["patch", "create", "-t", "Three commits", "-B", "feature"]);
repo.git(&["checkout", "main"]);
harness.push_head();
repo.git(&["push", "origin", "feature"]);
harness.push_collab_refs();
out.trim()
.strip_prefix("Created patch ")
.expect("patch create prints the id")
.to_string()
}
/// The file paths `patch diff --stat` names, which is what the page must match.
fn stat_paths(harness: &ServerHarness, id: &str) -> Vec<String> {
harness
.work_repo()
.run_ok(&["patch", "diff", id, "--stat"])
.lines()
.filter_map(|line| line.split_once('|'))
.map(|(path, _)| path.trim().to_string())
.collect()
}
#[test]
fn patch_diff_page_shows_every_file_the_patch_touches() {
let harness = ServerHarness::new("range");
let id = patch_of_three_commits(&harness);
let paths = stat_paths(&harness, &id);
assert_eq!(
paths,
vec!["first.rs", "second.rs", "third.rs"],
"the CLI oracle itself must see all three files"
);
let page = harness.get_ok(&format!("/range/patches/{id}/diff"));
for path in &paths {
assert!(
page.body.contains(path.as_str()),
"`patch diff --stat` names {path}, so the patch diff page must show it; \
a page missing it is showing one commit instead of the patch"
);
}
}
#[test]
fn patch_detail_links_to_the_range_diff() {
let harness = ServerHarness::new("range");
let id = patch_of_three_commits(&harness);
let page = harness.get_ok(&format!("/range/patches/{id}"));
let href = page
.body
.split("href=\"")
.filter_map(|rest| rest.split_once('"'))
.map(|(href, _)| href)
.find(|href| href.contains("/patches/") && href.ends_with("/diff"))
.unwrap_or_else(|| {
panic!(
"the patch page must offer the patch's own diff; without the link the \
only diff a reader can reach is one commit of it"
)
})
.to_string();
let linked = harness.get_ok(&href);
assert!(
linked.body.contains("first.rs"),
"the link from the patch page must reach the patch's whole diff, not one commit \
of it: {href} does not show the first commit's file"
);
}
/// A patch whose branch was never pushed — the shape an agent worktree leaves
/// behind when its branch is deleted after `patch create`. The commits reach
/// the server only as revision refs, so a diff that resolved its head by
/// branch name would find nothing to show.
#[test]
fn patch_diff_page_works_without_the_head_branch() {
let harness = ServerHarness::new("range");
let repo = harness.work_repo();
repo.git(&["checkout", "-b", "gone"]);
repo.commit_file("orphan.rs", "pub fn orphan() {}\n", "add orphan");
let out = repo.run_ok(&["patch", "create", "-t", "Never pushed", "-B", "gone"]);
repo.git(&["checkout", "main"]);
let id = out
.trim()
.strip_prefix("Created patch ")
.expect("patch create prints the id")
.to_string();
harness.push_head();
harness.push_collab_refs();
assert!(
!harness
.work_repo()
.git(&["ls-remote", "--heads", "origin", "gone"])
.contains("gone"),
"the branch must be absent on the server for this test to mean anything"
);
let page = harness.get_ok(&format!("/range/patches/{id}/diff"));
assert!(
page.body.contains("orphan.rs"),
"the patch's commits reached the server as revision refs, so its diff must \
render without the branch that once named them"
);
}