#![cfg(all(feature = "serialize", feature = "deserialize"))]
use serde::Deserialize;
fn unwrap_snippet(err: &serde_saphyr::Error) -> &serde_saphyr::Error {
match err {
serde_saphyr::Error::WithSnippet { error, .. } => error,
other => other,
}
}
#[derive(Debug, Deserialize, PartialEq)]
struct Person {
name: String,
}
#[derive(Debug, Deserialize, PartialEq)]
enum Document {
#[serde(rename = "person")]
Person { name: String, age: u8 },
#[serde(rename = "pet")]
Pet { kind: String },
}
#[test]
fn multiple_documents_one_no_markers() {
let y = "name: John\n";
let docs: Vec<Person> = serde_saphyr::from_multiple(y).expect("parse single doc as multi");
assert_eq!(docs.len(), 1);
assert_eq!(docs[0].name, "John");
}
#[test]
fn single_document_entrypoint_rejects_multiple_documents() {
let y = "name: A\n---\nname: B\n";
let err = serde_saphyr::from_str::<Person>(y).expect_err("expected multi-doc stream to fail");
match unwrap_snippet(&err) {
serde_saphyr::Error::MultipleDocuments { .. } => {}
other => panic!("expected MultipleDocuments error, got {other:?}"),
}
}
#[test]
fn multiple_documents_one_with_markers() {
let y = "---\nname: Jane\n...\n";
let docs: Vec<Person> = serde_saphyr::from_multiple(y).expect("parse single doc delimited");
assert_eq!(docs.len(), 1);
assert_eq!(docs[0].name, "Jane");
}
#[test]
fn multiple_documents_two_documents() {
let y = "name: A\n---\nname: B\n";
let docs: Vec<Person> = serde_saphyr::from_multiple(y).expect("parse two docs");
assert_eq!(docs.len(), 2);
assert_eq!(docs[0].name, "A");
assert_eq!(docs[1].name, "B");
}
#[test]
fn multiple_documents_cross_document_anchor_error() {
let y = "name: &a John\n---\nname: *a\n";
let err = serde_saphyr::from_multiple::<Person>(y)
.expect_err("expected cross-document alias to fail");
match &err {
serde_saphyr::Error::UnknownAnchor { .. } => {}
serde_saphyr::Error::WithSnippet { error, .. }
if matches!(error.as_ref(), serde_saphyr::Error::UnknownAnchor { .. }) => {}
other => panic!("expected unknown anchor error, got {other:?}"),
}
}
#[test]
fn multiple_documents_empty_document_cases() {
let y1 = "---\n...\n";
let docs1: Vec<Person> = serde_saphyr::from_multiple(y1).expect("parse empty doc 1");
assert!(
docs1.is_empty(),
"expected empty vec for explicit empty document, got: {:?}",
docs1
);
let y2 = "---\n";
let docs2: Vec<Person> = serde_saphyr::from_multiple(y2).expect("parse empty doc 2");
assert!(
docs2.is_empty(),
"expected empty vec for start-only empty document, got: {:?}",
docs2
);
let y3 = "---\n---\n...\n";
let docs3: Vec<Person> = serde_saphyr::from_multiple(y3).expect("parse multiple empty docs");
assert!(
docs3.is_empty(),
"expected empty vec when only empty documents present, got: {:?}",
docs3
);
let y4 = "";
let docs4: Vec<Person> =
serde_saphyr::from_multiple(y4).expect("parse completely empty stream");
assert!(
docs4.is_empty(),
"expected empty vec for empty stream, got: {:?}",
docs4
);
}
#[test]
fn multiple_documents_preserve_quoted_null_like_scalars() {
let y = "\"\"\n---\n\"~\"\n---\n\"null\"\n";
let docs: Vec<String> = serde_saphyr::from_multiple(y).expect("parse quoted null-like docs");
assert_eq!(docs, vec![String::new(), "~".to_owned(), "null".to_owned()]);
}
#[test]
fn multiple_documents_strips_bom_and_skips_plain_null_like_documents() {
let y = "\u{FEFF}~\n---\nname: Bom\n---\nnull\n---\nname: Done\n";
let docs: Vec<Person> = serde_saphyr::from_multiple(y).expect("parse documents with BOM");
assert_eq!(
docs,
vec![
Person {
name: "Bom".to_owned(),
},
Person {
name: "Done".to_owned(),
},
]
);
}
#[test]
fn from_slice_multiple_with_options_rejects_invalid_utf8() {
let err = serde_saphyr::from_slice_multiple_with_options::<Person>(
&[0xFF],
serde_saphyr::options! {},
)
.expect_err("invalid UTF-8 input should fail");
assert!(matches!(err, serde_saphyr::Error::InvalidUtf8Input));
}
#[test]
fn multiple_documents_enum_variants() {
let y = "person:\n name: Alice\n age: 30\n---\npet:\n kind: cat\n---\nperson:\n name: Bob\n age: 25\n";
let docs: Vec<Document> = serde_saphyr::from_multiple(y).expect("parse enum documents");
assert_eq!(
docs,
vec![
Document::Person {
name: "Alice".to_owned(),
age: 30,
},
Document::Pet {
kind: "cat".to_owned(),
},
Document::Person {
name: "Bob".to_owned(),
age: 25,
},
],
);
}