use std::collections::HashMap;
pub type StoreMap = HashMap<String, serde_json::Value>;
pub trait Store {
fn fetch_value(&self, key: &str) -> Option<&serde_json::Value>;
}
impl<T: Store> Store for Vec<T> {
fn fetch_value(&self, key: &str) -> Option<&serde_json::Value> {
for s in self.iter() {
let value = s.fetch_value(key);
if value.is_some() {
return value;
}
}
None
}
}
impl<T: Store> Store for [T] {
fn fetch_value(&self, key: &str) -> Option<&serde_json::Value> {
for s in self {
let value = s.fetch_value(key);
if value.is_some() {
return value;
}
}
None
}
}
impl<T: Store> Store for &[T] {
fn fetch_value(&self, key: &str) -> Option<&serde_json::Value> {
for s in self.iter() {
let value = s.fetch_value(key);
if value.is_some() {
return value;
}
}
None
}
}
#[derive(Debug)]
pub struct VariableStore {
map: StoreMap,
}
impl Default for VariableStore {
fn default() -> Self {
Self {
map: Default::default(),
}
}
}
impl Store for VariableStore {
fn fetch_value(&self, key: &str) -> Option<&serde_json::Value> {
self.map.get(key)
}
}
impl VariableStore {
pub fn from_map(map: StoreMap) -> Self {
Self { map }
}
}
impl From<StoreMap> for VariableStore {
fn from(value: StoreMap) -> Self {
VariableStore::from_map(value)
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::factory;
pub fn parse(value: &str) -> serde_json::Value {
match serde_json::from_str(value) {
Ok(v) => v,
Err(_) => serde_json::to_value(value).unwrap_or(serde_json::Value::Null),
}
}
pub fn equal<T: Store>(store: &T, key: &str, value: &str) -> bool {
let variable = match store.fetch_value(key) {
Some(v) => v,
None => return false,
};
let value: serde_json::Value = serde_json::from_str(value).unwrap();
variable == &value
}
#[test]
fn variable_replacement_works() {
let mut map = StoreMap::new();
map.insert("key".to_string(), self::parse("value"));
map.insert("number".to_string(), self::parse("123"));
map.insert("bool".to_string(), self::parse("false"));
let store = VariableStore::from_map(map);
let hydrated = factory::match_and_replace(&store, "{{key}}");
assert_eq!(hydrated, "value");
let hydrated = factory::match_and_replace(&store, "{{bool}} == {{number}}");
assert_eq!(hydrated, "false == 123");
}
#[test]
fn json_variable_replacement_works() {
let mut map = StoreMap::new();
map.insert("header.status".to_string(), self::parse("200"));
map.insert(
"r.headers.content-type".to_string(),
self::parse("application/json"),
);
let store = VariableStore::from_map(map);
let hydrated = factory::match_and_replace(&store, "{{r.headers.content-type}}");
assert_eq!(hydrated, "application/json");
let hydrated = factory::match_and_replace(&store, "{{header.status}} == 200");
assert_eq!(hydrated, "200 == 200");
}
#[test]
fn json_array_variable_replacement_works() {
let mut map = StoreMap::new();
map.insert("r.body.[0].title".to_string(), self::parse("hello world"));
let store = VariableStore::from_map(map);
let hydrated =
factory::match_and_replace(&store, "\"{{r.body.[0].title}}\" == \"hello world\"");
assert_eq!(hydrated, "\"hello world\" == \"hello world\"");
}
}