use std::collections::HashMap;
use noyalib::{
Mapping, MappingAny, Number, Tag, TaggedValue, Value, from_str, from_value, to_string,
};
use serde::{Deserialize, Serialize};
#[test]
fn mapping_display_multi_entry() {
let mut m = Mapping::new();
let _ = m.insert("a", Value::from(1));
let _ = m.insert("b", Value::from(2));
let _ = m.insert("c", Value::from(3));
let s = format!("{m}");
assert!(s.starts_with('{'));
assert!(s.ends_with('}'));
assert_eq!(s.matches(", ").count(), 2);
assert!(s.contains("a: 1"));
assert!(s.contains("c: 3"));
}
#[test]
fn mapping_serialize_roundtrip() {
let mut m = Mapping::new();
let _ = m.insert("k1", Value::from("v1"));
let _ = m.insert("k2", Value::from(2));
let yaml = to_string(&m).expect("serialize Mapping");
assert!(yaml.contains("k1"));
assert!(yaml.contains("k2"));
}
#[test]
fn mapping_deserialize_directly() {
let yaml = "alpha: 1\nbeta: 2\n";
let m: Mapping = from_str(yaml).expect("deserialize Mapping");
assert_eq!(m.get("alpha").unwrap().as_i64(), Some(1));
assert_eq!(m.get("beta").unwrap().as_i64(), Some(2));
}
#[test]
fn mapping_any_display_multi_entry() {
let mut m = MappingAny::new();
let _ = m.insert(Value::from(1), Value::from("one"));
let _ = m.insert(Value::from(2), Value::from("two"));
let _ = m.insert(Value::from(3), Value::from("three"));
let s = format!("{m}");
assert!(s.starts_with('{'));
assert!(s.ends_with('}'));
assert_eq!(s.matches(", ").count(), 2);
}
#[test]
fn mapping_any_serialize_roundtrip() {
let mut m = MappingAny::new();
let _ = m.insert(Value::from("a"), Value::from(1));
let _ = m.insert(Value::from("b"), Value::from(2));
let yaml = to_string(&m).expect("serialize MappingAny");
assert!(yaml.contains("a"));
assert!(yaml.contains("b"));
}
#[test]
fn mapping_any_deserialize_directly() {
let yaml = "alpha: 1\nbeta: 2\n";
let m: MappingAny = from_str(yaml).expect("deserialize MappingAny");
assert_eq!(m.len(), 2);
}
#[test]
fn number_cmp_large_integer_vs_float_round_trip() {
let big = 1_i64 << 54;
let i = Number::Integer(big);
let f = Number::Float(big as f64);
assert_eq!(i.cmp(&f), std::cmp::Ordering::Equal);
}
#[test]
fn number_cmp_large_negative_integer_vs_float() {
let big = -(1_i64 << 60) - 1;
let i = Number::Integer(big);
let f = Number::Float(-1.0e30);
let _ = i.cmp(&f);
let _ = f.cmp(&i);
}
#[test]
fn number_cmp_large_pos_integer_with_small_float() {
let big = (1_i64 << 60) + 1;
let i = Number::Integer(big);
let f = Number::Float(1.0);
assert!(i > f);
assert!(f < i);
}
#[test]
fn number_cmp_nan_int() {
let i = Number::Integer(0);
let nan = Number::Float(f64::NAN);
assert!(i < nan);
assert!(nan > i);
}
#[test]
fn tagged_value_serialize_direct() {
let tv = TaggedValue::new(Tag::new("!Custom"), Value::from(42));
let s = to_string(&tv).expect("serialize TaggedValue");
assert!(s.contains("Custom"));
assert!(s.contains("42"));
}
#[test]
fn tagged_value_deserialize_direct() {
let yaml = "myTag: 42\n";
let tv: TaggedValue = from_str(yaml).expect("deserialize TaggedValue");
assert_eq!(tv.value().as_i64(), Some(42));
assert_eq!(tv.tag().as_str(), "myTag");
}
#[test]
fn tagged_value_deserialize_empty_map_errors() {
let yaml = "{}\n";
let r: Result<TaggedValue, _> = from_str(yaml);
assert!(r.is_err());
}
#[test]
fn tag_preserving_round_trip_via_from_value() {
let yaml = "!MyTag\nfoo\n";
let v: Value = from_str(yaml).expect("from_str tagged scalar");
assert!(v.is_tagged());
let tv = v.as_tagged().expect("Value::Tagged");
assert_eq!(tv.tag().as_str(), "!MyTag");
assert_eq!(tv.value().as_str(), Some("foo"));
}
#[test]
fn tag_preserving_round_trip_nested_tagged_sequence() {
let yaml = "!Outer\n- !Inner foo\n- !Inner bar\n";
let v: Value = from_str(yaml).expect("nested tagged");
assert!(v.is_tagged());
}
#[test]
fn tag_preserving_round_trip_through_from_value_value() {
let inner = Value::String("payload".into());
let tag = Tag::new("!My");
let tagged = Value::Tagged(Box::new(TaggedValue::new(tag, inner)));
let v: Value = from_value(&tagged).expect("from_value clone path");
assert!(v.is_tagged());
}
#[test]
fn apply_merge_inside_sequence() {
let mut v: Value =
from_str("- a: &x\n k: 1\n- <<: *x\n m: 2\n").expect("parse merge in seq");
v.apply_merge().expect("apply_merge over Sequence");
let seq = v.as_sequence().unwrap();
assert_eq!(seq[1].get("k").unwrap().as_i64(), Some(1));
}
#[test]
fn apply_merge_inside_tagged() {
let mut v: Value = from_str("!Cfg\na: &x {k: 1}\nb:\n <<: *x\n").expect("parse tagged merge");
v.apply_merge().expect("apply_merge over Tagged");
let inner = v.untag_ref();
let mapping = inner.as_mapping().unwrap();
let b = mapping.get("b").unwrap();
assert_eq!(b.get("k").unwrap().as_i64(), Some(1));
}
#[test]
fn get_path_mut_wildcard_returns_none() {
let mut v: Value = from_str("a: 1\n").expect("parse");
assert!(v.get_path_mut("a.*").is_none());
assert!(v.get_path_mut("**.a").is_none());
}
#[test]
fn query_wildcard_into_sequence() {
let v: Value = from_str("- 1\n- 2\n- 3\n").expect("parse seq");
let r = v.query("*");
assert_eq!(r.len(), 3);
}
#[test]
fn query_wildcard_into_mapping() {
let v: Value = from_str("a: 1\nb: 2\n").expect("parse map");
let r = v.query("*");
assert_eq!(r.len(), 2);
}
#[test]
fn query_wildcard_no_match_on_scalar() {
let v = Value::from(42_i64);
let r = v.query("*");
assert_eq!(r.len(), 0);
}
#[test]
fn query_recursive_descent_into_sequence() {
let v: Value = from_str("data:\n - name: alpha\n - name: beta\n").expect("parse seq of map");
let r = v.query("..name");
assert_eq!(r.len(), 2);
}
#[test]
fn query_recursive_descent_into_tagged() {
let v: Value = from_str("!Cfg\nname: alpha\n").expect("parse tagged");
let r = v.query("..name");
assert!(!r.is_empty());
}
#[test]
fn value_display_sequence_multi() {
let v: Value = from_str("- 1\n- 2\n- 3\n").expect("parse seq");
let s = format!("{v}");
assert!(s.starts_with('['));
assert!(s.ends_with(']'));
assert_eq!(s.matches(", ").count(), 2);
}
#[test]
fn value_display_mapping_multi() {
let v: Value = from_str("a: 1\nb: 2\nc: 3\n").expect("parse map");
let s = format!("{v}");
assert!(s.starts_with('{'));
assert!(s.ends_with('}'));
assert_eq!(s.matches(", ").count(), 2);
}
#[test]
fn value_index_or_insert_into_sequence_via_tagged() {
let inner = Value::Sequence(vec![Value::from(10), Value::from(20)]);
let mut v = Value::Tagged(Box::new(TaggedValue::new(Tag::new("!Wrap"), inner)));
let elem = &mut v[0];
assert_eq!(elem.as_i64(), Some(10));
}
#[test]
fn value_index_into_via_value_string_key() {
let v: Value = from_str("a: 1\n").expect("parse");
let key = Value::from("a");
assert_eq!(v.get(&key).and_then(Value::as_i64), Some(1));
}
#[test]
fn value_index_into_via_value_int_key_for_seq() {
let v: Value = from_str("- 10\n- 20\n").expect("parse");
let key = Value::from(1_i64);
assert_eq!(v.get(&key).and_then(Value::as_i64), Some(20));
}
#[test]
fn value_index_into_mut_via_value_int_key() {
let mut v: Value = from_str("- 10\n- 20\n").expect("parse");
let key = Value::from(0_i64);
if let Some(elem) = v.get_mut(&key) {
*elem = Value::from(99);
}
assert_eq!(v[0].as_i64(), Some(99));
}
#[test]
fn value_index_into_via_value_negative_int_returns_none() {
let v: Value = from_str("- 1\n").expect("parse");
let key = Value::from(-1_i64);
assert!(v.get(&key).is_none());
}
#[derive(Debug, Deserialize, Serialize, PartialEq)]
struct Wrapper {
data: Value,
}
#[test]
fn value_deserialize_sequence_via_serde_json() {
let json = r#"{"data": [1, 2, 3]}"#;
let w: Wrapper = serde_json::from_str(json).expect("from_json");
assert!(w.data.is_sequence());
assert_eq!(w.data.as_sequence().unwrap().len(), 3);
}
#[test]
fn value_deserialize_string_via_serde_json() {
let json = r#"{"data": "hello"}"#;
let w: Wrapper = serde_json::from_str(json).expect("from_json string");
assert_eq!(w.data.as_str(), Some("hello"));
}
#[test]
fn value_deserialize_unit_via_serde_json_null() {
let json = r#"{"data": null}"#;
let w: Wrapper = serde_json::from_str(json).expect("from_json null");
assert!(w.data.is_null());
}
#[test]
fn value_deserialize_float_via_serde_json() {
let json = r#"{"data": 3.14}"#;
let w: Wrapper = serde_json::from_str(json).expect("from_json float");
assert!(w.data.as_f64().unwrap() > 3.0);
}
#[test]
fn value_deserialize_bool_via_serde_json() {
let json = r#"{"data": true}"#;
let w: Wrapper = serde_json::from_str(json).expect("from_json bool");
assert_eq!(w.data.as_bool(), Some(true));
}
#[test]
fn value_deserialize_nested_map_via_serde_json() {
let json = r#"{"data": {"k": 1, "k2": 2}}"#;
let w: Wrapper = serde_json::from_str(json).expect("from_json map");
assert!(w.data.is_mapping());
assert_eq!(w.data.as_mapping().unwrap().len(), 2);
}
#[test]
fn value_visit_map_tag_preserving_path() {
let yaml = "!Custom\nname: alpha\nport: 8080\n";
let v: Value = from_str(yaml).expect("from_str tagged map");
assert!(v.is_tagged());
let inner = v.untag();
assert!(inner.is_mapping());
}
#[test]
fn value_visit_map_tag_preserving_with_complex_inner() {
let yaml = "!T 42\n";
let v: Value = from_str(yaml).expect("from_str tagged scalar");
assert!(v.is_tagged());
}
#[derive(Debug, Deserialize, PartialEq)]
enum E {
A,
B,
Tup(i32, i32),
}
#[test]
fn value_ref_deserialize_enum_string_variant() {
let v = Value::from("A");
let e: E = from_value(&v).expect("string enum variant");
assert_eq!(e, E::A);
}
#[test]
fn value_ref_deserialize_enum_via_mapping() {
let mut m = Mapping::new();
let _ = m.insert("Tup", Value::Sequence(vec![Value::from(1), Value::from(2)]));
let v = Value::Mapping(m);
let e: E = from_value(&v).expect("tuple enum");
assert_eq!(e, E::Tup(1, 2));
}
#[test]
fn interpolate_properties_walks_tagged() {
let mut v: Value = from_str("!Cfg\n name: ${who}\n").expect("parse");
let mut props: HashMap<String, String> = HashMap::new();
let _ = props.insert("who".into(), "world".into());
v.interpolate_properties(&props).expect("interpolate");
let inner = v.untag_ref();
let m = inner.as_mapping().unwrap();
assert_eq!(m.get("name").unwrap().as_str(), Some("world"));
}
#[test]
fn interpolate_properties_walks_sequence() {
let mut v: Value = from_str("- ${a}\n- ${b}\n").expect("parse seq");
let mut props: HashMap<String, String> = HashMap::new();
let _ = props.insert("a".into(), "alpha".into());
let _ = props.insert("b".into(), "beta".into());
v.interpolate_properties(&props).expect("interpolate seq");
let s = v.as_sequence().unwrap();
assert_eq!(s[0].as_str(), Some("alpha"));
assert_eq!(s[1].as_str(), Some("beta"));
}
#[test]
fn mapping_cmp_value_difference() {
let mut m1 = Mapping::new();
let _ = m1.insert("k", Value::from(1));
let mut m2 = Mapping::new();
let _ = m2.insert("k", Value::from(2));
assert!(m1 < m2);
}
#[test]
fn mapping_any_cmp_value_difference() {
let mut m1 = MappingAny::new();
let _ = m1.insert(Value::from("k"), Value::from(1));
let mut m2 = MappingAny::new();
let _ = m2.insert(Value::from("k"), Value::from(2));
assert!(m1 < m2);
}