rust_rest_test 0.1.1

An executable that can be used to run "unit tests" on a rust api
use colored::Colorize;
use serde_json::Value;

#[derive(Debug, Clone)]
pub enum JsonExpectation {
    Has(Vec<String>),
    Eq(Vec<String>, String),
}

pub fn check_all(json: &Value, expectations: &Vec<JsonExpectation>) -> Result<(), Vec<String>> {
    let all_errors: Vec<String> = expectations
        .iter()
        .map(|t| check(json, t))
        .filter(|t| t.is_err())
        .map(|t| t.err().unwrap())
        .collect();
    if all_errors.len() == 0 {
        Ok(())
    } else {
        Err(all_errors)
    }
}

pub fn check(json: &Value, expectation: &JsonExpectation) -> Result<(), String> {
    match expectation {
        JsonExpectation::Has(path) => check_has(json, path),
        JsonExpectation::Eq(path, val) => check_eq(json, path, val),
    }
}

pub fn check_has(json: &Value, path: &Vec<String>) -> Result<(), String> {
    get_value_for_path(json, path)
        // Map the json result to void otherwise return the same error
        .map(|_| ())
        .map_err(|error_message| {
            format!("Testing: Has {}\n{}", path.join("."), error_message.red())
        })
}

pub fn check_eq(json: &Value, path: &Vec<String>, val: &String) -> Result<(), String> {
    match get_value_for_path(json, path) {
        Ok(json_val) => {
            let err_msg = format!("{}{}", "Invalid json value: ".red(), val.red());
            let json_expected: Value = serde_json::from_str(val.as_str()).expect(err_msg.as_str());
            if !json_expected.eq(&json_val) {
                Err(format!("\tExpected: {}\n\tFound: {}", val, json_val))
            } else {
                Ok(())
            }
        }
        Err(error_message) => Err(error_message),
    }
    .map_err(|error_message| {
        format!(
            "Testing: Eq {} {}\n{}",
            path.join("."),
            val,
            error_message.red()
        )
    })
}

fn get_value_for_path(json: &Value, path: &Vec<String>) -> Result<Value, String> {
    let mut current_json = json;
    for key in path {
        current_json = current_json
            .get(&key)
            .ok_or(format!("\tKey \"{}\" does not exist", key))?;
    }
    Ok(current_json.clone())
}