use crate::{
config::{TestBaseConfiguration, TestEndpoint},
endpoint::Endpoint,
error::RatError,
store::{Store, StoreMap, VariableStore},
};
use regex::{Captures, Regex};
use std::{cell::OnceCell, collections::HashMap};
pub fn endpoint<S: Store>(
store: &S,
test: &TestBaseConfiguration,
endpoint: &TestEndpoint,
) -> Endpoint {
let url = match_and_replace(store, &endpoint.url);
let endpoint = Endpoint::new(&url, &endpoint.method, test.verbose);
endpoint.unwrap()
}
const REGEX: OnceCell<Regex> = OnceCell::new();
const PATTERN: &str = r#"\{\{(([\.]?(\w+[-]?|\[\d+\]))+)\}\}"#;
pub fn match_and_replace<S: Store>(store: &S, hydrate: &str) -> String {
let r = REGEX;
let rgx: &Regex = r.get_or_init(|| Regex::new(PATTERN).expect("pattern is invalid"));
let result = rgx.replace_all(hydrate, |cap: &Captures| {
let key = &cap[1];
log::debug!("{:#?} {}", cap, key);
let value = if let Some(x) = store.fetch_value(key) {
x
} else {
return format!("{{{{{}}}}}", key);
};
value
.as_str()
.map(|f| f.to_string())
.unwrap_or(value.to_string())
});
result.into_owned()
}
pub fn outputs<T: Store>(
store: &T,
outputs_from_config: HashMap<String, String>,
) -> Result<VariableStore, RatError> {
let mut evaluated_outputs = StoreMap::default();
for (key, value) in outputs_from_config.into_iter() {
let value = match_and_replace(store, &value);
evaluated_outputs.insert(key, serde_json::to_value(&value)?);
}
log::info!("{:#?}", evaluated_outputs);
Ok(evaluated_outputs.into())
}
pub fn reponse(response: reqwest::blocking::Response) -> Result<Vec<VariableStore>, RatError> {
let store_response: VariableStore = util::store_from_response(&response)?.into();
let store_response_body = util::store_from_response_body(response)?;
Ok(vec![store_response, store_response_body])
}
mod util {
use crate::{
error::RatError,
store::{StoreMap, VariableStore},
};
pub fn store_from_response(
response: &reqwest::blocking::Response,
) -> Result<StoreMap, RatError> {
let mut store = StoreMap::default();
store.insert(
"r.status".to_string(),
serde_json::to_value(response.status().as_u16()).unwrap(),
);
for (key, value) in response.headers().iter().filter(|(_, v)| !v.is_empty()) {
let key = format!("r.headers.{}", key);
let value = serde_json::to_value(
value
.to_str()
.map_err(|e| RatError::ParsingError(e.to_string()))?,
)?;
for (k, v) in self::parse_v2(key, value) {
store.insert(k, v);
}
}
Ok(store)
}
pub fn store_from_response_body(
response: reqwest::blocking::Response,
) -> Result<VariableStore, RatError> {
let value: serde_json::Value = response.json()?;
let mut store = StoreMap::default();
for v in self::parse_v2(String::from("r.body"), value) {
store.insert(v.0, v.1);
}
Ok(store.into())
}
pub fn parse_v2(key: String, value: serde_json::Value) -> Vec<(String, serde_json::Value)> {
let mut result = Vec::new();
match value {
serde_json::Value::Null => result.push((key, value)),
serde_json::Value::Bool(_) => result.push((key, value)),
serde_json::Value::Number(_) => result.push((key, value)),
serde_json::Value::String(_) => result.push((key, value)),
serde_json::Value::Array(x) => {
for (i, item) in x.into_iter().enumerate() {
let key = format!("{}.[{}]", key, i);
result.append(&mut self::parse_v2(key, item));
}
}
serde_json::Value::Object(x) => {
for (name, field) in x {
let key = format!("{}.{}", key, name);
result.append(&mut self::parse_v2(key, field));
}
}
};
result
}
}