paper-gap 0.1.2

Local CLI for finding research papers with missing, weak, or stale public code
Documentation
use paper_gap::{analyse, repos::Repository};

fn repo(url: &str) -> Repository {
    Repository {
        forge: "github".into(),
        url: url.into(),
        owner: "a".into(),
        name: "b".into(),
        description: None,
        primary_language: Some("Rust".into()),
        stars: Some(1),
        forks: Some(0),
        license: Some("MIT".into()),
        archived: Some(false),
        default_branch: Some("main".into()),
        last_commit_date: Some("2026-01-01T00:00:00Z".into()),
        source_provider: "github".into(),
    }
}

#[test]
fn deduplicates_repositories_by_normalized_url() {
    let repos = analyse::dedup_repositories(vec![
        repo("https://github.com/a/b"),
        repo("https://github.com/a/b/"),
        repo("https://github.com/a/b.git"),
    ]);
    assert_eq!(repos.len(), 1);
}

#[test]
fn scores_no_public_implementation() {
    let assessment = analyse::assess(&[], &[]);
    assert_eq!(assessment.components.no_code_score, 50);
    assert_eq!(assessment.implementation_gap_score, 50);
    assert_eq!(assessment.gaps.len(), 2);
}

#[test]
fn scores_unclear_license_when_all_repos_lack_license() {
    let mut repository = repo("https://github.com/a/b");
    repository.license = None;
    let assessment = analyse::assess(&[], &[repository]);
    assert_eq!(assessment.components.license_gap_score, 10);
    assert!(assessment.implementation_gap_score >= 10);
}

#[test]
fn detects_archived_repository() {
    let mut repository = repo("https://github.com/a/b");
    repository.archived = Some(true);
    let analysis = analyse::analyze_repository(&repository);
    assert!(analysis.is_archived);
    let assessment = analyse::assess(&[], &[repository]);
    assert_eq!(assessment.components.stale_repo_score, 15);
}