use crate::Error;

use super::*;

#[test]
fn new() {
    let data = [0u8; 10];
    let buffer = ReadBuffer::from(&data);

    assert_eq!(buffer.len(), 10);
    assert_eq!(buffer.consumed(), 0);

    let mut data = [0u8; 20];
    let buffer = WriteBuffer::from(&mut data);

    assert_eq!(buffer.capacity(), 20);
    assert_eq!(buffer.written(), 0);
}

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

    assert!(buffer.write(4, |buf| buf.copy_from_slice(b"1234")).is_ok());
    assert_eq!(buffer.written(), 4);

    assert!(buffer
        .write(10, |_| {})
        .is_err_and(|error| error == Error::OutOfMemory));

    assert!(buffer.write(3, |buf| buf.copy_from_slice(b"abc")).is_ok());
    assert_eq!(buffer.written(), 7);
    assert_eq!(buffer.view().len(), 7);

    assert_eq!(buffer.view(), b"1234abc");
}

#[test]
fn read() {
    let data = b"ok\01234";
    let mut buffer = ReadBuffer::from(data);

    assert!(buffer
        .read(2, |buf| {
            assert_eq!(buf, b"ok");
        })
        .is_ok());

    assert!(buffer
        .read(1, |buf| {
            assert_eq!(buf, b"\0");
        })
        .is_ok());

    assert!(buffer
        .read(0, |buf| {
            assert_eq!(buf.len(), 0);
        })
        .is_ok());

    assert!(buffer
        .read(10, |buf| {
            assert_eq!(buf, b"ok");
        })
        .is_err_and(|error| error == Error::OutOfMemory));

    assert_eq!(buffer.remaining(), b"1234");
    assert_eq!(buffer.consumed(), 3);
}

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

    assert!(buffer
        .write(8, |buf| buf.copy_from_slice(b"itworks!"))
        .is_ok());

    let mut buffer = buffer.into_read_buffer();
    assert!(buffer.read(2, |buf| assert_eq!(buf, b"it")).is_ok());

    assert_eq!(buffer.consumed(), 2);
    assert_eq!(buffer.remaining(), b"works!");
}

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

    buffer.discard(2).unwrap_or_else(|_| panic!());
    assert_eq!(buffer.written(), 2);

    let snapshot = buffer.snapshot();

    buffer.discard(1).unwrap_or_else(|_| panic!());
    assert_eq!(buffer.written(), 3);

    buffer.restore(snapshot);
    assert_eq!(buffer.written(), 2);

    let mut buffer = ReadBuffer::from(&data);

    buffer.discard(2).unwrap_or_else(|_| panic!());
    assert_eq!(buffer.consumed(), 2);

    let snapshot = buffer.snapshot();

    buffer.discard(1).unwrap_or_else(|_| panic!());
    assert_eq!(buffer.consumed(), 3);

    buffer.restore(snapshot);
    assert_eq!(buffer.consumed(), 2);
}

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

    buffer.write(2, |_| {}).unwrap_or_else(|_| panic!());
    assert!(!buffer.flagged());

    assert!(buffer.write(3, |_| {}).is_err());
    assert!(buffer.flagged());

    buffer.unflag();
    assert!(!buffer.flagged());

    assert!(buffer.discard(3).is_err());
    assert!(buffer.flagged());

    buffer.unflag();
    assert!(!buffer.flagged());

    buffer.discard(2).unwrap_or_else(|_| panic!());
    assert!(!buffer.flagged());
}
