strop-engine 0.46.0

strop editor engine: documents, grammar, services and sessions — no frontend UI dependencies
#![cfg(strop_loom)]

use super::super::*;
use crate::editor::events::{AppEvent, TryRecvError, MAX_SEMANTIC_EVENTS};
use strop_core::worker::{Outcome, Ticket, WorkerId};
use strop_picker::PickerMsg;

#[test]
fn loom_source_sink_finished_survives_a_full_lane() {
    let mut builder = loom::model::Builder::new();
    builder.preemption_bound = Some(3);
    builder.check(|| {
        let ticket = Ticket {
            request: WorkerId::new(1),
            key: PickerKey {
                picker: PickerId(WorkerId::new(2)),
                cwd: "/".into(),
            },
        };
        let (tx, rx) = crate::editor::events::channel();
        let sink = Editor::app_source_sink(tx.clone(), ticket.clone());
        for _ in 0..MAX_SEMANTIC_EVENTS {
            tx.send(AppEvent::QuitIntent).unwrap();
        }
        assert!(tx.send(AppEvent::QuitIntent).is_err());

        let producer =
            loom::thread::spawn(move || sink.send(PickerMsg::Finished(Outcome::Success(()))));
        drop(tx);
        let mut quit_events = 0usize;
        let mut finished = None;
        loop {
            match rx.try_recv() {
                Ok(AppEvent::QuitIntent) => quit_events += 1,
                Ok(AppEvent::Picker(event)) => finished = Some(event),
                Ok(_) => panic!("unexpected event"),
                Err(TryRecvError::Empty) => loom::thread::yield_now(),
                Err(TryRecvError::Disconnected) => break,
            }
        }
        assert!(
            producer.join().unwrap(),
            "the source must see terminal delivery accepted"
        );
        assert_eq!(quit_events, MAX_SEMANTIC_EVENTS);
        let finished = finished.expect("Finished was stranded");
        assert_eq!(finished.ticket, ticket);
        assert!(matches!(
            &finished.msg,
            PickerMsg::Finished(Outcome::Success(()))
        ));
    });
}