#![allow(
clippy::unwrap_used,
clippy::expect_used,
clippy::indexing_slicing,
clippy::arithmetic_side_effects
)]
use oneyaml::{Document, Settings, Stream, Value, path};
const INVALID: [&[u8]; 8] = [
b"\x80a: \xff\xfe\n- \xc3\n\xe2\x82",
b"a: 1\nb: [2,\n \xff]\nc: \xfe\n",
b"\xff\xfe\x00\xd8a\x00:\x00 \x00\x00\xdc",
b"\xfe\xff\xd8\x00\x00a\x00\n\xdc\x00\xdc\x00",
b"\x00\x00\xfe\xff\x00\x11\x00\x00\x00\x00\x00a\xff",
b"\x80",
b"a: b\n\xc0\xc1\xf5\xff",
b"a\n---\nb: \xff\n---\n\xfe c\n",
];
fn line_col(text: &str, at: usize) -> (usize, usize) {
let before = &text[..at];
let line = before.matches('\n').count() + 1;
let col = before.rsplit('\n').next().unwrap().chars().count() + 1;
(line, col)
}
#[test]
fn strict_from_slice_reports_the_first_run_as_a_whole_decode_does() {
let s = Settings::new();
for bytes in INVALID {
let recovering = Stream::from_slice_recovering(bytes, &s);
let first = recovering.diagnostics()[0].clone();
let text = recovering.value().to_string();
let (line, column) = line_col(&text, first.primary.span.start);
for e in [
Document::from_slice_with(bytes, &s).map(drop).unwrap_err(),
Stream::from_slice_with(bytes, &s).map(drop).unwrap_err(),
oneyaml::from_slice_with::<Value>(bytes, &s).unwrap_err(),
] {
assert_eq!(e.diagnostic(), &first, "{bytes:?}");
let at = e.location().unwrap();
assert_eq!((at.line(), at.column()), (line, column), "{bytes:?}");
assert!(e.warnings().is_empty());
}
}
let bom = b"\xff\xfea\x00:\x00 \x001\x00\n\x00";
assert_eq!(
Document::from_slice(bom).unwrap().to_bytes().as_slice(),
bom
);
}
#[test]
fn compact_runs_give_the_input_back() {
let s = Settings::new();
for bytes in INVALID {
let p = Document::from_slice_recovering(bytes, &s);
assert!(p.has_errors(), "{bytes:?}");
assert_eq!(p.value().to_bytes().as_slice(), bytes, "{bytes:?}");
let st = Stream::from_slice_recovering(bytes, &s).into_value();
let joined: Vec<u8> = st.documents().flat_map(|d| d.to_bytes()).collect();
assert_eq!(joined.as_slice(), bytes, "{bytes:?}");
}
let bytes = b"a: \xff\n---\nb: \xfe\xfd\n";
let st = Stream::from_slice_recovering(bytes, &s).into_value();
let docs: Vec<Vec<u8>> = st.documents().map(|d| d.to_bytes()).collect();
assert_eq!(
docs,
[b"a: \xff\n".to_vec(), b"---\nb: \xfe\xfd\n".to_vec()]
);
let per_doc: Vec<usize> = st.documents().map(|d| d.diagnostics().len()).collect();
assert_eq!(per_doc, [1, 1]);
}
#[test]
fn slot_indexes_survive_clones_and_edits() {
let src: String = (0..200).map(|i| format!("k{i}: {i}\n")).collect();
let mut a = Document::parse(src.as_str()).unwrap();
assert_eq!(a.get_path(&path!["k150"]).unwrap().text(), "150");
let mut b = a.clone();
let _ = a.remove_path(&path!["k3"]).unwrap();
b.set_path(&path!["k3"], "x").unwrap();
b.set_path(&path!["new"], 7).unwrap();
a.set_path(&path!["k199"], [1, 2]).unwrap();
for (d, k3) in [(&a, None), (&b, Some("x"))] {
assert_eq!(
d.get_path(&path!["k3"])
.map(|n| n.text().into_owned())
.as_deref(),
k3
);
assert_eq!(d.get_path(&path!["k150"]).unwrap().text(), "150");
assert_eq!(d.check_lookup_indexes(), Ok(1 + usize::from(k3.is_none())));
}
assert_eq!(b.get_path(&path!["new"]).unwrap().text(), "7");
assert!(a.get_path(&path!["new"]).is_none());
}