use serde_json::{Value, json};
use super::Config;
fn sample() -> Value {
json!({
"listen": "127.0.0.1:8740",
"origin": "https://studio.example",
"files": "/opt/haematite/studio",
"stores": {"wards": "/run/haematite/wards.sock"},
"lys": {
"issuer": "https://lys.example/",
"client_id": "studio",
"secret_file": "/etc/haematite/studio.secret",
"redirect": "https://studio.example/callback"
}
})
}
fn parsed(value: &Value) -> Result<Config, String> {
Config::parse(value.to_string().as_bytes())
}
#[test]
fn a_whole_config_is_taken_with_its_defaults() -> Result<(), String> {
let config = parsed(&sample())?;
let site = config.site();
assert_eq!(site.origin, "https://studio.example");
assert_eq!(site.stores.len(), 1);
assert_eq!(config.limits().max_connections, 64);
Ok(())
}
#[test]
fn each_unsafe_field_is_refused_by_name() -> Result<(), String> {
let cases: [(&str, Value, &str); 9] = [
("/listen", json!("0.0.0.0:8740"), "listen"),
("/origin", json!("http://studio.example"), "origin"),
("/origin", json!("https://studio.example/app"), "origin"),
("/files", json!("studio"), "files"),
("/stores", json!({}), "stores"),
(
"/stores",
json!({"a/b": "/run/haematite/a.sock"}),
"store name",
),
("/stores", json!({"wards": "wards.sock"}), "store socket"),
(
"/lys/redirect",
json!("https://elsewhere.example/callback"),
"redirect",
),
("/lys/secret_file", json!("studio.secret"), "secret_file"),
];
for (pointer, value, named) in cases {
let mut config = sample();
let slot = config
.pointer_mut(pointer)
.ok_or_else(|| format!("the sample has no {pointer}"))?;
*slot = value.clone();
let message = parsed(&config)
.err()
.ok_or_else(|| format!("{pointer} = {value} was taken"))?;
assert!(message.contains(named), "{pointer} = {value}: {message}");
}
Ok(())
}
#[test]
fn an_unknown_field_is_refused() -> Result<(), String> {
let mut config = sample();
config
.as_object_mut()
.ok_or("the sample is not an object")?
.insert("secret".to_owned(), json!("x"));
assert!(parsed(&config).is_err());
Ok(())
}