apollo-configuration 0.4.0

A typed, friendly configuration system for Apollo products.
Documentation
use apollo_configuration::configuration;
use apollo_configuration::parse_yaml;
use apollo_configuration::types::{IpAddr, Ipv4Addr, Ipv6Addr};
use serde::{Deserialize, Serialize};

#[configuration]
struct IpConfig {
    #[config(required)]
    address: IpAddr,
    #[config(required)]
    v4_address: Ipv4Addr,
    #[config(required)]
    v6_address: Ipv6Addr,
}

#[test]
fn ip_addresses_parse() {
    let config: IpConfig = parse_yaml(
        r#"
        address: 192.168.1.1
        v4_address: 10.0.0.1
        v6_address: "2001:db8::1"
        "#,
        &Default::default(),
    )
    .unwrap();

    assert_eq!(
        *config.address,
        std::net::IpAddr::V4(std::net::Ipv4Addr::new(192, 168, 1, 1))
    );
    assert_eq!(*config.v4_address, std::net::Ipv4Addr::new(10, 0, 0, 1));
    assert_eq!(
        *config.v6_address,
        "2001:db8::1".parse::<std::net::Ipv6Addr>().unwrap()
    );
}

#[test]
fn ip_address_error_message() {
    let result = parse_yaml::<IpConfig>(
        r#"
        address: not-an-ip
        v4_address: 10.0.0.1
        v6_address: "::1"
        "#,
        &Default::default(),
    );
    let err = result.expect_err("should fail to parse invalid IP");
    assert_eq!(
        format!("{err}"),
        "failed to parse value: invalid IP address syntax"
    );
}

#[derive(Debug, Deserialize, Serialize)]
struct SerializableIpConfig {
    ip: IpAddr,
    ipv4: Ipv4Addr,
    ipv6: Ipv6Addr,
}

#[test]
fn ip_addr_serializes() {
    let config: SerializableIpConfig = serde_yaml::from_str(
        r#"
        ip: 192.168.1.1
        ipv4: 10.0.0.1
        ipv6: "2001:db8::1"
        "#,
    )
    .unwrap();
    let yaml = serde_yaml::to_string(&config).unwrap();
    insta::assert_snapshot!(yaml, @r"
    ip: 192.168.1.1
    ipv4: 10.0.0.1
    ipv6: 2001:db8::1
    ");
}