allow-policy-legacy 0.1.9

Legacy policy adapters for cargo-allow migrations.
Documentation
use toml::Value;

pub(crate) fn normalize_unsafe_family(kind: &str) -> String {
    match kind.trim() {
        "unsafe-block" | "unsafe block" => "unsafe_block".to_string(),
        "unsafe-fn" | "unsafe function" | "unsafe_fn" => "unsafe_fn".to_string(),
        "unsafe-impl" | "unsafe impl" => "unsafe_impl".to_string(),
        "unsafe-trait" | "unsafe trait" => "unsafe_trait".to_string(),
        "unsafe-extern" | "unsafe extern" | "unsafe-extern-block" | "unsafe extern block" => {
            "unsafe_extern_block".to_string()
        }
        "unsafe-attr" | "unsafe attribute" | "unsafe-attribute" => "unsafe_attr".to_string(),
        other => other.replace('-', "_"),
    }
}

pub(crate) fn has_glob_meta(input: &str) -> bool {
    input
        .chars()
        .any(|ch| matches!(ch, '*' | '?' | '[' | ']' | '{' | '}' | ','))
}

pub(crate) fn normalize_legacy_expires(expires: Option<String>) -> Option<String> {
    expires.map(|value| {
        if value == "permanent" {
            "never".to_string()
        } else {
            value
        }
    })
}

pub(crate) fn is_clippy_exceptions_policy(table: &toml::Table) -> bool {
    matches!(
        table.get("policy").and_then(Value::as_str),
        Some("clippy-exceptions" | "clippy-exception-allowlist" | "clippy-allowlist")
    )
}

pub(crate) fn normalize_lint_attribute_family(family: &str) -> String {
    match family.trim() {
        "allow" | "allow-attribute" | "allow_attribute" => "allow_attribute".to_string(),
        "expect" | "expect-attribute" | "expect_attribute" => "expect_attribute".to_string(),
        other => other.to_string(),
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn normalizes_unsafe_family_aliases_and_fallbacks() {
        let cases = [
            (" unsafe-block ", "unsafe_block"),
            ("unsafe block", "unsafe_block"),
            ("unsafe-fn", "unsafe_fn"),
            ("unsafe function", "unsafe_fn"),
            ("unsafe_fn", "unsafe_fn"),
            ("unsafe-impl", "unsafe_impl"),
            ("unsafe impl", "unsafe_impl"),
            ("unsafe-trait", "unsafe_trait"),
            ("unsafe trait", "unsafe_trait"),
            ("unsafe-extern", "unsafe_extern_block"),
            ("unsafe extern", "unsafe_extern_block"),
            ("unsafe-extern-block", "unsafe_extern_block"),
            ("unsafe extern block", "unsafe_extern_block"),
            ("unsafe-attr", "unsafe_attr"),
            ("unsafe attribute", "unsafe_attr"),
            ("unsafe-attribute", "unsafe_attr"),
            ("custom-family", "custom_family"),
        ];

        for (input, expected) in cases {
            assert_eq!(normalize_unsafe_family(input), expected);
        }
    }

    #[test]
    fn detects_glob_meta_characters() {
        for input in [
            "src/*.rs",
            "src/file?.rs",
            "src/[ab].rs",
            "src/file].rs",
            "src/{lib,main}.rs",
            "src/file}.rs",
            "src/lib.rs,src/main.rs",
        ] {
            assert!(has_glob_meta(input));
        }

        assert!(!has_glob_meta("src/lib.rs"));
        assert!(!has_glob_meta("src/path-with-dashes.rs"));
    }

    #[test]
    fn normalizes_legacy_permanent_expiry_only() {
        assert_eq!(
            normalize_legacy_expires(Some("permanent".to_string())),
            Some("never".to_string())
        );
        assert_eq!(
            normalize_legacy_expires(Some("2026-12-31".to_string())),
            Some("2026-12-31".to_string())
        );
        assert_eq!(normalize_legacy_expires(None), None);
    }

    #[test]
    fn recognizes_clippy_exception_policy_aliases() {
        for policy in [
            "clippy-exceptions",
            "clippy-exception-allowlist",
            "clippy-allowlist",
        ] {
            let mut table = toml::Table::new();
            table.insert("policy".to_string(), Value::String(policy.to_string()));

            assert!(is_clippy_exceptions_policy(&table));
        }

        let mut table = toml::Table::new();
        table.insert("policy".to_string(), Value::String("other".to_string()));
        assert!(!is_clippy_exceptions_policy(&table));
        assert!(!is_clippy_exceptions_policy(&toml::Table::new()));
    }

    #[test]
    fn normalizes_lint_attribute_family_aliases_and_fallbacks() {
        let cases = [
            (" allow ", "allow_attribute"),
            ("allow-attribute", "allow_attribute"),
            ("allow_attribute", "allow_attribute"),
            ("expect", "expect_attribute"),
            ("expect-attribute", "expect_attribute"),
            ("expect_attribute", "expect_attribute"),
            ("custom", "custom"),
        ];

        for (input, expected) in cases {
            assert_eq!(normalize_lint_attribute_family(input), expected);
        }
    }
}