1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
// SPDX-License-Identifier: MIT OR Apache-2.0
// Copyright (c) 2026 Noyalib. All rights reserved.
//! Inserting a key must not steal a keep-chomped scalar's blank lines
//! (#429).
//!
//! A blank line is normally trivia and a new sibling may be spliced in
//! above it. Under `|+` or `>+` it is not: "keep" chomping makes the
//! trailing line breaks part of the value. Splicing above them adds the
//! key that was asked for *and* silently shortens a different key's
//! value.
//!
//! Nothing fails when that happens — the document still parses, every
//! byte is still present, and the raw-text diff looks like an ordinary
//! insertion. Only the value changed, which is why this needs a test
//! rather than review.
#![allow(clippy::unwrap_used, clippy::expect_used)]
use noyalib::cst::parse_document;
/// The reported case: the scalar is nested, the insert is at the root.
#[test]
fn a_root_insert_keeps_a_nested_keep_chomped_value_intact() {
let mut doc = parse_document("a:\n b: |+\n x\n\n").unwrap();
doc.insert_entry("", "c", "2").unwrap();
assert_eq!(format!("{doc}"), "a:\n b: |+\n x\n\nc: 2\n");
}
/// `>+` keeps its trailing breaks for the same reason `|+` does.
#[test]
fn folded_keep_chomping_is_treated_the_same() {
let mut doc = parse_document("a:\n b: >+\n x\n\n").unwrap();
doc.insert_entry("", "c", "2").unwrap();
assert_eq!(format!("{doc}"), "a:\n b: >+\n x\n\nc: 2\n");
}
/// Several kept blank lines, not just one.
#[test]
fn every_kept_blank_line_stays_with_the_scalar() {
let mut doc = parse_document("a:\n b: |+\n x\n\n\n\n").unwrap();
doc.insert_entry("", "c", "2").unwrap();
assert_eq!(format!("{doc}"), "a:\n b: |+\n x\n\n\n\nc: 2\n");
}
/// Clip chomping (the default) does *not* keep trailing breaks, so the
/// blank line there is trivia and the key goes above it as before.
///
/// Without this the fix could have been "always skip trailing blanks",
/// which would move keys for every document that happens to end in one.
#[test]
fn clip_chomping_still_places_the_key_above_the_blank_line() {
let mut doc = parse_document("a:\n b: |\n x\n\n").unwrap();
doc.insert_entry("", "c", "2").unwrap();
let out = format!("{doc}");
assert!(
out.contains("c: 2"),
"the key must still be inserted: {out:?}"
);
assert!(
out.starts_with("a:\n b: |\n x\n"),
"the scalar must be untouched: {out:?}"
);
}
/// The value itself must survive a round trip, not merely the bytes.
#[test]
fn the_kept_value_round_trips_after_the_insert() {
let mut doc = parse_document("a:\n b: |+\n x\n\n").unwrap();
doc.insert_entry("", "c", "2").unwrap();
let out = format!("{doc}");
let reparsed = parse_document(&out).expect("reparse");
assert_eq!(format!("{reparsed}"), out, "not stable on a second parse");
}