strop-engine 0.22.0

strop editor engine: documents, grammar dispatch, services, sessions — no terminal
Documentation
use super::*;
use crate::editor::document::RemoteDocument;
use crate::editor::{Document, Key};
use serde_json::json;
use strop_core::Buffer;
use strop_remote::{ReadLimit, ReadSelection, RemoteSize, RemoteWindow};

fn fixture(selection: ReadSelection) -> Editor {
    let file = RemoteFile::parse("ssh://fixture/work/file.txt").unwrap();
    let mut editor = Editor::new_in(Buffer::from_text("origin\n"), "/isolated".into());
    editor.tape = std::rc::Rc::new(strop_trace::replay::Tape::fixture(|_, _| {
        Err(std::io::Error::other(
            "native observation forbidden in ownership fixture",
        ))
    }));
    let document = editor.docs.insert(Document::remote(
        Buffer::from_text("before\n"),
        RemoteDocument {
            file,
            window: RemoteWindow::resolve(&selection, RemoteSize::new(7)),
            selection,
            connection: None,
            return_to: None,
            write: None,
        },
    ));
    editor.switch_to(document);
    editor
}
fn version(file: &RemoteFile, length: usize) -> RemoteVersion {
    let digest = [0u8; 32];
    serde_json::from_value(json!({"file": file, "stamp": {
        "device": 1, "inode": 1, "size": length, "mtime_ns": 1, "ctime_ns": 1,
        "mode": 416, "uid": 1, "gid": 1, "content": digest, "attributes": digest
    }}))
    .unwrap()
}
fn enable(editor: &mut Editor) {
    editor.enable_remote_edit().unwrap();
    let ticket = editor.remote.writes.pending[&editor.current()].clone();
    let version = version(&ticket.key.file, editor.buf().len_bytes());
    editor.remote_write_done(Completion {
        ticket,
        outcome: Outcome::Success(RemoteWriteResult::Enabled(version)),
    });
    assert!(!editor.buf().readonly);
}
fn receipt(editor: &Editor, ticket: &Ticket<RemoteWriteKey>) -> RemoteSaveReceipt {
    let length = editor.remote.writes.attempts[&ticket.key.document]
        .contents
        .len_bytes();
    serde_json::from_value(json!({"version": version(&ticket.key.file, length)})).unwrap()
}

#[test]
fn cancelled_admission_cannot_publish_a_queued_write_grant() {
    let mut editor = fixture(ReadSelection::Full);
    editor.enable_remote_edit().unwrap();
    let ticket = editor.remote.writes.pending[&editor.current()].clone();
    let ready = version(&ticket.key.file, editor.buf().len_bytes());
    editor.feed(Key::Esc);
    editor.remote_write_done(Completion {
        ticket,
        outcome: Outcome::Success(RemoteWriteResult::Enabled(ready)),
    });
    assert!(
        editor.buf().readonly,
        "cancelled authority cannot be revived by queued success"
    );
    editor.feed_text("iNOT-ALLOWED<esc>");
    assert_eq!(editor.buf().text(), "before\n");
}

#[test]
fn pending_edit_admission_and_follow_cannot_share_a_document() {
    let limit = ReadLimit::new(32).unwrap();
    let mut editor = fixture(ReadSelection::Tail(limit));
    let document = editor.current();
    editor.enable_remote_edit().unwrap();
    let ticket = editor.remote.writes.pending[&document].clone();
    editor.start_remote_follow(document, limit);
    assert!(
        !editor.remote_following(document),
        "pending write authority excludes automatic replacement"
    );
    let ready = version(&ticket.key.file, editor.buf().len_bytes());
    editor.remote_write_done(Completion {
        ticket,
        outcome: Outcome::Success(RemoteWriteResult::Enabled(ready)),
    });
    editor.feed_text("A draft<esc>");
    assert!(editor.buf().dirty);
    assert!(!editor.remote_following(document));
    assert_eq!(editor.buf().text(), "before draft\n");
}

#[test]
fn older_save_receipt_keeps_new_edits_and_does_not_close_the_pane() {
    let mut editor = fixture(ReadSelection::Full);
    enable(&mut editor);
    let document = editor.current();
    editor.feed_text("A first<esc>");
    editor.request_save(None, false, true);
    let ticket = editor.remote.writes.pending[&document].clone();
    let saved = receipt(&editor, &ticket);
    editor.feed_text("A newer<esc>");
    editor.remote_write_done(Completion {
        ticket,
        outcome: Outcome::Success(RemoteWriteResult::Saved(saved)),
    });
    assert_eq!(editor.current(), document);
    assert!(!editor.should_quit);
    assert!(editor.buf().dirty);
    assert_eq!(editor.buf().text(), "before first newer\n");
    assert!(
        editor.buf().path.is_none(),
        "remote saves never install a local path"
    );
}

#[test]
fn write_and_quit_does_not_discard_an_explicit_destination() {
    for command in [":wq /tmp/export<cr>", ":wq! ssh://other/work/file<cr>"] {
        let mut editor = fixture(ReadSelection::Full);
        enable(&mut editor);
        let document = editor.current();
        editor.feed_text("A draft<esc>");
        editor.feed_text(command);
        // A broken dispatcher can issue a write to the original file. Settle
        // that effect if issued, then assert the consumer-visible refusal.
        if let Some(ticket) = editor.remote.writes.pending.get(&document).cloned() {
            let saved = receipt(&editor, &ticket);
            editor.remote_write_done(Completion {
                ticket,
                outcome: Outcome::Success(RemoteWriteResult::Saved(saved)),
            });
        }
        assert!(editor.docs.get(document).is_some_and(|doc| doc.buf.dirty));
        assert_eq!(editor.current(), document);
        assert!(!editor.should_quit);
    }
}

#[test]
fn cancellation_does_not_discard_a_save_receipt_already_queued() {
    let mut editor = fixture(ReadSelection::Full);
    enable(&mut editor);
    editor.feed_text("A draft<esc>");
    let document = editor.current();
    editor.request_save(None, false, false);
    let ticket = editor.remote.writes.pending[&document].clone();
    let saved = receipt(&editor, &ticket);
    editor.cancel_remote_write(document);
    editor.remote_write_done(Completion {
        ticket,
        outcome: Outcome::Success(RemoteWriteResult::Saved(saved)),
    });
    assert!(
        !editor.buf().dirty,
        "a confirmed commit outranks an ineffective late cancellation"
    );
    assert_eq!(editor.buf().text(), "before draft\n");
}