alef 0.82.2

Opinionated polyglot binding generator for Rust libraries
Documentation
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AsyncApiFixture {
    pub spec: serde_json::Value,
    #[serde(default)]
    pub expected: serde_json::Value,
    #[serde(default)]
    pub validation: Option<serde_json::Value>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WebSocketFixture {
    pub handler: WebSocketHandler,
    pub session: WebSocketSession,
    #[serde(default)]
    pub expected: serde_json::Value,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WebSocketHandler {
    pub route: String,
    pub behavior: String,
    #[serde(default)]
    pub message_schema: Option<serde_json::Value>,
    #[serde(default)]
    pub on_connect_action: Option<String>,
    #[serde(default)]
    pub on_disconnect_action: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WebSocketSession {
    #[serde(default)]
    pub messages: Vec<WebSocketMessage>,
    #[serde(default)]
    pub close_code: Option<u16>,
    #[serde(default)]
    pub abnormal_close: bool,
    #[serde(default)]
    pub expected_receive_count: Option<usize>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WebSocketMessage {
    pub direction: WebSocketMessageDirection,
    #[serde(default)]
    pub frame_type: WebSocketFrameType,
    #[serde(default)]
    pub payload: Option<serde_json::Value>,
    #[serde(default)]
    pub raw_text: Option<String>,
    #[serde(default)]
    pub payload_base64: Option<String>,
    #[serde(default)]
    pub close_code: Option<u16>,
    #[serde(default)]
    pub close_reason: Option<String>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum WebSocketMessageDirection {
    Send,
    Receive,
}

#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum WebSocketFrameType {
    #[default]
    Json,
    Text,
    Binary,
    Ping,
    Pong,
    Close,
}

#[cfg(test)]
mod tests {
    use super::{AsyncApiFixture, WebSocketFixture, WebSocketFrameType, WebSocketMessageDirection};

    #[test]
    fn asyncapi_operation_fixture_keeps_spec_and_validation_recipe() {
        let fixture: AsyncApiFixture = serde_json::from_value(serde_json::json!({
            "spec": {"asyncapi": "3.0.0", "operations": {"publishEvent": {"action": "send"}}},
            "validation": {"message": "Event", "payload": {"id": 7}},
            "expected": {"valid": true}
        }))
        .expect("AsyncAPI fixture is valid");

        assert_eq!(fixture.spec["asyncapi"], "3.0.0");
        assert_eq!(fixture.validation.expect("validation recipe")["message"], "Event");
    }

    #[test]
    fn websocket_session_keeps_ordered_protocol_actions() {
        let fixture: WebSocketFixture = serde_json::from_value(serde_json::json!({
            "handler": {"route": "/events", "behavior": "echo"},
            "session": {"messages": [
                {"direction": "send", "payload": {"event": "ready"}},
                {"direction": "receive", "frame_type": "binary", "payload_base64": "AQI="}
            ], "close_code": 1000}
        }))
        .expect("WebSocket fixture is valid");

        assert_eq!(fixture.handler.route, "/events");
        assert_eq!(fixture.session.messages[0].direction, WebSocketMessageDirection::Send);
        assert_eq!(fixture.session.messages[1].frame_type, WebSocketFrameType::Binary);
    }
}