pinakes/crates/pinakes-server/tests/books.rs
NotAShelf 9d58927cb4
pinakes-server: add utoipa annotations to all routes; fix tests
Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I28cf5b7b7cff8e90e123d624d97cf9656a6a6964
2026-03-22 22:04:51 +03:00

150 lines
3.6 KiB
Rust

mod common;
use axum::http::StatusCode;
use common::{
delete_authed,
get,
get_authed,
patch_json_authed,
post_json_authed,
put_json_authed,
response_body,
setup_app,
setup_app_with_auth,
};
use tower::ServiceExt;
#[tokio::test]
async fn list_books_empty() {
let app = setup_app().await;
let resp = app.oneshot(get("/api/v1/books")).await.unwrap();
assert_eq!(resp.status(), StatusCode::OK);
let body = response_body(resp).await;
let items = body.as_array().expect("array response");
assert!(items.is_empty());
}
#[tokio::test]
async fn get_book_metadata_not_found() {
let app = setup_app().await;
let fake_id = uuid::Uuid::now_v7();
let resp = app
.oneshot(get(&format!("/api/v1/books/{fake_id}/metadata")))
.await
.unwrap();
assert_eq!(resp.status(), StatusCode::NOT_FOUND);
}
#[tokio::test]
async fn list_books_with_filters() {
let app = setup_app().await;
let resp = app
.oneshot(get("/api/v1/books?author=Tolkien&limit=10"))
.await
.unwrap();
assert_eq!(resp.status(), StatusCode::OK);
}
#[tokio::test]
async fn list_series_empty() {
let app = setup_app().await;
let resp = app.oneshot(get("/api/v1/books/series")).await.unwrap();
assert_eq!(resp.status(), StatusCode::OK);
}
#[tokio::test]
async fn list_authors_empty() {
let app = setup_app().await;
let resp = app
.oneshot(get("/api/v1/books/authors?offset=0&limit=50"))
.await
.unwrap();
assert_eq!(resp.status(), StatusCode::OK);
}
#[tokio::test]
async fn reading_progress_nonexistent_book() {
let (app, _, _, viewer) = setup_app_with_auth().await;
let fake_id = uuid::Uuid::now_v7();
let resp = app
.clone()
.oneshot(get_authed(
&format!("/api/v1/books/{fake_id}/progress"),
&viewer,
))
.await
.unwrap();
// Nonexistent book always returns 404.
assert_eq!(resp.status(), StatusCode::NOT_FOUND);
}
#[tokio::test]
async fn update_reading_progress_nonexistent_book() {
let (app, _, _, viewer) = setup_app_with_auth().await;
let fake_id = uuid::Uuid::now_v7();
let resp = app
.clone()
.oneshot(put_json_authed(
&format!("/api/v1/books/{fake_id}/progress"),
r#"{"current_page":42}"#,
&viewer,
))
.await
.unwrap();
// Nonexistent book: handler verifies existence first, so always 404.
assert_eq!(resp.status(), StatusCode::NOT_FOUND);
}
#[tokio::test]
async fn reading_list_empty() {
let (app, _, _, viewer) = setup_app_with_auth().await;
let resp = app
.clone()
.oneshot(get_authed("/api/v1/books/reading-list", &viewer))
.await
.unwrap();
assert_eq!(resp.status(), StatusCode::OK);
}
#[tokio::test]
async fn import_media_requires_editor() {
let (app, _, _, viewer) = setup_app_with_auth().await;
let resp = app
.clone()
.oneshot(post_json_authed(
"/api/v1/media/import",
r#"{"path":"/tmp/test.txt"}"#,
&viewer,
))
.await
.unwrap();
assert_eq!(resp.status(), StatusCode::FORBIDDEN);
}
#[tokio::test]
async fn update_media_requires_editor() {
let (app, _, _, viewer) = setup_app_with_auth().await;
let fake_id = uuid::Uuid::now_v7();
let resp = app
.clone()
.oneshot(patch_json_authed(
&format!("/api/v1/media/{fake_id}"),
r#"{"title":"new"}"#,
&viewer,
))
.await
.unwrap();
assert_eq!(resp.status(), StatusCode::FORBIDDEN);
}
#[tokio::test]
async fn delete_media_requires_editor() {
let (app, _, _, viewer) = setup_app_with_auth().await;
let fake_id = uuid::Uuid::now_v7();
let resp = app
.clone()
.oneshot(delete_authed(&format!("/api/v1/media/{fake_id}"), &viewer))
.await
.unwrap();
assert_eq!(resp.status(), StatusCode::FORBIDDEN);
}