extern crate reqwest;
#[macro_use]
extern crate serde_json;

use reqwest::{Client, Response, StatusCode};

mod common;

fn assert_method_not_allowed_response(mut actual_response: Response) {
    let expected_response_json = json!({
        "error": {
            "status_code": 405,
            "message": "Specified method is invalid for this resource",
        },
    });
    assert_eq!(actual_response.status(), StatusCode::MethodNotAllowed);
    let actual_response_json: serde_json::Value = actual_response.json().unwrap();
    assert_eq!(actual_response_json, expected_response_json);
}

#[test]
fn test_calling_get_on_missing_api_endpoint_returns_404() {
    let api_base_uri = common::api_base_url();
    let test_client = Client::new();

    let missing_api_url = api_base_uri.join("/api/missing/resource").unwrap();

    let expected_response_json = json!({
        "error": {
            "status_code": 404,
            "message": "Resource not found.",
            "resource": "/api/missing/resource",
        }
    });

    let mut actual_response = test_client.get(missing_api_url).send().unwrap();

    assert_eq!(actual_response.status(), StatusCode::NotFound);
    let actual_response_json: serde_json::Value = actual_response.json().unwrap();
    assert_eq!(actual_response_json, expected_response_json);
}

#[test]
fn test_calling_post_on_missing_api_endpoint_returns_405() {
    let api_base_uri = common::api_base_url();
    let test_client = Client::new();

    let missing_api_url = api_base_uri.join("/api/missing/resource").unwrap();
    let missing_data = json!({"invalid": "data"});

    let actual_response = test_client
        .post(missing_api_url)
        .json(&missing_data)
        .send()
        .unwrap();
    assert_method_not_allowed_response(actual_response);
}

#[test]
fn test_calling_put_on_missing_api_endpoint_returns_405() {
    let api_base_uri = common::api_base_url();
    let test_client = Client::new();

    let missing_api_url = api_base_uri.join("/api/missing/resource").unwrap();
    let missing_data = json!({"invalid": "data"});

    let actual_response = test_client
        .put(missing_api_url)
        .json(&missing_data)
        .send()
        .unwrap();
    assert_method_not_allowed_response(actual_response);
}

#[test]
fn test_calling_delete_on_missing_api_endpoint_returns_405() {
    let api_base_uri = common::api_base_url();
    let test_client = Client::new();

    let missing_api_url = api_base_uri.join("/api/missing/resource").unwrap();

    let actual_response = test_client.delete(missing_api_url).send().unwrap();
    assert_method_not_allowed_response(actual_response);
}
