carapax 0.36.0

A Telegram Bot Framework
Documentation
use std::{error::Error, fmt};

use tokio::sync::Mutex;

use crate::{
    core::context::{Context, Ref},
    types::Update,
};

use super::*;

#[derive(Clone)]
struct UpdateStore(Arc<Mutex<Vec<Update>>>);

impl UpdateStore {
    fn new() -> Self {
        Self(Arc::new(Mutex::new(Vec::new())))
    }

    async fn push(&self, update: Update) {
        self.0.lock().await.push(update)
    }

    async fn count(&self) -> usize {
        self.0.lock().await.len()
    }
}

async fn handler_ok(store: Ref<UpdateStore>, update: Update) {
    store.push(update).await;
}

async fn handler_error(store: Ref<UpdateStore>, update: Update) -> HandlerResult {
    store.push(update).await;
    Err(HandlerError::new(ErrorMock))
}

#[derive(Debug)]
struct ErrorMock;

impl Error for ErrorMock {}

impl fmt::Display for ErrorMock {
    fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
        write!(out, "Test error")
    }
}

fn create_update() -> Update {
    serde_json::from_value(serde_json::json!({
        "update_id": 1,
        "message": {
            "message_id": 1111,
            "date": 0,
            "from": {"id": 1, "is_bot": false, "first_name": "test"},
            "chat": {"id": 1, "type": "private", "first_name": "test"},
            "text": "test message from private chat"
        }
    }))
    .unwrap()
}

#[tokio::test]
async fn chain() {
    macro_rules! assert_handle {
        ($strategy:ident, $count:expr, $($handler:expr),*) => {{
            let mut context = Context::default();
            context.insert(UpdateStore::new());
            let context = Arc::new(context);
            let mut chain = Chain::$strategy();
            $(chain = chain.with($handler);)*
            let update = create_update();
            let input = HandlerInput {
                context: context.clone(),
                update
            };
            let result = chain.handle(input).await;
            let count = context.get::<UpdateStore>().unwrap().count().await;
            assert_eq!(count, $count);
            result
        }};
    }

    let result = assert_handle!(all, 2, handler_ok, handler_error, handler_ok);
    assert!(result.is_err());
    let result = assert_handle!(once, 1, handler_ok, handler_error, handler_ok);
    assert!(matches!(result, Ok(())));

    let result = assert_handle!(all, 1, handler_error, handler_ok);
    assert!(result.is_err());
    let result = assert_handle!(once, 1, handler_error, handler_ok);
    assert!(result.is_err());

    let result = assert_handle!(all, 2, handler_ok, handler_ok);
    assert!(matches!(result, Ok(())));
    let result = assert_handle!(once, 1, handler_ok, handler_ok);
    assert!(matches!(result, Ok(())));
}