strop-engine 0.32.4

strop editor engine: documents, grammar, services and sessions — no frontend UI dependencies
use super::*;

use crate::editor::test_support::remote::{document, snapshot_editor as editor};
use strop_remote::ReadSelection;

#[test]
fn follow_moves_the_eof_cursor_but_not_marks_or_jump_history() {
    let mut e = editor("first\nend\n");
    let id = e.current();
    let old_tail = 8; // final character of "end"
    e.set_head(old_tail);
    e.feed_text("ma");
    e.push_jump();
    e.publish_source_snapshot(id, document("first\nend\nnew\n", ReadSelection::Full), true)
        .unwrap();
    assert_eq!(e.head(), 12); // final character of the appended "new"
    e.jump_back();
    assert_eq!(e.head(), old_tail);
    e.feed_text("`a");
    assert_eq!(e.head(), old_tail);
}

#[test]
fn browsing_does_not_become_eof_stickiness() {
    let mut e = editor("first\nend\n");
    let id = e.current();
    e.set_head(1);
    e.publish_source_snapshot(id, document("first\nend\nnew\n", ReadSelection::Full), true)
        .unwrap();
    assert_eq!(e.head(), 1);
}

#[test]
fn refresh_clamps_the_column_within_the_original_line() {
    let mut e = editor("abcdefgh\nsecond\nthird\n");
    let id = e.current();
    e.set_head(6);
    e.publish_source_snapshot(
        id,
        document("x\nsecond\nthird\n", ReadSelection::Full),
        false,
    )
    .unwrap();
    assert_eq!(e.buf().line_of(e.head()), 0);
    assert_eq!(e.head(), 0);
}

#[test]
fn shrink_clamps_browsing_to_a_real_grapheme() {
    let mut e = editor("first\nold tail\n");
    let id = e.current();
    e.set_head(8);
    e.publish_source_snapshot(id, document("e\u{301}\n", ReadSelection::Full), true)
        .unwrap();
    assert_eq!(
        e.head(),
        0,
        "neither the virtual EOF row nor a combining codepoint is a cursor target"
    );
}

#[test]
fn same_path_snapshots_never_share_cached_gutters() {
    let mut e = editor("abcdef\n");
    let full = e.current();
    e.blame_gutters.insert(
        full,
        crate::editor::BlameGutter {
            lines: vec![strop_git::memory::BlameLine {
                sha: "1234".into(),
                author: "first snapshot".into(),
                age: "1d".into(),
                ts: 1,
            }],
            revision: e.buf().revision(),
            request: None,
        },
    );
    // A tail may cover an entire small file. Same path, line count and buffer
    // revision still do not make two captured contents the same document.
    let tail = e.docs.insert(document(
        "uvwxyz\n",
        ReadSelection::Tail(ReadLimit::new(7).unwrap()),
    ));
    assert!(e.blame_gutter_for(full).is_some());
    assert!(e.blame_gutter_for(tail).is_none());
}

#[test]
fn historical_permalink_uses_the_rendered_source_coordinate() {
    let mut e = editor("working\n");
    let repo = strop_git::RepoTarget::Remote {
        endpoint: RemoteEndpoint::parse("ssh://fixture").unwrap(),
        workdir: "/repo".into(),
    };
    e.git = Some(strop_git::GitContext {
        repo: repo.clone(),
        head_sha: None,
        head_branch: None,
        remotes: vec![(
            "origin".into(),
            "https://github.com/acme/project.git".into(),
        )],
    });
    let hunk = strop_git::Hunk {
        kind: strop_git::HunkKind::Change,
        old_start: 40,
        old_count: 1,
        new_start: 40,
        new_count: 1,
        lines: vec![
            strop_git::DiffLine {
                origin: strop_git::LineOrigin::Deletion,
                old_lineno: Some(40),
                new_lineno: None,
                text: b"old".to_vec(),
                has_newline: true,
            },
            strop_git::DiffLine {
                origin: strop_git::LineOrigin::Addition,
                old_lineno: None,
                new_lineno: Some(40),
                text: b"new".to_vec(),
                has_newline: true,
            },
        ],
    };
    e.open_delta(
        "delta",
        crate::editor::git_memory::PreparedDiff::new("app.log".into(), vec![hunk]),
        None,
        Some(crate::editor::git_memory::CommitFiles {
            repo,
            sha: "0123456789abcdef0123456789abcdef01234567".into(),
            files: crate::editor::git_memory::PreparedFiles::new(
                "0123456789abcdef0123456789abcdef01234567".into(),
                Vec::new(),
            ),
            current: "app.log".into(),
        }),
    );
    e.set_head(e.buf().line_start(3));
    e.yank_permalink();
    assert!(
        e.register(None).text.ends_with("/app.log#L40"),
        "{}: {}",
        e.message,
        e.register(None).text
    );
    e.set_head(e.buf().line_start(2));
    assert!(
        e.build_permalink(crate::editor::permalink::PermalinkIntent::Yank)
            .is_err(),
        "a deleted line has no location in the selected commit"
    );
}