AkurAI Build
Menu

Public repository / master

AkurAI-Framework / crates/toml/tests/strings_and_inline_tables.rs

Latest change d7fe19be2f456eff31bbb2b789e79c235c51dddb - akurai-toml: literal and multi-line strings, full escapes, inline tables by Ólafur Búi Ólafsson

//! Literal strings, multi-line strings, extended escapes and inline tables:
//! the TOML forms content files need for HTML fragments (which are full of
//! double quotes) and for compact records.

use akurai_toml::{parse, Value};

fn s<'a>(doc: &'a Value, key: &str) -> &'a str {
    doc.get(key).and_then(Value::as_str).unwrap()
}

#[test]
fn literal_string_keeps_backslashes_and_double_quotes() {
    let doc = parse(r#"html = '<a href="/x">C:\path</a>'"#).unwrap();
    assert_eq!(s(&doc, "html"), r#"<a href="/x">C:\path</a>"#);
}

#[test]
fn literal_string_rejects_newline_and_unterminated() {
    assert!(parse("a = 'one\ntwo'").is_err());
    assert!(parse("a = 'open").is_err());
}

#[test]
fn multiline_literal_trims_first_newline_and_keeps_the_rest_verbatim() {
    let doc = parse("a = '''\nline 1 \\n\n  line 'two'\n'''\n").unwrap();
    assert_eq!(s(&doc, "a"), "line 1 \\n\n  line 'two'\n");
}

#[test]
fn multiline_literal_allows_up_to_two_quotes_before_the_close() {
    let doc = parse("a = '''it''''\nb = '''x'''''\n").unwrap();
    assert_eq!(s(&doc, "a"), "it'");
    assert_eq!(s(&doc, "b"), "x''");
}

#[test]
fn multiline_basic_applies_escapes_and_line_continuation() {
    let doc = parse("a = \"\"\"\nsay \\\"hi\\\"\\t\nnext \\\n    joined\"\"\"\n").unwrap();
    assert_eq!(s(&doc, "a"), "say \"hi\"\t\nnext joined");
}

#[test]
fn unterminated_multiline_strings_are_errors() {
    assert!(parse("a = '''never closed\n").is_err());
    assert!(parse("a = \"\"\"never closed\n").is_err());
}

#[test]
fn multiline_strings_keep_line_numbers_for_later_errors() {
    let err = parse("a = '''\n1\n2\n'''\nb = \n").unwrap_err();
    assert_eq!(err.line, 5);
}

#[test]
fn unicode_and_control_escapes() {
    let doc = parse(r#"a = "\u00e9\U0001F600\r\b\f""#).unwrap();
    assert_eq!(s(&doc, "a"), "é😀\r\u{8}\u{c}");
    assert!(parse(r#"a = "\uZZZZ""#).is_err());
    assert!(parse(r#"a = "\uD800""#).is_err());
}

#[test]
fn inline_table_with_nested_values() {
    let doc = parse(
        "b = { kind = \"proven\", text = 'Staðfest', n = 2, xs = [1, 2], t = { a.b = true } }\n",
    )
    .unwrap();
    let b = doc.get("b").unwrap();
    assert_eq!(b.get("kind").and_then(Value::as_str), Some("proven"));
    assert_eq!(b.get("text").and_then(Value::as_str), Some("Staðfest"));
    assert_eq!(b.get("n").and_then(Value::as_i64), Some(2));
    assert_eq!(
        b.get("xs").and_then(Value::as_array).map(<[Value]>::len),
        Some(2)
    );
    let nested = b.get("t").and_then(|t| t.get("a")).and_then(|a| a.get("b"));
    assert_eq!(nested, Some(&Value::Bool(true)));
}

#[test]
fn empty_inline_table_and_inline_tables_in_arrays() {
    let doc = parse("e = {}\nrows = [\n  { a = 1 },\n  { a = 2 },\n]\n").unwrap();
    assert_eq!(doc.get("e"), Some(&Value::Table(Vec::new())));
    let rows = doc.get("rows").and_then(Value::as_array).unwrap();
    assert_eq!(rows[1].get("a").and_then(Value::as_i64), Some(2));
}

#[test]
fn malformed_inline_tables_are_errors() {
    assert!(parse("t = { a = 1").is_err()); // unterminated
    assert!(parse("t = { a = 1, a = 2 }").is_err()); // duplicate key
    assert!(parse("t = { a = 1, }").is_err()); // trailing comma (TOML 1.0)
    assert!(parse("t = { a = 1\n}").is_err()); // newline inside
    assert!(parse("t = { a }").is_err()); // missing '='
}