yamp 0.1.0

Yet Another Minimal Parser - A safe, predictable YAML parser that treats all values as strings
Documentation
#![deny(clippy::all)]

use std::borrow::Cow;
use yamp::{YamlValue, emit, parse};

#[test]
fn test_multiline_round_trip() {
    // Test that we can parse and re-emit multiline strings
    let yaml = r#"
description: |
  This is a multiline string
  that preserves line breaks.
other: value
"#;

    let parsed = parse(yaml).expect("Failed to parse multiline");
    let emitted = emit(&parsed);

    // Debug output
    println!("Original YAML:\n{}", yaml);
    println!("Emitted YAML:\n{}", emitted);

    let reparsed = parse(&emitted).expect("Failed to reparse emitted multiline");

    // Check that the description values match
    if let YamlValue::Object(map1) = &parsed.value
        && let YamlValue::Object(map2) = &reparsed.value
    {
        let desc1 = &map1.get(&Cow::Borrowed("description")).unwrap().value;
        let desc2 = &map2.get(&Cow::Borrowed("description")).unwrap().value;
        assert_eq!(
            desc1, desc2,
            "Description values don't match after round-trip"
        );

        let other1 = &map1.get(&Cow::Borrowed("other")).unwrap().value;
        let other2 = &map2.get(&Cow::Borrowed("other")).unwrap().value;
        assert_eq!(other1, other2, "Other values don't match after round-trip");
    }
}

#[test]
fn test_quoted_string_with_escaped_newline() {
    let yaml = r#"description: "Line 1\nLine 2\nLine 3""#;

    let parsed = parse(yaml).expect("Failed to parse quoted string with escaped newlines");

    if let YamlValue::Object(map) = &parsed.value
        && let YamlValue::String(s) = &map.get(&Cow::Borrowed("description")).unwrap().value
    {
        // The \n should be preserved as literal text, not interpreted
        assert_eq!(s.as_ref(), "Line 1\\nLine 2\\nLine 3");
    }
}

#[test]
fn test_quoted_string_across_multiple_lines() {
    let yaml = r#"description: "This is a string
that continues on the next line
and even a third line""#;

    let parsed = parse(yaml).expect("Failed to parse quoted string across lines");

    if let YamlValue::Object(map) = &parsed.value
        && let YamlValue::String(s) = &map.get(&Cow::Borrowed("description")).unwrap().value
    {
        // Actual newlines in quoted strings should be preserved
        assert_eq!(
            s.as_ref(),
            "This is a string\nthat continues on the next line\nand even a third line"
        );
    }
}

#[test]
fn test_literal_multiline() {
    // YAML multiline strings with | (literal) preserve line breaks
    let yaml = r#"
description: |
  This is a multiline string
  that preserves line breaks.
"#;

    let parsed = parse(yaml).expect("Failed to parse literal multiline");

    if let YamlValue::Object(map) = &parsed.value
        && let YamlValue::String(s) = &map.get(&Cow::Borrowed("description")).unwrap().value
    {
        assert_eq!(
            s.as_ref(),
            "This is a multiline string\nthat preserves line breaks.\n"
        );
    }
}

#[test]
fn test_folded_multiline() {
    // YAML multiline strings with > (folded) join lines with spaces
    let yaml = r#"
description: >
  This is a folded multiline string
  that joins lines together.
"#;

    let parsed = parse(yaml).expect("Failed to parse folded multiline");

    if let YamlValue::Object(map) = &parsed.value
        && let YamlValue::String(s) = &map.get(&Cow::Borrowed("description")).unwrap().value
    {
        assert_eq!(
            s.as_ref(),
            "This is a folded multiline string that joins lines together.\n"
        );
    }
}

#[test]
fn test_literal_with_strip_chomp() {
    // Test |- (literal with strip chomping - removes all trailing newlines)
    let yaml = r#"
description: |-
  Line 1
  Line 2

"#;

    let parsed = parse(yaml).expect("Failed to parse literal with strip chomp");

    if let YamlValue::Object(map) = &parsed.value
        && let YamlValue::String(s) = &map.get(&Cow::Borrowed("description")).unwrap().value
    {
        assert_eq!(s.as_ref(), "Line 1\nLine 2");
    }
}

#[test]
fn test_literal_with_keep_chomp() {
    // Test |+ (literal with keep chomping - keeps all trailing newlines)
    let yaml = r#"
description: |+
  Line 1
  Line 2

"#;

    let parsed = parse(yaml).expect("Failed to parse literal with keep chomp");

    if let YamlValue::Object(map) = &parsed.value
        && let YamlValue::String(s) = &map.get(&Cow::Borrowed("description")).unwrap().value
    {
        // Note: our current implementation doesn't capture trailing blank lines
        // This is a known limitation we can improve later
        assert_eq!(s.as_ref(), "Line 1\nLine 2\n");
    }
}

#[test]
fn test_folded_with_strip_chomp() {
    // Test >- (folded with strip chomping)
    let yaml = r#"
description: >-
  This is a folded
  multiline string.

"#;

    let parsed = parse(yaml).expect("Failed to parse folded with strip chomp");

    if let YamlValue::Object(map) = &parsed.value
        && let YamlValue::String(s) = &map.get(&Cow::Borrowed("description")).unwrap().value
    {
        assert_eq!(s.as_ref(), "This is a folded multiline string.");
    }
}

#[test]
fn test_long_quoted_string() {
    let yaml = r#"
poem: "Roses are red,
Violets are blue,
YAML is simple,
And YAMP is too!"
"#;

    let parsed = parse(yaml).expect("Failed to parse multiline quoted string");

    if let YamlValue::Object(map) = &parsed.value
        && let YamlValue::String(s) = &map.get(&Cow::Borrowed("poem")).unwrap().value
    {
        assert_eq!(
            s.as_ref(),
            "Roses are red,\nViolets are blue,\nYAML is simple,\nAnd YAMP is too!"
        );
    }
}