deslop 0.2.0

A static analyzer that spots low-context and AI-assisted code patterns across naming, concurrency, security, performance, and test quality.
Documentation
use super::FixtureWorkspace;

#[test]
fn test_missing_ctx_http() {
    let workspace = FixtureWorkspace::new();
    workspace.write_file("http.go", go_fixture!("missing_context.txt"));

    let report = workspace.scan();

    assert!(
        report
            .findings
            .iter()
            .any(|finding| finding.rule_id == "missing_context")
    );
}

#[test]
fn test_ctx_http() {
    let workspace = FixtureWorkspace::new();
    workspace.write_file("http.go", go_fixture!("context_aware_http.txt"));

    let report = workspace.scan();

    assert!(
        !report
            .findings
            .iter()
            .any(|finding| finding.rule_id == "missing_context")
    );
}

#[test]
fn test_missing_cancel() {
    let workspace = FixtureWorkspace::new();
    workspace.write_file("cancel.go", go_fixture!("context_cancel_slop.txt"));

    let report = workspace.scan();

    assert!(report.findings.iter().any(|finding| {
        finding.rule_id == "missing_cancel_call" && finding.function_name.as_deref() == Some("Run")
    }));
}

#[test]
fn test_ctx_cancel() {
    let workspace = FixtureWorkspace::new();
    workspace.write_file("cancel.go", go_fixture!("context_cancel_clean.txt"));

    let report = workspace.scan();

    assert!(
        !report
            .findings
            .iter()
            .any(|finding| finding.rule_id == "missing_cancel_call")
    );
}

#[test]
fn test_sleep_loops() {
    let workspace = FixtureWorkspace::new();
    workspace.write_file("poll.go", go_fixture!("sleep_polling.txt"));

    let report = workspace.scan();

    assert!(
        report
            .findings
            .iter()
            .any(|finding| finding.rule_id == "sleep_polling")
    );
}

#[test]
fn test_sleep_ok() {
    let workspace = FixtureWorkspace::new();
    workspace.write_file("poll.go", go_fixture!("sleep_clean.txt"));

    let report = workspace.scan();

    assert!(
        !report
            .findings
            .iter()
            .any(|finding| finding.rule_id == "sleep_polling")
    );
}

#[test]
fn test_busy_wait() {
    let workspace = FixtureWorkspace::new();
    workspace.write_file("wait.go", go_fixture!("busy_waiting_slop.txt"));

    let report = workspace.scan();

    assert!(
        report
            .findings
            .iter()
            .any(|finding| finding.rule_id == "busy_waiting")
    );
}

#[test]
fn test_select_ok() {
    let workspace = FixtureWorkspace::new();
    workspace.write_file("wait.go", go_fixture!("busy_waiting_clean.txt"));

    let report = workspace.scan();

    assert!(
        !report
            .findings
            .iter()
            .any(|finding| finding.rule_id == "busy_waiting")
    );
}

#[test]
fn test_missing_ctx_exec() {
    let workspace = FixtureWorkspace::new();
    workspace.write_file("exec.go", go_fixture!("missing_context_exec.txt"));

    let report = workspace.scan();

    assert!(report.findings.iter().any(|finding| {
        finding.rule_id == "missing_context" && finding.message.contains("context-aware work")
    }));
}

#[test]
fn test_ctx_exec() {
    let workspace = FixtureWorkspace::new();
    workspace.write_file("exec.go", go_fixture!("context_aware_exec.txt"));

    let report = workspace.scan();

    assert!(
        !report
            .findings
            .iter()
            .any(|finding| finding.rule_id == "missing_context")
    );
}

#[test]
fn test_context_wrapper_slop() {
    let workspace = FixtureWorkspace::new();
    workspace.write_file("wrapper.go", go_fixture!("context_wrapper_slop.txt"));

    let report = workspace.scan();

    assert!(
        report
            .findings
            .iter()
            .any(|finding| finding.rule_id == "missing_context_propagation")
    );
    assert!(
        report
            .findings
            .iter()
            .any(|finding| finding.rule_id == "context_background_used")
    );
}

#[test]
fn test_context_wrapper_clean() {
    let workspace = FixtureWorkspace::new();
    workspace.write_file("wrapper.go", go_fixture!("context_wrapper_clean.txt"));

    let report = workspace.scan();

    assert!(
        !report
            .findings
            .iter()
            .any(|finding| finding.rule_id == "missing_context_propagation")
    );
    assert!(
        !report
            .findings
            .iter()
            .any(|finding| finding.rule_id == "context_background_used")
    );
}

#[test]
fn test_context_wrapper_alias_slop() {
    let workspace = FixtureWorkspace::new();
    workspace.write_file(
        "wrapper_alias.go",
        go_fixture!("context_wrapper_alias_slop.txt"),
    );

    let report = workspace.scan();

    assert!(report.findings.iter().any(|finding| {
        finding.rule_id == "missing_context_propagation"
            && finding.function_name.as_deref() == Some("Fetch")
    }));
    assert!(report.findings.iter().any(|finding| {
        finding.rule_id == "context_background_used"
            && finding.function_name.as_deref() == Some("Fetch")
    }));
}

#[test]
fn test_context_receiver_wrapper_slop() {
    let workspace = FixtureWorkspace::new();
    workspace.write_file(
        "receiver_wrapper.go",
        go_fixture!("context_receiver_wrapper_slop.txt"),
    );

    let report = workspace.scan();

    assert!(report.findings.iter().any(|finding| {
        finding.rule_id == "missing_context_propagation"
            && finding.function_name.as_deref() == Some("Fetch")
    }));
}

#[test]
fn test_context_nested_wrapper_slop() {
    let workspace = FixtureWorkspace::new();
    workspace.write_file(
        "nested_wrapper.go",
        go_fixture!("context_nested_wrapper_slop.txt"),
    );

    let report = workspace.scan();

    assert!(report.findings.iter().any(|finding| {
        finding.rule_id == "missing_context_propagation"
            && finding.function_name.as_deref() == Some("Fetch")
            && finding.message.contains("wrapper chain")
    }));
}

#[test]
fn test_context_db_query_wrapper_slop() {
    let workspace = FixtureWorkspace::new();
    workspace.write_file("db_wrapper.go", go_fixture!("context_db_query_slop.txt"));

    let report = workspace.scan();

    assert!(report.findings.iter().any(|finding| {
        finding.rule_id == "missing_context_propagation"
            && finding.function_name.as_deref() == Some("Load")
            && finding.message.contains("context-aware DB variant")
    }));
}

#[test]
fn test_documented_context_detach_is_allowed() {
    let workspace = FixtureWorkspace::new();
    workspace.write_file(
        "detach.go",
        go_fixture!("context_documented_detach_clean.txt"),
    );

    let report = workspace.scan();

    assert!(!report.findings.iter().any(|finding| {
        matches!(
            finding.rule_id.as_str(),
            "missing_context_propagation" | "context_background_used"
        )
    }));
}

#[test]
fn test_context_propagation_severity_override() {
    let workspace = FixtureWorkspace::new();
    workspace.write_file(
        "receiver_wrapper.go",
        go_fixture!("context_receiver_wrapper_slop.txt"),
    );
    workspace.write_file(
        ".deslop.toml",
        "[severity_overrides]\nmissing_context_propagation = \"error\"\n",
    );

    let report = workspace.scan();

    assert!(report.findings.iter().any(|finding| {
        finding.rule_id == "missing_context_propagation"
            && matches!(finding.severity, deslop::Severity::Error)
    }));
}