tests/filter_dsl.rs

//! Integration-level tests for the filter DSL: parse, compile, evaluate.

use ripgrab::filter::dsl::{evaluate, parse_and_compile, EvalContext};

fn ctx(pairs: &[(&str, &str)]) -> EvalContext {
    let mut c = EvalContext::new();
    for (k, v) in pairs {
        c.set(k, *v);
    }
    c
}

#[test]
fn full_pipeline_simple() {
    let f = parse_and_compile("status >= 400 and host = \"api\"").unwrap();
    assert!(evaluate(&f, &ctx(&[("status", "503"), ("host", "api")])));
    assert!(!evaluate(&f, &ctx(&[("status", "200"), ("host", "api")])));
    assert!(!evaluate(&f, &ctx(&[("status", "503"), ("host", "web")])));
}

#[test]
fn regex_escape_handling() {
    let f = parse_and_compile(r#"body ~ /failed\s+to/"#).unwrap();
    assert!(evaluate(&f, &ctx(&[("body", "failed  to connect")])));
    assert!(!evaluate(&f, &ctx(&[("body", "failedto connect")])));
}

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

#[test]
fn precedence_with_or_and_not() {
    let f = parse_and_compile(
        "not status = 200 or (host = \"api\" and status >= 500)",
    )
    .unwrap();
    assert!(evaluate(&f, &ctx(&[("status", "404"), ("host", "web")])));
    assert!(evaluate(&f, &ctx(&[("status", "503"), ("host", "api")])));
    assert!(!evaluate(&f, &ctx(&[("status", "200"), ("host", "web")])));
}

#[test]
fn integer_coercion_failures_are_falsy() {
    let f = parse_and_compile("status >= 400").unwrap();
    assert!(!evaluate(&f, &ctx(&[("status", "not-a-number")])));
}

#[test]
fn regex_on_integer_is_type_mismatch() {
    let err = parse_and_compile("status ~ 1").unwrap_err();
    assert!(err.to_string().contains("integer"));
}

#[test]
fn empty_context_only_satisfies_negatives() {
    let f = parse_and_compile("not status = 200").unwrap();
    assert!(evaluate(&f, &ctx(&[])));
}

#[test]
fn multiple_fields_all_required() {
    let f = parse_and_compile(
        "host = \"api\" and route ~ /orders/ and status = 200",
    )
    .unwrap();
    assert!(evaluate(
        &f,
        &ctx(&[("host", "api"), ("route", "/orders/123"), ("status", "200")]),
    ));
}