use std::collections::BTreeMap;
use camel_dsl::env_interpolation::interpolate_env_with;
use super::{SUPPORTED_REGISTRY_KINDS, TestDocError, TestDocument};
fn interpolate_identifier(
value: &str,
position: &str,
lookup: &dyn Fn(&str) -> Option<String>,
) -> Result<String, TestDocError> {
interpolate_env_with(value, lookup).map_err(|var| TestDocError::EnvUnresolved {
var,
field: position.to_string(),
})
}
fn rebuild_identifier_map<V>(
map: BTreeMap<String, V>,
position: &str,
collision: impl Fn(&str) -> TestDocError,
lookup: &dyn Fn(&str) -> Option<String>,
) -> Result<BTreeMap<String, V>, TestDocError> {
let mut rebuilt = BTreeMap::new();
for (key, value) in map {
let resolved = interpolate_identifier(&key, position, lookup)?;
if rebuilt.contains_key(&resolved) {
return Err(collision(&resolved));
}
rebuilt.insert(resolved, value);
}
Ok(rebuilt)
}
pub(super) fn interpolate_identifier_fields(doc: &mut TestDocument) -> Result<(), TestDocError> {
let env = doc.env.clone();
let lookup = &|name: &str| env.get(name).cloned();
if let Some(repos) = doc.repositories.as_mut() {
for (kind, map) in [
(SUPPORTED_REGISTRY_KINDS[0], &mut repos.cache),
(SUPPORTED_REGISTRY_KINDS[1], &mut repos.idempotent),
(SUPPORTED_REGISTRY_KINDS[2], &mut repos.claim_check),
] {
if let Some(map) = map.as_mut() {
*map = rebuild_identifier_map(
std::mem::take(map),
&format!("repositories.{kind}"),
|resolved| {
TestDocError::InvalidRepositories(format!(
"repositories.{kind}: duplicate repository name \
`{resolved}` after interpolation"
))
},
lookup,
)?;
}
}
}
if let Some(beans) = doc.beans.as_mut() {
*beans = rebuild_identifier_map(
std::mem::take(beans),
"beans",
|resolved| {
TestDocError::InvalidBeans(format!(
"beans: duplicate bean name `{resolved}` after interpolation"
))
},
lookup,
)?;
}
if let Some(intercepts) = doc.intercepts.as_mut() {
let taken = std::mem::take(intercepts);
*intercepts = rebuild_identifier_map(
taken,
"intercepts",
|resolved| {
TestDocError::InterceptInvalid(format!(
"intercepts: duplicate source `{resolved}` after interpolation"
))
},
lookup,
)?;
for action in intercepts.values_mut() {
if let Some(target) = action.skip_to.as_mut() {
*target = interpolate_identifier(target, "intercepts.skipTo", lookup)?;
}
if let Some(target) = action.divert_copy_to.as_mut() {
*target = interpolate_identifier(target, "intercepts.divertCopyTo", lookup)?;
}
}
}
doc.expects = rebuild_identifier_map(
std::mem::take(&mut doc.expects),
"expects",
|resolved| {
TestDocError::Yaml(format!(
"duplicate expectation endpoint `{resolved}` after interpolation"
))
},
lookup,
)?;
if let Some(sequence) = doc.sequence.as_mut() {
for (index, entry) in sequence.iter_mut().enumerate() {
*entry = interpolate_identifier(entry, &format!("sequence[{index}]"), lookup)?;
}
}
for (index, input) in doc.inputs.iter_mut().enumerate() {
input.to = interpolate_identifier(&input.to, &format!("inputs[{index}].to"), lookup)?;
}
Ok(())
}