Skip to content

Commit

Permalink
Add /tags related errors and their integration tests (#469)
Browse files Browse the repository at this point in the history
* Unit tests for tags_endpoint

* Add `/tags` related errors and their integration tests
  • Loading branch information
oguzkocer authored Jan 16, 2025
1 parent 6ef8d83 commit 1cdc5c7
Show file tree
Hide file tree
Showing 5 changed files with 314 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package rs.wordpress.api.kotlin

import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Test
import uniffi.wp_api.PostListParams
import uniffi.wp_api.SparseTagFieldWithEditContext
import uniffi.wp_api.TagCreateParams
import uniffi.wp_api.TagListParams
import uniffi.wp_api.TagUpdateParams
import uniffi.wp_api.WpErrorCode
import uniffi.wp_api.wpAuthenticationFromUsernameAndPassword
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
Expand Down Expand Up @@ -104,4 +106,13 @@ class TagsEndpointTest {
assertEquals("new_slug", updatedTag.slug)
restoreTestServer()
}

@Test
fun testErrorTermInvalid() = runTest {
val result =
client.request { requestBuilder ->
requestBuilder.tags().retrieveWithEditContext(9999999)
}
assert(result.wpErrorCode() is WpErrorCode.TermInvalid)
}
}
4 changes: 4 additions & 0 deletions wp_api/src/api_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ pub enum WpErrorCode {
CannotRead,
#[serde(rename = "rest_cannot_read_post")]
CannotReadPost,
#[serde(rename = "rest_cannot_update")]
CannotUpdate,
#[serde(rename = "rest_cannot_view")]
CannotView,
#[serde(rename = "rest_cannot_view_plugin")]
Expand Down Expand Up @@ -213,6 +215,8 @@ pub enum WpErrorCode {
PostInvalidPageNumber,
#[serde(rename = "rest_taxonomy_invalid")]
TaxonomyInvalid,
#[serde(rename = "rest_term_invalid")]
TermInvalid,
#[serde(rename = "rest_type_invalid")]
TypeInvalid,
#[serde(rename = "rest_not_logged_in")]
Expand Down
222 changes: 222 additions & 0 deletions wp_api/src/request/endpoint/tags_endpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,225 @@ impl DerivedRequest for TagsRequest {
super::macros::default_sparse_field_implementation_from_field_name!(SparseTagFieldWithEditContext);
super::macros::default_sparse_field_implementation_from_field_name!(SparseTagFieldWithEmbedContext);
super::macros::default_sparse_field_implementation_from_field_name!(SparseTagFieldWithViewContext);

#[cfg(test)]
mod tests {
use super::*;
use crate::{
generate,
posts::PostId,
request::endpoint::{
tests::{fixture_api_base_url, validate_wp_v2_endpoint},
ApiBaseUrl,
},
tags::{TagId, WpApiParamTagsOrderBy},
WpApiParamOrder,
};
use rstest::*;
use std::sync::Arc;

#[rstest]
#[case(TagListParams::default(), "")]
#[case(generate!(TagListParams, (page, Some(2))), "page=2")]
#[case(generate!(TagListParams, (per_page, Some(2))), "per_page=2")]
#[case(generate!(TagListParams, (search, Some("foo".to_string()))), "search=foo")]
#[case(generate!(TagListParams, (exclude, vec![TagId(1), TagId(2)])), "exclude=1%2C2")]
#[case(generate!(TagListParams, (include, vec![TagId(1), TagId(2)])), "include=1%2C2")]
#[case(generate!(TagListParams, (offset, Some(2))), "offset=2")]
#[case(generate!(TagListParams, (order, Some(WpApiParamOrder::Asc))), "order=asc")]
#[case(generate!(TagListParams, (order, Some(WpApiParamOrder::Desc))), "order=desc")]
#[case(generate!(TagListParams, (orderby, Some(WpApiParamTagsOrderBy::Id))), "orderby=id")]
#[case(generate!(TagListParams, (orderby, Some(WpApiParamTagsOrderBy::Include))), "orderby=include")]
#[case(generate!(TagListParams, (orderby, Some(WpApiParamTagsOrderBy::Name))), "orderby=name")]
#[case(generate!(TagListParams, (orderby, Some(WpApiParamTagsOrderBy::Slug))), "orderby=slug")]
#[case(generate!(TagListParams, (orderby, Some(WpApiParamTagsOrderBy::IncludeSlugs))), "orderby=include_slugs")]
#[case(generate!(TagListParams, (orderby, Some(WpApiParamTagsOrderBy::TermGroup))), "orderby=term_group")]
#[case(generate!(TagListParams, (orderby, Some(WpApiParamTagsOrderBy::Description))), "orderby=description")]
#[case(generate!(TagListParams, (orderby, Some(WpApiParamTagsOrderBy::Count))), "orderby=count")]
#[case(generate!(TagListParams, (hide_empty, Some(true))), "hide_empty=true")]
#[case(generate!(TagListParams, (post, Some(PostId(3)))), "post=3")]
#[case(generate!(TagListParams, (slug, vec!["slug_1".to_string(), "slug_2".to_string()])), "slug=slug_1%2Cslug_2")]
// TODO
#[case(
tag_list_params_with_all_fields(),
EXPECTED_QUERY_PAIRS_FOR_TAG_LIST_PARAMS_WITH_ALL_FIELDS
)]
fn list_tags(
endpoint: TagsRequestEndpoint,
#[case] params: TagListParams,
#[case] expected_additional_params: &str,
) {
let expected_path = |context: &str| {
if expected_additional_params.is_empty() {
format!("/tags?context={}", context)
} else {
format!("/tags?context={}&{}", context, expected_additional_params)
}
};
validate_wp_v2_endpoint(
endpoint.list_with_edit_context(&params),
&expected_path("edit"),
);
validate_wp_v2_endpoint(
endpoint.list_with_embed_context(&params),
&expected_path("embed"),
);
validate_wp_v2_endpoint(
endpoint.list_with_view_context(&params),
&expected_path("view"),
);
}

#[rstest]
#[case(TagListParams::default(), &[], "/tags?context=edit&_fields=")]
#[case(generate!(TagListParams, (orderby, Some(WpApiParamTagsOrderBy::Id))), &[SparseTagFieldWithEditContext::Count], "/tags?context=edit&orderby=id&_fields=count")]
#[case(tag_list_params_with_all_fields(), ALL_SPARSE_TAG_FIELDS_WITH_EDIT_CONTEXT, &format!("/tags?context=edit&{}&{}", EXPECTED_QUERY_PAIRS_FOR_TAG_LIST_PARAMS_WITH_ALL_FIELDS, EXPECTED_QUERY_PAIRS_FOR_ALL_SPARSE_TAG_FIELDS_WITH_EDIT_CONTEXT))]
fn filter_list_tags_with_edit_context(
endpoint: TagsRequestEndpoint,
#[case] params: TagListParams,
#[case] fields: &[SparseTagFieldWithEditContext],
#[case] expected_path: &str,
) {
validate_wp_v2_endpoint(
endpoint.filter_list_with_edit_context(&params, fields),
expected_path,
);
}

#[rstest]
#[case(TagListParams::default(), &[], "/tags?context=embed&_fields=")]
#[case(generate!(TagListParams, (orderby, Some(WpApiParamTagsOrderBy::Slug))), &[SparseTagFieldWithEmbedContext::Link], "/tags?context=embed&orderby=slug&_fields=link")]
#[case(tag_list_params_with_all_fields(), ALL_SPARSE_TAG_FIELDS_WITH_EMBED_CONTEXT, &format!("/tags?context=embed&{}&{}", EXPECTED_QUERY_PAIRS_FOR_TAG_LIST_PARAMS_WITH_ALL_FIELDS, EXPECTED_QUERY_PAIRS_FOR_ALL_SPARSE_TAG_FIELDS_WITH_EMBED_CONTEXT))]
fn filter_list_tags_with_embed_context(
endpoint: TagsRequestEndpoint,
#[case] params: TagListParams,
#[case] fields: &[SparseTagFieldWithEmbedContext],
#[case] expected_path: &str,
) {
validate_wp_v2_endpoint(
endpoint.filter_list_with_embed_context(&params, fields),
expected_path,
);
}

#[rstest]
#[case(TagListParams::default(), &[], "/tags?context=view&_fields=")]
#[case(generate!(TagListParams, (orderby, Some(WpApiParamTagsOrderBy::Include))), &[SparseTagFieldWithViewContext::Description], "/tags?context=view&orderby=include&_fields=description")]
#[case(tag_list_params_with_all_fields(), ALL_SPARSE_TAG_FIELDS_WITH_VIEW_CONTEXT, &format!("/tags?context=view&{}&{}", EXPECTED_QUERY_PAIRS_FOR_TAG_LIST_PARAMS_WITH_ALL_FIELDS, EXPECTED_QUERY_PAIRS_FOR_ALL_SPARSE_TAG_FIELDS_WITH_VIEW_CONTEXT))]
fn filter_list_tags_with_view_context(
endpoint: TagsRequestEndpoint,
#[case] params: TagListParams,
#[case] fields: &[SparseTagFieldWithViewContext],
#[case] expected_path: &str,
) {
validate_wp_v2_endpoint(
endpoint.filter_list_with_view_context(&params, fields),
expected_path,
);
}

const EXPECTED_QUERY_PAIRS_FOR_TAG_LIST_PARAMS_WITH_ALL_FIELDS: &str = "page=11&per_page=22&search=s_q&exclude=1111%2C1112&include=2111%2C2112&offset=11111&order=desc&orderby=slug&hide_empty=true&post=33333&slug=slug_1%2Cslug_2";
fn tag_list_params_with_all_fields() -> TagListParams {
TagListParams {
page: Some(11),
per_page: Some(22),
search: Some("s_q".to_string()),
exclude: vec![TagId(1111), TagId(1112)],
include: vec![TagId(2111), TagId(2112)],
offset: Some(11111),
order: Some(WpApiParamOrder::Desc),
orderby: Some(WpApiParamTagsOrderBy::Slug),
hide_empty: Some(true),
post: Some(PostId(33333)),
slug: vec!["slug_1".to_string(), "slug_2".to_string()],
}
}

#[rstest]
fn retrieve_tag(endpoint: TagsRequestEndpoint) {
let tag_id = TagId(54);
let expected_path = |context: &str| format!("/tags/54?context={}", context);
validate_wp_v2_endpoint(
endpoint.retrieve_with_edit_context(&tag_id),
&expected_path("edit"),
);
validate_wp_v2_endpoint(
endpoint.retrieve_with_embed_context(&tag_id),
&expected_path("embed"),
);
validate_wp_v2_endpoint(
endpoint.retrieve_with_view_context(&tag_id),
&expected_path("view"),
);
}

#[rstest]
#[case(None, &[], "/tags/54?context=view&_fields=")]
#[case(Some("foo"), &[SparseTagFieldWithViewContext::Count], "/tags/54?context=view&_fields=count")]
#[case(Some("foo"), ALL_SPARSE_TAG_FIELDS_WITH_VIEW_CONTEXT, &format!("/tags/54?context=view&{}", EXPECTED_QUERY_PAIRS_FOR_ALL_SPARSE_TAG_FIELDS_WITH_VIEW_CONTEXT))]
fn filter_retrieve_tag_with_view_context(
endpoint: TagsRequestEndpoint,
#[case] password: Option<&str>,
#[case] fields: &[SparseTagFieldWithViewContext],
#[case] expected_path: &str,
) {
validate_wp_v2_endpoint(
endpoint.filter_retrieve_with_view_context(&TagId(54), fields),
expected_path,
);
}

#[rstest]
fn create_tag(endpoint: TagsRequestEndpoint) {
validate_wp_v2_endpoint(endpoint.create(), "/tags");
}

#[rstest]
fn delete_tag(endpoint: TagsRequestEndpoint) {
validate_wp_v2_endpoint(endpoint.delete(&TagId(54)), "/tags/54?force=true");
}

#[rstest]
fn update_tag(endpoint: TagsRequestEndpoint) {
validate_wp_v2_endpoint(endpoint.update(&TagId(54)), "/tags/54");
}

const EXPECTED_QUERY_PAIRS_FOR_ALL_SPARSE_TAG_FIELDS_WITH_EDIT_CONTEXT: &str =
"_fields=id%2Ccount%2Cdescription%2Clink%2Cname%2Cslug%2Ctaxonomy";
const ALL_SPARSE_TAG_FIELDS_WITH_EDIT_CONTEXT: &[SparseTagFieldWithEditContext; 7] = &[
SparseTagFieldWithEditContext::Id,
SparseTagFieldWithEditContext::Count,
SparseTagFieldWithEditContext::Description,
SparseTagFieldWithEditContext::Link,
SparseTagFieldWithEditContext::Name,
SparseTagFieldWithEditContext::Slug,
SparseTagFieldWithEditContext::Taxonomy,
];

const EXPECTED_QUERY_PAIRS_FOR_ALL_SPARSE_TAG_FIELDS_WITH_EMBED_CONTEXT: &str =
"_fields=id%2Clink%2Cname%2Cslug%2Ctaxonomy";
const ALL_SPARSE_TAG_FIELDS_WITH_EMBED_CONTEXT: &[SparseTagFieldWithEmbedContext; 5] = &[
SparseTagFieldWithEmbedContext::Id,
SparseTagFieldWithEmbedContext::Link,
SparseTagFieldWithEmbedContext::Name,
SparseTagFieldWithEmbedContext::Slug,
SparseTagFieldWithEmbedContext::Taxonomy,
];

const EXPECTED_QUERY_PAIRS_FOR_ALL_SPARSE_TAG_FIELDS_WITH_VIEW_CONTEXT: &str =
"_fields=id%2Ccount%2Cdescription%2Clink%2Cname%2Cslug%2Ctaxonomy";
const ALL_SPARSE_TAG_FIELDS_WITH_VIEW_CONTEXT: &[SparseTagFieldWithViewContext; 7] = &[
SparseTagFieldWithViewContext::Id,
SparseTagFieldWithViewContext::Count,
SparseTagFieldWithViewContext::Description,
SparseTagFieldWithViewContext::Link,
SparseTagFieldWithViewContext::Name,
SparseTagFieldWithViewContext::Slug,
SparseTagFieldWithViewContext::Taxonomy,
];

#[fixture]
fn endpoint(fixture_api_base_url: Arc<ApiBaseUrl>) -> TagsRequestEndpoint {
TagsRequestEndpoint::new(fixture_api_base_url)
}
}
1 change: 1 addition & 0 deletions wp_api_integration_tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ pub const MEDIA_TEST_FILE_PATH: &str = "../test_media.jpg";
pub const MEDIA_TEST_FILE_CONTENT_TYPE: &str = "image/jpeg";
pub const CATEGORY_ID_1: CategoryId = CategoryId(1);
pub const TAG_ID_100: TagId = TagId(100);
pub const TAG_ID_INVALID: TagId = TagId(99999999);
pub const POST_TEMPLATE_SINGLE_WITH_SIDEBAR: &str = "single-with-sidebar";

pub fn api_client() -> WpApiClient {
Expand Down
76 changes: 76 additions & 0 deletions wp_api_integration_tests/tests/test_tags_err.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use serial_test::parallel;
use wp_api::{
tags::{TagCreateParams, TagListParams, TagUpdateParams},
WpErrorCode,
};
use wp_api_integration_tests::{
api_client, api_client_as_subscriber, AssertWpError, POST_ID_INVALID, TAG_ID_100,
TAG_ID_INVALID,
};

#[tokio::test]
#[parallel]
async fn create_err_cannot_create() {
api_client_as_subscriber()
.tags()
.create(&TagCreateParams {
name: "foo".to_string(),
description: None,
slug: None,
})
.await
.assert_wp_error(WpErrorCode::CannotCreate);
}

#[tokio::test]
#[parallel]
async fn delete_err_cannot_delete() {
api_client_as_subscriber()
.tags()
.delete(&TAG_ID_100)
.await
.assert_wp_error(WpErrorCode::CannotDelete);
}

#[tokio::test]
#[parallel]
async fn list_err_forbidden_context() {
api_client_as_subscriber()
.tags()
.list_with_edit_context(&TagListParams::default())
.await
.assert_wp_error(WpErrorCode::ForbiddenContext);
}

#[tokio::test]
#[parallel]
async fn list_err_post_invalid_id() {
api_client()
.tags()
.list_with_edit_context(&TagListParams {
post: Some(POST_ID_INVALID),
..Default::default()
})
.await
.assert_wp_error(WpErrorCode::PostInvalidId);
}

#[tokio::test]
#[parallel]
async fn retrieve_err_term_invalid() {
api_client()
.tags()
.retrieve_with_edit_context(&TAG_ID_INVALID)
.await
.assert_wp_error(WpErrorCode::TermInvalid);
}

#[tokio::test]
#[parallel]
async fn update_err_cannot_update() {
api_client_as_subscriber()
.tags()
.update(&TAG_ID_100, &TagUpdateParams::default())
.await
.assert_wp_error(WpErrorCode::CannotUpdate);
}

0 comments on commit 1cdc5c7

Please sign in to comment.