catalyst 0.2.9

A lightweight API testing tool
Documentation
use crate::models::test::{JsonAssertion, Test};
use serde_json::Value;
use std::collections::HashMap;

pub struct Result {
    pub ok: bool,
    pub status: (u16, u16),
    pub time_ms: u64,
    pub errors: Vec<String>,
}

pub fn check(
    test: &Test,
    status: u16,
    body: &Value,
    time_ms: u64,
    vars: &HashMap<String, String>,
) -> Result {
    let mut errors = Vec::new();

    if status != test.expected_status {
        errors.push(format!(
            "Status {status}, expected {}",
            test.expected_status
        ));
    }

    if let Some(max) = test.max_response_time && time_ms > max {
        errors.push(format!("Time {time_ms}ms > {max}ms"));
    }

    if let Some(expected) = &test.expected_body
        && !super::assertions::body_matches(
            &super::variables::replace_variables_in_json(expected, vars),
            body,
        ) {
        errors.push("Body mismatch".into());
    }

    if let Some(assertions) = &test.assertions {
        for assertion in assertions {
            if !super::assertions::validate_assertion(&process_assertion(assertion, vars), body) {
                errors.push(format!("Failed: {assertion:?}"));
            }
        }
    }

    Result {
        ok: errors.is_empty(),
        status: (test.expected_status, status),
        time_ms,
        errors,
    }
}

fn process_assertion(assertion: &JsonAssertion, vars: &HashMap<String, String>) -> JsonAssertion {
    match assertion {
        JsonAssertion::Exact(v) | JsonAssertion::Contains(v) => {
            let processed = super::variables::replace_variables_in_json(v, vars);
            if matches!(assertion, JsonAssertion::Exact(_)) {
                JsonAssertion::Exact(processed)
            } else {
                JsonAssertion::Contains(processed)
            }
        }
        JsonAssertion::Regex(p) => JsonAssertion::Regex(replace_vars(p, vars)),
        JsonAssertion::PathRegex(path, pattern) => {
            JsonAssertion::PathRegex(replace_vars(path, vars), replace_vars(pattern, vars))
        }
    }
}

fn replace_vars(s: &str, vars: &HashMap<String, String>) -> String {
    let mut result = s.to_string();
    for (k, v) in vars {
        result = result.replace(&format!("{{{{{k}}}}}"), v);
    }
    result
}