prlens 0.1.0

One queue for all your PRs — aggregates GitHub and Bitbucket review requests into a single interactive view
Documentation
use async_trait::async_trait;
use chrono::Utc;
use super::{Provider, ProviderError, AuthStatus};
use crate::models::{PullRequest, PrIdentifier, User, PrState, ReviewStatus};

pub struct MockProvider;

#[async_trait]
impl Provider for MockProvider {
    fn name(&self) -> &'static str {
        "mock"
    }

    fn display_name(&self) -> &'static str {
        "Mock"
    }

    async fn check_auth(&self) -> AuthStatus {
        AuthStatus::Available
    }

    async fn list_prs(&self) -> Result<Vec<PullRequest>, ProviderError> {
        let pr1 = PullRequest {
            id: PrIdentifier {
                provider: "mock".to_string(),
                owner: "acme".to_string(),
                repo: "widget".to_string(),
                number: 42,
            },
            number: 42,
            title: "feat: add XDG config loading".to_string(),
            url: "https://github.com/acme/widget/pull/42".to_string(),
            author: User {
                login: "alice".to_string(),
                display_name: Some("Alice Smith".to_string()),
                avatar_url: None,
            },
            reviewers: vec![],
            repo_full_name: "acme/widget".to_string(),
            provider: "mock".to_string(),
            head_branch: "feat/xdg-config".to_string(),
            base_branch: "main".to_string(),
            state: PrState::Open,
            review_status: ReviewStatus::NeedsReview,
            ci_status: None,
            draft: false,
            created_at: Utc::now() - chrono::Duration::hours(2),
            updated_at: Utc::now() - chrono::Duration::minutes(30),
            labels: vec![],
            comment_count: 3,
            additions: Some(47),
            deletions: Some(12),
        };

        let pr2 = PullRequest {
            id: PrIdentifier {
                provider: "mock".to_string(),
                owner: "acme".to_string(),
                repo: "core".to_string(),
                number: 7,
            },
            number: 7,
            title: "fix: handle empty provider list gracefully".to_string(),
            url: "https://github.com/acme/core/pull/7".to_string(),
            author: User {
                login: "bob".to_string(),
                display_name: Some("Bob Jones".to_string()),
                avatar_url: None,
            },
            reviewers: vec![],
            repo_full_name: "acme/core".to_string(),
            provider: "mock".to_string(),
            head_branch: "fix/empty-providers".to_string(),
            base_branch: "main".to_string(),
            state: PrState::Open,
            review_status: ReviewStatus::NeedsReview,
            ci_status: None,
            draft: false,
            created_at: Utc::now() - chrono::Duration::hours(5),
            updated_at: Utc::now() - chrono::Duration::hours(1),
            labels: vec![],
            comment_count: 0,
            additions: Some(8),
            deletions: Some(2),
        };

        Ok(vec![pr1, pr2])
    }

    async fn get_pr_details(&self, _pr_id: &PrIdentifier) -> Result<PullRequest, ProviderError> {
        Err(ProviderError::NotImplemented { provider: "mock".to_string() })
    }

    async fn get_pr_diff(&self, _pr_id: &PrIdentifier) -> Result<String, ProviderError> {
        Err(ProviderError::NotImplemented { provider: "mock".to_string() })
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn mock_provider_list_prs() {
        let mock = MockProvider;
        let prs = mock.list_prs().await.unwrap();
        assert_eq!(prs.len(), 2);
        assert_eq!(prs[0].number, 42);
        assert_eq!(prs[1].author.login, "bob");
    }
}