use multi_base::{decode, decode_into, encode, encode_into, Base};
#[test]
fn test_large_input_encoding() {
let large_input = vec![0xAB; 1024 * 1024];
let encoded = encode(Base::Base64, &large_input);
assert!(encoded.starts_with('m'));
let (base, decoded) = decode(&encoded, true).unwrap();
assert_eq!(base, Base::Base64);
assert_eq!(decoded, large_input);
}
#[test]
fn test_large_input_with_buffer_reuse() {
let large_input = vec![0xCD; 100 * 1024];
let mut encode_buffer = String::new();
encode_into(Base::Base64, &large_input, &mut encode_buffer);
assert!(encode_buffer.starts_with('m'));
let mut decode_buffer = Vec::new();
let base = decode_into(&encode_buffer, true, &mut decode_buffer).unwrap();
assert_eq!(base, Base::Base64);
assert_eq!(decode_buffer, large_input);
}
#[test]
fn test_single_byte_maximum() {
let test_bytes = vec![0, 1, 127, 128, 255];
for byte in test_bytes {
let input = vec![byte];
for base in all_bases() {
let encoded = encode(base, &input);
let (decoded_base, decoded) = decode(&encoded, true).unwrap();
assert_eq!(decoded_base, base);
if base == Base::Identity && std::str::from_utf8(&input).is_err() {
continue;
}
assert_eq!(
decoded, input,
"Failed for base {:?} with byte {}",
base, byte
);
}
}
}
#[test]
fn test_empty_input_encoding() {
let empty: &[u8] = &[];
for base in all_bases() {
let encoded = encode(base, empty);
let (decoded_base, decoded) = decode(&encoded, true).unwrap();
assert_eq!(decoded_base, base);
assert_eq!(decoded, empty);
}
}
#[test]
fn test_malformed_prefix_rejection() {
let invalid_prefixes = vec![
"x", "!test", "?data", "@hello", "#world", ];
for input in invalid_prefixes {
let result = decode(input, true);
assert!(result.is_err(), "Should reject invalid prefix: {}", input);
}
}
#[test]
fn test_truncated_data_rejection() {
let valid_encoded = encode(Base::Base64, b"hello world");
for len in 1..valid_encoded.len() {
let truncated = &valid_encoded[..len];
let result = decode(truncated, true);
let _ = result;
}
}
#[test]
fn test_prefix_only_inputs() {
let prefixes = vec!['m', 'z', 'f', 'b', 'u'];
for prefix in prefixes {
let prefix_only = format!("{}", prefix);
let result = decode(&prefix_only, true);
match result {
Ok((_, data)) => {
assert_eq!(data.len(), 0);
}
Err(_) => {
}
}
}
}
#[test]
fn test_identity_with_invalid_utf8() {
let invalid_utf8_sequences = vec![
vec![0xFF], vec![0xFF, 0xFE], vec![0x80], vec![0xC0, 0x80], vec![0xED, 0xA0, 0x80], vec![0xF4, 0x90, 0x80, 0x80], ];
for invalid_bytes in invalid_utf8_sequences {
let encoded = encode(Base::Identity, &invalid_bytes);
assert!(encoded.starts_with('\0'));
let (base, _decoded) = decode(&encoded, true).unwrap();
assert_eq!(base, Base::Identity);
}
}
#[test]
fn test_repeated_operations_safety() {
let data = b"test data for repeated operations";
for _ in 0..1000 {
for base in all_bases() {
let encoded = encode(base, data);
let (decoded_base, decoded) = decode(&encoded, true).unwrap();
assert_eq!(decoded_base, base);
assert_eq!(&decoded[..], data);
}
}
}
#[test]
fn test_concurrent_safety() {
use std::thread;
let handles: Vec<_> = (0..10)
.map(|i| {
thread::spawn(move || {
let data = format!("thread {}", i);
for base in all_bases() {
let encoded = encode(base, data.as_bytes());
let (_, decoded) = decode(&encoded, true).unwrap();
assert_eq!(decoded, data.as_bytes());
}
})
})
.collect();
for handle in handles {
handle.join().unwrap();
}
}
#[test]
fn test_malicious_patterns_rejection() {
let malicious_inputs = vec![
"m\0\0\0\0",
"z\x01\x02\x03",
"mAAAA!!!!", "fGGGG", "z00000", ];
for input in malicious_inputs {
let result = decode(input, true);
assert!(result.is_err() || result.is_ok());
}
}
#[test]
fn test_buffer_reuse_safety() {
let mut encode_buf = String::new();
let mut decode_buf = Vec::new();
for size in &[10, 100, 1000, 10000] {
let data = vec![0xAB; *size];
encode_into(Base::Base64, &data, &mut encode_buf);
let base = decode_into(&encode_buf, true, &mut decode_buf).unwrap();
assert_eq!(base, Base::Base64);
assert_eq!(decode_buf, data);
assert_eq!(decode_buf.len(), *size);
}
}
#[test]
fn test_capacity_calculation_safety() {
let sizes = vec![100, 1_000, 10_000, 100_000, 1_000_000];
for size in sizes {
let data = vec![0xFF; size];
let encoded = encode(Base::Base64, &data);
assert!(!encoded.is_empty());
let (base, decoded) = decode(&encoded, true).unwrap();
assert_eq!(base, Base::Base64);
assert_eq!(decoded.len(), size);
}
}
#[test]
fn test_all_error_paths() {
assert!(decode("", true).is_err());
assert!(decode("x123", true).is_err());
assert!(decode("fZZZZ", true).is_err()); assert!(decode("z0000", true).is_err());
assert!(decode("m!!!!", true).is_err()); }
#[test]
fn test_encoded_string_security() {
use multi_base::EncodedString;
let valid = EncodedString::new("zCn8eVZg").unwrap();
assert_eq!(valid.base(), Base::Base58Btc);
assert!(EncodedString::new("").is_err());
assert!(EncodedString::new("xInvalid").is_err());
let long_string = format!("z{}", "A".repeat(1_000_000));
let validated = EncodedString::new(long_string).unwrap();
assert_eq!(validated.base(), Base::Base58Btc);
}
#[test]
fn test_resource_exhaustion_resistance() {
let data = b"test";
for _ in 0..10_000 {
let encoded = encode(Base::Base64, data);
let _ = decode(&encoded, true);
}
}
#[test]
fn test_zero_length_all_bases() {
let empty: &[u8] = &[];
for base in all_bases() {
let encoded = encode(base, empty);
let (decoded_base, decoded) = decode(&encoded, true).unwrap();
assert_eq!(decoded_base, base);
assert_eq!(decoded.len(), 0);
}
}
fn all_bases() -> Vec<Base> {
vec![
Base::Identity,
Base::Base2,
Base::Base8,
Base::Base10,
Base::Base16Lower,
Base::Base16Upper,
Base::Base32Lower,
Base::Base32Upper,
Base::Base32PadLower,
Base::Base32PadUpper,
Base::Base32HexLower,
Base::Base32HexUpper,
Base::Base32HexPadLower,
Base::Base32HexPadUpper,
Base::Base32Z,
Base::Base36Lower,
Base::Base36Upper,
Base::Base58Flickr,
Base::Base58Btc,
Base::Base64,
Base::Base64Pad,
Base::Base64Url,
Base::Base64UrlPad,
Base::Base256Emoji,
]
}