#![allow(
    clippy::indexing_slicing,
    reason = "unwraps are allowed anywhere in tests"
)]

use super::{CiExactLen, CiMaxLen, Warning};
use crate::{
    json::{self, FromJson as _},
    warning,
};

const LEN: usize = 3;

#[test]
fn should_parse_max_len() {
    let input = "hel";
    let (output, warnings) = max_len(input);
    assert!(warnings.is_empty(), "{:#?}", warnings.path_id_map());
    assert_eq!(output, input);
}

#[test]
fn should_fail_on_max_len() {
    let input = "hello";
    let (output, warnings) = max_len(input);
    let warnings = warnings.into_path_as_str_map();
    let warnings = &warnings["$"];
    let [Warning::InvalidLengthMax { length }] = warnings.as_slice() else {
        panic!("expected one InvalidLengthMax warning, got {warnings:?}");
    };
    let length = *length;
    assert_eq!(length, LEN);
    assert_eq!(output, input);
}

#[test]
fn should_parse_exact_len() {
    let input = "hel";
    let (output, warnings) = expect_len(input);
    assert!(warnings.is_empty(), "{:#?}", warnings.path_id_map());
    assert_eq!(output, input);
}

#[test]
fn should_fail_on_exact_len() {
    let input = "hello";
    let (output, warnings) = expect_len(input);
    let warnings = warnings.into_path_as_str_map();
    let warnings = &warnings["$"];
    let [Warning::InvalidLengthExact { length }] = warnings.as_slice() else {
        panic!("expected one InvalidLengthExact warning, got {warnings:?}");
    };
    let length = *length;
    assert_eq!(length, LEN);
    assert_eq!(output, input);
}

#[track_caller]
fn max_len(s: &str) -> (String, warning::Set<Warning>) {
    let quoted_input = format!(r#""{s}""#);
    let doc = json::parse((&*quoted_input).into()).unwrap();
    let output = CiMaxLen::<'_, LEN>::from_json(doc.root()).unwrap();
    let (output, warnings) = output.into_parts();
    (output.to_string(), warnings)
}

#[track_caller]
fn expect_len(s: &str) -> (String, warning::Set<Warning>) {
    let quoted_input = format!(r#""{s}""#);
    let doc = json::parse((&*quoted_input).into()).unwrap();
    let output = CiExactLen::<'_, LEN>::from_json(doc.root()).unwrap();
    let (output, warnings) = output.into_parts();
    (output.to_string(), warnings)
}
