#![allow(missing_docs)]
use std::collections::BTreeMap;
use std::sync::Arc;
use noyalib::{from_str, from_str_with_config, ParserConfig, TagRegistry};
use serde::Deserialize;
use serde_bytes::ByteBuf;
#[test]
fn coverage_stream_merge_value_non_alias_falls_back() {
let yaml = "\
target:
<<:
x: 1
y: 2
";
let m: BTreeMap<String, BTreeMap<String, i64>> = from_str(yaml).expect("ast fallback handles");
assert_eq!(m["target"]["x"], 1);
assert_eq!(m["target"]["y"], 2);
}
#[test]
fn coverage_stream_anchor_with_inner_alias_replay() {
let yaml = "\
shared: &shared 42
container: &c
ref: *shared
copy: *c
";
let v: noyalib::Value = from_str(yaml).expect("alias-in-anchor parses to Value");
let container = v
.get_path("container")
.and_then(|x| x.as_mapping())
.unwrap();
assert_eq!(container.get("ref").and_then(|x| x.as_i64()), Some(42));
let copy = v.get_path("copy").and_then(|x| x.as_mapping()).unwrap();
assert_eq!(copy.get("ref").and_then(|x| x.as_i64()), Some(42));
}
#[test]
fn coverage_stream_anchored_scalar_seq_map_alias() {
let yaml1 = "\
a: &x hello
b: *x
";
let m1: BTreeMap<String, String> = from_str(yaml1).unwrap();
assert_eq!(m1["b"], "hello");
let yaml2 = "\
a: &x [1, 2, 3]
b: *x
";
let m2: BTreeMap<String, Vec<i64>> = from_str(yaml2).unwrap();
assert_eq!(m2["b"], vec![1, 2, 3]);
let yaml3 = "\
a: &x {k: 1}
b: *x
";
let m3: BTreeMap<String, BTreeMap<String, i64>> = from_str(yaml3).unwrap();
assert_eq!(m3["b"]["k"], 1);
}
#[test]
fn coverage_stream_unknown_anchor_alias() {
let yaml = "\
target:
ref: *missing
";
let res: Result<BTreeMap<String, BTreeMap<String, String>>, _> = from_str(yaml);
assert!(res.is_err());
}
#[test]
fn coverage_stream_merge_with_nested_local_content() {
let yaml = "\
base: &b
k1: 1
k2: 2
target:
<<: *b
nested_seq: [a, b, c]
nested_map:
inner: deep
";
let v: BTreeMap<String, BTreeMap<String, noyalib::Value>> = from_str(yaml).unwrap();
let target = &v["target"];
assert_eq!(target["k1"].as_i64(), Some(1));
assert!(target["nested_seq"].is_sequence());
assert!(target["nested_map"].is_mapping());
}
#[test]
fn coverage_stream_merge_with_alias_in_local_tail() {
let yaml = "\
shared: &s deep_value
base: &b
k: 1
target:
<<: *b
copy: *s
";
let v: noyalib::Value = from_str(yaml).expect("alias in local tail parses");
let target = v.get_path("target").and_then(|x| x.as_mapping()).unwrap();
assert_eq!(
target.get("copy").and_then(|x| x.as_str()),
Some("deep_value")
);
}
#[test]
fn coverage_stream_option_some_scalar() {
#[derive(Deserialize)]
struct Doc {
x: Option<i64>,
y: Option<i64>,
}
let yaml = "x: 5\ny: ~\n";
let d: Doc = from_str(yaml).unwrap();
assert_eq!(d.x, Some(5));
assert_eq!(d.y, None);
}
#[test]
fn coverage_stream_ignored_any_skips_complex_value() {
#[derive(Deserialize)]
struct Small {
keep: i64,
}
let yaml = "\
keep: 42
extra:
nested:
- 1
- 2
more:
a: x
b: y
";
let s: Small = from_str(yaml).unwrap();
assert_eq!(s.keep, 42);
}
#[test]
fn coverage_stream_tagged_str_restores_tag_for_fallback() {
#[derive(Deserialize)]
struct Doc {
value: String,
}
let yaml = "value: !!str 42\n";
let d: Doc = from_str(yaml).unwrap();
assert_eq!(d.value, "42");
}
#[test]
fn coverage_stream_seq_via_value_target() {
let yaml = "[1, two, 3.0, true, null]\n";
let v: Vec<noyalib::Value> = from_str(yaml).unwrap();
assert_eq!(v.len(), 5);
assert_eq!(v[0].as_i64(), Some(1));
assert_eq!(v[1].as_str(), Some("two"));
assert!(v[2].as_f64().is_some());
assert_eq!(v[3].as_bool(), Some(true));
assert!(v[4].is_null());
}
#[test]
fn coverage_stream_bool_typemismatch_for_int() {
let res: Result<bool, _> = from_str("42\n");
assert!(res.is_err());
}
#[test]
fn coverage_stream_i64_typemismatch_for_string() {
let res: Result<i64, _> = from_str("hello\n");
assert!(res.is_err());
}
#[test]
fn coverage_stream_i64_accepts_whole_float() {
let n: i64 = from_str("42.0\n").unwrap();
assert_eq!(n, 42);
}
#[test]
fn coverage_stream_u64_typemismatch_for_negative() {
let res: Result<u64, _> = from_str("-1\n");
assert!(res.is_err());
}
#[test]
fn coverage_stream_u64_accepts_whole_nonneg_float() {
let n: u64 = from_str("7.0\n").unwrap();
assert_eq!(n, 7);
}
#[test]
fn coverage_stream_f64_accepts_int() {
let f: f64 = from_str("5\n").unwrap();
assert!((f - 5.0).abs() < 1e-9);
}
#[test]
fn coverage_stream_f64_typemismatch_for_string() {
let res: Result<f64, _> = from_str("not_a_number\n");
assert!(res.is_err());
}
#[test]
fn coverage_stream_str_rejects_non_string_plain() {
let res: Result<String, _> = from_str("42\n");
assert!(res.is_err());
}
#[test]
fn coverage_stream_str_quoted_scalar_passes() {
let s: String = from_str("\"hello\"\n").unwrap();
assert_eq!(s, "hello");
}
#[test]
fn coverage_stream_str_block_scalar_passes() {
let s: String = from_str("|\n block text\n").unwrap();
assert_eq!(s, "block text\n");
}
#[test]
fn coverage_stream_unit_mismatch_errors() {
#[derive(Deserialize)]
#[allow(dead_code)]
struct UnitField {
u: (),
}
let res: Result<UnitField, _> = from_str("u: not_null\n");
assert!(res.is_err());
}
#[test]
fn coverage_stream_unit_struct_accepts_null() {
#[derive(Deserialize)]
struct U;
#[derive(Deserialize)]
#[allow(dead_code)]
struct Doc {
u: U,
}
let _: Doc = from_str("u: ~\n").unwrap();
}
#[test]
fn coverage_stream_spanned_falls_back() {
use noyalib::Spanned;
#[derive(Deserialize)]
struct Doc {
inner: Spanned<String>,
}
let yaml = "inner: hello\n";
let d: Doc = from_str(yaml).unwrap();
assert_eq!(d.inner.value, "hello");
}
#[test]
fn coverage_stream_newtype_with_core_tag() {
#[derive(Deserialize, PartialEq, Debug)]
struct Wrap(i64);
#[derive(Deserialize)]
struct Doc {
v: Wrap,
}
let yaml = "v: !!int 42\n";
let d: Doc = from_str(yaml).unwrap();
assert_eq!(d.v, Wrap(42));
}
#[test]
fn coverage_stream_seq_typemismatch() {
let res: Result<Vec<i64>, _> = from_str("not_a_seq\n");
assert!(res.is_err());
}
#[test]
fn coverage_stream_map_typemismatch() {
let res: Result<BTreeMap<String, i64>, _> = from_str("not_a_map\n");
assert!(res.is_err());
}
#[derive(Debug, Deserialize, PartialEq)]
enum E {
Unit,
Tup(i32, i32),
Strukt { a: i32 },
NewT(String),
}
#[test]
fn coverage_stream_enum_unit_from_scalar() {
#[derive(Deserialize)]
struct Doc {
e: E,
}
let d: Doc = from_str("e: Unit\n").unwrap();
assert_eq!(d.e, E::Unit);
}
#[test]
fn coverage_stream_enum_newtype_variant() {
#[derive(Deserialize)]
struct Doc {
e: E,
}
let d: Doc = from_str("e:\n NewT: hello\n").unwrap();
assert_eq!(d.e, E::NewT("hello".into()));
}
#[test]
fn coverage_stream_enum_struct_variant() {
#[derive(Deserialize)]
struct Doc {
e: E,
}
let d: Doc = from_str("e:\n Strukt:\n a: 1\n").unwrap();
assert_eq!(d.e, E::Strukt { a: 1 });
}
#[test]
fn coverage_stream_enum_tuple_variant() {
#[derive(Deserialize)]
struct Doc {
e: E,
}
let d: Doc = from_str("e:\n Tup: [1, 2]\n").unwrap();
assert_eq!(d.e, E::Tup(1, 2));
}
#[test]
fn coverage_stream_ignored_any_at_top_level() {
use serde::de::IgnoredAny;
let _: IgnoredAny = from_str("a: 1\nb: 2\n").unwrap();
}
#[test]
fn coverage_stream_bytes_from_plain_string() {
#[derive(Deserialize)]
struct Doc {
b: ByteBuf,
}
let d: Doc = from_str("b: hello\n").unwrap();
assert_eq!(d.b.as_ref(), b"hello");
}
#[test]
fn coverage_stream_bytes_rejects_null() {
#[derive(Deserialize)]
#[allow(dead_code)]
struct Doc {
b: ByteBuf,
}
let res: Result<Doc, _> = from_str("b: ~\n");
assert!(res.is_err());
}
#[test]
fn coverage_stream_bytes_rejects_bool() {
#[derive(Deserialize)]
#[allow(dead_code)]
struct Doc {
b: ByteBuf,
}
let res: Result<Doc, _> = from_str("b: true\n");
assert!(res.is_err());
}
#[test]
fn coverage_stream_bytes_rejects_int() {
#[derive(Deserialize)]
#[allow(dead_code)]
struct Doc {
b: ByteBuf,
}
let res: Result<Doc, _> = from_str("b: 42\n");
assert!(res.is_err());
}
#[test]
fn coverage_stream_bytes_rejects_float() {
#[derive(Deserialize)]
#[allow(dead_code)]
struct Doc {
b: ByteBuf,
}
let res: Result<Doc, _> = from_str("b: 3.14\n");
assert!(res.is_err());
}
#[test]
fn coverage_stream_bytes_binary_invalid() {
#[derive(Deserialize)]
#[allow(dead_code)]
struct Doc {
b: ByteBuf,
}
let res: Result<Doc, _> = from_str("b: !!binary \"$$not_b64$$\"\n");
assert!(res.is_err());
}
#[test]
fn coverage_stream_merge_empty_sequence() {
let yaml = "\
target:
<<: []
k: 1
";
let v: BTreeMap<String, BTreeMap<String, i64>> = from_str(yaml).unwrap();
assert_eq!(v["target"]["k"], 1);
}
#[test]
fn coverage_stream_merge_sequence_with_non_alias_falls_back() {
let yaml = "\
target:
<<:
- a: 1
b: 2
";
let v: BTreeMap<String, BTreeMap<String, i64>> = from_str(yaml).unwrap();
assert_eq!(v["target"]["a"], 1);
assert_eq!(v["target"]["b"], 2);
}
#[test]
fn coverage_stream_duplicate_first_skips_later() {
use noyalib::DuplicateKeyPolicy;
let yaml = "k: 1\nk: 2\nk: 3\n";
let cfg = ParserConfig::new().duplicate_key_policy(DuplicateKeyPolicy::First);
let m: BTreeMap<String, i64> = from_str_with_config(yaml, &cfg).unwrap();
assert_eq!(m["k"], 1);
}
#[test]
fn coverage_stream_duplicate_error_returns_error() {
use noyalib::DuplicateKeyPolicy;
let yaml = "k: 1\nk: 2\n";
let cfg = ParserConfig::new().duplicate_key_policy(DuplicateKeyPolicy::Error);
let res: Result<BTreeMap<String, i64>, _> = from_str_with_config(yaml, &cfg);
assert!(res.is_err());
}
#[test]
fn coverage_stream_enum_with_struct_variant_mapping() {
#[derive(Debug, Deserialize, PartialEq)]
enum Choice {
Pair { a: i32, b: i32 },
}
let yaml = "Pair: {a: 1, b: 2}\n";
let c: Choice = from_str(yaml).unwrap();
assert_eq!(c, Choice::Pair { a: 1, b: 2 });
}
#[test]
fn coverage_stream_tag_registry_strips_custom_tag() {
#[derive(Deserialize, PartialEq, Debug)]
struct Celsius(f64);
#[derive(Deserialize)]
struct Doc {
t: Celsius,
}
let registry = Arc::new(TagRegistry::new().with("!Celsius"));
let cfg = ParserConfig::new().tag_registry(Arc::clone(®istry));
let yaml = "t: !Celsius 42.0\n";
let d: Doc = from_str_with_config(yaml, &cfg).unwrap();
assert_eq!(d.t, Celsius(42.0));
}
#[test]
fn coverage_stream_tag_registry_strips_seq_tag() {
let registry = Arc::new(TagRegistry::new().with("!Items"));
let cfg = ParserConfig::new().tag_registry(Arc::clone(®istry));
let yaml = "items: !Items [1, 2, 3]\n";
#[derive(Deserialize)]
struct Doc {
items: Vec<i64>,
}
let d: Doc = from_str_with_config(yaml, &cfg).unwrap();
assert_eq!(d.items, vec![1, 2, 3]);
}
#[test]
fn coverage_stream_tag_registry_strips_map_tag() {
let registry = Arc::new(TagRegistry::new().with("!Cfg"));
let cfg = ParserConfig::new().tag_registry(Arc::clone(®istry));
let yaml = "cfg: !Cfg {a: 1, b: 2}\n";
#[derive(Deserialize)]
struct Doc {
cfg: BTreeMap<String, i64>,
}
let d: Doc = from_str_with_config(yaml, &cfg).unwrap();
assert_eq!(d.cfg["a"], 1);
}
#[test]
fn coverage_stream_unregistered_tag_falls_back() {
let yaml = "v: !Custom 42\n";
let v: noyalib::Value = from_str(yaml).unwrap();
assert!(v.is_mapping());
}
#[test]
fn coverage_stream_legacy_sexagesimal_int() {
let yaml = "60:00\n";
let cfg = ParserConfig::new().legacy_sexagesimal(true);
let n: i64 = from_str_with_config(yaml, &cfg).unwrap();
assert_eq!(n, 3600);
}
#[test]
fn coverage_stream_legacy_sexagesimal_float() {
let yaml = "60:00.5\n";
let cfg = ParserConfig::new().legacy_sexagesimal(true);
let f: f64 = from_str_with_config(yaml, &cfg).unwrap();
assert!((f - 3600.5).abs() < 1e-9);
}
#[test]
fn coverage_stream_legacy_sexagesimal_negative() {
let yaml = "-1:30:00\n";
let cfg = ParserConfig::new().legacy_sexagesimal(true);
let n: i64 = from_str_with_config(yaml, &cfg).unwrap();
assert_eq!(n, -(3600 + 1800));
}
#[test]
fn coverage_stream_legacy_sexagesimal_invalid_falls_through() {
let yaml = "x: 1:99\n";
let cfg = ParserConfig::new().legacy_sexagesimal(true);
let m: BTreeMap<String, String> = from_str_with_config(yaml, &cfg).unwrap();
assert_eq!(m["x"], "1:99");
}
#[test]
fn coverage_stream_legacy_sexagesimal_empty_part() {
let yaml = "x: 1::00\n";
let cfg = ParserConfig::new().legacy_sexagesimal(true);
let m: BTreeMap<String, String> = from_str_with_config(yaml, &cfg).unwrap();
assert_eq!(m["x"], "1::00");
}
#[test]
fn coverage_stream_legacy_sexagesimal_falls_back_to_float() {
let yaml = "1.5\n";
let cfg = ParserConfig::new().legacy_sexagesimal(true);
let f: f64 = from_str_with_config(yaml, &cfg).unwrap();
assert!((f - 1.5).abs() < 1e-9);
}
#[test]
fn coverage_stream_legacy_sexagesimal_falls_back_to_string() {
let yaml = "x: notnum:abc\n";
let cfg = ParserConfig::new().legacy_sexagesimal(true);
let m: BTreeMap<String, String> = from_str_with_config(yaml, &cfg).unwrap();
assert_eq!(m["x"], "notnum:abc");
}
#[test]
fn coverage_stream_hex_integer() {
let n: i64 = from_str("0xFF\n").unwrap();
assert_eq!(n, 255);
}
#[test]
fn coverage_stream_octal_o_prefix() {
let n: i64 = from_str("0o17\n").unwrap();
assert_eq!(n, 15);
}
#[test]
fn coverage_stream_legacy_octal_bare_zero_prefix() {
let yaml = "0644\n";
let cfg = ParserConfig::new().legacy_octal_numbers(true);
let n: i64 = from_str_with_config(yaml, &cfg).unwrap();
assert_eq!(n, 0o644);
}
#[test]
fn coverage_stream_merge_with_nested_seq_in_source() {
let yaml = "\
base: &b
list: [1, 2]
flag: true
target:
<<: *b
extra: x
";
let v: BTreeMap<String, BTreeMap<String, noyalib::Value>> = from_str(yaml).unwrap();
let target = &v["target"];
assert!(target["list"].is_sequence());
assert_eq!(target["flag"].as_bool(), Some(true));
assert_eq!(target["extra"].as_str(), Some("x"));
}
#[test]
fn coverage_stream_merge_with_nested_map_in_source() {
let yaml = "\
base: &b
inner:
a: 1
b: 2
flag: true
target:
<<: *b
extra: x
";
let v: BTreeMap<String, BTreeMap<String, noyalib::Value>> = from_str(yaml).unwrap();
let target = &v["target"];
assert!(target["inner"].is_mapping());
}
#[test]
fn coverage_stream_merge_local_seq_value_releases_d() {
let yaml = "\
base: &b {a: 1}
target:
<<: *b
list: [x, y]
follow: 9
";
let v: BTreeMap<String, BTreeMap<String, noyalib::Value>> = from_str(yaml).unwrap();
let t = &v["target"];
assert!(t["list"].is_sequence());
assert_eq!(t["follow"].as_i64(), Some(9));
}
#[test]
fn coverage_stream_merge_local_alias_value() {
let yaml = "\
base: &b {a: 1}
shared: &s sharedval
target:
<<: *b
ref: *s
follow: 9
";
let v: noyalib::Value = from_str(yaml).expect("alias-as-value tail parses");
let target = v.get_path("target").and_then(|x| x.as_mapping()).unwrap();
assert_eq!(
target.get("ref").and_then(|x| x.as_str()),
Some("sharedval")
);
assert_eq!(target.get("follow").and_then(|x| x.as_i64()), Some(9));
}
#[test]
fn coverage_stream_filter_merge_seq_value() {
let yaml = "\
base: &b
k_seq: [1, 2, 3]
k_str: hello
target:
<<: *b
";
let v: BTreeMap<String, BTreeMap<String, noyalib::Value>> = from_str(yaml).unwrap();
assert!(v["target"]["k_seq"].is_sequence());
}
#[test]
fn coverage_stream_filter_merge_map_value() {
let yaml = "\
base: &b
k_map:
deep: 1
k_str: hello
target:
<<: *b
";
let v: BTreeMap<String, BTreeMap<String, noyalib::Value>> = from_str(yaml).unwrap();
assert!(v["target"]["k_map"].is_mapping());
}
#[test]
fn coverage_stream_filter_merge_local_overrides_source() {
let yaml = "\
base: &b
k: from_base
target:
<<: *b
k: from_local
";
let v: BTreeMap<String, BTreeMap<String, String>> = from_str(yaml).unwrap();
assert_eq!(v["target"]["k"], "from_local");
}
#[test]
fn coverage_stream_recursion_limit_exceeded() {
let yaml = "a:\n b:\n c:\n d: 1\n";
let cfg = ParserConfig::new().max_depth(2);
let res: Result<BTreeMap<String, noyalib::Value>, _> = from_str_with_config(yaml, &cfg);
assert!(res.is_err());
}
#[test]
fn coverage_stream_max_sequence_length_exceeded() {
let yaml = "[1, 2, 3, 4, 5]\n";
let cfg = ParserConfig::new().max_sequence_length(2);
let res: Result<Vec<i64>, _> = from_str_with_config(yaml, &cfg);
assert!(res.is_err());
}
#[test]
fn coverage_stream_max_mapping_keys_exceeded() {
let yaml = "a: 1\nb: 2\nc: 3\n";
let cfg = ParserConfig::new().max_mapping_keys(2);
let res: Result<BTreeMap<String, i64>, _> = from_str_with_config(yaml, &cfg);
assert!(res.is_err());
}
#[test]
fn coverage_stream_max_alias_expansions_exceeded() {
let yaml = "\
a: &a 1
b: &b
- *a
- *a
- *a
c:
- *b
- *b
- *b
";
let cfg = ParserConfig::new().max_alias_expansions(1);
let res: Result<BTreeMap<String, noyalib::Value>, _> = from_str_with_config(yaml, &cfg);
assert!(res.is_err());
}
#[test]
fn coverage_stream_core_tag_str_via_streaming_de() {
let registry = Arc::new(TagRegistry::new().with("!!str"));
let cfg = ParserConfig::new().tag_registry(Arc::clone(®istry));
let yaml = "v: !!str 42\n";
#[derive(Deserialize)]
struct Doc {
v: String,
}
let d: Doc = from_str_with_config(yaml, &cfg).unwrap();
assert_eq!(d.v, "42");
}
#[test]
fn coverage_stream_partial_consumption_drops_seq() {
let yaml = "values:\n - 1\n - 2\n - not_a_number\n";
#[derive(Deserialize)]
#[allow(dead_code)]
struct Doc {
values: Vec<i64>,
}
let res: Result<Doc, _> = from_str(yaml);
assert!(res.is_err());
}
#[test]
fn coverage_stream_trailing_garbage_after_value_propagates() {
let yaml = "key: ok\n: bad\n";
let res: Result<BTreeMap<String, String>, _> = from_str(yaml);
let _ = res;
}