use std::collections::HashMap;
use std::path::PathBuf;
fn fixture_dir() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/testdata/hocon/properties-syntax")
}
fn expected_dir() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/testdata/expected/properties-syntax")
}
fn hocon_to_json(v: &hocon::HoconValue) -> serde_json::Value {
match v {
hocon::HoconValue::Object(map) => serde_json::Value::Object(
map.iter()
.map(|(k, val)| (k.clone(), hocon_to_json(val)))
.collect(),
),
hocon::HoconValue::Array(arr) => {
serde_json::Value::Array(arr.iter().map(hocon_to_json).collect())
}
hocon::HoconValue::Scalar(sv) => serde_json::Value::String(sv.raw.clone()),
other => panic!("unexpected variant: {other:?}"),
}
}
fn key_to_lookup_path(key: &str) -> String {
if key.is_empty()
|| key.contains('.')
|| key.contains('"')
|| key.contains('\\')
|| key.contains(' ')
|| key.contains('\t')
{
let escaped = key.replace('\\', "\\\\").replace('"', "\\\"");
format!("\"{escaped}\"")
} else {
key.to_string()
}
}
fn config_to_json(config: &hocon::Config) -> serde_json::Value {
let mut m = serde_json::Map::new();
for key in config.keys() {
if let Some(val) = config.get(&key_to_lookup_path(key)) {
m.insert(key.to_string(), hocon_to_json(val));
}
}
serde_json::Value::Object(m)
}
fn run_ps_fixture(stem: &str) {
let props_path = fixture_dir().join(format!("{stem}.properties"));
let expected_path = expected_dir().join(format!("{stem}-expected.json"));
let path_str = props_path.to_string_lossy().replace('\\', "/");
let wrapper = format!(r#"include file("{path_str}")"#);
let env: HashMap<String, String> = HashMap::new();
let cfg = hocon::parse_with_env(&wrapper, &env)
.unwrap_or_else(|e| panic!("properties-syntax/{stem}.properties: unexpected error {e:?}"));
let got = config_to_json(&cfg);
let json_src = std::fs::read_to_string(&expected_path)
.unwrap_or_else(|e| panic!("failed to read {}: {}", expected_path.display(), e));
let expected: serde_json::Value = serde_json::from_str(&json_src)
.unwrap_or_else(|e| panic!("invalid JSON in {}: {}", expected_path.display(), e));
assert_eq!(
got,
expected,
"properties-syntax {stem}: mismatch against the Lightbend oracle\n got: {}\n expected: {}",
serde_json::to_string_pretty(&got).unwrap(),
serde_json::to_string_pretty(&expected).unwrap(),
);
}
#[test]
fn ps01_continuation() {
run_ps_fixture("ps01-continuation");
}
#[test]
fn ps02_escapes() {
run_ps_fixture("ps02-escapes");
}
#[test]
fn ps03_separators() {
run_ps_fixture("ps03-separators");
}
#[test]
fn ps04_value_whitespace() {
run_ps_fixture("ps04-value-whitespace");
}
#[test]
fn ps05_astral() {
run_ps_fixture("ps05-astral");
}