src/filter/dsl/parser/lexer_test.rs

#[cfg(test)]
mod tests {
    use crate::filter::dsl::parser::lexer::{tokenize, Token};

    fn tokens(input: &str) -> Vec<Token> {
        tokenize(input).unwrap().into_iter().map(|s| s.token).collect()
    }

    #[test]
    fn splits_simple_comparison() {
        let got = tokens("status >= 400");
        assert_eq!(
            got,
            vec![Token::Ident("status".into()), Token::Ge, Token::Int(400)],
        );
    }

    #[test]
    fn recognizes_boolean_keywords() {
        let got = tokens("a and b or not c");
        assert_eq!(
            got,
            vec![
                Token::Ident("a".into()),
                Token::And,
                Token::Ident("b".into()),
                Token::Or,
                Token::Not,
                Token::Ident("c".into()),
            ],
        );
    }

    #[test]
    fn parses_string_literal_with_escape() {
        let got = tokens(r#"host = "api\"prod""#);
        assert_eq!(
            got,
            vec![
                Token::Ident("host".into()),
                Token::Eq,
                Token::Str("api\"prod".into()),
            ],
        );
    }

    #[test]
    fn parses_regex_literal() {
        let got = tokens("body ~ /oops\\d+/");
        assert_eq!(
            got,
            vec![
                Token::Ident("body".into()),
                Token::Tilde,
                Token::Regex("oops\\d+".into()),
            ],
        );
    }

    #[test]
    fn rejects_unterminated_string() {
        let err = tokenize("host = \"api").unwrap_err();
        assert!(err.to_string().contains("unterminated"));
    }

    #[test]
    fn rejects_unterminated_regex() {
        let err = tokenize("body ~ /abc").unwrap_err();
        assert!(err.to_string().contains("unterminated"));
    }

    #[test]
    fn rejects_bare_minus() {
        assert!(tokenize("status = -").is_err());
    }

    #[test]
    fn accepts_negative_integer() {
        let got = tokens("offset = -15");
        assert_eq!(
            got,
            vec![Token::Ident("offset".into()), Token::Eq, Token::Int(-15)],
        );
    }
}