paper-gap 0.2.2

Local CLI for finding research papers with missing, weak, or stale public code
Documentation
use paper_gap::sources::{self, DiscoverKind, ProviderKind, SourceFilter};

#[test]
fn filters_paper_and_repo_sources() {
    let papers = sources::filter(sources::builtin(), SourceFilter::Papers);
    assert!(papers.iter().any(|p| p.id == "arxiv"));
    assert!(papers.iter().any(|p| p.id == "openalex"));
    assert!(papers.iter().all(|p| matches!(
        p.kind,
        ProviderKind::Paper | ProviderKind::Metadata | ProviderKind::Both
    )));

    let repos = sources::filter(sources::builtin(), SourceFilter::Repos);
    assert!(repos.iter().any(|p| p.id == "github"));
    assert!(repos.iter().any(|p| p.id == "gitlab"));
    assert!(repos.iter().any(|p| p.id == "codeberg"));
    assert!(repos.iter().all(|p| p.kind == ProviderKind::Repo));
}

#[test]
fn discovery_queries_cover_all_kinds() {
    assert!(
        sources::discovery_queries(DiscoverKind::Papers)
            .iter()
            .any(|q| q.contains("preprint"))
    );
    assert!(
        sources::discovery_queries(DiscoverKind::Repos)
            .iter()
            .any(|q| q.contains("Forgejo"))
    );
    assert!(
        sources::discovery_queries(DiscoverKind::All).len()
            > sources::discovery_queries(DiscoverKind::Repos).len()
    );
}

#[test]
fn parses_duckduckgo_html_as_low_confidence_informational_sources() {
    let html = r#"<a rel="nofollow" class="result__a" href="https://example.org/api">Example API docs</a>"#;
    let sources = sources::parse_duckduckgo_html(
        DiscoverKind::Papers,
        "scholarly metadata APIs",
        "https://duckduckgo.com/html/?q=x",
        html,
    );
    assert_eq!(sources.len(), 1);
    assert_eq!(sources[0].discovery_backend, "duckduckgo_html");
    assert_eq!(sources[0].url, "https://example.org/api");
    assert_eq!(sources[0].kind, "papers");
    assert_eq!(sources[0].source_type, "aggregator_api");
    assert_eq!(sources[0].confidence, "low");
    assert!(sources[0].evidence_snippets[0].contains("Example API docs"));
}

#[test]
fn parses_brave_results_with_api_evidence() {
    let json = r#"{"web":{"results":[{"title":"Example API docs","url":"https://example.org/api","description":"Official API documentation"}]}}"#;
    let found = sources::parse_brave_json(
        DiscoverKind::Papers,
        "scholarly metadata APIs",
        "https://api.search.brave.com/search?q=x",
        json,
    )
    .unwrap();
    assert_eq!(found.len(), 1);
    assert_eq!(found[0].discovery_backend, "brave_api");
    assert_eq!(found[0].confidence, "medium");
    assert_eq!(found[0].api_available, "yes");
    assert_eq!(
        found[0].docs_url.as_deref(),
        Some("https://example.org/api")
    );
}

#[test]
fn deduplicates_discovered_sources_by_domain() {
    let html = concat!(
        "<a class=\"result__a\" href=\"https://example.org/api\">API</a>\n",
        "<a class=\"result__a\" href=\"https://www.example.org/docs\">Docs</a>"
    );
    let found = sources::parse_duckduckgo_html(
        DiscoverKind::Papers,
        "scholarly metadata APIs",
        "https://duckduckgo.com/html/?q=x",
        html,
    );
    assert_eq!(sources::deduplicate_discovered_sources(found).len(), 1);
}