#![allow(
unused_comparisons,
unused_results,
clippy::approx_constant,
clippy::absurd_extreme_comparisons
)]
use std::collections::HashMap;
use noyalib::{
DuplicateKeyPolicy, Mapping, MappingAny, ParserConfig, Spanned, Tag, TaggedValue, Value,
from_str, from_str_with_config, from_value, to_string,
};
use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize, PartialEq)]
enum Variant {
Unit,
Newtype(i32),
Tuple(i32, String),
Struct { x: i32, y: String },
}
#[test]
fn tagged_value_variants_via_yaml() {
let yaml = "Unit: ~";
let result: Variant = from_str(yaml).unwrap();
assert_eq!(result, Variant::Unit);
let yaml2 = "Newtype: 42";
let result2: Variant = from_str(yaml2).unwrap();
assert_eq!(result2, Variant::Newtype(42));
let yaml3 = "Tuple:\n - 1\n - hello";
let result3: Variant = from_str(yaml3).unwrap();
assert_eq!(result3, Variant::Tuple(1, "hello".into()));
let yaml4 = "Struct:\n x: 10\n y: world";
let result4: Variant = from_str(yaml4).unwrap();
assert_eq!(
result4,
Variant::Struct {
x: 10,
y: "world".into()
}
);
}
#[test]
fn tagged_value_map_access_via_from_value() {
#[derive(Debug, Deserialize, PartialEq)]
enum Color {
Red,
Blue,
}
#[derive(Debug, Deserialize, PartialEq)]
struct Palette {
#[serde(with = "noyalib::with::singleton_map")]
color: Color,
}
let yaml = "color:\n Red: ~";
let p: Palette = from_str(yaml).unwrap();
assert_eq!(p.color, Color::Red);
}
#[test]
fn tagged_value_deserialize_from_map() {
let yaml = "mytag: myval";
let tv: TaggedValue = from_str(yaml).unwrap();
assert_eq!(tv.tag().as_str(), "mytag");
}
#[test]
fn value_deserializer_any_null() {
let v = Value::Null;
let result: () = from_value(&v).unwrap();
assert_eq!(result, ());
}
#[test]
fn value_deserializer_any_bool() {
let v = Value::Bool(true);
let result: bool = from_value(&v).unwrap();
assert!(result);
}
#[test]
fn value_deserializer_any_integer() {
let v = Value::from(42);
let result: i64 = from_value(&v).unwrap();
assert_eq!(result, 42);
}
#[test]
fn value_deserializer_any_float() {
let v = Value::from(3.14);
let result: f64 = from_value(&v).unwrap();
assert!((result - 3.14).abs() < 0.001);
}
#[test]
fn value_deserializer_any_string() {
let v = Value::from("hello");
let result: String = from_value(&v).unwrap();
assert_eq!(result, "hello");
}
#[test]
fn value_deserializer_any_sequence() {
let v = Value::Sequence(vec![Value::from(1), Value::from(2)]);
let result: Vec<i32> = from_value(&v).unwrap();
assert_eq!(result, vec![1, 2]);
}
#[test]
fn value_deserializer_any_mapping() {
let mut m = Mapping::new();
let _ = m.insert("a", Value::from(1));
let v = Value::Mapping(m);
let result: HashMap<String, i32> = from_value(&v).unwrap();
assert_eq!(result["a"], 1);
}
#[test]
fn value_deserializer_any_tagged() {
let yaml = "!!str tagged_string";
let v: Value = from_str(yaml).unwrap();
assert_eq!(v.as_str(), Some("tagged_string"));
}
#[test]
fn value_deserializer_enum_string() {
#[derive(Debug, Deserialize, PartialEq)]
enum Color {
Red,
Blue,
}
let v = Value::from("Red");
let c: Color = from_value(&v).unwrap();
assert_eq!(c, Color::Red);
}
#[test]
fn value_deserializer_enum_tagged() {
let yaml = "Unit: ~";
let result: Variant = from_str(yaml).unwrap();
assert_eq!(result, Variant::Unit);
}
#[test]
fn value_deserializer_struct() {
#[derive(Debug, Deserialize, PartialEq)]
struct Foo {
x: i32,
y: String,
}
let mut m = Mapping::new();
let _ = m.insert("x", Value::from(5));
let _ = m.insert("y", Value::from("hi"));
let v = Value::Mapping(m);
let result: Foo = from_value(&v).unwrap();
assert_eq!(
result,
Foo {
x: 5,
y: "hi".into()
}
);
}
#[test]
fn value_deserializer_spanned_struct() {
let yaml = "name: hello\ncount: 42";
#[derive(Debug, Deserialize)]
struct Cfg {
name: Spanned<String>,
count: Spanned<i64>,
}
let cfg: Cfg = from_str(yaml).unwrap();
assert_eq!(cfg.name.value, "hello");
assert!(cfg.name.start.line() >= 1);
assert!(cfg.name.start.column() >= 0);
assert!(cfg.name.start.index() >= 0);
assert!(cfg.name.end.line() >= 1);
assert!(cfg.name.end.column() >= 0);
assert!(cfg.name.end.index() >= 0);
assert_eq!(cfg.count.value, 42);
}
#[test]
fn value_into_deserializer() {
use serde::de::IntoDeserializer;
let val = Value::from("test");
let deser: &Value = (&val).into_deserializer();
let result: String = Deserialize::deserialize(deser).unwrap();
assert_eq!(result, "test");
}
#[test]
fn apply_merge_sequence_in_merge() {
let mut m = Mapping::new();
let _ = m.insert("<<", Value::Sequence(vec![Value::Sequence(vec![])]));
let mut v = Value::Mapping(m);
assert!(v.apply_merge().is_err());
}
#[test]
fn apply_merge_tagged_in_merge() {
let mut m = Mapping::new();
let _ = m.insert(
"<<",
Value::Tagged(Box::new(TaggedValue::new(Tag::new("t"), Value::Null))),
);
let mut v = Value::Mapping(m);
assert!(v.apply_merge().is_err());
}
#[test]
fn apply_merge_scalar_in_merge() {
let mut m = Mapping::new();
let _ = m.insert("<<", Value::from("scalar"));
let mut v = Value::Mapping(m);
assert!(v.apply_merge().is_err());
}
#[test]
fn apply_merge_on_sequence() {
let mut v = Value::Sequence(vec![Value::from(1), Value::from(2)]);
assert!(v.apply_merge().is_ok());
}
#[test]
fn apply_merge_on_tagged() {
let mut v = Value::Tagged(Box::new(TaggedValue::new(
Tag::new("t"),
Value::from("val"),
)));
assert!(v.apply_merge().is_ok());
}
#[test]
fn untag_recursive() {
let seq = Value::Sequence(vec![Value::Tagged(Box::new(TaggedValue::new(
Tag::new("t"),
Value::from(1),
)))]);
let untagged = seq.untag();
if let Value::Sequence(s) = untagged {
assert_eq!(s[0].as_i64(), Some(1));
}
let mut m = Mapping::new();
let _ = m.insert(
"k",
Value::Tagged(Box::new(TaggedValue::new(Tag::new("t"), Value::from(2)))),
);
let v = Value::Mapping(m);
let untagged = v.untag();
if let Value::Mapping(m) = untagged {
assert_eq!(m.get("k").unwrap().as_i64(), Some(2));
}
}
#[test]
fn value_index_or_insert_usize_tagged() {
let mut v = Value::Tagged(Box::new(TaggedValue::new(
Tag::new("s"),
Value::Sequence(vec![Value::from(10)]),
)));
v[0] = Value::from(99);
match &v {
Value::Tagged(t) => match t.value() {
Value::Sequence(s) => assert_eq!(s[0].as_i64(), Some(99)),
_ => panic!("expected sequence"),
},
_ => panic!("expected tagged"),
}
}
#[test]
fn value_index_or_insert_str_tagged() {
let mut m = Mapping::new();
let _ = m.insert("k", Value::from(1));
let mut v = Value::Tagged(Box::new(TaggedValue::new(Tag::new("m"), Value::Mapping(m))));
v["k"] = Value::from(42);
match &v {
Value::Tagged(t) => match t.value() {
Value::Mapping(m) => assert_eq!(m.get("k").unwrap().as_i64(), Some(42)),
_ => panic!("expected mapping"),
},
_ => panic!("expected tagged"),
}
}
#[test]
fn value_index_string_types() {
let mut m = Mapping::new();
let _ = m.insert("key", Value::from(1));
let v = Value::Mapping(m);
let r = v.get("key");
assert!(r.is_some());
assert_eq!(r.unwrap().as_i64(), Some(1));
}
#[test]
fn value_index_with_value_integer() {
let v = Value::Sequence(vec![Value::from(10), Value::from(20)]);
let idx = Value::from(0i64);
let result = v.get(&idx);
assert!(result.is_some());
}
#[test]
fn value_index_with_value_string() {
let mut m = Mapping::new();
let _ = m.insert("k", Value::from(1));
let v = Value::Mapping(m);
let idx = Value::from("k");
let result = v.get(&idx);
assert!(result.is_some());
}
#[test]
fn mapping_any_ord_equal_keys_equal_values() {
let mut m1 = MappingAny::new();
let mut m2 = MappingAny::new();
let _ = m1.insert(Value::from("a"), Value::from(1));
let _ = m1.insert(Value::from("b"), Value::from(2));
let _ = m2.insert(Value::from("a"), Value::from(1));
let _ = m2.insert(Value::from("b"), Value::from(2));
assert_eq!(m1.cmp(&m2), std::cmp::Ordering::Equal);
}
#[test]
fn get_path_with_bracket_edge_case() {
let yaml = "a:\n b: 1";
let v: Value = from_str(yaml).unwrap();
let _ = v.get_path("a]b");
let _ = v.get_path("a[0]");
}
#[test]
fn single_quoted_multiline_with_breaks() {
let yaml = "key: 'first line\n second line\n\n after blank'";
let v: Value = from_str(yaml).unwrap();
let s = v["key"].as_str().unwrap();
assert!(s.contains("first"), "got: {s:?}");
}
#[test]
fn single_quoted_with_escaped_quotes_and_spaces() {
let yaml = "key: 'it''s spaced'";
let v: Value = from_str(yaml).unwrap();
assert_eq!(v["key"].as_str().unwrap(), "it's spaced");
}
#[test]
fn single_quoted_unterminated() {
let result: Result<Value, _> = from_str("key: 'unterminated");
assert!(result.is_err());
}
#[test]
fn double_quoted_unterminated() {
let result: Result<Value, _> = from_str("key: \"unterminated");
assert!(result.is_err());
}
#[test]
fn double_quoted_multiline_with_folding() {
let yaml = "key: \"first\n second\n\n after blank\"";
let v: Value = from_str(yaml).unwrap();
let s = v["key"].as_str().unwrap();
assert!(s.contains("first"), "got: {s:?}");
}
#[test]
fn double_quoted_all_escapes() {
let yaml = "a: \"\\0\\a\\b\\t\\n\\v\\f\\r\\e\\ \\\"\\/\\\\\\N\\_\\L\\P\"";
let v: Value = from_str(yaml).unwrap();
let s = v["a"].as_str().unwrap();
assert!(s.contains('\0'));
assert!(s.contains('\x07'));
assert!(s.contains('\t'));
assert!(s.contains('\n'));
}
#[test]
fn double_quoted_hex_escapes() {
let yaml = "a: \"\\x41\\u0042\\U00000043\"";
let v: Value = from_str(yaml).unwrap();
assert_eq!(v["a"].as_str().unwrap(), "ABC");
}
#[test]
fn double_quoted_line_continuation() {
let yaml = "key: \"line1\\\n line2\"";
let v: Value = from_str(yaml).unwrap();
assert_eq!(v["key"].as_str().unwrap(), "line1line2");
}
#[test]
fn double_quoted_unknown_escape() {
let result: Result<Value, _> = from_str("key: \"\\q\"");
assert!(result.is_err());
}
#[test]
fn double_quoted_invalid_unicode() {
let result: Result<Value, _> = from_str("key: \"\\UD800\"");
assert!(result.is_err());
}
#[test]
fn block_literal_with_empty_first_line() {
let yaml = "key: |\n\n\n content\n";
let v: Value = from_str(yaml).unwrap();
let s = v["key"].as_str().unwrap();
assert!(s.contains("content"));
}
#[test]
fn block_literal_end_by_dedent() {
let yaml = "key: |\n block content\nnot_block: val";
let v: Value = from_str(yaml).unwrap();
assert_eq!(v["key"].as_str().unwrap(), "block content\n");
assert_eq!(v["not_block"].as_str().unwrap(), "val");
}
#[test]
fn block_literal_eof_terminates() {
let yaml = "key: |\n content";
let v: Value = from_str(yaml).unwrap();
assert!(v["key"].as_str().unwrap().contains("content"));
}
#[test]
fn block_folded_leading_blank_preserves_newline() {
let yaml = "key: >\n normal\n indented\n back";
let v: Value = from_str(yaml).unwrap();
let s = v["key"].as_str().unwrap();
assert!(s.contains('\n'));
}
#[test]
fn block_literal_utf8_content() {
let yaml = "key: |\n café ñ 日本語";
let v: Value = from_str(yaml).unwrap();
let s = v["key"].as_str().unwrap();
assert!(s.contains("café"));
}
#[test]
fn block_clip_chomping() {
let yaml = "key: |\n content\n\n\n";
let v: Value = from_str(yaml).unwrap();
assert_eq!(v["key"].as_str().unwrap(), "content\n");
}
#[test]
fn scan_error_display() {
let result: Result<Value, _> = from_str("key: \"\\q\"");
let err = result.unwrap_err();
let msg = err.to_string();
assert!(!msg.is_empty());
}
#[test]
fn crlf_line_endings() {
let yaml = "key: value\r\nkey2: value2\r\n";
let v: Value = from_str(yaml).unwrap();
assert_eq!(v["key2"].as_str().unwrap(), "value2");
}
#[test]
fn flow_context_roll_indent() {
let yaml = "[1, [2, 3], {a: b}]";
let v: Value = from_str(yaml).unwrap();
assert!(v.as_sequence().is_some());
}
#[test]
fn bom_at_start() {
let yaml = "\u{FEFF}key: value";
let v: Value = from_str(yaml).unwrap();
assert_eq!(v["key"].as_str().unwrap(), "value");
}
#[test]
fn flow_value_and_key_context() {
let yaml = "{a: 1, b: 2, c: [3, 4]}";
let v: Value = from_str(yaml).unwrap();
assert_eq!(v["a"].as_i64(), Some(1));
assert_eq!(v["b"].as_i64(), Some(2));
}
#[test]
fn implicit_key_value() {
let yaml = "simple: value\nnested:\n inner: deep";
let v: Value = from_str(yaml).unwrap();
assert_eq!(v["nested"]["inner"].as_str(), Some("deep"));
}
#[test]
fn plain_scalar_multiline() {
let yaml = "key: this is\n a multiline\n plain scalar";
let v: Value = from_str(yaml).unwrap();
let s = v["key"].as_str().unwrap();
assert!(s.contains("this is"));
assert!(s.contains("multiline"));
}
#[test]
fn multi_document_with_end_markers() {
let yaml = "---\nfirst: 1\n...\n---\nsecond: 2\n...\n---\n...\n";
let docs = noyalib::load_all(yaml).unwrap();
assert!(docs.len() >= 2);
}
#[test]
fn block_sequence_with_empty_entries() {
let yaml = "- \n- value\n- ";
let v: Value = from_str(yaml).unwrap();
let seq = v.as_sequence().unwrap();
assert!(seq.len() >= 2);
}
#[test]
fn explicit_key_mapping() {
let yaml = "? explicit_key\n: explicit_value\n? another\n: value2";
let v: Value = from_str(yaml).unwrap();
assert_eq!(v["explicit_key"].as_str(), Some("explicit_value"));
}
#[test]
fn flow_mapping_entries() {
let yaml = "{a: 1, b: , c: 3}";
let v: Value = from_str(yaml).unwrap();
assert_eq!(v["a"].as_i64(), Some(1));
assert!(v["b"].is_null());
}
#[test]
fn flow_sequence_with_implicit_mapping() {
let yaml = "[{a: 1}, b, c: d]";
let v: Value = from_str(yaml).unwrap();
assert!(v.as_sequence().is_some());
}
#[test]
fn anchor_with_tag() {
let yaml = "key: &anc !!str tagged_and_anchored\nref: *anc";
let v: Value = from_str(yaml).unwrap();
let s = v["ref"].as_str().unwrap();
assert_eq!(s, "tagged_and_anchored");
}
#[test]
fn block_mapping_empty_value() {
let yaml = "key1:\nkey2: value2";
let v: Value = from_str(yaml).unwrap();
assert!(v["key1"].is_null());
assert_eq!(v["key2"].as_str(), Some("value2"));
}
#[test]
fn indentless_sequence_after_key() {
let yaml = "items:\n - a\n - b\n - c";
let v: Value = from_str(yaml).unwrap();
let seq = v["items"].as_sequence().unwrap();
assert_eq!(seq.len(), 3);
}
#[test]
fn loader_multi_document() {
let yaml = "---\na: 1\n...\n---\nb: 2\n...";
let docs = noyalib::load_all(yaml).unwrap();
let collected: Vec<_> = docs.collect();
assert_eq!(collected.len(), 2);
}
#[test]
fn loader_sequence_with_anchor() {
let yaml = "&seq\n- 1\n- 2\n- 3";
let v: Value = from_str(yaml).unwrap();
assert_eq!(v.as_sequence().unwrap().len(), 3);
}
#[test]
fn loader_merge_key_from_anchor() {
let yaml = "defaults: &d\n a: 1\n b: 2\nitem:\n <<: *d\n c: 3";
let v: Value = from_str(yaml).unwrap();
assert_eq!(v["item"]["a"].as_i64(), Some(1));
assert_eq!(v["item"]["c"].as_i64(), Some(3));
}
#[test]
fn loader_duplicate_key_error() {
let config = ParserConfig::new().duplicate_key_policy(DuplicateKeyPolicy::Error);
let result: Result<Value, _> = from_str_with_config("a: 1\na: 2", &config);
assert!(result.is_err());
}
#[test]
fn loader_duplicate_key_first() {
let config = ParserConfig::new().duplicate_key_policy(DuplicateKeyPolicy::First);
let v: Value = from_str_with_config("a: 1\na: 2", &config).unwrap();
assert_eq!(v["a"].as_i64(), Some(1));
}
#[test]
fn loader_mapping_key_push_value() {
let yaml = "a: 1\nb: 2\nc: 3";
let v: Value = from_str(yaml).unwrap();
assert_eq!(v.as_mapping().unwrap().len(), 3);
}
#[test]
fn loader_merge_in_value() {
let yaml = "base: &base\n x: 1\nchild:\n <<: *base\n y: 2";
let v: Value = from_str(yaml).unwrap();
assert_eq!(v["child"]["x"].as_i64(), Some(1));
}
#[test]
fn loader_tagged_scalar_custom() {
let yaml = "!custom value";
let v: Value = from_str(yaml).unwrap();
assert!(!v.is_null(), "got: {v:?}");
}
#[test]
fn loader_hex_octal_integers() {
let yaml = "hex: 0xFF\noctal: 0o77";
let v: Value = from_str(yaml).unwrap();
assert_eq!(v["hex"].as_i64(), Some(255));
assert_eq!(v["octal"].as_i64(), Some(63));
}
#[test]
fn loader_large_integer_overflow() {
let yaml = "big: 99999999999999999999";
let v: Value = from_str(yaml).unwrap();
assert!(v["big"].as_f64().is_some());
}
#[test]
fn deserialize_identifier_for_enum() {
#[derive(Debug, Deserialize, PartialEq)]
enum Dir {
North,
South,
}
let v: Dir = from_str("North").unwrap();
assert_eq!(v, Dir::North);
}
#[test]
fn spanned_all_location_fields() {
let yaml = "hello";
let s: Spanned<String> = from_str(yaml).unwrap();
assert_eq!(s.value, "hello");
let _ = s.start.line();
let _ = s.start.column();
let _ = s.start.index();
let _ = s.end.line();
let _ = s.end.column();
let _ = s.end.index();
}
#[test]
fn serialize_tagged_custom_tag() {
let tagged = TaggedValue::new(Tag::new("!color"), Value::from("red"));
let v = Value::Tagged(Box::new(tagged));
let s = to_string(&v).unwrap();
assert!(s.contains("!color"), "{s}");
assert!(s.contains("red"), "{s}");
}
#[test]
fn serialize_empty_string_quoted() {
let v = Value::from("");
let s = to_string(&v).unwrap();
assert!(s.contains("''") || s.contains("\"\"") || s.trim().is_empty());
}
#[test]
fn serialize_string_with_control_char() {
let v = Value::from("hello\x07world");
let s = to_string(&v).unwrap();
assert!(s.contains('"') || s.contains("\\a"), "{s}");
}
#[test]
fn serialize_internal_tag_fallbacks() {
let v = Value::Tagged(Box::new(TaggedValue::new(
Tag::new("__noya_unknown"),
Value::from(42),
)));
let s = to_string(&v).unwrap();
assert!(s.contains("42"), "{s}");
}
#[test]
fn serialize_number_like_strings() {
let v = Value::from(".inf");
let s = to_string(&v).unwrap();
assert!(s.contains('\'') || s.contains('"'), "got: {s}");
}
#[test]
fn singleton_map_with_serialize_deserialize() {
#[derive(Debug, Serialize, Deserialize, PartialEq)]
enum Action {
GetRequest,
PostData,
}
fn my_ser<S: serde::Serializer>(v: &Action, s: S) -> Result<S::Ok, S::Error> {
noyalib::with::singleton_map_with::serialize_with(v, s, |k| {
noyalib::with::singleton_map_with::to_snake_case(k)
})
}
fn my_de<'de, D: serde::Deserializer<'de>>(d: D) -> Result<Action, D::Error> {
noyalib::with::singleton_map_with::deserialize_with(d, |k| {
noyalib::with::singleton_map_with::to_pascal_case(k)
})
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct Cmd {
#[serde(serialize_with = "my_ser", deserialize_with = "my_de")]
action: Action,
}
let cmd = Cmd {
action: Action::GetRequest,
};
let yaml = to_string(&cmd).unwrap();
assert!(yaml.contains("get_request"), "got: {yaml}");
let rt: Cmd = from_str(&yaml).unwrap();
assert_eq!(rt, cmd);
}
#[test]
fn singleton_map_with_unit_variant() {
#[derive(Debug, Serialize, Deserialize, PartialEq)]
enum Flag {
Active,
}
fn my_ser<S: serde::Serializer>(v: &Flag, s: S) -> Result<S::Ok, S::Error> {
noyalib::with::singleton_map_with::serialize_with(v, s, |k| k.to_lowercase())
}
fn my_de<'de, D: serde::Deserializer<'de>>(d: D) -> Result<Flag, D::Error> {
noyalib::with::singleton_map_with::deserialize_with(d, |k| {
let mut c = k.chars();
match c.next() {
Some(f) => f.to_uppercase().to_string() + c.as_str(),
None => String::new(),
}
})
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct Config {
#[serde(serialize_with = "my_ser", deserialize_with = "my_de")]
flag: Flag,
}
let cfg = Config { flag: Flag::Active };
let yaml = to_string(&cfg).unwrap();
assert!(yaml.contains("active"), "got: {yaml}");
let rt: Config = from_str(&yaml).unwrap();
assert_eq!(rt, cfg);
}
#[test]
fn from_kebab_case_edge_cases() {
use noyalib::with::singleton_map_with::from_kebab_case;
assert_eq!(from_kebab_case(""), "");
assert_eq!(from_kebab_case("-"), "");
assert_eq!(from_kebab_case("a--b"), "AB");
}
#[test]
fn singleton_map_recursive_tagged_value() {
#[derive(Debug, Serialize, Deserialize, PartialEq)]
enum Op {
Add(i32),
Sub(i32),
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]
struct Ops {
#[serde(with = "noyalib::with::singleton_map_recursive")]
ops: Vec<Op>,
}
let ops = Ops {
ops: vec![Op::Add(1), Op::Sub(2)],
};
let yaml = to_string(&ops).unwrap();
let rt: Ops = from_str(&yaml).unwrap();
assert_eq!(rt, ops);
}
#[test]
fn path_parent_and_depth() {
use noyalib::Path;
let root = Path::Root;
assert!(root.parent().is_none());
assert_eq!(root.depth(), 0);
let seq = root.index(0);
assert!(seq.parent().is_some());
assert_eq!(seq.depth(), 1);
let map = root.key("k");
assert!(map.parent().is_some());
assert_eq!(map.depth(), 1);
let seq2 = map.index(0);
let deep = seq2.key("nested");
assert_eq!(deep.depth(), 3);
}
#[test]
fn commented_roundtrip_no_comment() {
use noyalib::Commented;
let c = Commented::new("hello", "my comment");
let yaml = to_string(&c).unwrap();
assert!(yaml.contains("# my comment"));
let rt: Commented<String> = from_str(&yaml).unwrap();
assert_eq!(rt.value, "hello");
assert!(rt.comment.is_empty());
}
#[test]
fn alias_unknown_anchor_error() {
let result: Result<Value, _> = from_str("key: *nonexistent");
assert!(result.is_err());
}
#[test]
fn mapping_with_anchored_value() {
let yaml = "&map\na: 1\nb: 2";
let v: Value = from_str(yaml).unwrap();
assert_eq!(v["a"].as_i64(), Some(1));
}
#[test]
fn merge_key_sequence_of_mappings() {
let yaml = "a: &a\n x: 1\nb: &b\n y: 2\nc:\n <<:\n - *a\n - *b\n z: 3";
let v: Value = from_str(yaml).unwrap();
assert_eq!(v["c"]["x"].as_i64(), Some(1));
assert_eq!(v["c"]["y"].as_i64(), Some(2));
assert_eq!(v["c"]["z"].as_i64(), Some(3));
}
#[test]
fn spanned_nested_fields() {
#[derive(Debug, Deserialize)]
struct Item {
name: Spanned<String>,
value: Spanned<i64>,
}
let yaml = "name: test\nvalue: 42";
let item: Item = from_str(yaml).unwrap();
assert_eq!(item.name.value, "test");
assert_eq!(item.value.value, 42);
assert!(item.name.start.line() >= 1);
assert!(item.value.start.line() >= 1);
}
#[test]
fn load_all_as_with_spans() {
#[derive(Debug, Deserialize)]
#[allow(dead_code)]
struct Doc {
name: String,
}
let yaml = "---\nname: a\n---\nname: b";
let docs: Vec<Doc> = noyalib::load_all_as(yaml).unwrap();
assert_eq!(docs.len(), 2);
}