//! EOL and CRLF handling tests (Section 3.4).

use crate::{parse, Entry, ParseError};

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

/// LF-terminated lines are parsed correctly.
#[test]
fn lf_terminator() {
    let input = b"A=1\nB=2\n";
    let entries = parse(input).unwrap();
    assert_eq!(entries, vec![kv(1, "A", "1"), kv(2, "B", "2")]);
}

/// CRLF-terminated lines are parsed correctly.
#[test]
fn crlf_terminator() {
    let input = b"A=1\r\nB=2\r\n";
    let entries = parse(input).unwrap();
    assert_eq!(entries, vec![kv(1, "A", "1"), kv(2, "B", "2")]);
}

/// Intermixing LF and CRLF is allowed.
#[test]
fn mixed_lf_crlf() {
    let input = b"A=1\r\nB=2\nC=3\r\n";
    let entries = parse(input).unwrap();
    assert_eq!(entries, vec![
        kv(1, "A", "1"),
        kv(2, "B", "2"),
        kv(3, "C", "3"),
    ]);
}

/// Missing final EOL yields `MissingFinalEolError`.
#[test]
fn missing_final_eol() {
    let errors = parse(b"KEY=value").unwrap_err();
    assert_eq!(errors, vec![ParseError::MissingFinalEolError]);
}

/// A file with only a newline (single blank line) is valid.
#[test]
fn single_newline_only() {
    let entries = parse(b"\n").unwrap();
    // No KV entries, no errors (blank suppressed by default).
    assert!(entries.is_empty());
}

/// CRLF at end of single blank line is valid.
#[test]
fn single_crlf_only() {
    let entries = parse(b"\r\n").unwrap();
    assert!(entries.is_empty());
}

/// The CR in CRLF must NOT appear in the value.
#[test]
fn cr_in_value_is_error() {
    // The CR is not followed by LF in the value position.
    let input = b"KEY=val\r ue\n";
    let errors = parse(input).unwrap_err();
    assert_eq!(errors, vec![ParseError::InvalidCharacterError { line: 1 }]);
}

/// A CRLF line followed by another line produces correct line numbers.
#[test]
fn crlf_line_numbers() {
    let input = b"A=1\r\nB=2\r\nC=3\r\n";
    let entries = parse(input).unwrap();
    let lines: Vec<u32> = entries.iter().map(|e| match e {
        Entry::Kv { line, .. } => *line,
        _ => 0,
    }).collect();
    assert_eq!(lines, vec![1, 2, 3]);
}
