paper-gap 0.2.2

Local CLI for finding research papers with missing, weak, or stale public code
Documentation
use std::process::Command;

fn bin() -> &'static str {
    env!("CARGO_BIN_EXE_paper-gap")
}

#[test]
fn help_command_runs() {
    let output = Command::new(bin()).arg("--help").output().unwrap();
    assert!(output.status.success());
    assert!(String::from_utf8_lossy(&output.stdout).contains("paper-gap"));
}

#[test]
fn sources_commands_emit_json() {
    for args in [
        vec!["sources"],
        vec!["sources", "--papers"],
        vec!["sources", "--repos"],
    ] {
        let output = Command::new(bin()).args(args).output().unwrap();
        assert!(output.status.success());
        serde_json::from_slice::<serde_json::Value>(&output.stdout).unwrap();
    }
}

#[test]
fn report_formats_json_input_as_markdown_and_json() {
    let input = std::env::temp_dir().join(format!("paper-gap-report-{}.json", std::process::id()));
    std::fs::write(&input, r#"{"paper_results":[]}"#).unwrap();

    let markdown = Command::new(bin())
        .args([
            "report",
            "--input",
            input.to_str().unwrap(),
            "--format",
            "markdown",
        ])
        .output()
        .unwrap();
    assert!(markdown.status.success());
    assert!(String::from_utf8_lossy(&markdown.stdout).contains("# paper-gap report"));

    let json = Command::new(bin())
        .args([
            "report",
            "--input",
            input.to_str().unwrap(),
            "--format",
            "json",
        ])
        .output()
        .unwrap();
    assert!(json.status.success());
    serde_json::from_slice::<serde_json::Value>(&json.stdout).unwrap();

    let _ = std::fs::remove_file(input);
}

#[test]
fn scan_rejects_missing_or_blank_selectors_without_network_access() {
    for args in [vec!["scan"], vec!["scan", "--query", "   "]] {
        let output = Command::new(bin()).args(args).output().unwrap();
        assert!(!output.status.success());
        assert!(String::from_utf8_lossy(&output.stderr).contains("scan needs"));
    }
}

#[test]
fn scan_rejects_incompatible_paper_sources_without_network_access() {
    for (args, message) in [
        (
            vec!["scan", "--paper-source", "openalex", "--category", "cs.PL"],
            "--category is only supported by arxiv",
        ),
        (
            vec!["scan", "--paper-source", "arxiv", "--from", "2026-06-01"],
            "--paper-source arxiv needs --query or --category",
        ),
    ] {
        let output = Command::new(bin()).args(args).output().unwrap();
        assert!(!output.status.success());
        assert!(String::from_utf8_lossy(&output.stderr).contains(message));
    }
}