#![allow(missing_docs)]
#![allow(clippy::unwrap_used)]
use noyalib::borrowed::TransformReason;
use noyalib::from_str_borrowing;
use serde::Deserialize;
use std::borrow::Cow;
#[test]
fn cow_str_target_handles_plain_and_escaped() {
#[derive(Debug, Deserialize)]
struct CowDoc<'a> {
#[serde(borrow)]
plain: Cow<'a, str>,
#[serde(borrow)]
escaped: Cow<'a, str>,
}
let yaml = "plain: hello\nescaped: \"line\\nbreak\"\n";
let v: CowDoc<'_> = from_str_borrowing(yaml).unwrap();
assert_eq!(v.plain, "hello");
assert_eq!(v.escaped, "line\nbreak");
}
#[test]
fn terminal_scalar_borrows_zero_copy() {
let yaml = "value: terminal";
#[derive(Debug, Deserialize)]
struct One<'a> {
value: &'a str,
}
let v: One<'_> = from_str_borrowing(yaml).unwrap();
assert_eq!(v.value, "terminal");
let yaml_range = yaml.as_ptr() as usize..(yaml.as_ptr() as usize + yaml.len());
assert!(
yaml_range.contains(&(v.value.as_ptr() as usize)),
"scalar should borrow from input slice"
);
}
#[test]
fn typical_yaml_borrows_zero_copy() {
#[derive(Debug, Deserialize)]
struct Doc<'a> {
name: &'a str,
role: &'a str,
}
let yaml = "name: noyalib\nrole: parser\n";
let v: Doc<'_> = from_str_borrowing(yaml).unwrap();
assert_eq!(v.name, "noyalib");
assert_eq!(v.role, "parser");
let yaml_range = yaml.as_ptr() as usize..(yaml.as_ptr() as usize + yaml.len());
assert!(yaml_range.contains(&(v.name.as_ptr() as usize)));
assert!(yaml_range.contains(&(v.role.as_ptr() as usize)));
}
#[test]
fn cow_target_works_with_typical_yaml() {
#[derive(Debug, Deserialize)]
struct One<'a> {
#[serde(borrow)]
value: Cow<'a, str>,
}
let v: One<'_> = from_str_borrowing("value: hello\n").unwrap();
assert_eq!(v.value, "hello");
}
#[test]
fn strict_str_target_errors_clearly_when_owned() {
#[derive(Debug, Deserialize)]
struct One<'a> {
#[allow(dead_code)]
s: &'a str,
}
let yaml = "s: \"with\\nescape\"\n";
let res: Result<One<'_>, _> = from_str_borrowing(yaml);
assert!(res.is_err(), "expected borrow failure on escaped scalar");
}
#[test]
fn transform_reason_messages_are_stable() {
assert!(TransformReason::EscapeSequence.as_str().contains("escape"));
assert!(TransformReason::LineFold.as_str().contains("line"));
assert!(TransformReason::TagResolution.as_str().contains("tag"));
assert!(TransformReason::QuotedScalar.as_str().contains("quoted"));
assert!(TransformReason::AliasExpansion.as_str().contains("alias"));
}
#[test]
fn transform_reason_implements_display() {
use core::fmt::Write;
let mut s = String::new();
write!(&mut s, "{}", TransformReason::LineFold).unwrap();
assert!(s.contains("line"));
}
#[test]
fn transform_reason_traits() {
let a = TransformReason::EscapeSequence;
let b = a;
assert_eq!(a, b);
let mut hasher = std::collections::hash_map::DefaultHasher::new();
use core::hash::Hasher;
use std::hash::Hash;
a.hash(&mut hasher);
let _ = hasher.finish();
let dbg = format!("{a:?}");
assert!(dbg.contains("Escape"));
}
#[test]
fn from_str_borrowing_with_config_respects_strict_mode() {
use noyalib::ParserConfig;
let cfg = ParserConfig::strict();
let s: Cow<'_, str> = noyalib::from_str_borrowing_with_config("hello\n", &cfg).unwrap();
assert_eq!(s, "hello");
}
#[test]
fn from_str_borrowing_rejects_oversize_input() {
use noyalib::ParserConfig;
let cfg = ParserConfig::new().max_document_length(4);
let res: Result<Cow<'_, str>, _> =
noyalib::from_str_borrowing_with_config("hello world\n", &cfg);
assert!(res.is_err(), "oversize input must error");
}