//! Shebang handling tests (Sections 3.5, 6.4).

use crate::{parse, parse_with_config, Entry, ParserConfig};

fn kv(line: u32, key: &str, value: &str) -> Entry {
    Entry::Kv {
        line,
        key: key.to_owned(),
        value: value.to_owned(),
    }
}

/// Shebang is detected on the first line when it starts with `#!`.
#[test]
fn shebang_detected() {
    let config = ParserConfig {
        emit_shebang: true,
        ..ParserConfig::default()
    };
    let input = b"#!/usr/bin/env kvf\nKEY=value\n";
    let entries = parse_with_config(input, &config).unwrap();
    assert_eq!(
        entries[0],
        Entry::Shebang {
            text: "#!/usr/bin/env kvf".to_owned()
        }
    );
}

/// Shebang is line 0; KV lines start at line 1.
#[test]
fn shebang_is_line_zero_kv_starts_at_one() {
    let config = ParserConfig {
        emit_shebang: true,
        ..ParserConfig::default()
    };
    let input = b"#!/usr/bin/env kvf\nKEY=value\n";
    let entries = parse_with_config(input, &config).unwrap();
    assert_eq!(entries[1], kv(1, "KEY", "value"));
}

/// Shebang content is preserved verbatim (including `#!` prefix), without EOL.
#[test]
fn shebang_verbatim() {
    let config = ParserConfig {
        emit_shebang: true,
        ..ParserConfig::default()
    };
    let input = b"#!/usr/bin/env kvf --strict\nKEY=v\n";
    let entries = parse_with_config(input, &config).unwrap();
    assert_eq!(
        entries[0],
        Entry::Shebang {
            text: "#!/usr/bin/env kvf --strict".to_owned()
        }
    );
}

/// Shebang is suppressed when `emit_shebang` is false (the default).
#[test]
fn shebang_suppressed_by_default() {
    let input = b"#!/usr/bin/env kvf\nKEY=value\n";
    let entries = parse(input).unwrap();
    assert!(!entries.iter().any(|e| matches!(e, Entry::Shebang { .. })));
    assert_eq!(entries[0], kv(1, "KEY", "value"));
}

/// A `#!` that appears on line 2 or later is a regular comment, not a shebang.
#[test]
fn shebang_only_on_first_line() {
    let input = b"KEY=value\n#!/not/a/shebang\n";
    let entries = parse(input).unwrap();
    // The second line is a comment, not a shebang entry.
    assert!(!entries.iter().any(|e| matches!(e, Entry::Shebang { .. })));
    assert!(entries
        .iter()
        .any(|e| matches!(e, Entry::Comment { line: 2, .. })));
}

/// Shebang line with CRLF terminator.
#[test]
fn shebang_crlf() {
    let config = ParserConfig {
        emit_shebang: true,
        ..ParserConfig::default()
    };
    let input = b"#!/usr/bin/env kvf\r\nKEY=value\n";
    let entries = parse_with_config(input, &config).unwrap();
    assert_eq!(
        entries[0],
        Entry::Shebang {
            text: "#!/usr/bin/env kvf".to_owned()
        }
    );
}
