use super::*;
use crate::Span;
use crate::arena::Arena;
fn sp(s: u32, e: u32) -> Span {
Span::new(s, e)
}
#[test]
fn constructors() {
let arena = Arena::new();
let v = Item::string_spanned("hello", sp(0, 5));
assert_eq!(v.tag(), TAG_STRING);
assert_eq!(v.as_str(), Some("hello"));
assert_eq!(v.span_unchecked(), sp(0, 5));
assert_eq!(*v.type_str(), "string");
let v = Item::integer_spanned(42, sp(0, 2));
assert_eq!(v.tag(), TAG_INTEGER);
assert_eq!(v.as_i64(), Some(42));
assert_eq!(v.as_u64(), Some(42));
assert_eq!(v.span_unchecked(), sp(0, 2));
assert_eq!(*v.type_str(), "integer");
let v = Item::integer_spanned(-9999, sp(0, 5));
assert_eq!(v.as_i64(), Some(-9999));
assert_eq!(v.as_u64(), None);
let v = Item::integer_spanned(u64::MAX as i128, sp(0, 20));
assert_eq!(v.as_i64(), None);
assert_eq!(v.as_u64(), Some(u64::MAX));
let v = Item::float_spanned(3.15, sp(0, 4));
assert_eq!(v.tag(), TAG_FLOAT);
assert_eq!(v.as_f64(), Some(3.15));
assert_eq!(v.span_unchecked(), sp(0, 4));
assert_eq!(*v.type_str(), "float");
let t = Item::boolean(true, sp(0, 4));
let f = Item::boolean(false, sp(5, 10));
assert_eq!(t.tag(), TAG_BOOLEAN);
assert_eq!(t.as_bool(), Some(true));
assert_eq!(f.as_bool(), Some(false));
assert_eq!(*t.type_str(), "boolean");
let mut arr = InternalArray::new();
arr.push(Item::integer_spanned(1, sp(0, 1)), &arena);
arr.push(Item::integer_spanned(2, sp(2, 3)), &arena);
let v = Item::array(arr, sp(0, 3));
assert_eq!(v.tag(), TAG_ARRAY);
assert_eq!(v.as_array().unwrap().len(), 2);
assert_eq!(*v.type_str(), "array");
let mut tab = InnerTable::new();
tab.insert_unique(
Key {
name: "k",
span: sp(0, 1),
},
Item::integer_spanned(10, sp(2, 4)),
&arena,
);
let v = Item::table(tab, sp(0, 4));
assert_eq!(v.tag(), TAG_TABLE);
assert_eq!(v.as_table().unwrap().len(), 1);
assert_eq!(*v.type_str(), "table");
assert_eq!(
Item::table_header(InnerTable::new(), sp(0, 0)).type_str(),
&"table"
);
assert_eq!(
Item::table_dotted(InnerTable::new(), sp(0, 0)).type_str(),
&"table"
);
let empty = Item::table(InnerTable::new(), sp(0, 0));
assert!(!empty.has_keys());
let mut tab = InnerTable::new();
tab.insert_unique(
Key {
name: ("x"),
span: sp(0, 1),
},
Item::integer_spanned(1, sp(0, 1)),
&arena,
);
let v = Item::table(tab, sp(0, 1));
assert!(v.has_keys());
assert!(v.has_key("x"));
assert!(!v.has_key("y"));
}
#[test]
fn table_variant_flags() {
let v = Item::table_header(InnerTable::new(), sp(0, 10));
assert_eq!(v.tag(), TAG_TABLE);
assert_eq!(v.flag(), FLAG_HEADER);
assert!(v.has_header_bit());
assert!(v.as_table().is_some());
let v = Item::table_dotted(InnerTable::new(), sp(0, 10));
assert_eq!(v.tag(), TAG_TABLE);
assert_eq!(v.flag(), FLAG_DOTTED);
assert!(v.has_dotted_bit());
assert!(v.as_table().is_some());
let v = Item::array_aot(InternalArray::new(), sp(10, 20));
assert!(v.is_aot());
assert_eq!(v.flag(), FLAG_AOT);
assert_eq!(v.span_unchecked(), sp(10, 20));
let v = Item::table_frozen(InnerTable::new(), sp(5, 15));
assert!(v.is_frozen());
assert!(v.as_table().is_some());
assert_eq!(v.span_unchecked(), sp(5, 15));
}
#[test]
fn span_bit_packing() {
let tags_and_constructors: Vec<(u32, Item<'_>)> = vec![
(TAG_STRING, Item::string_spanned("x", sp(100, 200))),
(TAG_INTEGER, Item::integer_spanned(0, sp(100, 200))),
(TAG_FLOAT, Item::float_spanned(0.0, sp(100, 200))),
(TAG_BOOLEAN, Item::boolean(false, sp(100, 200))),
(TAG_ARRAY, Item::array(InternalArray::new(), sp(100, 200))),
(TAG_TABLE, Item::table(InnerTable::new(), sp(100, 200))),
(
TAG_TABLE,
Item::table_header(InnerTable::new(), sp(100, 200)),
),
(
TAG_TABLE,
Item::table_dotted(InnerTable::new(), sp(100, 200)),
),
];
for (expected_tag, v) in &tags_and_constructors {
assert_eq!(v.tag(), *expected_tag);
assert_eq!(v.span_unchecked(), sp(100, 200), "tag={expected_tag}");
}
let max_start = (1u32 << 28) - 1;
let max_end = (1u32 << 28) - 1;
let v = Item::integer_spanned(0, sp(max_start, max_end));
assert_eq!(v.span_unchecked().start, max_start);
assert_eq!(v.span_unchecked().end, max_end);
}
#[test]
fn value_and_type_checks() {
let vals: Vec<Item<'_>> = vec![
Item::string_spanned("s", sp(0, 1)),
Item::integer_spanned(1, sp(0, 1)),
Item::float_spanned(1.0, sp(0, 1)),
Item::boolean(true, sp(0, 1)),
Item::array(InternalArray::new(), sp(0, 1)),
Item::table(InnerTable::new(), sp(0, 1)),
];
let expected = ["string", "integer", "float", "boolean", "array", "table"];
for (v, exp) in vals.iter().zip(expected.iter()) {
let kind = match v.value() {
Value::String(_) => "string",
Value::Integer(_) => "integer",
Value::Float(_) => "float",
Value::Boolean(_) => "boolean",
Value::Array(_) => "array",
Value::Table(_) => "table",
Value::DateTime(_) => "moment",
};
assert_eq!(kind, *exp);
}
let v = Item::integer_spanned(42, sp(0, 2));
assert!(v.as_str().is_none());
assert!(v.as_bool().is_none());
assert!(v.as_array().is_none());
assert!(v.as_table().is_none());
let v = Item::string_spanned("s", sp(0, 1));
assert!(v.as_i64().is_none());
assert!(v.as_f64().is_none());
assert!(v.as_bool().is_none());
assert!(v.as_array().is_none());
assert!(v.as_table().is_none());
let v = Item::boolean(true, sp(0, 4));
assert!(v.as_str().is_none());
assert!(v.as_i64().is_none());
assert!(v.as_f64().is_none());
assert!(v.as_array().is_none());
assert!(v.as_table().is_none());
}
#[test]
fn as_f64_converts_integers() {
let v = Item::float_spanned(3.15, sp(0, 4));
assert_eq!(v.as_f64(), Some(3.15));
let v = Item::integer_spanned(42, sp(0, 2));
assert_eq!(v.as_f64(), Some(42.0));
let v = Item::integer_spanned(-100, sp(0, 4));
assert_eq!(v.as_f64(), Some(-100.0));
let v = Item::integer_spanned(0, sp(0, 1));
assert_eq!(v.as_f64(), Some(0.0));
assert!(Item::string_spanned("s", sp(0, 1)).as_f64().is_none());
assert!(Item::boolean(true, sp(0, 4)).as_f64().is_none());
assert!(
Item::array(InternalArray::new(), sp(0, 2))
.as_f64()
.is_none()
);
assert!(Item::table(InnerTable::new(), sp(0, 2)).as_f64().is_none());
let item = Item::integer_spanned(99, sp(0, 2));
let maybe = MaybeItem::from_ref(&item);
assert_eq!(maybe.as_f64(), Some(99.0));
let item = Item::float_spanned(2.5, sp(0, 3));
let maybe = MaybeItem::from_ref(&item);
assert_eq!(maybe.as_f64(), Some(2.5));
assert!(NONE.as_f64().is_none());
}
#[test]
fn value_mut_all_types() {
let arena = Arena::new();
let mut v = Item::string_spanned("hello", sp(0, 5));
if let ValueMut::String(s) = v.value_mut() {
assert_eq!(&**s, "hello");
} else {
panic!("expected String");
}
let mut v = Item::integer_spanned(10, sp(0, 2));
if let ValueMut::Integer(i) = v.value_mut() {
*i = Integer::from(99i64);
}
assert_eq!(v.as_i64(), Some(99));
let mut v = Item::float_spanned(1.0, sp(0, 3));
if let ValueMut::Float(f) = v.value_mut() {
*f = 2.5;
}
assert_eq!(v.as_f64(), Some(2.5));
let mut v = Item::boolean(false, sp(0, 5));
if let ValueMut::Boolean(b) = v.value_mut() {
*b = true;
}
assert_eq!(v.as_bool(), Some(true));
let mut v = Item::array(InternalArray::new(), sp(0, 2));
if let ValueMut::Array(a) = v.value_mut() {
a.push(Item::integer_spanned(42, sp(0, 2)), &arena);
}
assert_eq!(v.as_array().unwrap().len(), 1);
let mut v = Item::table(InnerTable::new(), sp(0, 2));
if let ValueMut::Table(t) = v.value_mut() {
t.insert_unique(
Key {
name: ("x"),
span: sp(0, 1),
},
Item::integer_spanned(1, sp(0, 1)),
&arena,
);
}
assert_eq!(v.as_table().unwrap().len(), 1);
}
#[test]
fn type_error_helpers() {
let v = Item::integer_spanned(42, sp(0, 2));
let err = v.expected(&"a string");
assert!(matches!(err.kind(), crate::ErrorKind::Wanted { .. }));
assert_eq!(err.span(), sp(0, 2));
}
#[cfg(feature = "from-toml")]
#[test]
fn expect_helpers() {
let arena = Arena::new();
let mut ctx = crate::de::Context {
arena: &arena,
index: Default::default(),
errors: Vec::new(),
source: "",
};
let v = Item::string_spanned("hello", sp(0, 5));
let s = v.require_string(&mut ctx).unwrap();
assert_eq!(s, "hello");
let v = Item::integer_spanned(42, sp(0, 2));
assert!(v.require_string(&mut ctx).is_err());
assert_eq!(ctx.errors.len(), 1);
assert!(matches!(
ctx.errors[0].kind(),
crate::ErrorKind::Wanted { .. }
));
let mut arr = InternalArray::new();
arr.push(Item::integer_spanned(1, sp(0, 1)), &arena);
let v = Item::array(arr, sp(0, 5));
let a = v.require_array(&mut ctx).unwrap();
assert_eq!(a.len(), 1);
let v = Item::integer_spanned(42, sp(0, 2));
assert!(v.require_array(&mut ctx).is_err());
assert!(matches!(
ctx.errors.last().unwrap().kind(),
crate::ErrorKind::Wanted { .. }
));
let mut tab = InnerTable::new();
tab.insert_unique(
Key {
name: ("k"),
span: sp(0, 1),
},
Item::integer_spanned(1, sp(0, 1)),
&arena,
);
let v = Item::table(tab, sp(0, 5));
let t = v.require_table(&mut ctx).unwrap();
assert_eq!(t.len(), 1);
let v = Item::integer_spanned(42, sp(0, 2));
assert!(v.require_table(&mut ctx).is_err());
assert!(matches!(
ctx.errors.last().unwrap().kind(),
crate::ErrorKind::Wanted { .. }
));
}
#[test]
fn mut_accessors() {
let arena = Arena::new();
let mut v = Item::array(InternalArray::new(), sp(0, 2));
let a = v.as_array_mut().unwrap();
a.push(Item::integer_spanned(1, sp(0, 1)), &arena);
assert_eq!(v.as_array().unwrap().len(), 1);
let mut v = Item::integer_spanned(42, sp(0, 2));
assert!(v.as_array_mut().is_none());
let mut v = Item::table(InnerTable::new(), sp(0, 2));
let t = v.as_table_mut().unwrap();
t.insert_unique(
Key {
name: ("k"),
span: sp(0, 1),
},
Item::integer_spanned(1, sp(0, 1)),
&arena,
);
assert_eq!(v.as_table().unwrap().len(), 1);
let mut v = Item::integer_spanned(42, sp(0, 2));
assert!(v.as_table_mut().is_none());
}
#[test]
fn parse_method() {
let v = Item::string_spanned("42", sp(0, 2));
let parsed: i32 = v.parse::<i32>().unwrap();
assert_eq!(parsed, 42);
let v = Item::string_spanned("not_a_number", sp(0, 12));
let err = v.parse::<i32>().unwrap_err();
assert!(matches!(err.kind(), crate::ErrorKind::Custom(_)));
let v = Item::integer_spanned(42, sp(0, 2));
let err = v.parse::<i32>().unwrap_err();
assert!(matches!(err.kind(), crate::ErrorKind::Wanted { .. }));
}
#[test]
fn spanned_table_set_span_preserves_flag() {
let mut v = Item::table_header(InnerTable::new(), sp(10, 20));
unsafe { v.as_table_mut_unchecked() }.set_span_start(99);
assert_eq!(v.tag(), TAG_TABLE);
assert_eq!(v.flag(), FLAG_HEADER);
assert_eq!(v.span_unchecked().start, 99);
unsafe { v.as_table_mut_unchecked() }.set_span_end(200);
assert_eq!(v.flag(), FLAG_HEADER);
assert_eq!(v.span_unchecked().end, 200);
}
#[test]
fn key_basics() {
let k = Key {
name: ("mykey"),
span: sp(0, 5),
};
assert_eq!(k.as_str(), "mykey");
let a = Key {
name: ("same"),
span: sp(0, 4),
};
let b = Key {
name: ("same"),
span: sp(10, 14),
};
assert_eq!(a, b);
let a = Key {
name: ("aaa"),
span: sp(0, 3),
};
let b = Key {
name: ("bbb"),
span: sp(0, 3),
};
assert!(a < b);
assert_eq!(a.cmp(&a), std::cmp::Ordering::Equal);
let k = Key {
name: ("test"),
span: sp(0, 4),
};
let borrowed: &str = std::borrow::Borrow::borrow(&k);
assert_eq!(borrowed, "test");
assert_eq!(format!("{:?}", k), "test");
assert_eq!(format!("{}", k), "test");
}
#[test]
fn item_debug_fmt() {
let v = Item::string_spanned("hello", sp(0, 5));
assert_eq!(format!("{:?}", v), "\"hello\"");
let v = Item::integer_spanned(42, sp(0, 2));
assert_eq!(format!("{:?}", v), "42");
let v = Item::float_spanned(3.15, sp(0, 4));
assert_eq!(format!("{:?}", v), "3.15");
let v = Item::boolean(true, sp(0, 4));
assert_eq!(format!("{:?}", v), "true");
let arena = Arena::new();
let mut arr = InternalArray::new();
arr.push(Item::integer_spanned(1, sp(0, 1)), &arena);
let v = Item::array(arr, sp(0, 3));
assert!(format!("{:?}", v).contains("1"));
let v = Item::table(InnerTable::new(), sp(0, 2));
let debug = format!("{:?}", v);
assert_eq!(debug, "{}");
}
#[test]
fn item_index_operators() {
let arena = Arena::new();
let mut tab = InnerTable::new();
tab.insert_unique(
Key {
name: ("name"),
span: sp(0, 4),
},
Item::string_spanned("alice", sp(5, 10)),
&arena,
);
tab.insert_unique(
Key {
name: ("age"),
span: sp(11, 14),
},
Item::integer_spanned(30, sp(15, 17)),
&arena,
);
let item = Item::table(tab, sp(0, 17));
assert_eq!(item["name"].as_str(), Some("alice"));
assert_eq!(item["age"].as_i64(), Some(30));
assert!(item["missing"].item().is_none());
let mut arr = InternalArray::new();
arr.push(Item::integer_spanned(10, sp(0, 2)), &arena);
arr.push(Item::string_spanned("two", sp(3, 6)), &arena);
arr.push(Item::boolean(true, sp(7, 11)), &arena);
let item = Item::array(arr, sp(0, 11));
assert_eq!(item[0].as_i64(), Some(10));
assert_eq!(item[1].as_str(), Some("two"));
assert_eq!(item[2].as_bool(), Some(true));
assert!(item[3].item().is_none());
assert!(item[100].item().is_none());
let int_item = Item::integer_spanned(42, sp(0, 2));
assert!(int_item["anything"].item().is_none());
assert!(Item::string_spanned("s", sp(0, 1))["k"].item().is_none());
assert!(Item::boolean(true, sp(0, 4))["k"].item().is_none());
assert!(
Item::array(InternalArray::new(), sp(0, 2))["k"]
.item()
.is_none()
);
assert!(int_item[0].item().is_none());
assert!(Item::string_spanned("s", sp(0, 1))[0].item().is_none());
assert!(Item::table(InnerTable::new(), sp(0, 2))[0].item().is_none());
}
#[test]
fn maybe_item_chained_and_none_propagation() {
let arena = Arena::new();
let mut scores = InternalArray::new();
scores.push(Item::integer_spanned(100, sp(0, 3)), &arena);
scores.push(Item::integer_spanned(200, sp(4, 7)), &arena);
let mut user_tab = InnerTable::new();
user_tab.insert_unique(
Key {
name: ("name"),
span: sp(0, 4),
},
Item::string_spanned("alice", sp(5, 10)),
&arena,
);
user_tab.insert_unique(
Key {
name: ("scores"),
span: sp(11, 17),
},
Item::array(scores, sp(18, 25)),
&arena,
);
let mut users = InternalArray::new();
users.push(Item::table(user_tab, sp(0, 25)), &arena);
let mut root = InnerTable::new();
root.insert_unique(
Key {
name: ("users"),
span: sp(0, 5),
},
Item::array(users, sp(6, 30)),
&arena,
);
let root_item = Item::table(root, sp(0, 30));
assert_eq!(root_item["users"][0]["name"].as_str(), Some("alice"));
assert_eq!(root_item["users"][0]["scores"][0].as_i64(), Some(100));
assert_eq!(root_item["users"][0]["scores"][1].as_i64(), Some(200));
assert!(root_item["users"][0]["scores"][2].item().is_none());
assert!(root_item["users"][0]["missing"].item().is_none());
assert!(root_item["users"][1].item().is_none());
assert!(root_item["nope"][0]["name"].item().is_none());
let maybe = &root_item["users"][0]["name"];
assert!(!maybe.span().is_empty());
assert!(matches!(maybe.value(), Some(Value::String(_))));
let none = &root_item["missing"];
assert!(none.span().is_empty());
assert!(none.value().is_none());
let item = Item::integer_spanned(42, sp(0, 2));
assert!(item["a"]["b"]["c"].item().is_none());
assert!(item["a"][0]["b"][1].item().is_none());
assert!(item[0][1][2].item().is_none());
assert!(item[0]["key"][1]["nested"].item().is_none());
let none = &item["missing"];
assert!(none.as_str().is_none());
assert!(none.as_i64().is_none());
assert!(none.as_u64().is_none());
assert!(none.as_f64().is_none());
assert!(none.as_bool().is_none());
assert!(none.as_array().is_none());
assert!(none.as_table().is_none());
assert!(none.as_datetime().is_none());
}
#[test]
fn datetime_items() {
let arena = Arena::new();
let input = "dt = 2023-06-15T12:30:45Z\nd = 2023-06-15\nt = 12:30:45";
let doc = crate::parser::parse(input, &arena).unwrap();
let dt_item = doc.table().get("dt").unwrap();
let dt = dt_item.as_datetime().unwrap();
assert_eq!(dt.date().unwrap().year, 2023);
assert_eq!(*dt_item.type_str(), "datetime");
assert!(matches!(dt_item.value(), Value::DateTime(_)));
let mut dt_item_owned = Item::moment(*dt_item.as_datetime().unwrap(), dt_item.span_unchecked());
assert!(matches!(dt_item_owned.value_mut(), ValueMut::DateTime(_)));
let debug = format!("{:?}", dt_item);
assert!(debug.contains("2023"));
let int_item = Item::integer_spanned(42, sp(0, 2));
assert!(int_item.as_datetime().is_none());
let maybe = MaybeItem::from_ref(dt_item);
assert!(maybe.as_datetime().is_some());
let int_item = Item::integer_spanned(42, sp(0, 2));
let maybe = MaybeItem::from_ref(&int_item);
assert!(maybe.as_datetime().is_none());
assert!(NONE.as_datetime().is_none());
}
#[test]
fn kind_enum() {
let kinds = [
Kind::String,
Kind::Integer,
Kind::Float,
Kind::Boolean,
Kind::Array,
Kind::Table,
Kind::DateTime,
];
for kind in kinds {
let s = kind.as_str();
assert!(!s.is_empty());
assert_eq!(format!("{kind}"), s);
assert_eq!(format!("{kind:?}"), format!("\"{s}\""));
}
assert!(matches!(
Item::string_spanned("s", sp(0, 1)).kind(),
Kind::String
));
assert!(matches!(
Item::integer_spanned(1, sp(0, 1)).kind(),
Kind::Integer
));
assert!(matches!(
Item::float_spanned(1.0, sp(0, 1)).kind(),
Kind::Float
));
assert!(matches!(
Item::boolean(true, sp(0, 1)).kind(),
Kind::Boolean
));
assert!(matches!(
Item::array(InternalArray::new(), sp(0, 1)).kind(),
Kind::Array
));
assert!(matches!(
Item::table(InnerTable::new(), sp(0, 1)).kind(),
Kind::Table
));
}
#[test]
fn clone_in_scalars() {
let arena = Arena::new();
let orig = Item::string_spanned("hello", sp(1, 6));
let cloned = orig.clone_in(&arena);
assert_eq!(cloned.as_str(), Some("hello"));
assert_eq!(cloned.span_unchecked(), sp(1, 6));
let orig = Item::integer_spanned(-42, sp(0, 3));
let cloned = orig.clone_in(&arena);
assert_eq!(cloned.as_i64(), Some(-42));
assert_eq!(cloned.span_unchecked(), sp(0, 3));
let orig = Item::float_spanned(3.15, sp(10, 14));
let cloned = orig.clone_in(&arena);
assert_eq!(cloned.as_f64(), Some(3.15));
assert_eq!(cloned.span_unchecked(), sp(10, 14));
let orig = Item::boolean(true, sp(0, 4));
let cloned = orig.clone_in(&arena);
assert_eq!(cloned.as_bool(), Some(true));
assert_eq!(cloned.span_unchecked(), sp(0, 4));
}
#[test]
fn clone_in_datetime() {
let arena = Arena::new();
let input = "dt = 2023-06-15T12:30:45Z";
let doc = crate::parser::parse(input, &arena).unwrap();
let dt_item = doc.table().get("dt").unwrap();
let cloned = dt_item.clone_in(&arena);
assert_eq!(cloned.as_datetime().unwrap().date().unwrap().year, 2023);
assert_eq!(cloned.span_unchecked(), dt_item.span_unchecked());
}
#[test]
fn clone_in_array() {
let arena = Arena::new();
let mut arr = InternalArray::new();
arr.push(Item::integer_spanned(1, sp(0, 1)), &arena);
arr.push(Item::string_spanned("two", sp(2, 5)), &arena);
arr.push(Item::boolean(false, sp(6, 11)), &arena);
let orig = Item::array(arr, sp(0, 11));
let cloned = orig.clone_in(&arena);
let ca = cloned.as_array().unwrap();
assert_eq!(ca.len(), 3);
assert_eq!(ca[0].as_i64(), Some(1));
assert_eq!(ca[1].as_str(), Some("two"));
assert_eq!(ca[2].as_bool(), Some(false));
assert_eq!(cloned.span_unchecked(), sp(0, 11));
assert_eq!(cloned.flag(), orig.flag());
}
#[test]
fn clone_in_table() {
let arena = Arena::new();
let mut tab = InnerTable::new();
tab.insert_unique(
Key {
name: "x",
span: sp(0, 1),
},
Item::integer_spanned(10, sp(2, 4)),
&arena,
);
tab.insert_unique(
Key {
name: "y",
span: sp(5, 6),
},
Item::string_spanned("hi", sp(7, 9)),
&arena,
);
let orig = Item::table(tab, sp(0, 9));
let cloned = orig.clone_in(&arena);
let ct = cloned.as_table().unwrap();
assert_eq!(ct.len(), 2);
assert_eq!(ct.get("x").unwrap().as_i64(), Some(10));
assert_eq!(ct.get("y").unwrap().as_str(), Some("hi"));
assert_eq!(cloned.span_unchecked(), sp(0, 9));
assert_eq!(cloned.flag(), orig.flag());
}
#[test]
fn clone_in_nested() {
let arena = Arena::new();
let mut t1 = InnerTable::new();
t1.insert_unique(
Key {
name: "name",
span: sp(0, 4),
},
Item::string_spanned("a", sp(5, 6)),
&arena,
);
t1.insert_unique(
Key {
name: "val",
span: sp(7, 10),
},
Item::integer_spanned(1, sp(11, 12)),
&arena,
);
let mut t2 = InnerTable::new();
t2.insert_unique(
Key {
name: "name",
span: sp(13, 17),
},
Item::string_spanned("b", sp(18, 19)),
&arena,
);
t2.insert_unique(
Key {
name: "val",
span: sp(20, 23),
},
Item::integer_spanned(2, sp(24, 25)),
&arena,
);
let mut arr = InternalArray::new();
arr.push(Item::table(t1, sp(0, 12)), &arena);
arr.push(Item::table(t2, sp(13, 25)), &arena);
let mut root = InnerTable::new();
root.insert_unique(
Key {
name: "items",
span: sp(0, 5),
},
Item::array(arr, sp(6, 26)),
&arena,
);
let orig = Item::table(root, sp(0, 26));
let cloned = orig.clone_in(&arena);
assert_eq!(cloned["items"][0]["name"].as_str(), Some("a"));
assert_eq!(cloned["items"][0]["val"].as_i64(), Some(1));
assert_eq!(cloned["items"][1]["name"].as_str(), Some("b"));
assert_eq!(cloned["items"][1]["val"].as_i64(), Some(2));
let ct = cloned.as_table().unwrap();
let items = ct.get("items").unwrap().as_array().unwrap();
let first = items.get(0).unwrap().as_table().unwrap();
assert_eq!(first.get("val").unwrap().as_i64(), Some(1));
assert_eq!(orig["items"][0]["val"].as_i64(), Some(1));
}
#[test]
fn clone_in_preserves_flags() {
let arena = Arena::new();
let orig = Item::table_header(InnerTable::new(), sp(0, 10));
let cloned = orig.clone_in(&arena);
assert_eq!(cloned.flag(), FLAG_HEADER);
let orig = Item::table_dotted(InnerTable::new(), sp(0, 10));
let cloned = orig.clone_in(&arena);
assert_eq!(cloned.flag(), FLAG_DOTTED);
let orig = Item::table_frozen(InnerTable::new(), sp(0, 10));
let cloned = orig.clone_in(&arena);
assert!(cloned.is_frozen());
let orig = Item::array_aot(InternalArray::new(), sp(0, 10));
let cloned = orig.clone_in(&arena);
assert!(cloned.is_aot());
}
#[test]
fn clone_in_empty_containers() {
let arena = Arena::new();
let orig = Item::array(InternalArray::new(), sp(0, 2));
let cloned = orig.clone_in(&arena);
assert_eq!(cloned.as_array().unwrap().len(), 0);
assert_eq!(cloned.span_unchecked(), sp(0, 2));
let orig = Item::table(InnerTable::new(), sp(0, 2));
let cloned = orig.clone_in(&arena);
assert_eq!(cloned.as_table().unwrap().len(), 0);
assert_eq!(cloned.span_unchecked(), sp(0, 2));
}