gitee-cli-rs 0.2.2

A gh-like command-line client for Gitee
Documentation
use gitee_cli_rs::api::client::Client;
use gitee_cli_rs::error::GiteeError;
use gitee_cli_rs::models::{Issue, IssueState};

fn client(server: &mockito::ServerGuard) -> Client {
    Client::new(format!("{}/api/v5", server.url()), "fake-token".into())
}

fn api_path(path: &str) -> String {
    format!("/api/v5{path}")
}

#[test]
fn get_401_maps_to_unauthorized() {
    let mut server = mockito::Server::new();
    let path = "/user";
    server
        .mock("GET", api_path(path).as_str())
        .with_status(401)
        .with_body(r#"{"message":"401 Unauthorized"}"#)
        .create();

    let client = client(&server);
    let err = client
        .get::<Issue>(path, &[])
        .expect_err("expected unauthorized");

    assert!(matches!(err, GiteeError::Unauthorized));
}

#[test]
fn patch_issues_404_project_or_enterprise_maps_to_api() {
    let mut server = mockito::Server::new();
    let path = "/repos/owner/issues/I1";
    server
        .mock("PATCH", api_path(path).as_str())
        .with_status(404)
        .with_body(r#"{"message":"project or enterprise"}"#)
        .create();

    let client = client(&server);
    let err = client
        .patch_json::<Issue>(path, &serde_json::json!({"repo": "r", "title": "t", "state": "open"}))
        .expect_err("expected api error");

    match err {
        GiteeError::Api { status, message } => {
            assert_eq!(status, 404);
            assert!(message.to_lowercase().contains("project or enterprise"));
        }
        other => panic!("expected Api error, got {other:?}"),
    }
}

#[test]
fn get_404_project_or_enterprise_stays_not_found() {
    let mut server = mockito::Server::new();
    let path = "/repos/owner/repo/issues/I1";
    server
        .mock("GET", api_path(path).as_str())
        .with_status(404)
        .with_body(r#"{"message":"project or enterprise"}"#)
        .create();

    let client = client(&server);
    let err = client
        .get::<Issue>(path, &[])
        .expect_err("expected not found");

    match err {
        GiteeError::NotFound(p) => assert_eq!(p, path),
        other => panic!("expected NotFound for non-PATCH, got {other:?}"),
    }
}

#[test]
fn get_404_maps_to_not_found_with_path() {
    let mut server = mockito::Server::new();
    let path = "/repos/owner/missing";
    server
        .mock("GET", api_path(path).as_str())
        .with_status(404)
        .with_body(r#"{"message":"Not Found"}"#)
        .create();

    let client = client(&server);
    let err = client
        .get::<Issue>(path, &[])
        .expect_err("expected not found");

    match err {
        GiteeError::NotFound(p) => assert_eq!(p, path),
        other => panic!("expected NotFound, got {other:?}"),
    }
}

#[test]
fn get_422_maps_to_api_with_json_message() {
    let mut server = mockito::Server::new();
    let path = "/repos/owner/repo/issues";
    server
        .mock("GET", api_path(path).as_str())
        .with_status(422)
        .with_body(r#"{"message":"title is required"}"#)
        .create();

    let client = client(&server);
    let err = client
        .get::<Issue>(path, &[])
        .expect_err("expected api error");

    match err {
        GiteeError::Api { status, message } => {
            assert_eq!(status, 422);
            assert_eq!(message, "title is required");
        }
        other => panic!("expected Api error, got {other:?}"),
    }
}

#[test]
fn get_500_non_json_body_uses_trimmed_text() {
    let mut server = mockito::Server::new();
    let path = "/repos/owner/repo/issues";
    let body = format!("  {}  ", "x".repeat(350));
    let expected = format!("{}", "x".repeat(300));
    server
        .mock("GET", api_path(path).as_str())
        .with_status(500)
        .with_body(body)
        .create();

    let client = client(&server);
    let err = client
        .get::<Issue>(path, &[])
        .expect_err("expected api error");

    match err {
        GiteeError::Api { status, message } => {
            assert_eq!(status, 500);
            assert_eq!(message, expected);
        }
        other => panic!("expected Api error, got {other:?}"),
    }
}

#[test]
fn get_200_deserializes_issue() {
    let mut server = mockito::Server::new();
    let path = "/repos/owner/repo/issues/1";
    let body = r#"{
        "number": "42",
        "title": "Bug report",
        "state": "open",
        "html_url": "https://gitee.com/owner/repo/issues/I42"
    }"#;
    server
        .mock("GET", api_path(path).as_str())
        .with_status(200)
        .with_header("content-type", "application/json")
        .with_body(body)
        .create();

    let client = client(&server);
    let issue: Issue = client.get(path, &[]).expect("expected success");

    assert_eq!(issue.number, "42");
    assert_eq!(issue.title, "Bug report");
    assert_eq!(issue.state, IssueState::Open);
    assert_eq!(
        issue.html_url,
        "https://gitee.com/owner/repo/issues/I42"
    );
}