wolfcose 0.1.0

Safe Rust API for wolfSSL wolfCOSE.
#![allow(missing_docs)]

use wolfcose::{
    from_slice_detailed, to_vec, CborDeserializer, CborItemReader, CborMajorType, CborSerializer,
    CborValue, DetailedError, Error, ErrorContext,
};

#[test]
fn detailed_error_contexts_and_display_are_exercised() {
    let trailing = [0x01, 0x02];
    let err = from_slice_detailed::<u8>(&trailing).unwrap_err();
    assert_eq!(
        err.context,
        ErrorContext::Cbor(wolfcose::CborErrorKind::TrailingData {
            position: 1,
            len: 2
        })
    );
    assert_eq!(err.clone().into_error(), Error::CborMalformed);
    assert!(err.to_string().contains("TrailingData"));

    let wrong_type = to_vec("wrong").unwrap();
    let err = from_slice_detailed::<u8>(&wrong_type).unwrap_err();
    assert_eq!(err.error, Error::CborType);
    let ErrorContext::Cbor(wolfcose::CborErrorKind::UnexpectedType { expected, .. }) = err.context
    else {
        panic!("expected detailed CBOR type context");
    };
    assert_eq!(expected, None);

    assert_eq!(
        DetailedError::from(Error::Unsupported).context,
        ErrorContext::None
    );
    assert_eq!(
        DetailedError::new(
            Error::CoseKeyType,
            ErrorContext::Cose(wolfcose::CoseErrorKind::KeyMismatch)
        )
        .error,
        Error::CoseKeyType
    );
    assert_eq!(
        DetailedError::new(
            Error::CborMalformed,
            ErrorContext::MissingField("field".to_owned())
        )
        .context,
        ErrorContext::MissingField("field".to_owned())
    );
    assert_eq!(
        DetailedError::new(
            Error::CborMalformed,
            ErrorContext::Field("field".to_owned())
        )
        .context,
        ErrorContext::Field("field".to_owned())
    );
}

#[test]
fn stream_reader_and_serializer_escape_hatches_work() {
    let encoded = to_vec(&CborValue::Array(vec![
        CborValue::Unsigned(1),
        CborValue::Text("two".to_owned()),
    ]))
    .unwrap();
    let mut reader = CborItemReader::new(&encoded);
    assert_eq!(reader.position(), 0);
    assert_eq!(reader.remaining(), encoded.len());
    let head = reader.next_head().unwrap().unwrap();
    assert_eq!(head.major_type, CborMajorType::ARRAY);
    assert_eq!(head.value, 2);
    assert_eq!(reader.decoder_mut().decode_u64().unwrap(), 1);
    assert!(reader.skip_next().unwrap());
    assert!(!reader.skip_next().unwrap());
    assert_eq!(reader.next_head().unwrap(), None);

    let mut out = [0; 64];
    let mut serializer = CborSerializer::new(&mut out);
    assert!(serializer.is_empty());
    serializer.encoder_mut().encode_tag(24).unwrap();
    serializer.bytes(b"wrapped").unwrap();
    assert!(!serializer.is_empty());
    assert_eq!(serializer.len(), serializer.as_written().len());

    let mut deserializer = CborDeserializer::new(serializer.as_written());
    assert_eq!(deserializer.decoder_mut().decode_tag().unwrap(), 24);
    assert_eq!(deserializer.bytes().unwrap(), b"wrapped");
    assert!(deserializer.is_finished());
}

#[test]
fn error_code_mapping_covers_known_variants() {
    for error in [
        Error::InvalidArgument,
        Error::BufferTooSmall,
        Error::CborMalformed,
        Error::CborType,
        Error::CborOverflow,
        Error::CborDepth,
        Error::CoseBadTag,
        Error::CoseBadAlgorithm,
        Error::CoseSignatureFailed,
        Error::CoseDecryptFailed,
        Error::CoseBadHeader,
        Error::CoseKeyType,
        Error::CoseMacFailed,
        Error::Crypto,
        Error::Unsupported,
        Error::MacFailed,
        Error::DetachedPayload,
    ] {
        assert_eq!(Error::from(error.code()), error);
        assert!(error.to_string().contains("wolfCOSE error"));
    }
    assert_eq!(Error::from(123456), Error::Unknown(123456));
    assert_eq!(Error::Unknown(123456).code(), 123456);
}