wsb-daemon 0.248.6265

wsb's daemon: the workbench, the GitHub mirror's schedule and peer continuity, for every workspace on the machine
//! What a person is shown about a conflict, and what they must never be shown.

use super::*;

fn text(value: &str) -> Side {
    Side {
        present: true,
        size: value.len() as u64,
        text: Some(value.to_string()),
    }
}

fn missing() -> Side {
    Side {
        present: false,
        size: 0,
        text: None,
    }
}

fn binary(size: u64) -> Side {
    Side {
        present: true,
        size,
        text: None,
    }
}

fn compared(here: Side, there: Side) -> Versions {
    compare(&RepositoryId::root(), "src/main.rs", here, there)
}

/// TEST9998: two versions of one path produce a diff of exactly those two.
///
/// The point of the whole route: a conflict is a decision, and a person
/// deciding needs to see what they are deciding between. A count of conflicts
/// and two words ("here modified · there modified") is not that.
#[test]
fn test9998_two_versions_produce_a_diff_between_them() {
    let versions = compared(
        text("fn main() {\n    one();\n}\n"),
        text("fn main() {\n    two();\n}\n"),
    );

    let diff = versions.diff.expect("a diff between two texts");
    assert!(diff.contains("-    one();"), "this machine's line is missing:\n{diff}");
    assert!(diff.contains("+    two();"), "the peer's line is missing:\n{diff}");
    // Named for the two MACHINES, not for the scratch files the diff was made
    // from — which is what git would otherwise call them.
    assert!(diff.contains("a/src/main.rs"), "{diff}");
    assert!(diff.contains("(this machine)"), "{diff}");
    assert!(diff.contains("(the peer)"), "{diff}");
    assert_eq!(versions.reason, None, "a diff needs no excuse");
    // Both versions travel with it, so the page can offer either whole.
    assert!(versions.here.text.unwrap().contains("one();"));
    assert!(versions.there.text.unwrap().contains("two();"));
}

/// TEST9999: when there is no diff to show, WHY is part of the answer.
///
/// Each of these renders as an empty diff otherwise, and an empty diff reads
/// as "these are the same" — which is the one thing that is not true about a
/// conflict. A person who believes it keeps the wrong side.
#[test]
fn test9999_every_undiffable_conflict_says_why() {
    let deleted_here = compared(missing(), text("still here\n"));
    assert_eq!(deleted_here.reason.as_deref(), Some("deleted_here"));
    assert!(deleted_here.diff.is_none());
    assert!(!deleted_here.here.present);

    let deleted_there = compared(text("still here\n"), missing());
    assert_eq!(deleted_there.reason.as_deref(), Some("deleted_there"));
    assert!(deleted_there.diff.is_none());

    // Not text: shown as a fact rather than as mojibake.
    let binary_side = compared(binary(64), text("readable\n"));
    assert_eq!(binary_side.reason.as_deref(), Some("binary"));
    assert!(binary_side.diff.is_none());

    // Too big to hold two of in memory, which is a different fact from binary
    // — the file is fine, this is a limit.
    let huge = compared(binary(MAX_BYTES + 1), text("small\n"));
    assert_eq!(huge.reason.as_deref(), Some("too_large"));

    // And the case that means the conflict is over: both sides now hold the
    // same bytes. Reported as such rather than as an empty diff.
    let same = compared(text("agreed\n"), text("agreed\n"));
    assert_eq!(same.reason.as_deref(), Some("identical"));
    assert!(same.diff.is_none());
}

/// TEST10000: relabelling the diff header leaves the content alone.
///
/// The `---`/`+++` lines are rewritten to name the two machines. A CONTENT
/// line can begin with the same characters — a removed line starting with
/// "--" is not a header — and rewriting one of those would show the reader a
/// line their file does not contain.
#[test]
fn test10000_relabelling_leaves_the_content_alone() {
    let versions = compared(text("keep\n-- not a header\n"), text("keep\n-- changed\n"));
    let diff = versions.diff.expect("a diff");
    let (header, body) = diff
        .split_once("@@")
        .map(|(head, rest)| (head.to_string(), format!("@@{rest}")))
        .expect("a diff has a hunk");

    // The header names the machines.
    assert!(header.contains("--- a/src/main.rs"), "{header}");
    assert!(header.contains("(this machine)"), "{header}");
    assert_eq!(
        header.lines().filter(|line| line.starts_with("--- ")).count(),
        1,
        "one header line, not one per line that looks like one:\n{header}"
    );

    // The body is untouched. A removed line reading "-- not a header" renders
    // as "--- not a header" — a '-' marker plus its content — and that is the
    // reader's own file, not a header to rewrite.
    assert!(
        body.lines().any(|line| line == "--- not a header"),
        "a removed line that looks like a header must survive as content:\n{body}"
    );
    assert!(
        body.lines().any(|line| line == "+-- changed"),
        "the peer's line must survive:\n{body}"
    );
    assert!(
        !body.contains("this machine") && !body.contains("the peer"),
        "nothing inside a hunk may be relabelled:\n{body}"
    );
}