liminal-cli 0.2.1

The liminal command: serve the network, maintain its stores, or serve its discovery MCP over stdio
Documentation
//! SDK-017 R1: a line over the limit is refused by name and the next line is
//! read whole; a message is one line.

use std::io::Cursor;

use serde_json::json;

use super::{FrameError, Incoming, read_message, write_message};

#[test]
fn overlong_line_is_refused_and_the_next_line_is_read_whole() -> Result<(), FrameError> {
    let long = "x".repeat(200);
    let input = format!("{long}\n{{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"ping\"}}\n");
    let mut reader = Cursor::new(input.into_bytes());
    assert_eq!(
        read_message(&mut reader, 64),
        Err(FrameError::Overlong { limit: 64 })
    );
    let next = read_message(&mut reader, 64)?;
    assert_eq!(
        next,
        Some(Incoming::Request {
            id: json!(1),
            method: "ping".to_owned(),
            params: serde_json::Map::new(),
        })
    );
    assert_eq!(read_message(&mut reader, 64)?, None);
    Ok(())
}

#[test]
fn a_line_exactly_at_the_limit_is_read() -> Result<(), FrameError> {
    let line = "{\"jsonrpc\":\"2.0\",\"method\":\"notifications/initialized\"}";
    let mut reader = Cursor::new(format!("{line}\n").into_bytes());
    let message = read_message(&mut reader, line.len() + 1)?;
    assert_eq!(
        message,
        Some(Incoming::Notification {
            method: "notifications/initialized".to_owned(),
            params: serde_json::Map::new(),
        })
    );
    Ok(())
}

#[test]
fn not_json_and_not_a_request_are_told_apart() {
    let mut reader = Cursor::new(b"not json\n".to_vec());
    assert!(matches!(
        read_message(&mut reader, 64),
        Err(FrameError::NotJson { .. })
    ));
    let mut reader =
        Cursor::new(b"{\"jsonrpc\":\"2.0\",\"id\":null,\"method\":\"ping\"}\n".to_vec());
    assert_eq!(
        read_message(&mut reader, 64),
        Err(FrameError::NotRequest {
            message: "id is null"
        })
    );
}

#[test]
fn a_written_message_is_one_line() -> Result<(), std::io::Error> {
    let mut out = Vec::new();
    write_message(&mut out, &json!({ "text": "two\nlines" }))?;
    assert_eq!(out.split_inclusive(|b| *b == b'\n').count(), 1);
    assert_eq!(out.last(), Some(&b'\n'));
    Ok(())
}