use pretty_assertions::{assert_eq, assert_ne};
use std::{convert::TryFrom, io::Cursor, str::FromStr};
use crate::types::{
Error, SerializableTtlvType, TtlvBigInteger, TtlvBoolean, TtlvByteString, TtlvDateTime, TtlvEnumeration,
TtlvInteger, TtlvLongInteger, TtlvTag, TtlvTextString, TtlvType,
};
use assert_matches::assert_matches;
#[test]
fn test_item_tag() {
assert!(TtlvTag::from_str("").is_err());
assert!(TtlvTag::from_str(" ").is_err());
assert!(TtlvTag::from_str("XYZ").is_err());
#[allow(non_snake_case)]
let ZERO_TAG = TtlvTag::from([0x00u8, 0x00u8, 0x00u8]);
#[allow(non_snake_case)]
let ONE_TAG = TtlvTag::from([0x00u8, 0x00u8, 0x01u8]);
assert_eq!(ZERO_TAG, TtlvTag::from_str("0").unwrap());
assert_eq!(ZERO_TAG, TtlvTag::from_str("000").unwrap());
assert_eq!(ZERO_TAG, TtlvTag::from_str("0x0").unwrap());
assert_eq!(ONE_TAG, TtlvTag::from_str("1").unwrap());
assert_eq!(ONE_TAG, TtlvTag::from_str("001").unwrap());
assert_eq!(ONE_TAG, TtlvTag::from_str("0x1").unwrap());
assert_eq!(
TtlvTag::from([0x42u8, 0x00u8, 0xAAu8]),
TtlvTag::from_str("0x4200AA").unwrap()
);
assert_eq!(ZERO_TAG, ZERO_TAG);
assert_ne!(ONE_TAG, ZERO_TAG);
}
#[test]
fn test_item_type() {
assert_matches!(TtlvType::try_from(0x00), Err(Error::InvalidTtlvType(0x00)));
assert_matches!(TtlvType::try_from(0x01), Ok(TtlvType::Structure));
assert_matches!(TtlvType::try_from(0x02), Ok(TtlvType::Integer));
assert_matches!(TtlvType::try_from(0x03), Ok(TtlvType::LongInteger));
assert_matches!(TtlvType::try_from(0x04), Ok(TtlvType::BigInteger));
assert_matches!(TtlvType::try_from(0x05), Ok(TtlvType::Enumeration));
assert_matches!(TtlvType::try_from(0x06), Ok(TtlvType::Boolean));
assert_matches!(TtlvType::try_from(0x07), Ok(TtlvType::TextString));
assert_matches!(TtlvType::try_from(0x08), Ok(TtlvType::ByteString));
assert_matches!(TtlvType::try_from(0x09), Ok(TtlvType::DateTime));
assert_matches!(TtlvType::try_from(0x0A), Err(Error::UnsupportedTtlvType(0x0A)));
for i in 0x0B..0xFF {
assert_matches!(TtlvType::try_from(i), Err(Error::InvalidTtlvType(n)) if n == i);
}
}
fn spec_ttlv_to_vec_tlv(s: &str) -> Vec<u8> {
hex::decode(s.replace("42 00 20 | ", "").replace(" ", "").replace("|", "")).unwrap()
}
#[test]
fn test_spec_ttlv_integer() {
let spec_tlv_bytes = spec_ttlv_to_vec_tlv("42 00 20 | 02 | 00 00 00 04 | 00 00 00 08 00 00 00 00");
let mut serialized_tlv_bytes = Vec::new();
assert!(TtlvInteger(8).write(&mut serialized_tlv_bytes).is_ok());
assert_eq!(spec_tlv_bytes, serialized_tlv_bytes);
let mut readable_spec_lv_bytes = Cursor::new(&spec_tlv_bytes[1..]);
let v = TtlvInteger::read(&mut readable_spec_lv_bytes);
assert!(v.is_ok());
assert_eq!(8, *(v.unwrap()));
}
#[test]
fn test_spec_ttlv_long_integer() {
let spec_tlv_bytes = spec_ttlv_to_vec_tlv("42 00 20 | 03 | 00 00 00 08 | 01 B6 9B 4B A5 74 92 00");
let mut serialized_tlv_bytes = Vec::new();
assert!(TtlvLongInteger(123456789000000000)
.write(&mut serialized_tlv_bytes)
.is_ok());
assert_eq!(spec_tlv_bytes, serialized_tlv_bytes);
let mut readable_spec_lv_bytes = Cursor::new(&spec_tlv_bytes[1..]);
let v = TtlvLongInteger::read(&mut readable_spec_lv_bytes);
assert!(v.is_ok());
assert_eq!(123456789000000000, *(v.unwrap()));
}
#[test]
fn test_spec_ttlv_big_integer() {
let spec_tlv_bytes =
spec_ttlv_to_vec_tlv("42 00 20 | 04 | 00 00 00 10 | 00 00 00 00 03 FD 35 EB 6B C2 DF 46 18 08 00 00");
let big_int = num_bigint::BigInt::parse_bytes(b"1234567890000000000000000000", 10).unwrap();
let mut serialized_tlv_bytes = Vec::new();
assert!(TtlvBigInteger(big_int.to_signed_bytes_be())
.write(&mut serialized_tlv_bytes)
.is_ok());
assert_eq!(spec_tlv_bytes, serialized_tlv_bytes);
let mut readable_spec_lv_bytes = Cursor::new(&spec_tlv_bytes[1..]);
let v = TtlvBigInteger::read(&mut readable_spec_lv_bytes);
assert!(v.is_ok());
assert_eq!(big_int, num_bigint::BigInt::from_signed_bytes_be(&(*(v.unwrap()))));
}
#[test]
fn test_spec_ttlv_enumeration() {
let mut actual = Vec::new();
let expected = spec_ttlv_to_vec_tlv("42 00 20 | 05 | 00 00 00 04 | 00 00 00 FF 00 00 00 00");
TtlvEnumeration(255).write(&mut actual).unwrap();
assert_eq!(expected, actual);
}
#[test]
fn test_spec_ttlv_boolean() {
let mut actual = Vec::new();
let expected = spec_ttlv_to_vec_tlv("42 00 20 | 06 | 00 00 00 08 | 00 00 00 00 00 00 00 01");
TtlvBoolean(true).write(&mut actual).unwrap();
assert_eq!(expected, actual);
}
#[test]
fn test_spec_ttlv_text_string() {
let mut actual = Vec::new();
let expected =
spec_ttlv_to_vec_tlv("42 00 20 | 07 | 00 00 00 0B | 48 65 6C 6C 6F 20 57 6F 72 6C 64 00 00 00 00 00");
TtlvTextString("Hello World".to_string()).write(&mut actual).unwrap();
assert_eq!(expected, actual);
}
#[test]
fn test_spec_ttlv_byte_string() {
let mut actual = Vec::new();
let expected = spec_ttlv_to_vec_tlv("42 00 20 | 08 | 00 00 00 03 | 01 02 03 00 00 00 00 00");
TtlvByteString(vec![0x01u8, 0x02u8, 0x03u8]).write(&mut actual).unwrap();
assert_eq!(expected, actual);
}
#[test]
fn test_spec_ttlv_date_time() {
use chrono::TimeZone;
let mut actual = Vec::new();
let expected = spec_ttlv_to_vec_tlv("42 00 20 | 09 | 00 00 00 08 | 00 00 00 00 47 DA 67 F8");
let dt = chrono::Utc
.datetime_from_str("Friday, March 14, 2008, 11:56:40 GMT", "%A, %B %d, %Y, %H:%M:%S GMT")
.unwrap();
let dt_i64 = dt.timestamp();
let expected_i64 = i64::from_be_bytes(*b"\x00\x00\x00\x00\x47\xDA\x67\xF8");
assert_eq!(expected_i64, dt_i64);
TtlvDateTime(dt_i64).write(&mut actual).unwrap();
assert_eq!(expected, actual);
}
#[test]
#[should_panic]
fn test_spec_ttlv_interval() {
todo!()
}
#[test]
#[should_panic]
fn test_spec_ttlv_structure() {
panic!("NOT IN SCOPE FOR THIS MODULE");
}