hitman 0.12.1

A command line tool for hitting API endpoints
Documentation
use anyhow::bail;
use toml::{Table, Value};

#[derive(Clone)]
pub struct Scope(Table);

#[derive(Debug, Clone, PartialEq)]
pub enum Replacement {
    Value(String),

    ValueNotFound {
        key: String,
    },

    MultipleValuesFound {
        key: String,
        values: Vec<toml::Value>,
    },
}

impl From<Table> for Scope {
    fn from(env: Table) -> Self {
        Self(env)
    }
}

impl Scope {
    pub fn lookup(&self, key: &str) -> anyhow::Result<Replacement> {
        let rep = match self.0.get(key) {
            None => Replacement::ValueNotFound { key: key.into() },
            Some(Value::String(v)) => Replacement::Value(v.clone()),
            Some(Value::Integer(v)) => Replacement::Value(v.to_string()),
            Some(Value::Float(v)) => Replacement::Value(v.to_string()),
            Some(Value::Boolean(v)) => Replacement::Value(v.to_string()),
            Some(Value::Array(arr)) => Replacement::MultipleValuesFound {
                key: key.into(),
                values: arr.clone(),
            },
            Some(_) => bail!("Type not supported"),
        };

        Ok(rep)
    }

    pub fn extract(&self) -> Option<&Value> {
        self.0.get("_extract")
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    fn create_env() -> Scope {
        toml::from_str::<Table>(
            r#"
            url = "example.com"
            token = "abc123"
            integer = 42
            float = 99.99
            boolean = true
            api_url1 = "foo.com"

            nested = "the answer is {{integer}}"
            multiple = ["a", "b", "c"]
            "#,
        )
        .unwrap()
        .into()
    }

    #[test]
    fn finds_variable() {
        let rep = create_env();
        let res = rep.lookup("url").unwrap();

        assert_eq!(res, Replacement::Value("example.com".into()));
    }

    #[test]
    fn finds_integer() {
        let rep = create_env();
        let res = rep.lookup("integer").unwrap();

        assert_eq!(res, Replacement::Value("42".into()));
    }

    #[test]
    fn finds_float() {
        let rep = create_env();
        let res = rep.lookup("float").unwrap();

        assert_eq!(res, Replacement::Value("99.99".into()));
    }

    #[test]
    fn finds_boolean() {
        let rep = create_env();
        let res = rep.lookup("boolean").unwrap();

        assert_eq!(res, Replacement::Value("true".into()));
    }

    #[test]
    fn fails_for_multiple() {
        let rep = create_env();
        let res = rep.lookup("multiple").unwrap();

        assert_eq!(
            res,
            Replacement::MultipleValuesFound {
                key: "multiple".into(),
                values: vec!["a".into(), "b".into(), "c".into()]
            }
        );
    }

    #[test]
    fn fails_for_missing() {
        let rep = create_env();
        let res = rep.lookup("missing").unwrap();

        assert_eq!(
            res,
            Replacement::ValueNotFound {
                key: "missing".into()
            }
        );
    }
}