use super::*;
use crate::{Marker, WriteBuffer};

#[test]
fn unsigned() {
    let mut data = [0u8; 20];
    let mut buffer = WriteBuffer::from(&mut data);

    let marker = write_unsigned(&mut buffer, 127).unwrap_or_else(|_| panic!());
    assert!(matches!(marker, Marker::ImmPos { value: 127 }));

    let marker = write_unsigned(&mut buffer, 128).unwrap_or_else(|_| panic!());
    assert!(matches!(marker, Marker::U8));

    let marker = write_unsigned(&mut buffer, 256).unwrap_or_else(|_| panic!());
    assert!(matches!(marker, Marker::U16));

    let marker = write_unsigned(&mut buffer, 65536).unwrap_or_else(|_| panic!());
    assert!(matches!(marker, Marker::U32));

    let marker = write_unsigned(&mut buffer, 4294967296).unwrap_or_else(|_| panic!());
    assert!(matches!(marker, Marker::U64));

    assert_eq!(
        &data,
        &[
            0b01111111, // PosImm
            0b11001000, 0x80, // U8
            0b11001001, 0x01, 0x00, // U16
            0b11001010, 0x00, 0x01, 0x00, 0x00, // U32
            0b11001011, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // U64
        ]
    )
}

#[test]
fn signed() {
    let mut data = [0u8; 20];
    let mut buffer = WriteBuffer::from(&mut data);

    let marker = write_signed(&mut buffer, -32).unwrap_or_else(|_| panic!());
    assert!(matches!(marker, Marker::ImmNeg { value: -32 }));

    let marker = write_signed(&mut buffer, -128).unwrap_or_else(|_| panic!());
    assert!(matches!(marker, Marker::I8));

    let marker = write_signed(&mut buffer, -256).unwrap_or_else(|_| panic!());
    assert!(matches!(marker, Marker::I16));

    let marker = write_signed(&mut buffer, -65536).unwrap_or_else(|_| panic!());
    assert!(matches!(marker, Marker::I32));

    let marker = write_signed(&mut buffer, -4294967296).unwrap_or_else(|_| panic!());
    assert!(matches!(marker, Marker::I64));

    assert_eq!(
        &data,
        &[
            0b11100000, // NegImm
            0b11001100, 0x80, // I8
            0b11001101, 0xff, 0x00, // I16
            0b11001110, 0xff, 0xff, 0x00, 0x00, // I32
            0b11001111, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, // I64
        ]
    )
}

#[test]
fn ascii() {
    let mut data = [0u8; 39];
    let mut buffer = WriteBuffer::from(&mut data);

    let marker = write_str(&mut buffer, "ok").unwrap_or_else(|_| panic!());
    assert!(matches!(marker, Marker::ImmStr { len: 2 }));

    let marker = write_str(&mut buffer, "").unwrap_or_else(|_| panic!());
    assert!(matches!(marker, Marker::ImmStr { len: 0 }));

    let marker =
        write_str(&mut buffer, "12345678123456781234567812345678!").unwrap_or_else(|_| panic!());
    assert!(matches!(marker, Marker::S8));

    assert_eq!(
        &data,
        &[
            0b10000010, b'o', b'k',       // StrImm, "ok"
            0b10000000, // StrImm
            0b11010000, 33, // S8
            b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', // "12345678"
            b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', // "12345678"
            b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', // "12345678"
            b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', // "12345678"
            b'!'
        ]
    );
}

#[test]
fn null() {
    let mut data = [0u8; 1];
    let mut buffer = WriteBuffer::from(&mut data);

    let marker = write_null(&mut buffer).unwrap_or_else(|_| panic!());
    assert!(matches!(marker, Marker::Null));

    assert_eq!(&data, &[0b11011110]);
}

#[test]
fn boolean() {
    let mut data = [0u8; 2];
    let mut buffer = WriteBuffer::from(&mut data);

    let marker = write_bool(&mut buffer, true).unwrap_or_else(|_| panic!());
    assert!(matches!(marker, Marker::Bool { value: true }));

    let marker = write_bool(&mut buffer, false).unwrap_or_else(|_| panic!());
    assert!(matches!(marker, Marker::Bool { value: false }));

    assert_eq!(&data, &[0b11011101, 0b11011100]);
}

#[test]
fn float() {
    let mut data = [0u8; 14];
    let mut buffer = WriteBuffer::from(&mut data);

    let marker = write_f32(&mut buffer, -1.5).unwrap_or_else(|_| panic!());
    assert!(matches!(marker, Marker::F32));

    let marker = write_f64(&mut buffer, 10.7).unwrap_or_else(|_| panic!());
    assert!(matches!(marker, Marker::F64));

    assert_eq!(
        data,
        [
            0b11011010, 0xbf, 0xc0, 0x00, 0x00, // F32
            0b11011011, 0x40, 0x25, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, // F64
        ]
    );
}

#[test]
fn bin() {
    let mut data = [0u8; 4];
    let mut buffer = WriteBuffer::from(&mut data);

    let marker = write_bin(&mut buffer, b"ok").unwrap_or_else(|_| panic!());
    assert!(matches!(marker, Marker::B8));

    assert_eq!(data, [0b11010100, 2, b'o', b'k',])
}

#[test]
fn array() {
    let mut data = [0u8; 12];
    let mut buffer = WriteBuffer::from(&mut data);

    let marker = write_array(&mut buffer, Some(15)).unwrap_or_else(|_| panic!());
    assert!(matches!(marker, Marker::ImmArr { len: 15 }));

    let marker = write_array(&mut buffer, Some(128)).unwrap_or_else(|_| panic!());
    assert!(matches!(marker, Marker::A8));

    let marker = write_array(&mut buffer, Some(256)).unwrap_or_else(|_| panic!());
    assert!(matches!(marker, Marker::A16));

    let marker = write_array(&mut buffer, Some(65536)).unwrap_or_else(|_| panic!());
    assert!(matches!(marker, Marker::A32));

    let marker = write_array(&mut buffer, None).unwrap_or_else(|_| panic!());
    assert!(matches!(marker, Marker::AFlex));

    assert_eq!(
        data,
        [
            0b10101111, // ArrImm
            0b11000000, 0x80, // A8
            0b11000001, 0x01, 0x00, // A16
            0b11000010, 0x00, 0x01, 0x00, 0x00,       // A32
            0b11000011, // AFlex
        ]
    )
}

#[test]
fn map() {
    let mut data = [0u8; 12];
    let mut buffer = WriteBuffer::from(&mut data);

    let marker = write_map(&mut buffer, Some(15)).unwrap_or_else(|_| panic!());
    assert!(matches!(marker, Marker::ImmMap { len: 15 }));

    let marker = write_map(&mut buffer, Some(128)).unwrap_or_else(|_| panic!());
    assert!(matches!(marker, Marker::M8));

    let marker = write_map(&mut buffer, Some(256)).unwrap_or_else(|_| panic!());
    assert!(matches!(marker, Marker::M16));

    let marker = write_map(&mut buffer, Some(65536)).unwrap_or_else(|_| panic!());
    assert!(matches!(marker, Marker::M32));

    let marker = write_map(&mut buffer, None).unwrap_or_else(|_| panic!());
    assert!(matches!(marker, Marker::MFlex));

    assert_eq!(
        data,
        [
            0b10111111, // MapImm
            0b11000100, 0x80, // M8
            0b11000101, 0x01, 0x00, // M16
            0b11000110, 0x00, 0x01, 0x00, 0x00,       // M32
            0b11000111, // MFlex
        ]
    )
}

#[test]
fn terminator() {
    let mut data = [0u8; 1];
    let mut buffer = WriteBuffer::from(&mut data);

    let marker = write_terminator(&mut buffer).unwrap_or_else(|_| panic!());
    assert!(matches!(marker, Marker::Term));

    assert_eq!(data, [0b11011111]);
}
