use std::collections::BTreeMap;
use noyalib::{Mapping, ParserConfig, Value};
#[derive(Debug, serde::Deserialize, serde::Serialize, PartialEq)]
struct Cfg {
name: String,
port: u16,
enabled: bool,
}
#[test]
fn from_str_with_explicit_merge_policy_routes_through_ast() {
let yaml = "\
defaults: &defaults
retry: 3
prod:
<<: *defaults
region: us-east-1
";
let cfg = ParserConfig::default().merge_key_policy(noyalib::MergeKeyPolicy::AsOrdinary);
let v: Value = noyalib::from_str_with_config(yaml, &cfg).expect("parse");
let m = v.as_mapping().expect("map");
let prod = m.get("prod").and_then(|v| v.as_mapping()).expect("prod");
assert!(prod.contains_key("region"));
}
#[test]
fn from_str_with_binary_tag_ignored_for_string() {
let yaml = "data: !!binary SGVsbG8=\n";
let cfg = ParserConfig::default().ignore_binary_tag_for_string(true);
let m: BTreeMap<String, String> = noyalib::from_str_with_config(yaml, &cfg).expect("parse");
assert_eq!(m.get("data").map(String::as_str), Some("SGVsbG8="));
}
#[test]
fn from_value_into_typed_struct() {
let v = Value::Mapping(Mapping::from_iter([
("name".to_string(), Value::String("noyalib".into())),
("port".to_string(), Value::from(8080_i64)),
("enabled".to_string(), Value::Bool(true)),
]));
let cfg: Cfg = noyalib::from_value(&v).expect("from_value typed");
assert_eq!(cfg.name, "noyalib");
assert_eq!(cfg.port, 8080);
assert!(cfg.enabled);
}
#[test]
fn from_value_into_value_clones_directly() {
let original = Value::Mapping(Mapping::from_iter([("a".to_string(), Value::from(1_i64))]));
let cloned: Value = noyalib::from_value(&original).expect("from_value Value");
assert_eq!(original, cloned);
}
#[test]
fn from_value_into_btreemap() {
let v = Value::Mapping(Mapping::from_iter([
("alpha".to_string(), Value::from(1_i64)),
("beta".to_string(), Value::from(2_i64)),
]));
let m: BTreeMap<String, i64> = noyalib::from_value(&v).expect("btreemap");
assert_eq!(m.get("alpha"), Some(&1));
assert_eq!(m.get("beta"), Some(&2));
}
#[test]
fn from_slice_handles_valid_utf8() {
let bytes = b"name: noyalib\nport: 8080\nenabled: true\n";
let cfg: Cfg = noyalib::from_slice(bytes).expect("from_slice valid utf8");
assert_eq!(cfg.name, "noyalib");
}
#[test]
fn from_slice_rejects_invalid_utf8() {
let bytes = b"name: \xff\xfeinvalid";
let r: Result<Cfg, _> = noyalib::from_slice(bytes);
assert!(r.is_err(), "must reject non-utf8");
}
#[test]
fn from_slice_into_value() {
let bytes = b"foo: bar\n";
let v: Value = noyalib::from_slice(bytes).expect("from_slice value");
assert_eq!(
v.as_mapping()
.and_then(|m| m.get("foo"))
.and_then(|v| v.as_str()),
Some("bar")
);
}
#[test]
fn from_reader_round_trips_typed() {
let yaml = "name: noyalib\nport: 8080\nenabled: true\n";
let cursor = std::io::Cursor::new(yaml);
let cfg: Cfg = noyalib::from_reader(cursor).expect("from_reader typed");
assert_eq!(cfg.name, "noyalib");
assert_eq!(cfg.port, 8080);
}
#[test]
fn from_reader_into_value() {
let yaml = "foo: bar\nbaz: qux\n";
let cursor = std::io::Cursor::new(yaml);
let v: Value = noyalib::from_reader(cursor).expect("from_reader Value");
assert_eq!(v.as_mapping().map(|m| m.len()), Some(2));
}
#[test]
fn from_reader_with_config() {
let yaml = "key: value\n";
let cursor = std::io::Cursor::new(yaml);
let cfg = ParserConfig::default();
let m: BTreeMap<String, String> =
noyalib::from_reader_with_config(cursor, &cfg).expect("from_reader_with_config");
assert_eq!(m.get("key").map(String::as_str), Some("value"));
}
#[test]
fn from_str_strict_rejects_unknown_field() {
let yaml = "name: noyalib\nport: 8080\nenabled: true\nextra: oops\n";
let r: Result<Cfg, _> = noyalib::from_str_strict(yaml);
assert!(r.is_err(), "strict mode rejects unknown `extra`");
}
#[test]
fn from_str_strict_passes_when_clean() {
let yaml = "name: noyalib\nport: 8080\nenabled: true\n";
let cfg: Cfg = noyalib::from_str_strict(yaml).expect("strict clean");
assert_eq!(cfg.name, "noyalib");
}
#[test]
fn from_slice_strict_rejects_unknown_field() {
let bytes = b"name: x\nport: 1\nenabled: true\nextra: oops\n";
let r: Result<Cfg, _> = noyalib::from_slice_strict(bytes);
assert!(r.is_err());
}
#[test]
fn from_reader_strict_rejects_unknown_field() {
let bytes = b"name: x\nport: 1\nenabled: true\nextra: oops\n";
let cursor = std::io::Cursor::new(bytes);
let r: Result<Cfg, _> = noyalib::from_reader_strict(cursor);
assert!(r.is_err());
}
#[test]
fn from_str_invalid_yaml_returns_error() {
let yaml = "key: [unclosed\n";
let r: Result<Value, _> = noyalib::from_str(yaml);
assert!(r.is_err());
}
#[test]
fn from_str_typed_into_wrong_shape_errors() {
let yaml = "[1, 2, 3]\n";
let r: Result<Cfg, _> = noyalib::from_str(yaml);
assert!(r.is_err(), "sequence cannot deserialise into struct");
}
#[test]
fn deserializer_new_then_deserialize_value() {
use serde::Deserialize;
let v = Value::from(42_i64);
let de = noyalib::Deserializer::new(&v);
let out: i64 = i64::deserialize(de).expect("deserialise i64");
assert_eq!(out, 42);
}