configbuilder-pattern-loader 0.1.0

configbuilder-pattern: loader domain, trait contract + tech-agnostic reference implementation.
Documentation
//! Integration tests for `DefaultLoader` against a real `LoaderOps` test double,
//! exercising the `toml`/`serde` dependencies through the public API.

use configbuilder_pattern_loader::{
    ConfigError, DefaultLoader, FeatureRecord, Loader, LoaderOps, RawFeature,
};

struct StaticLoaderOps {
    raw: toml::Value,
}

impl LoaderOps for StaticLoaderOps {
    fn load_section_value(&self, key: &str) -> Result<toml::Value, ConfigError> {
        Ok(self
            .raw
            .get(key)
            .cloned()
            .unwrap_or(toml::Value::Table(Default::default())))
    }

    fn validate_dirs(&self) -> Result<(), ConfigError> {
        Ok(())
    }

    fn load_feature_raw(&self, key: &str) -> Result<RawFeature, ConfigError> {
        Ok(RawFeature {
            value: self.raw.get(key).cloned(),
            record: Box::new(FeatureRecord {
                section_name: key.to_owned(),
                enabled: self.raw.get(key).is_some(),
                override_source: None,
                requires: &[],
                metadata: Box::default(),
            }),
        })
    }
}

#[derive(Debug, Default, serde::Deserialize, PartialEq)]
#[serde(default)]
struct DemoSection {
    value: String,
}

fn must<T, E>(result: Result<T, E>) -> T {
    result.unwrap_or_else(|_| std::process::abort())
}

/// @covers: load_section
#[test]
fn test_load_section_deserializes_real_toml_via_public_api() {
    let loader = DefaultLoader {
        ops: Box::new(StaticLoaderOps {
            raw: must(toml::from_str("[demo]\nvalue = \"ok\"")),
        }),
    };
    let section: DemoSection = must(loader.load_section("demo"));
    assert_eq!(section.value, "ok");
}

/// @covers: load_section
#[test]
fn test_load_section_returns_default_when_absent() {
    let loader = DefaultLoader {
        ops: Box::new(StaticLoaderOps {
            raw: toml::Value::Table(Default::default()),
        }),
    };
    let section: DemoSection = must(loader.load_section("missing"));
    assert_eq!(section, DemoSection::default());
}