use decoder::{decode, MAX_ARRAY_SIZE};
use std::collections::BTreeMap;
use {CborError, CborType};

// First test all the basic types
fn test_decoder(bytes: Vec<u8>, expected: CborType) {
    let result = decode(&bytes);
    assert!(result.is_ok());
    assert_eq!(result.unwrap(), expected);
}

fn test_decoder_error(bytes: Vec<u8>, expected_error: CborError) {
    let result = decode(&bytes);
    assert!(result.is_err());
    assert_eq!(result.unwrap_err(), expected_error);
}

fn test_integer(bytes: Vec<u8>, expected: u64) {
    let decoded = decode(&bytes).unwrap();
    match decoded {
        CborType::Integer(val) => assert_eq!(val, expected),
        _ => assert_eq!(1, 0),
    }
}

fn test_integer_all(bytes: Vec<u8>, expected_value: u64) {
    let expected = CborType::Integer(expected_value);
    test_decoder(bytes.clone(), expected);
    test_integer(bytes, expected_value);
}

#[test]
fn test_integer_objects() {
    let bytes: Vec<u8> = vec![0x00];
    test_integer_all(bytes, 0);

    let bytes = vec![0x01];
    test_integer_all(bytes, 1);

    let bytes = vec![0x0A];
    test_integer_all(bytes, 10);

    let bytes = vec![0x17];
    test_integer_all(bytes, 23);

    let bytes = vec![0x18, 0x18];
    test_integer_all(bytes, 24);

    let bytes = vec![0x18, 0x19];
    test_integer_all(bytes, 25);

    let bytes = vec![0x18, 0x64];
    test_integer_all(bytes, 100);

    let bytes = vec![0x19, 0x03, 0xe8];
    test_integer_all(bytes, 1000);

    let bytes = vec![0x1a, 0x00, 0x0f, 0x42, 0x40];
    test_integer_all(bytes, 1000000);

    let bytes = vec![0x1b, 0x00, 0x00, 0x00, 0xe8, 0xd4, 0xa5, 0x10, 0x00];
    test_integer_all(bytes, 1000000000000);

    let bytes = vec![0x1b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff];
    test_integer_all(bytes, 18446744073709551615);
}

#[cfg(test)]
fn test_tag(bytes: Vec<u8>, expected_tag: u64, expected_value: CborType) {
    let decoded = decode(&bytes).unwrap();
    match decoded {
        CborType::Tag(tag, value) => {
            assert_eq!(expected_tag, tag);
            assert_eq!(expected_value, *value);
        }
        _ => assert_eq!(1, 0),
    }
}

#[test]
fn test_tagged_objects() {
    let bytes: Vec<u8> = vec![0xD2, 0x02];
    let expected_tag_value = 0x12;
    let expected_value = CborType::Integer(2);
    let expected = CborType::Tag(expected_tag_value, Box::new(expected_value.clone()));
    test_decoder(bytes.clone(), expected);
    test_tag(bytes, expected_tag_value, expected_value);
}

#[test]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn test_arrays() {
    // []
    let bytes: Vec<u8> = vec![0x80];
    let expected = CborType::Array(vec![]);
    test_decoder(bytes, expected);

    // [1, 2, 3]
    let bytes: Vec<u8> = vec![0x83, 0x01, 0x02, 0x03];
    let tmp = vec![
        CborType::Integer(1),
        CborType::Integer(2),
        CborType::Integer(3),
    ];
    let expected = CborType::Array(tmp);
    test_decoder(bytes, expected);

    // [1, [2, 3], [4, 5]]
    let bytes: Vec<u8> = vec![0x83, 0x01, 0x82, 0x02, 0x03, 0x82, 0x04, 0x05];
    let tmp1 = vec![CborType::Integer(2), CborType::Integer(3)];
    let tmp2 = vec![CborType::Integer(4), CborType::Integer(5)];
    let tmp = vec![
        CborType::Integer(1),
        CborType::Array(tmp1),
        CborType::Array(tmp2),
    ];
    let expected = CborType::Array(tmp);
    test_decoder(bytes, expected);

    // [1, [[[[1]]]], [1]]
    let bytes: Vec<u8> = vec![0x83, 0x01, 0x81, 0x81, 0x81, 0x81, 0x01, 0x81, 0x02];
    let tmp = vec![
        CborType::Integer(1),
        CborType::Array(vec![
            CborType::Array(vec![
                CborType::Array(vec![
                    CborType::Array(vec![
                        CborType::Integer(1)])])])]),
        CborType::Array(vec![CborType::Integer(2)]),
    ];
    let expected = CborType::Array(tmp);
    test_decoder(bytes, expected);

    let bytes: Vec<u8> = vec![0x98, 0x1A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
                              0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
                              0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
                              0x17, 0x18, 0x18, 0x18, 0x19, 0x82, 0x81, 0x81,
                              0x81, 0x05, 0x81, 0x1A, 0x49, 0x96, 0x02, 0xD2];
    // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
    //  21, 22, 23, 24, 25, [[[[5]]], [1234567890]]]
    let tmp = vec![
        CborType::Integer(1),
        CborType::Integer(2),
        CborType::Integer(3),
        CborType::Integer(4),
        CborType::Integer(5),
        CborType::Integer(6),
        CborType::Integer(7),
        CborType::Integer(8),
        CborType::Integer(9),
        CborType::Integer(10),
        CborType::Integer(11),
        CborType::Integer(12),
        CborType::Integer(13),
        CborType::Integer(14),
        CborType::Integer(15),
        CborType::Integer(16),
        CborType::Integer(17),
        CborType::Integer(18),
        CborType::Integer(19),
        CborType::Integer(20),
        CborType::Integer(21),
        CborType::Integer(22),
        CborType::Integer(23),
        CborType::Integer(24),
        CborType::Integer(25),
        CborType::Array(vec![
            CborType::Array(vec![
                CborType::Array(vec![
                    CborType::Array(vec![
                        CborType::Integer(5)])])]),
            CborType::Array(vec![CborType::Integer(1234567890)])])
    ];
    let expected = CborType::Array(tmp);
    test_decoder(bytes, expected);
}

#[test]
fn test_signed_integer() {
    let bytes: Vec<u8> = vec![0x20];
    let expected = CborType::SignedInteger(-1);
    test_decoder(bytes, expected);

    let bytes = vec![0x29];
    let expected = CborType::SignedInteger(-10);
    test_decoder(bytes, expected);

    let bytes = vec![0x38, 0x63];
    let expected = CborType::SignedInteger(-100);
    test_decoder(bytes, expected);

    let bytes = vec![0x39, 0x03, 0xe7];
    let expected = CborType::SignedInteger(-1000);
    test_decoder(bytes, expected);

    let bytes = vec![0x39, 0x27, 0x0F];
    let expected = CborType::SignedInteger(-10000);
    test_decoder(bytes, expected);

    let bytes = vec![0x3A, 0x00, 0x01, 0x86, 0x9F];
    let expected = CborType::SignedInteger(-100000);
    test_decoder(bytes, expected);

    let bytes = vec![0x3B, 0x00, 0x00, 0x00, 0xE8, 0xD4, 0xA5, 0x0F, 0xFF];
    let expected = CborType::SignedInteger(-1000000000000);
    test_decoder(bytes, expected);
}

#[test]
fn test_byte_strings() {
    let bytes: Vec<u8> = vec![0x40];
    let expected = CborType::Bytes(vec![]);
    test_decoder(bytes, expected);

    // 01020304
    let bytes: Vec<u8> = vec![0x44, 0x01, 0x02, 0x03, 0x04];
    let expected = CborType::Bytes(vec![0x01, 0x02, 0x03, 0x04]);
    test_decoder(bytes, expected);

    // 0102030405060708090A0B0C0D0E0F10203040506070
    let bytes: Vec<u8> = vec![
        0x56, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
        0x0f, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
    ];
    let expected = CborType::Bytes(vec![
        0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
        0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
    ]);
    test_decoder(bytes, expected);

    let bytes: Vec<u8> = vec![
        0x59, 0x01, 0x0E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF,
    ];
    let expected = CborType::Bytes(vec![
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    ]);
    test_decoder(bytes, expected);
}

#[test]
fn test_maps() {
    // {}
    let bytes: Vec<u8> = vec![0xa0];
    let expected: BTreeMap<CborType, CborType> = BTreeMap::new();
    test_decoder(bytes, CborType::Map(expected));

    // {1: 2, 3: 4}
    let bytes: Vec<u8> = vec![0xa2, 0x01, 0x02, 0x03, 0x04];
    let mut expected: BTreeMap<CborType, CborType> = BTreeMap::new();
    expected.insert(CborType::Integer(1), CborType::Integer(2));
    expected.insert(CborType::Integer(3), CborType::Integer(4));
    test_decoder(bytes, CborType::Map(expected));

    // TODO: strings aren't properly supported as keys yet.
    // {"a": 1, "b": [2, 3]}
    // let bytes: Vec<u8> = vec![0xa2, 0x61, 0x61, 0x01, 0x61, 0x62, 0x82, 0x02, 0x03];
    // let expected =
    //     CborType::Map(vec![
    //         CborMap{key: CborType::Integer(1), value: CborType::Integer(2)},
    //         CborMap{key: CborType::Integer(3), value: CborType::Integer(4)}]);
    // test_decoder(bytes, expected);

    // let bytes: Vec<u8> = vec![0x82, 0x61, 0x61, 0xa1, 0x61, 0x62, 0x61, 0x63];
    // test_decoder(bytes, "[a, {b: c}]");

    // let bytes: Vec<u8> = vec![0xa5, 0x61, 0x61, 0x61, 0x41, 0x61, 0x62, 0x61,
    //                           0x42, 0x61, 0x63, 0x61, 0x43, 0x61, 0x64, 0x61,
    //                           0x44, 0x61, 0x65, 0x61, 0x45];
    // test_decoder(bytes, "{a: A, b: B, c: C, d: D, e: E}");
}

#[test]
fn test_map_duplicate_keys() {
    let bytes: Vec<u8> = vec![0xa4, 0x01, 0x02, 0x02, 0x03, 0x01, 0x03, 0x04, 0x04];
    test_decoder_error(bytes, CborError::DuplicateMapKey);
}

#[test]
fn test_tag_with_no_value() {
    let bytes: Vec<u8> = vec![0xc0];
    test_decoder_error(bytes, CborError::TruncatedInput);
}

#[test]
fn test_truncated_int() {
    let bytes: Vec<u8> = vec![0x19, 0x03];
    test_decoder_error(bytes, CborError::TruncatedInput);
}

#[test]
fn test_truncated_array() {
    let bytes: Vec<u8> = vec![0x83, 0x01, 0x02];
    test_decoder_error(bytes, CborError::TruncatedInput);
}

#[test]
fn test_truncated_map() {
    let bytes: Vec<u8> = vec![0xa2, 0x01, 0x02, 0x00];
    test_decoder_error(bytes, CborError::TruncatedInput);
}

#[test]
fn test_malformed_integer() {
    let bytes: Vec<u8> = vec![0x1c];
    test_decoder_error(bytes, CborError::MalformedInput);
}

#[test]
fn test_signed_integer_too_large() {
    let bytes = vec![0x3b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff];
    test_decoder_error(bytes, CborError::InputValueOutOfRange);
}

#[test]
fn test_null() {
    let bytes = vec![0xf6];
    test_decoder(bytes, CborType::Null);
}

#[test]
fn test_null_in_array() {
    let bytes = vec![0x82, 0xf6, 0xf6];
    test_decoder(bytes, CborType::Array(vec![CborType::Null, CborType::Null]));
}

#[test]
fn test_major_type_7() {
    for i in 0..0x20 {
        if i != 22 {
            let bytes = vec![0xe0 | i];
            test_decoder_error(bytes, CborError::UnsupportedType);
        }
    }
}

#[test]
fn test_large_input() {
    let array = vec![0xFF; MAX_ARRAY_SIZE];
    let expected = CborType::Bytes(array.clone());
    let mut bytes = vec![0x5A, 0x08, 0x00, 0x00, 0x00];
    bytes.extend_from_slice(&array);
    test_decoder(bytes, expected);
}

#[test]
fn test_too_large_input() {
    let array = vec![0xFF; MAX_ARRAY_SIZE + 1];
    let mut bytes = vec![0x5A, 0x08, 0x00, 0x00, 0x01];
    bytes.extend_from_slice(&array);
    test_decoder_error(bytes, CborError::InputTooLarge);
}

// We currently don't support CBOR strings (issue #39).
#[test]
fn test_invalid_input() {
    let bytes = vec![0x60];
    test_decoder_error(bytes, CborError::UnsupportedType);
}

#[test]
fn test_avoid_stack_exhaustion_with_arrays() {
    let mut bytes: Vec<u8> = Vec::new();
    // Create a payload representing Array(Array(Array(Array(...(Array(0))))))
    // If the implementation is not careful, this will exhaust the stack.
    for _ in 1..10000 {
        bytes.push(0b1000_0001);
    }
    bytes.push(0);
    test_decoder_error(bytes, CborError::MalformedInput);
}

#[test]
fn test_avoid_stack_exhaustion_with_maps_1() {
    let mut bytes: Vec<u8> = Vec::new();
    // Create a payload representing Map(0: Map(0: Map(0: Map(...Map()))))
    // If the implementation is not careful, this will exhaust the stack.
    for _ in 1..10000 {
        bytes.push(0b1010_0001);
        bytes.push(0);
    }
    bytes.push(0b1010_0000);
    test_decoder_error(bytes, CborError::MalformedInput);
}

#[test]
fn test_avoid_stack_exhaustion_with_maps_2() {
    let mut bytes: Vec<u8> = Vec::new();
    // Create a payload representing Map(Map(Map(...(Map(): 0): 0): 0): 0)
    // If the implementation is not careful, this will exhaust the stack.
    for _ in 1..10000 {
        bytes.push(0b1010_0001);
    }
    bytes.push(0b1010_0000);
    for _ in 1..9999 {
        bytes.push(0);
    }
    test_decoder_error(bytes, CborError::MalformedInput);
}

#[test]
fn test_avoid_stack_exhaustion_with_tags() {
    let mut bytes: Vec<u8> = Vec::new();
    // Create a payload representing Tag(6: Tag(6: Tag(6: Tag(...Tag(0)))))
    // If the implementation is not careful, this will exhaust the stack.
    for _ in 1..10000 {
        bytes.push(0b1100_0110);
    }
    bytes.push(0);
    test_decoder_error(bytes, CborError::MalformedInput);
}
