use qubit_codec::ValueDecoder;
use qubit_codec::ValueEncoder;
use qubit_codec_misc::Base64Codec;
use qubit_codec_misc::Base64ErrorKind;
use qubit_codec_misc::MiscCodecError;
#[test]
fn test_standard_base64_roundtrip_with_padding() {
let codec = Base64Codec::standard();
let encoded = codec.encode(b"hello world");
assert_eq!("aGVsbG8gd29ybGQ=", encoded);
assert_eq!(
b"hello world".to_vec(),
codec.decode(&encoded).expect("base64 should decode")
);
}
#[test]
fn test_url_safe_base64_roundtrip_without_padding() {
let codec = Base64Codec::url_safe_no_pad();
let bytes = [0xfb, 0xff, 0xee, 0x00];
let encoded = codec.encode(&bytes);
assert_eq!("-__uAA", encoded);
assert_eq!(
bytes.to_vec(),
codec.decode(&encoded).expect("url-safe base64 should decode")
);
}
#[test]
fn test_base64_constructors_cover_padding_and_alphabet_variants() {
assert_eq!("aGk", Base64Codec::standard_no_pad().encode(b"hi"));
assert_eq!("++8=", Base64Codec::standard().encode(&[0xfb, 0xef]));
assert_eq!("--8=", Base64Codec::url_safe().encode(&[0xfb, 0xef]));
assert_eq!(
b"hi".to_vec(),
Base64Codec::standard_no_pad()
.decode("aGk")
.expect("standard no-pad base64 should decode")
);
assert_eq!(
vec![0xfb, 0xef],
Base64Codec::url_safe()
.decode("--8=")
.expect("url-safe padded base64 should decode")
);
assert_eq!(
b"hi".to_vec(),
Base64Codec::default()
.decode("aGk=")
.expect("default base64 should decode")
);
}
#[test]
fn test_base64_codec_equality_distinguishes_engine_variants() {
assert_eq!(Base64Codec::standard(), Base64Codec::default());
assert_eq!(Base64Codec::url_safe_no_pad(), Base64Codec::url_safe_no_pad());
assert_ne!(Base64Codec::standard(), Base64Codec::standard_no_pad());
assert_ne!(Base64Codec::standard(), Base64Codec::url_safe());
}
#[test]
fn test_decode_rejects_invalid_base64() {
let error = Base64Codec::standard()
.decode("@")
.expect_err("invalid base64 should fail");
assert!(matches!(
error,
MiscCodecError::InvalidBase64 {
kind: Base64ErrorKind::InvalidByte,
input_index: Some(0),
symbol: Some(b'@'),
input_length: None,
..
}
));
let source = std::error::Error::source(&error).expect("Base64 error should retain its dependency source");
assert_eq!(
Some(&base64::DecodeError::InvalidByte(0, b'@')),
source.downcast_ref::<base64::DecodeError>()
);
}
#[test]
fn test_decode_reports_base64_error_category_and_index() {
let invalid_last_symbol = Base64Codec::standard()
.decode("YR==")
.expect_err("non-canonical Base64 should fail");
assert!(matches!(
invalid_last_symbol,
MiscCodecError::InvalidBase64 {
kind: Base64ErrorKind::InvalidLastSymbol,
input_index: Some(1),
symbol: Some(b'R'),
input_length: None,
..
}
));
let invalid_length = Base64Codec::standard()
.decode("Y")
.expect_err("short Base64 should fail");
assert!(matches!(
invalid_length,
MiscCodecError::InvalidBase64 {
kind: Base64ErrorKind::InvalidLength,
input_index: None,
symbol: None,
input_length: Some(1),
..
}
));
}
#[test]
fn test_base64_codec_can_be_used_through_traits() {
let mut codec = Base64Codec::standard();
let encoded = ValueEncoder::<[u8]>::encode(&mut codec, b"abc").expect("base64 encode should succeed");
let decoded = ValueDecoder::<str>::decode(&mut codec, &encoded).expect("base64 decode should succeed");
assert_eq!("YWJj", encoded);
assert_eq!(b"abc".to_vec(), decoded);
}