extern crate std;
use super::*;
use crate::Error;
use std::prelude::v1::*;
fn decode(hex: &[u8]) -> Result<Vec<u8>, Error> {
let out_len = hex.len() / 2;
let mut dst = std::vec![0u8; out_len];
decode_to_slice_simd(hex, &mut dst)?;
Ok(dst)
}
#[test]
fn test_empty() {
assert_eq!(decode(b"").unwrap(), &[]);
}
#[test]
fn test_single_byte_lower() {
assert_eq!(decode(b"de").unwrap(), &[0xde]);
}
#[test]
fn test_single_byte_upper() {
assert_eq!(decode(b"DE").unwrap(), &[0xde]);
}
#[test]
fn test_single_byte_mixed() {
assert_eq!(decode(b"De").unwrap(), &[0xde]);
}
#[test]
fn test_known_vectors() {
let cases: &[(&[u8], &[u8])] = &[
(b"deadbeef", &[0xde, 0xad, 0xbe, 0xef]),
(b"DEADBEEF", &[0xde, 0xad, 0xbe, 0xef]),
(b"DeAdBeEf", &[0xde, 0xad, 0xbe, 0xef]),
(b"00ff", &[0x00, 0xff]),
(b"FF00", &[0xff, 0x00]),
(b"0000", &[0x00, 0x00]),
(b"ffff", &[0xff, 0xff]),
];
for (hex, expected) in cases {
assert_eq!(&decode(hex).unwrap(), expected, "hex: {hex:?}");
}
}
#[test]
fn test_exactly_one_chunk() {
let hex = b"0102030405060708";
assert_eq!(
decode(hex).unwrap(),
&[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]
);
}
#[test]
fn test_exactly_two_chunks() {
let hex = b"00112233445566778899aabbccddeeff";
let expected = &[
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
0xff,
];
assert_eq!(&decode(hex).unwrap(), expected);
}
#[test]
fn test_one_chunk_plus_tail() {
let hex = b"000102030405060708090a"; let expected: Vec<u8> = (0u8..=10).collect();
assert_eq!(decode(hex).unwrap(), expected);
}
#[test]
fn test_tail_only_no_full_chunk() {
let hex = b"010203";
assert_eq!(decode(hex).unwrap(), &[0x01, 0x02, 0x03]);
}
#[test]
fn test_chunk_boundary_minus_one() {
let hex = b"01020304050607";
assert_eq!(
decode(hex).unwrap(),
&[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07]
);
}
#[test]
fn test_chunk_boundary_plus_one() {
let hex = b"010203040506070809";
assert_eq!(
decode(hex).unwrap(),
&[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09]
);
}
#[test]
fn test_all_single_bytes_lower() {
for byte in 0u8..=255 {
let hex = std::format!("{byte:02x}");
assert_eq!(
decode(hex.as_bytes()).unwrap(),
&[byte],
"failed for 0x{byte:02x}"
);
}
}
#[test]
fn test_all_single_bytes_upper() {
for byte in 0u8..=255 {
let hex = std::format!("{byte:02X}");
assert_eq!(
decode(hex.as_bytes()).unwrap(),
&[byte],
"failed for 0x{byte:02X}"
);
}
}
#[test]
fn test_roundtrip_full_256() {
let src: Vec<u8> = (0u8..=255).collect();
let mut hex_buf = std::vec![0u8; src.len() * 2];
let n_enc = crate::encode_to_slice(&src, &mut hex_buf, true).unwrap();
let decoded = decode(&hex_buf[..n_enc]).unwrap();
assert_eq!(decoded, src);
}
#[test]
fn test_roundtrip_three_chunks() {
let src: Vec<u8> = (0u8..24).collect();
let mut hex_buf = std::vec![0u8; 48];
crate::encode_to_slice(&src, &mut hex_buf, true).unwrap();
assert_eq!(decode(&hex_buf).unwrap(), src);
}
#[test]
fn test_invalid_first_byte() {
let err = decode(b"Xf").unwrap_err();
assert_eq!(
err,
Error::InvalidByte {
index: 0,
byte: b'X'
}
);
}
#[test]
fn test_invalid_second_byte() {
let err = decode(b"fX").unwrap_err();
assert_eq!(
err,
Error::InvalidByte {
index: 1,
byte: b'X'
}
);
}
#[test]
fn test_invalid_byte_in_simd_chunk() {
let hex = *b"0102Xf0405060708";
let err = decode(&hex).unwrap_err();
assert_eq!(
err,
Error::InvalidByte {
index: 4,
byte: b'X'
}
);
}
#[test]
fn test_invalid_byte_in_second_chunk() {
let mut hex: Vec<u8> = b"0102030405060708".to_vec(); hex.extend_from_slice(b"Xf030405060708"); let err = decode(&hex).unwrap_err();
assert_eq!(
err,
Error::InvalidByte {
index: 16,
byte: b'X'
}
);
}
#[test]
fn test_invalid_byte_in_tail() {
let mut hex: Vec<u8> = b"0102030405060708".to_vec(); hex.extend_from_slice(b"Xf"); let err = decode(&hex).unwrap_err();
assert_eq!(
err,
Error::InvalidByte {
index: 16,
byte: b'X'
}
);
}
#[test]
fn test_invalid_byte_space() {
let err = decode(b"ff ff ").unwrap_err();
assert_eq!(
err,
Error::InvalidByte {
index: 2,
byte: b' ',
}
);
}
#[test]
fn test_invalid_g_off_by_one() {
let err = decode(b"gg").unwrap_err();
assert_eq!(
err,
Error::InvalidByte {
index: 0,
byte: b'g'
}
);
}
#[test]
fn test_invalid_g_upper_off_by_one() {
let err = decode(b"GG").unwrap_err();
assert_eq!(
err,
Error::InvalidByte {
index: 0,
byte: b'G'
}
);
}
#[test]
fn test_invalid_null_byte() {
let err = decode(&[0x00, b'f']).unwrap_err();
assert_eq!(
err,
Error::InvalidByte {
index: 0,
byte: 0x00
}
);
}
#[test]
fn test_invalid_high_ascii() {
let err = decode(&[0xFF, b'0']).unwrap_err();
assert_eq!(
err,
Error::InvalidByte {
index: 0,
byte: 0xFF
}
);
}
#[test]
fn test_no_partial_write_on_error_in_chunk() {
let hex = b"0102030405Xf0708";
let mut dst = std::vec![0xAAu8; 8];
let _ = decode_to_slice_simd(hex, &mut dst);
assert!(
dst.iter().all(|&b| b == 0xAA),
"dst was partially written: {dst:?}"
);
}
#[test]
fn test_no_partial_write_on_error_in_tail() {
let mut hex: Vec<u8> = b"0102030405060708".to_vec();
hex.extend_from_slice(b"ZZ");
let mut dst = std::vec![0xAAu8; 9];
let _ = decode_to_slice_simd(&hex, &mut dst);
assert!(
dst.iter().all(|&b| b == 0xAA),
"dst was partially written: {dst:?}"
);
}
#[test]
fn test_idempotent() {
let hex = b"deadbeefcafebabe0011223344556677";
let first = decode(hex).unwrap();
let second = decode(hex).unwrap();
assert_eq!(first, second);
}