stubr 0.6.2

Wiremock implemented in Rust
Documentation
use std::{
    collections::hash_map::DefaultHasher,
    fs::{create_dir_all, File},
    hash::{Hash, Hasher},
    path::PathBuf,
    str::FromStr,
};

use http_types::Url;
use log::info;

use crate::{model::JsonStub, server::stub_finder::StubFinder, StubrResult};

pub(crate) struct StubWriter {
    pub(crate) stub: JsonStub,
}

impl StubWriter {
    const RECORDED_TEST_DIR: &'static str = "stubs";

    pub(crate) fn write(&self, host: &str, output: Option<&PathBuf>) -> StubrResult<PathBuf> {
        let output = self.output_and_create(host, output);
        let path = output.join(self.stub_name());
        let file = File::create(&path)?;
        serde_json::to_writer_pretty(&file, &self.stub)?;
        info!("Recorded stub in {:?}", &file);
        Ok(path)
    }

    pub(crate) fn stub_name(&self) -> String {
        let mut hasher = DefaultHasher::new();
        self.stub.hash(&mut hasher);
        format!("{}{}.json", self.base_path().unwrap_or_default(), hasher.finish())
    }

    fn base_path(&self) -> Option<String> {
        self.stub.http_request.as_ref().and_then(|r| {
            r.url
                .url_path
                .as_ref()
                .map(|it| it.strip_prefix('/').unwrap_or(it))
                .map(|it| it.replace('/', "-"))
                .map(|it| format!("{it}-"))
        })
    }

    fn output_and_create(&self, host: &str, output: Option<&PathBuf>) -> PathBuf {
        let output = output
            .map(|it| it.to_path_buf())
            .unwrap_or_else(Self::default_output)
            .join(self.dir_name(host));
        if !output.exists() {
            create_dir_all(&output).unwrap_or_else(|_| panic!("Failed creating recorded stubs output directory at '{:?}'", &output));
        }
        output
    }

    fn dir_name(&self, host: &str) -> String {
        if host == "127.0.0.1" || host == "localhost" {
            String::from("localhost")
        } else if let Ok(url) = Url::from_str(host) {
            let (host, port) = url
                .host_str()
                .filter(|&h| h != "127.0.0.1")
                .map(|h| h.replace(|c: char| !c.is_alphanumeric(), "."))
                .map(|h| {
                    if let Some(p) = url.port() {
                        (h, format!("-{p}"))
                    } else {
                        (h, String::new())
                    }
                })
                .unwrap_or(("localhost".to_string(), String::new()));
            format!("{host}{port}")
        } else {
            String::from("default")
        }
    }

    fn default_output() -> PathBuf {
        StubFinder::output_dir().join(Self::RECORDED_TEST_DIR)
    }
}