apollo-configuration 0.4.0

A typed, friendly configuration system for Apollo products.
Documentation
use std::collections::HashMap;

use apollo_configuration::configuration;
use apollo_configuration::parse_yaml;
use apollo_configuration::types::Duration;
use apollo_configuration::types::Url;

#[configuration]
struct DurationConfig {
    #[config(required)]
    timeout: Duration,
}

#[configuration]
struct HashMapConfig {
    #[config(required)]
    endpoints: HashMap<String, Url>,
}

#[test]
fn hashmap_parses() {
    let config: HashMapConfig = parse_yaml(
        r#"
        endpoints:
          api: "https://api.example.com"
          auth: "https://auth.example.com"
        "#,
        &Default::default(),
    )
    .unwrap();

    assert_eq!(config.endpoints.len(), 2);
    assert_eq!(
        config.endpoints.get("api").unwrap().as_str(),
        "https://api.example.com/"
    );
}

#[test]
fn hashmap_empty_parses() {
    let config: HashMapConfig = parse_yaml("endpoints: {}", &Default::default()).unwrap();
    assert!(config.endpoints.is_empty());
}

#[test]
fn hashmap_value_error_message() {
    let result = parse_yaml::<HashMapConfig>(
        r#"
        endpoints:
          good: "https://example.com"
          bad: "://invalid"
        "#,
        &Default::default(),
    );
    let err = result.expect_err("should fail to parse invalid URL");
    assert_eq!(
        format!("{err}"),
        "failed to parse value: relative URL without a base"
    );
}

#[configuration]
struct NestedHashMapConfig {
    #[config(required)]
    configs: HashMap<String, DurationConfig>,
}

#[test]
fn hashmap_with_nested_config_parses() {
    let config: NestedHashMapConfig = parse_yaml(
        r#"
        configs:
          fast:
            timeout: 1s
          slow:
            timeout: 30s
        "#,
        &Default::default(),
    )
    .unwrap();

    assert_eq!(config.configs.len(), 2);
    assert_eq!(
        *config.configs.get("fast").unwrap().timeout,
        std::time::Duration::from_secs(1)
    );
    assert_eq!(
        *config.configs.get("slow").unwrap().timeout,
        std::time::Duration::from_secs(30)
    );
}