// Copyright 2023 Salesforce, Inc. All rights reserved.
use crate::{model::request::simple_request_content_type::ContentMatcher, HeaderValue};

///
/// Defines the allowed methods for a request to be considered a Simple CORS Request.
/// These methods can be: GET, HEAD, POST.
///
/// Envoy processes the method in the HTTP/2 :method header, ensuring that the extracted value
/// is in lowercase.
const ALLOWED_METHODS: [&str; 3] = ["get", "head", "post"];

#[derive(Default)]
pub struct AllowedMethods {}

impl ContentMatcher for AllowedMethods {
    fn matches(&self, value: &HeaderValue) -> bool {
        ALLOWED_METHODS
            .iter()
            .any(|allowed| allowed.eq_ignore_ascii_case(value))
    }
}

#[cfg(test)]
mod allowed_methods_tests {
    use super::AllowedMethods;
    use crate::model::request::simple_request_content_type::ContentMatcher;

    #[test]
    fn allowed_method_lowercase_matches() {
        let allowed_methods = AllowedMethods::default();

        assert!(allowed_methods.matches("get"));
        assert!(allowed_methods.matches("head"));
        assert!(allowed_methods.matches("post"));
    }

    #[test]
    fn allowed_method_uppercase_matches() {
        let allowed_methods = AllowedMethods::default();

        assert!(allowed_methods.matches("GET"));
        assert!(allowed_methods.matches("HEAD"));
        assert!(allowed_methods.matches("POST"));
    }

    #[test]
    fn allowed_method_mixed_case_matches() {
        let allowed_methods = AllowedMethods::default();

        assert!(allowed_methods.matches("GeT"));
        assert!(allowed_methods.matches("HeAd"));
        assert!(allowed_methods.matches("pOst"));
    }

    #[test]
    fn not_allowed_method_does_not_match() {
        let allowed_methods = AllowedMethods::default();

        assert!(
            !allowed_methods.matches("options"),
            "OPTIONS is not an Allowed Method"
        );
        assert!(
            !allowed_methods.matches("DELETE"),
            "DELETE is not an Allowed Method"
        );
        assert!(
            !allowed_methods.matches("DELETE"),
            "DELETE is not an Allowed Method"
        );
    }
}
