pub trait CascadePolicy: Sized + Clone {
fn merge(&mut self, layer: &Self);
fn resolve(layers: &[Option<&Self>], default: Self) -> Self {
let mut result = default;
for layer in layers.iter().flatten() {
result.merge(layer);
}
result
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug, Clone, Default, PartialEq, Eq)]
struct TestPolicy {
a: Option<u32>,
b: Option<String>,
}
impl CascadePolicy for TestPolicy {
fn merge(&mut self, layer: &Self) {
if let Some(v) = &layer.a {
self.a = Some(*v);
}
if let Some(v) = &layer.b {
self.b = Some(v.clone());
}
}
}
fn d() -> TestPolicy {
TestPolicy {
a: Some(1),
b: Some("base".into()),
}
}
#[test]
fn resolve_no_layers_returns_default() {
assert_eq!(TestPolicy::resolve(&[], d()), d());
}
#[test]
fn empty_layer_preserves_default() {
let empty = TestPolicy::default();
assert_eq!(TestPolicy::resolve(&[Some(&empty)], d()), d());
}
#[test]
fn single_layer_overrides_only_its_set_field() {
let layer = TestPolicy { a: Some(99), ..Default::default() };
let r = TestPolicy::resolve(&[Some(&layer)], d());
assert_eq!(r.a, Some(99));
assert_eq!(r.b, d().b, "unset field preserved");
}
#[test]
fn innermost_wins_per_field_and_for_same_field() {
let outer = TestPolicy { a: Some(10), ..Default::default() };
let inner = TestPolicy {
a: Some(50),
b: Some("inner".into()),
};
let r = TestPolicy::resolve(&[Some(&outer), Some(&inner)], TestPolicy::default());
assert_eq!(r.a, Some(50), "innermost layer wins the shared field");
assert_eq!(r.b, Some("inner".into()));
}
#[test]
fn none_layer_is_skipped() {
let inner = TestPolicy { a: Some(7), ..Default::default() };
let r = TestPolicy::resolve(&[None, Some(&inner), None], TestPolicy::default());
assert_eq!(r.a, Some(7));
}
#[test]
fn merge_is_idempotent() {
let layer = TestPolicy { a: Some(99), ..Default::default() };
let mut once = d();
let mut twice = d();
once.merge(&layer);
twice.merge(&layer);
twice.merge(&layer);
assert_eq!(once, twice, "re-applying the same layer is a no-op");
}
#[test]
fn resolve_is_deterministic() {
let l = TestPolicy { a: Some(3), ..Default::default() };
let refs = [Some(&l)];
assert_eq!(
TestPolicy::resolve(&refs, d()),
TestPolicy::resolve(&refs, d()),
);
}
#[test]
fn test_policy_obeys_the_cascade_law_harness() {
crate::testing::assert_cascade_laws_with_default(
d(),
&[
TestPolicy { a: Some(10), ..Default::default() },
TestPolicy { b: Some("layer".into()), ..Default::default() },
TestPolicy { a: Some(50), b: Some("both".into()) },
],
);
}
}