//! Tests for custom derive support. Without alloc feature.
//!
//! # Debugging with `cargo expand`
//!
//! To expand the Rust code generated by the proc macro when debugging
//! issues related to these tests, run:
//!
//! ```text
//! $ cargo expand --test derive_no_alloc --all-features
//! ```

#![cfg(feature = "derive")]
// TODO: fix needless_question_mark in the derive crate
#![allow(clippy::needless_question_mark)]

/// Custom derive test cases for the `Sequence` macro, without alloc.
mod sequence {
    use der::Decode;
    use der::Encode;
    use der::Sequence;

    #[derive(Sequence, Default, Eq, PartialEq, Debug)]
    #[asn1(tag_mode = "IMPLICIT")]
    pub struct TypeCheckArraysSequenceFieldAttributeCombinations {
        #[asn1(type = "OCTET STRING", deref = "true")]
        pub array_bytes: [u8; 2],

        #[asn1(type = "BIT STRING", deref = "true")]
        pub array_bits: [u8; 2],

        #[asn1(type = "OCTET STRING", context_specific = "0", deref = "true")]
        pub array_implicit_bytes: [u8; 2],

        #[asn1(type = "BIT STRING", context_specific = "1", deref = "true")]
        pub array_implicit_bits: [u8; 2],

        #[asn1(
            type = "OCTET STRING",
            context_specific = "2",
            tag_mode = "EXPLICIT",
            deref = "true"
        )]
        pub array_explicit_bytes: [u8; 2],

        #[asn1(
            type = "BIT STRING",
            context_specific = "3",
            tag_mode = "EXPLICIT",
            deref = "true"
        )]
        pub array_explicit_bits: [u8; 2],

        #[asn1(type = "BIT STRING", context_specific = "4", optional = "true")]
        pub array_optional_implicit_bits: Option<[u8; 2]>,

        #[asn1(type = "OCTET STRING", context_specific = "5", optional = "true")]
        pub array_optional_implicit_bytes: Option<[u8; 2]>,

        #[asn1(
            type = "BIT STRING",
            context_specific = "6",
            optional = "true",
            tag_mode = "EXPLICIT"
        )]
        pub array_optional_explicit_bits: Option<[u8; 2]>,

        #[asn1(
            type = "OCTET STRING",
            context_specific = "7",
            optional = "true",
            tag_mode = "EXPLICIT"
        )]
        pub array_optional_explicit_bytes: Option<[u8; 2]>,
    }

    #[test]
    fn type_combinations_arrays_instance() {
        let mut buf = [0u8; 100];
        let obj = TypeCheckArraysSequenceFieldAttributeCombinations {
            array_bytes: [0xAA, 0xBB],
            array_bits: [0xCC, 0xDD],

            array_implicit_bytes: [0, 1],
            array_implicit_bits: [2, 3],

            array_explicit_bytes: [4, 5],
            array_explicit_bits: [6, 7],

            array_optional_implicit_bits: Some([8, 9]),
            array_optional_implicit_bytes: Some([10, 11]),

            array_optional_explicit_bits: Some([12, 13]),
            array_optional_explicit_bytes: Some([14, 15]),
        };

        let der_encoded = obj.encode_to_slice(&mut buf).unwrap();
        let obj_decoded =
            TypeCheckArraysSequenceFieldAttributeCombinations::from_der(der_encoded).unwrap();
        assert_eq!(obj, obj_decoded);
    }
}
/// Custom derive test cases for the `Sequence` macro with heapless crate.
#[cfg(all(feature = "oid", feature = "heapless"))]
mod sequence_heapless_vec {
    use der::Decode;
    use der::Encode;
    use der::Sequence;
    use der::asn1::ObjectIdentifier;
    use hex_literal::hex;

    /// EU Tachograph Gen 2 certificate public key
    #[derive(Sequence, Debug, Clone)]
    #[asn1(tag_mode = "IMPLICIT")]
    pub struct G2CertificatePublicKey {
        pub domain_parameters: ObjectIdentifier,

        /// Public point is '04 xx .. xx   yy .. yy'
        ///
        /// Maximum: 1 + 2 * 66 bytes for Nist521
        #[asn1(context_specific = "6", type = "OCTET STRING", deref = "true")]
        pub public_point: heapless::Vec<u8, 133>,
    }

    static ROMANIA_PUBLIC_KEY: [u8; 80] = hex!(
        "
   30 4E 06 09 2B 24 03  03 02 08 01 01 07 86 41
04 86 23 90 68 B8 08 1F  5E 6B 49 EB 54 F7 8E 0D
FB E7 1F 85 26 15 60 73  7C 24 B0 10 24 F9 2A 02
03 67 80 3E 17 E9 F2 6E  D5 A5 4E 25 F9 B5 46 B1
90 3C DD 76 47 DB 1D 8E  E0 D9 86 D0 64 D8 3C DD
7F"
    );

    pub const BRAINPOOL_P_256_R_1: ObjectIdentifier =
        ObjectIdentifier::new_unwrap("1.3.36.3.3.2.8.1.1.7");

    #[test]
    fn heapless_vec_decode_encode() {
        let public_key = G2CertificatePublicKey::from_der(&ROMANIA_PUBLIC_KEY).unwrap();

        assert_eq!(public_key.domain_parameters, BRAINPOOL_P_256_R_1);
        assert_eq!(public_key.public_point.len(), 1 + 2 * (256 / 8));

        let mut buf = [0u8; 80];
        let pk_encoded = public_key.encode_to_slice(&mut buf).unwrap();

        assert_eq!(pk_encoded, ROMANIA_PUBLIC_KEY);
    }

    #[derive(Sequence, Debug, Clone)]
    #[allow(dead_code)]
    pub struct HeaplessTypeCheck {
        #[asn1(type = "OCTET STRING", deref = "true")]
        pub octet_string_heapless: heapless::Vec<u8, 16>,

        #[asn1(type = "OCTET STRING", deref = "true", tag_mode = "IMPLICIT")]
        pub octet_string_heapless_implicit: heapless::Vec<u8, 16>,

        #[asn1(context_specific = "0", type = "OCTET STRING", optional = "true")]
        pub opt_octet_string_heapless: Option<heapless::Vec<u8, 16>>,

        #[asn1(
            context_specific = "1",
            type = "OCTET STRING",
            optional = "true",
            tag_mode = "IMPLICIT"
        )]
        pub opt_octet_string_heapless_implicit: Option<heapless::Vec<u8, 16>>,
    }
}
