denki 0.1.2

CLI for controlling TP-Link smart home devices — denki (電気) means electricity in Japanese
Documentation
use crate::devices::{self, DeviceKind};

fn guard_kind(kind: &DeviceKind) -> Option<&DeviceKind> {
    match kind {
        DeviceKind::Tapo => None,
        k => Some(k),
    }
}

const GUARDED: &[&str] = &[
    "power",
    "dim",
    "color_temp",
    "color",
    "specs",
    "presets",
    "schedules",
    "led",
    "clock",
];

fn check(kind: &DeviceKind, feature: &str) -> anyhow::Result<()> {
    match feature {
        "power" => devices::can_control_power(kind),
        "dim" => devices::can_dim(kind),
        "color_temp" => devices::can_set_color_temp(kind),
        "color" => devices::can_set_color(kind),
        "specs" => devices::can_get_specs(kind),
        "presets" => devices::can_get_presets(kind),
        "schedules" => devices::can_get_schedules(kind),
        "led" => devices::can_control_led(kind),
        "clock" => devices::can_get_clock(kind),
        "energy" | "outlets" | "effects" => Ok(()),
        other => panic!(
            "devices.toml: unknown feature '{other}' — add it to check() or explain \
             why it has no guard"
        ),
    }
}

#[test]
fn listed_features_are_permitted_by_guards() {
    for dev in devices::all() {
        let Some(kind) = guard_kind(&dev.kind) else {
            continue;
        };
        for feature in &dev.supports {
            let result = check(kind, feature);
            assert!(
                result.is_ok(),
                "devices.toml: {} ({}) lists '{}' but the guard rejects it: {}",
                dev.model,
                dev.kind,
                feature,
                result.unwrap_err(),
            );
        }
    }
}

#[test]
fn unlisted_guarded_features_are_denied() {
    for dev in devices::all() {
        let Some(kind) = guard_kind(&dev.kind) else {
            continue;
        };
        for &feature in GUARDED {
            if dev.supports.iter().any(|f| f == feature) {
                continue;
            }
            let result = check(kind, feature);
            assert!(
                result.is_err(),
                "devices.toml: {} ({}) does NOT list '{}' but the guard permits it — \
                 add it to 'supports' or tighten the guard",
                dev.model,
                dev.kind,
                feature,
            );
        }
    }
}