#![cfg(test)]
use microformats::types::{Class, KnownClass};
use super::Action;
use crate::standards::{
indieauth::AccessToken,
micropub::action::{ActionResponse, CreationProperties},
};
async fn mock_micropub_request(
client: impl crate::http::Client,
endpoint: &url::Url,
token: &AccessToken,
action: &Action,
response: &ActionResponse,
message: impl ToString,
) {
assert_eq!(
action.send(&client, endpoint, token).await,
Ok(response.to_owned()),
"crafts expected response for {}",
message.to_string()
);
}
#[tracing_test::traced_test]
#[tokio::test]
async fn action_send_request() {
let mut client = crate::test::Client::new().await;
let token = AccessToken::new("a-bad-token");
client
.mock_server
.mock("POST", "/action-create-sync")
.with_header(http::header::CONTENT_TYPE.to_string(), "application/json")
.with_header(http::header::LOCATION.to_string(), "http://example.com/new")
.with_status(http::StatusCode::CREATED.as_u16().into())
.expect(1)
.create_async()
.await;
let u = format!("{}/action-create-sync", client.mock_server.url())
.parse()
.unwrap();
mock_micropub_request(
client,
&u,
&token,
&Action::Create {
properties: Box::new(CreationProperties {
r#type: Class::Known(KnownClass::Entry),
parameters: Default::default(),
extra_fields: Default::default(),
}),
files: Default::default(),
},
&ActionResponse::Created {
sync: true,
location: "http://example.com/new".parse().unwrap(),
rel: Default::default(),
},
"create sync",
)
.await;
}
#[test]
fn deser_creation_props() {
let props_json_in_list = serde_json::json!({
"type": ["h-entry"],
"properties": {
"slug": ["wow"],
"title": "grrr"
}
});
let create_props: CreationProperties =
serde_json::from_value(props_json_in_list).expect("converted props from json");
assert_eq!(create_props.parameters.slug, Some("wow".to_string()));
let props_json_in_str = serde_json::json!({
"type": ["h-entry"],
"properties": {
"slug": "wower",
"title": "grrr"
}
});
let create_props: CreationProperties =
serde_json::from_value(props_json_in_str).expect("converted props from json");
assert_eq!(create_props.parameters.slug, Some("wower".to_string()));
}
#[cfg(feature = "experimental_batch")]
mod batch_tests {
use super::*;
use crate::standards::micropub::action::{BatchActionResponse, BatchActionResult};
#[test]
fn batch_action_serialization() {
let create_action = Action::Create {
properties: Box::new(CreationProperties {
r#type: Class::Known(KnownClass::Entry),
parameters: Default::default(),
extra_fields: Default::default(),
}),
files: Default::default(),
};
let batch = Action::Batch {
actions: vec![create_action],
};
let json = batch.into_json();
assert_eq!(json["action"], "batch");
assert!(json["actions"].is_array());
}
#[test]
fn batch_action_deserialization() {
let json = serde_json::json!({
"action": "batch",
"actions": [
{
"type": ["h-entry"],
"properties": {
"content": ["hello world"]
}
}
]
});
let action: Action = serde_json::from_value(json).unwrap();
assert!(matches!(action, Action::Batch { .. }));
}
#[test]
fn batch_response_serialization() {
let response = BatchActionResponse::new(vec![
BatchActionResult::success(0, Some("https://example.com/post/1".parse().unwrap())),
BatchActionResult::failure(1, "Something went wrong".to_string()),
]);
let json = serde_json::to_string(&response).unwrap();
assert!(json.contains("\"index\":0"));
assert!(json.contains("\"success\":true"));
assert!(json.contains("\"index\":1"));
assert!(json.contains("\"success\":false"));
}
#[test]
fn batch_response_deserialization() {
let json = r#"{
"results": [
{"index": 0, "success": true, "location": "https://example.com/post/1"},
{"index": 1, "success": false, "error": "Failed to create post"}
]
}"#;
let response: BatchActionResponse = serde_json::from_str(json).unwrap();
assert_eq!(response.results.len(), 2);
assert!(response.results[0].success);
assert!(!response.results[1].success);
assert_eq!(response.success_count(), 1);
assert_eq!(response.failed_count(), 1);
}
#[test]
fn batch_mixed_actions() {
let json = serde_json::json!({
"action": "batch",
"actions": [
{
"type": ["h-entry"],
"properties": {"content": ["first post"]}
},
{
"action": "delete",
"url": "https://example.com/old-post"
}
]
});
let action: Action = serde_json::from_value(json).unwrap();
if let Action::Batch { actions } = action {
assert_eq!(actions.len(), 2);
assert!(matches!(actions[0], Action::Create { .. }));
assert!(matches!(actions[1], Action::Delete(_)));
} else {
panic!("Expected Batch action");
}
}
}