haematite-cli 0.21.3

The haematite command: serve a store, its door and Studio, answer MCP, query with jq, and host the store's assistant seat
Documentation
use std::io;

use super::{Error, events};

#[test]
fn remote_sse_flushes_a_message_before_reading_the_next_event() {
    let (sent, received) = std::sync::mpsc::channel();
    let mut emitted = 0;
    let reader = SignalledReader {
        first: io::Cursor::new(&b"data: {\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{}}\n\n"[..]),
        received,
    };
    let result = events(reader, |_| {
        emitted += 1;
        sent.send(()).map_err(io::Error::other)
    });
    assert!(result.is_ok());
    assert_eq!(emitted, 1);
}

struct SignalledReader {
    first: io::Cursor<&'static [u8]>,
    received: std::sync::mpsc::Receiver<()>,
}

impl io::Read for SignalledReader {
    fn read(&mut self, bytes: &mut [u8]) -> io::Result<usize> {
        let count = self.first.read(bytes)?;
        if count == 0 {
            self.received.try_recv().map_err(io::Error::other)?;
        }
        Ok(count)
    }
}

impl io::BufRead for SignalledReader {
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
        if self.first.position() == self.first.get_ref().len() as u64 {
            self.received.try_recv().map_err(io::Error::other)?;
        }
        self.first.fill_buf()
    }

    fn consume(&mut self, amount: usize) {
        self.first.consume(amount);
    }
}

#[test]
fn remote_sse_names_invalid_json_and_preserves_output_failure() {
    assert!(
        matches!(events(&b"data: not-json\n\n"[..], |_| Ok(())), Err(Error::Response(code)) if code == "haematite_mcp_remote_response_invalid")
    );
    assert!(
        matches!(events(&b"data: {}\n\n"[..], |_| Err(io::Error::from(io::ErrorKind::BrokenPipe))), Err(Error::Output(error)) if error.kind() == io::ErrorKind::BrokenPipe)
    );
}