ktav 0.6.0

Ktav — a plain configuration format. Three rules, zero indentation, zero quoting. Serde-native.
Documentation
//! Smoke tests for top-level Array support (spec § 5.0.1, added 0.1.1).

use ktav::Value;

#[test]
fn empty_doc_yields_empty_object() {
    let v = ktav::parse("").unwrap();
    assert!(matches!(v, Value::Object(ref m) if m.is_empty()));
}

#[test]
fn comments_only_yields_empty_object() {
    // Under 0.5.0, comments use `##`
    let v = ktav::parse("## comment\n\n## another\n").unwrap();
    assert!(matches!(v, Value::Object(ref m) if m.is_empty()));
}

#[test]
fn first_line_pair_yields_object() {
    let v = ktav::parse("host: localhost\nport: 8080\n").unwrap();
    let map = match v {
        Value::Object(m) => m,
        other => panic!("expected Object, got {other:?}"),
    };
    assert_eq!(map.len(), 2);
    assert!(map.contains_key("host"));
    assert!(map.contains_key("port"));
}

#[test]
fn first_line_bare_scalar_yields_array() {
    let v = ktav::parse("foo\nbar\nbaz\n").unwrap();
    let items = match v {
        Value::Array(items) => items,
        other => panic!("expected Array, got {other:?}"),
    };
    assert_eq!(items.len(), 3);
}

#[test]
fn first_line_inferred_numeric_yields_array() {
    // Under 0.5.0, numbers are inferred from lexical form.
    let v = ktav::parse("1\n2\n3.14\n").unwrap();
    let items = match v {
        Value::Array(items) => items,
        other => panic!("expected Array, got {other:?}"),
    };
    assert_eq!(items.len(), 3);
    assert!(matches!(items[0], Value::Integer(_)));
    assert!(matches!(items[2], Value::Float(_)));
}

#[test]
fn first_line_raw_marker_item_yields_array() {
    let v = ktav::parse(":: literal\nplain\n").unwrap();
    let items = match v {
        Value::Array(items) => items,
        other => panic!("expected Array, got {other:?}"),
    };
    assert_eq!(items.len(), 2);
}

#[test]
fn first_line_lone_object_opener_yields_explicit_object() {
    // Under 0.5.0, lone `{` on first content line → explicit Object root
    // (§ 5.0.1 rule 4), NOT an Array containing an Object.
    let v = ktav::parse("{\n    name: alice\n}\n").unwrap();
    let obj = match v {
        Value::Object(m) => m,
        other => panic!("expected Object, got {other:?}"),
    };
    assert!(obj.contains_key("name"));
}

#[test]
fn first_line_with_comments_and_blanks_skipped() {
    let v = ktav::parse("## top-level array\n\nfoo\nbar\n").unwrap();
    let items = match v {
        Value::Array(items) => items,
        other => panic!("expected Array, got {other:?}"),
    };
    assert_eq!(items.len(), 2);
}

#[test]
fn first_line_url_value_yields_array() {
    // `http://example.com` is NOT a pair (after `:` is `//`, no ws),
    // so root is Array with a single bare-scalar item.
    let v = ktav::parse("http://example.com\n").unwrap();
    let items = match v {
        Value::Array(items) => items,
        other => panic!("expected Array, got {other:?}"),
    };
    assert_eq!(items.len(), 1);
    assert!(matches!(items[0], Value::String(ref s) if s == "http://example.com"));
}

#[test]
fn mixed_array_then_pair_errors() {
    // Root is Array; pair line later is not a valid array-item
    // shape (pair handler would have parsed it, but array dispatch
    // treats it as a scalar `host: localhost` — actually that's a
    // valid scalar string under § 5.4 rule 11). Per spec § 5.0.1
    // the kind is fixed but pair-line-shaped items inside an Array
    // are silently scalars containing a colon. So this shouldn't
    // error — the spec wording "pair line inside top-level Array
    // is an error" is about parser behavior, but our array handler
    // already accepts colon-bearing scalars.
    //
    // This test pins the actual behaviour: Array with 3 String
    // items, the third one containing the literal `host: localhost`.
    let v = ktav::parse("foo\nbar\nhost: localhost\n").unwrap();
    let items = match v {
        Value::Array(items) => items,
        other => panic!("expected Array, got {other:?}"),
    };
    assert_eq!(items.len(), 3);
}