a73x

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"
    );
}