use std::collections::BTreeMap;
use jsonapi_core::{
Document, Identity, PrimaryData, Registry, Relationship, RelationshipData, Resource,
ResourceIdentifier, ResourceObject,
};
#[test]
fn test_spec_compound_document() {
let json = r#"{
"data": {
"type": "articles",
"id": "1",
"attributes": {
"title": "JSON:API paints my bikeshed!"
},
"relationships": {
"author": {
"data": {"type": "people", "id": "9"}
},
"comments": {
"data": [
{"type": "comments", "id": "5"},
{"type": "comments", "id": "12"}
]
}
},
"links": {
"self": "http://example.com/articles/1"
}
},
"included": [
{
"type": "people",
"id": "9",
"attributes": {
"first-name": "Dan",
"last-name": "Gebhardt",
"twitter": "dgeb"
},
"links": {
"self": "http://example.com/people/9"
}
},
{
"type": "comments",
"id": "5",
"attributes": {
"body": "First!"
},
"links": {
"self": "http://example.com/comments/5"
}
},
{
"type": "comments",
"id": "12",
"attributes": {
"body": "I like XML better"
},
"links": {
"self": "http://example.com/comments/12"
}
}
]
}"#;
let doc: Document<Resource> = serde_json::from_str(json).unwrap();
match &doc {
Document::Data {
data,
included,
links,
..
} => {
let article = match data {
PrimaryData::Single(r) => r.as_ref(),
_ => panic!("expected single resource"),
};
assert_eq!(article.resource_type(), "articles");
assert_eq!(article.resource_id(), Some("1"));
assert_eq!(article.attributes["title"], "JSON:API paints my bikeshed!");
assert!(article.relationships.contains_key("author"));
assert!(article.relationships.contains_key("comments"));
match &article.relationships["comments"] {
RelationshipData::ToMany(rids) => assert_eq!(rids.len(), 2),
_ => panic!("expected to-many"),
}
assert_eq!(included.len(), 3);
let registry = Registry::from_included(included).unwrap();
let dan: Resource = registry.get_by_id("people", "9").unwrap();
assert_eq!(dan.attributes["first-name"], "Dan");
let comment: Resource = registry.get_by_id("comments", "5").unwrap();
assert_eq!(comment.attributes["body"], "First!");
let _ = links;
}
_ => panic!("expected Document::Data"),
}
let serialized = serde_json::to_string(&doc).unwrap();
let _reparsed: Document<Resource> = serde_json::from_str(&serialized).unwrap();
}
#[test]
fn test_error_document() {
let json = r#"{
"errors": [
{
"status": "422",
"source": {"pointer": "/data/attributes/first-name"},
"title": "Invalid Attribute",
"detail": "First name must contain at least two characters."
}
],
"jsonapi": {"version": "1.1"}
}"#;
let doc: Document<Resource> = serde_json::from_str(json).unwrap();
match &doc {
Document::Errors {
errors, jsonapi, ..
} => {
assert_eq!(errors.len(), 1);
assert_eq!(errors[0].status.as_deref(), Some("422"));
assert_eq!(
errors[0].source.as_ref().unwrap().pointer.as_deref(),
Some("/data/attributes/first-name")
);
assert_eq!(jsonapi.as_ref().unwrap().version.as_deref(), Some("1.1"));
}
_ => panic!("expected Document::Errors"),
}
let serialized = serde_json::to_string(&doc).unwrap();
let _reparsed: Document<Resource> = serde_json::from_str(&serialized).unwrap();
}
#[test]
fn test_meta_only_document() {
let json = r#"{"meta":{"total-pages":13}}"#;
let doc: Document<Resource> = serde_json::from_str(json).unwrap();
match &doc {
Document::Meta { meta, .. } => {
assert_eq!(meta["total-pages"], 13);
}
_ => panic!("expected Document::Meta"),
}
}
#[test]
fn test_reject_data_and_errors() {
let json = r#"{"data":null,"errors":[]}"#;
let result: Result<Document<Resource>, _> = serde_json::from_str(json);
assert!(result.is_err());
assert!(
result
.unwrap_err()
.to_string()
.contains("must not contain both")
);
}
#[test]
fn test_reject_empty_document() {
let json = "{}";
let result: Result<Document<Resource>, _> = serde_json::from_str(json);
assert!(result.is_err());
}
#[test]
fn test_lid_only_identifier() {
let json = r#"{"type":"articles","lid":"temp-1"}"#;
let rid: ResourceIdentifier = serde_json::from_str(json).unwrap();
assert_eq!(rid.identity, Identity::Lid("temp-1".into()));
assert_eq!(serde_json::to_string(&rid).unwrap(), json);
}
#[test]
fn test_null_data_document() {
let json = r#"{"data":null}"#;
let doc: Document<Resource> = serde_json::from_str(json).unwrap();
match doc {
Document::Data {
data: PrimaryData::Null,
included,
..
} => assert!(included.is_empty()),
_ => panic!("expected Data with Null"),
}
}
#[test]
fn test_registry_get_via_relationship() {
let included = vec![Resource {
type_: "people".into(),
id: Some("9".into()),
lid: None,
attributes: serde_json::json!({"name": "Dan"}),
relationships: BTreeMap::new(),
links: None,
meta: None,
}];
let registry = Registry::from_included(&included).unwrap();
let rel: Relationship<Resource> =
Relationship::new(RelationshipData::ToOne(Some(ResourceIdentifier {
type_: "people".into(),
identity: Identity::Id("9".into()),
meta: None,
})));
let person: Resource = registry.get(&rel).unwrap();
assert_eq!(person.attributes["name"], "Dan");
}