paper-gap 0.3.2

Local CLI for finding research papers with missing, weak, or stale public code
Documentation
use chrono::NaiveDate;
use paper_gap::openalex::{self, SearchQuery};

#[test]
fn builds_search_url_with_dates_and_optional_email() {
    let url = openalex::search_url(
        &SearchQuery {
            query: Some("symbolic computation".into()),
            from: Some(NaiveDate::from_ymd_opt(2026, 6, 1).unwrap()),
            to: Some(NaiveDate::from_ymd_opt(2026, 6, 29).unwrap()),
            limit: 10,
        },
        Some("me@example.org"),
    );
    assert!(url.contains("search=symbolic%20computation"));
    assert!(url.contains("per-page=10"));
    assert!(url.contains("from_publication_date%3A2026-06-01"));
    assert!(url.contains("to_publication_date%3A2026-06-29"));
    assert!(url.contains("mailto=me%40example.org"));
}

#[test]
fn parses_and_normalizes_openalex_work() {
    let json = r#"{
      "results": [{
        "id": "https://openalex.org/W1",
        "title": "Fast FFT Methods",
        "doi": "https://doi.org/10.1234/example",
        "publication_date": "2026-06-01",
        "updated_date": "2026-06-02T00:00:00",
        "abstract_inverted_index": {"Fast": [0], "method": [2], "FFT": [1]},
        "authorships": [{"author": {"display_name": "Ada Lovelace"}}],
        "ids": {"openalex": "https://openalex.org/W1", "arxiv": "https://arxiv.org/abs/2603.21852"},
        "primary_location": {"landing_page_url": "https://example.org/paper"},
        "topics": [{"display_name": "Numerical Analysis"}]
      }]
    }"#;
    let papers = openalex::parse(json).unwrap();
    assert_eq!(papers.len(), 1);
    let paper = &papers[0];
    assert_eq!(paper.abstract_text, "Fast FFT method");
    assert_eq!(paper.doi.as_deref(), Some("10.1234/example"));
    assert_eq!(paper.arxiv_id.as_deref(), Some("2603.21852"));
    assert_eq!(paper.authors, vec!["Ada Lovelace"]);
    assert_eq!(paper.categories, vec!["Numerical Analysis"]);
    assert_eq!(paper.source_provider, "openalex");
}

#[test]
fn builds_filter_only_url_for_date_scan() {
    let url = openalex::search_url(
        &SearchQuery {
            query: None,
            from: Some(NaiveDate::from_ymd_opt(2026, 6, 1).unwrap()),
            to: Some(NaiveDate::from_ymd_opt(2026, 6, 29).unwrap()),
            limit: 25,
        },
        None,
    );
    assert!(!url.contains("search="));
    assert!(url.contains("from_publication_date%3A2026-06-01"));
    assert!(url.contains("to_publication_date%3A2026-06-29"));
}