#![cfg(feature = "std")]
#![cfg_attr(feature = "future_deprecations", allow(deprecated))]

use tls_codec::{Serialize, TlsVecU16, TlsVecU24, U24, VLByteSlice, VLBytes};

#[test]
fn serialize_primitives() {
    let mut v = Vec::new();
    77u8.tls_serialize(&mut v).expect("Error encoding u8");
    88u8.tls_serialize(&mut v).expect("Error encoding u8");
    355u16.tls_serialize(&mut v).expect("Error encoding u16");
    U24::try_from(65609usize)
        .unwrap()
        .tls_serialize(&mut v)
        .expect("Error encoding U24");
    let b = [77u8, 88, 1, 99, 1, 0, 73];
    assert_eq!(&b[..], &v[..]);
}

#[test]
fn serialize_tls_vec() {
    let mut v = Vec::new();
    1u8.tls_serialize(&mut v).expect("Error encoding u8");
    TlsVecU16::<u8>::from_slice(&[77, 88, 1, 99])
        .tls_serialize(&mut v)
        .expect("Error encoding u8");
    TlsVecU24::<u8>::from_slice(&[255, 42, 73])
        .tls_serialize(&mut v)
        .expect("Error encoding u8");

    let b = [1u8, 0, 4, 77, 88, 1, 99, 0, 0, 3, 255, 42, 73];
    assert_eq!(&b[..], &v[..]);
}

#[test]
fn serialize_var_len_vec() {
    let v = vec![9u8, 2, 98, 34, 55, 90, 54];
    let serialized = v.tls_serialize_detached().expect("Error encoding vector");
    assert_eq!(serialized, vec![7, 9, 2, 98, 34, 55, 90, 54]);

    let serialized = Vec::<u8>::new()
        .tls_serialize_detached()
        .expect("Error encoding vector");
    assert_eq!(serialized, vec![0x00]);
}

#[test]
fn serialize_var_len_bytes() {
    let v = VLBytes::new(vec![9u8, 2, 98, 34, 55, 90, 54]);
    let serialized = v.tls_serialize_detached().expect("Error encoding vector");
    assert_eq!(serialized, vec![7, 9, 2, 98, 34, 55, 90, 54]);

    let serialized = VLBytes::new(vec![])
        .tls_serialize_detached()
        .expect("Error encoding vector");
    assert_eq!(serialized, vec![0x00]);

    let v = vec![9u8, 2, 98, 34, 55, 90, 54];
    let serialized = VLByteSlice(&v)
        .tls_serialize_detached()
        .expect("Error encoding vector");
    assert_eq!(serialized, vec![7, 9, 2, 98, 34, 55, 90, 54]);

    let serialized = VLByteSlice(&[])
        .tls_serialize_detached()
        .expect("Error encoding vector");
    assert_eq!(serialized, vec![0x00]);
}

#[test]
fn serialize_var_len_boundaries() {
    let v = VLBytes::new(vec![99u8; 63]);
    let serialized = v.tls_serialize_detached().expect("Error encoding vector");
    assert_eq!(&serialized[0..5], &[63, 99, 99, 99, 99]);

    let v = VLBytes::new(vec![99u8; 64]);
    let serialized = v.tls_serialize_detached().expect("Error encoding vector");
    assert_eq!(&serialized[0..5], &[0x40, 64, 99, 99, 99]);

    let v = VLBytes::new(vec![99u8; 16383]);
    let serialized = v.tls_serialize_detached().expect("Error encoding vector");
    assert_eq!(&serialized[0..5], &[0x7f, 0xff, 99, 99, 99]);

    let v = VLBytes::new(vec![99u8; 16384]);
    let serialized = v.tls_serialize_detached().expect("Error encoding vector");
    assert_eq!(&serialized[0..5], &[0x80, 0, 0x40, 0, 99]);
}

#[test]
/// Test that serializations of [`VLBytes`] match for [`tls_codec::Serialize`]
/// and [`tls_codec::SerializeBytes`].
fn test_matching_vl_bytes_serialization() {
    use tls_codec::SerializeBytes;
    let byte_vec = VLBytes::new(vec![99u8; 16384]);
    assert_eq!(
        Serialize::tls_serialize_detached(&byte_vec).expect("Error encoding vector"),
        SerializeBytes::tls_serialize_bytes(&byte_vec).expect("Error encoding byte vector")
    );
}

struct SingleByteWriter<W>(W);

impl<W: std::io::Write> std::io::Write for SingleByteWriter<W> {
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        if buf.is_empty() {
            return Ok(0);
        }

        self.0.write(&buf[..1])
    }

    fn flush(&mut self) -> std::io::Result<()> {
        self.0.flush()
    }
}

#[test]
fn serialize_into_short_writer() {
    let mut short_writer = SingleByteWriter(vec![0u8; 32]);

    let first = [0u8, 1, 2];

    first.tls_serialize(&mut short_writer).unwrap();
    assert_eq!(short_writer.0.len(), 35);
    assert_eq!(&short_writer.0[short_writer.0.len() - 3..], &[0, 1, 2])
}
