kxio 3.1.0

Provides injectable Filesystem and Network resources to make code more testable
Documentation
use std::collections::HashMap;

use http::StatusCode;
//
use kxio::net::{Error, MockNet, Net};

use assert2::let_assert;

#[tokio::test]
async fn test_get_url() {
    //given
    let mock_net = kxio::net::mock();

    let url = "https://www.example.com";

    mock_net
        .on()
        .get(url)
        .respond(StatusCode::OK)
        .header("foo", "bar")
        .headers(HashMap::new())
        .body("Get OK")
        .expect("mock");

    //when
    let response = Net::from(mock_net).get(url).send().await.expect("response");

    //then
    assert_eq!(response.status(), http::StatusCode::OK);
    assert_eq!(response.bytes().await.expect("response body"), "Get OK");
}

#[tokio::test]
async fn test_post_url() {
    //given
    let net = kxio::net::mock();
    let client = net.client();

    let url = "https://www.example.com";

    net.on()
        .post(url)
        .respond(StatusCode::OK)
        .body("post OK")
        .expect("mock");

    //when
    let response = Net::from(net)
        .send(client.post(url))
        .await
        .expect("reponse");

    //then
    assert_eq!(response.status(), http::StatusCode::OK);
    assert_eq!(response.bytes().await.expect("response body"), "post OK");
}

#[tokio::test]
async fn test_put_url() {
    //given
    let net = kxio::net::mock();
    let client = net.client();

    let url = "https://www.example.com";

    net.on()
        .put(url)
        .respond(StatusCode::OK)
        .body("put OK")
        .expect("mock");

    //when
    let response = Net::from(net).send(client.put(url)).await.expect("reponse");

    //then
    assert_eq!(response.status(), http::StatusCode::OK);
    assert_eq!(response.bytes().await.expect("response body"), "put OK");
}

#[tokio::test]
async fn test_delete_url() {
    //given
    let net = kxio::net::mock();
    let client = net.client();

    let url = "https://www.example.com";

    net.on()
        .delete(url)
        .respond(StatusCode::OK)
        .body("delete OK")
        .expect("mock");

    //when
    let response = Net::from(net)
        .send(client.delete(url))
        .await
        .expect("reponse");

    //then
    assert_eq!(response.status(), http::StatusCode::OK);
    assert_eq!(response.bytes().await.expect("response body"), "delete OK");
}

#[tokio::test]
async fn test_head_url() {
    //given
    let net = kxio::net::mock();
    let client = net.client();

    let url = "https://www.example.com";

    net.on()
        .head(url)
        .respond(StatusCode::OK)
        .body("head OK")
        .expect("mock");

    //when
    let response = Net::from(net)
        .send(client.head(url))
        .await
        .expect("reponse");

    //then
    assert_eq!(response.status(), http::StatusCode::OK);
    assert_eq!(response.bytes().await.expect("response body"), "head OK");
}

#[tokio::test]
async fn test_patch_url() {
    //given
    let net = kxio::net::mock();
    let client = net.client();

    let url = "https://www.example.com";

    net.on()
        .patch(url)
        .respond(StatusCode::OK)
        .body("patch OK")
        .expect("mock");

    //when
    let response = Net::from(net)
        .send(client.patch(url))
        .await
        .expect("reponse");

    //then
    assert_eq!(response.status(), http::StatusCode::OK);
    assert_eq!(response.bytes().await.expect("response body"), "patch OK");
}

#[tokio::test]
async fn test_get_wrong_url() {
    //given
    let net = kxio::net::mock();
    let client = net.client();

    let url = "https://www.example.com";

    net.on()
        .get(url)
        .respond(StatusCode::OK)
        .body("Get OK")
        .expect("mock");

    let net = Net::from(net);

    //when
    let_assert!(
        Err(Error::UnexpectedMockRequest(invalid_request)) =
            net.send(client.get("https://some.other.url/")).await
    );

    //then
    assert_eq!(invalid_request.url().to_string(), "https://some.other.url/");

    // remove pending unmatched request - we never meant to match against it
    let mock_net = MockNet::try_from(net).await.expect("recover net");
    mock_net.reset();
}

#[tokio::test]
async fn test_post_by_method() {
    //given
    let net = kxio::net::mock();
    let client = net.client();

    // NOTE: No URL specified - so should match any URL
    net.on().respond(StatusCode::OK).body("").expect("mock");

    //when
    let response = Net::from(net)
        .send(client.post("https://some.other.url"))
        .await
        .expect("response");

    //then
    assert_eq!(response.status(), http::StatusCode::OK);
    assert_eq!(response.bytes().await.expect("response body"), "");
}

#[tokio::test]
async fn test_post_by_body() {
    //given
    let net = kxio::net::mock();
    let client = net.client();

    // No URL - so any POST with a matching body
    net.on()
        .body("match on body")
        .respond(StatusCode::OK)
        .body("response body")
        .expect("mock");

    //when
    let response = Net::from(net)
        .send(client.post("https://some.other.url").body("match on body"))
        .await
        .expect("response");

    //then
    assert_eq!(response.status(), http::StatusCode::OK);
    assert_eq!(
        response.bytes().await.expect("response body"),
        "response body"
    );
}

#[tokio::test]
async fn test_post_by_header() {
    //given
    let net = kxio::net::mock();
    let client = net.client();

    net.on()
        .header("test", "match")
        .respond(StatusCode::OK)
        .body("response body")
        .expect("mock");

    //when
    let response = Net::from(net)
        .send(
            client
                .post("https://some.other.url")
                .body("nay body")
                .header("test", "match"),
        )
        .await
        .expect("response");

    //then
    assert_eq!(response.status(), http::StatusCode::OK);
    assert_eq!(
        response.bytes().await.expect("response body"),
        "response body"
    );
}

#[tokio::test]
async fn test_post_by_header_wrong_value() {
    //given
    let mock_net = kxio::net::mock();
    let client = mock_net.client();

    mock_net
        .on()
        .header("test", "match")
        .respond(StatusCode::OK)
        .body("response body")
        .expect("mock");
    let net = Net::from(mock_net);

    //when
    let response = net
        .send(
            client
                .post("https://some.other.url")
                .body("nay body")
                .header("test", "no match"),
        )
        .await;

    //then
    let_assert!(Err(kxio::net::Error::UnexpectedMockRequest(_)) = response);

    MockNet::try_from(net).await.expect("recover mock").reset();
}

#[tokio::test]
#[should_panic]
async fn test_unused_post_as_net() {
    //given
    let mock_net = kxio::net::mock();

    let url = "https://www.example.com";

    mock_net
        .on()
        .post(url)
        .respond(StatusCode::OK)
        .body("Post OK")
        .expect("mock");

    let _net = Net::from(mock_net);

    //when
    // don't send the planned request
    // let _response = Net::from(net).send(client.post(url)).await.expect("send");

    //then
    // Drop implementation for net should panic
}

#[tokio::test]
#[should_panic]
async fn test_unused_post_as_mocknet() {
    //given
    let mock_net = kxio::net::mock();

    let url = "https://www.example.com";

    mock_net
        .on()
        .post(url)
        .respond(StatusCode::OK)
        .body("Post OK")
        .expect("mock");

    //when
    // don't send the planned request
    // let _response = Net::from(net).send(client.post(url)).await.expect("send");

    //then
    // Drop implementation for mock_net should panic
}