use crate::{decrypt_data, encrypt_data};
const PASSWORD: &[u8] = "test_password".as_bytes();
const LONG_PASSWORD: &[u8] = "very_long_password_with_many_characters_for_testing_purposes_123456789".as_bytes();
const EMPTY_PASSWORD: &[u8] = b"";
#[test_case::test_case("hello world".as_bytes())]
#[test_case::test_case(&[])]
#[test_case::test_case(&[1, 2, 3])]
#[test_case::test_case(&[3, 2, 1])]
fn test_basic_encrypt_decrypt_roundtrip(input: &[u8]) -> Result<(), crate::Error> {
let encrypted = encrypt_data(PASSWORD, input)?;
let decrypted = decrypt_data(PASSWORD, &encrypted)?;
assert_eq!(input, decrypted, "input is not equal output");
Ok(())
}
#[test]
fn test_encrypt_decrypt_with_different_passwords() -> Result<(), crate::Error> {
let data = b"sensitive data";
let password1 = b"password1";
let password2 = b"password2";
let encrypted = encrypt_data(password1, data)?;
let decrypted = decrypt_data(password1, &encrypted)?;
assert_eq!(data, decrypted.as_slice());
let result = decrypt_data(password2, &encrypted);
assert!(result.is_err(), "Decryption with wrong password should fail");
Ok(())
}
#[test]
fn test_encrypt_decrypt_empty_data() -> Result<(), crate::Error> {
let empty_data = b"";
let encrypted = encrypt_data(PASSWORD, empty_data)?;
let decrypted = decrypt_data(PASSWORD, &encrypted)?;
assert_eq!(empty_data, decrypted.as_slice());
Ok(())
}
#[test]
fn test_encrypt_decrypt_large_data() -> Result<(), crate::Error> {
let large_data = vec![0xAB; 1024 * 1024];
let encrypted = encrypt_data(PASSWORD, &large_data)?;
let decrypted = decrypt_data(PASSWORD, &encrypted)?;
assert_eq!(large_data, decrypted);
Ok(())
}
#[test]
fn test_encrypt_decrypt_with_empty_password() -> Result<(), crate::Error> {
let data = b"test data";
let encrypted = encrypt_data(EMPTY_PASSWORD, data)?;
let decrypted = decrypt_data(EMPTY_PASSWORD, &encrypted)?;
assert_eq!(data, decrypted.as_slice());
Ok(())
}
#[test]
fn test_encrypt_decrypt_with_long_password() -> Result<(), crate::Error> {
let data = b"test data with long password";
let encrypted = encrypt_data(LONG_PASSWORD, data)?;
let decrypted = decrypt_data(LONG_PASSWORD, &encrypted)?;
assert_eq!(data, decrypted.as_slice());
Ok(())
}
#[test]
fn test_encrypt_decrypt_binary_data() -> Result<(), crate::Error> {
let binary_patterns = [
vec![0x00; 100], vec![0xFF; 100], (0..=255u8).cycle().take(1000).collect::<Vec<u8>>(), [0xAA, 0x55].repeat(500), ];
for pattern in &binary_patterns {
let encrypted = encrypt_data(PASSWORD, pattern)?;
let decrypted = decrypt_data(PASSWORD, &encrypted)?;
assert_eq!(pattern, &decrypted, "Binary pattern mismatch");
}
Ok(())
}
#[test]
fn test_encrypt_decrypt_unicode_data() -> Result<(), crate::Error> {
let unicode_strings = [
"Hello, 世界! 🌍",
"Тест на русском языке",
"العربية اختبار",
"🚀🔐💻🌟⭐",
"Mixed: ASCII + 中文 + العربية + 🎉",
];
for text in &unicode_strings {
let data = text.as_bytes();
let encrypted = encrypt_data(PASSWORD, data)?;
let decrypted = decrypt_data(PASSWORD, &encrypted)?;
assert_eq!(data, decrypted.as_slice(), "Unicode data mismatch for: {text}");
}
Ok(())
}
#[test]
fn test_decrypt_with_corrupted_data() {
let data = b"test data";
let encrypted = encrypt_data(PASSWORD, data).expect("Encryption should succeed");
let corruption_tests = [
(0, "Corrupt first byte"),
(encrypted.len() - 1, "Corrupt last byte"),
(encrypted.len() / 2, "Corrupt middle byte"),
];
for (corrupt_index, description) in &corruption_tests {
let mut corrupted = encrypted.clone();
corrupted[*corrupt_index] ^= 0xFF;
let result = decrypt_data(PASSWORD, &corrupted);
assert!(result.is_err(), "{description} should cause decryption to fail");
}
}
#[test]
fn test_decrypt_with_truncated_data() {
let data = b"test data for truncation";
let encrypted = encrypt_data(PASSWORD, data).expect("Encryption should succeed");
let truncation_lengths = [
0, 10, 32, 44, encrypted.len() - 1, ];
for &length in &truncation_lengths {
let truncated = &encrypted[..length.min(encrypted.len())];
let result = decrypt_data(PASSWORD, truncated);
assert!(result.is_err(), "Truncated data (length {length}) should cause decryption to fail");
}
}
#[test]
fn test_decrypt_with_invalid_header() {
let data = b"test data";
let mut encrypted = encrypt_data(PASSWORD, data).expect("Encryption should succeed");
if encrypted.len() > 32 {
encrypted[32] = 0xFF; let result = decrypt_data(PASSWORD, &encrypted);
assert!(result.is_err(), "Invalid algorithm ID should cause decryption to fail");
}
}
#[test]
fn test_encryption_produces_different_outputs() -> Result<(), crate::Error> {
let data = b"same data";
let encrypted1 = encrypt_data(PASSWORD, data)?;
let encrypted2 = encrypt_data(PASSWORD, data)?;
assert_ne!(encrypted1, encrypted2, "Encryption should produce different outputs for same input");
let decrypted1 = decrypt_data(PASSWORD, &encrypted1)?;
let decrypted2 = decrypt_data(PASSWORD, &encrypted2)?;
assert_eq!(decrypted1, decrypted2);
assert_eq!(data, decrypted1.as_slice());
Ok(())
}
#[test]
fn test_encrypted_data_structure() -> Result<(), crate::Error> {
let data = b"test data";
let encrypted = encrypt_data(PASSWORD, data)?;
assert!(encrypted.len() > data.len(), "Encrypted data should be longer than original");
let min_expected_length = 32 + 1 + 12 + data.len() + 16;
assert!(
encrypted.len() >= min_expected_length,
"Encrypted data length {} should be at least {}",
encrypted.len(),
min_expected_length
);
Ok(())
}
#[test]
fn test_password_variations() -> Result<(), crate::Error> {
let data = b"test data";
let password_variations = [
b"a".as_slice(), b"12345".as_slice(), b"!@#$%^&*()".as_slice(), b"\x00\x01\x02\x03".as_slice(), "密码测试".as_bytes(), &[0xFF; 64], ];
for password in &password_variations {
let encrypted = encrypt_data(password, data)?;
let decrypted = decrypt_data(password, &encrypted)?;
assert_eq!(data, decrypted.as_slice(), "Failed with password: {password:?}");
}
Ok(())
}
#[test]
fn test_deterministic_with_same_salt_and_nonce() {
let data = b"test data";
let encrypted1 = encrypt_data(PASSWORD, data).expect("Encryption should succeed");
let encrypted2 = encrypt_data(PASSWORD, data).expect("Encryption should succeed");
assert_ne!(encrypted1, encrypted2, "Encryption should use random salt/nonce");
}
#[test]
fn test_cross_platform_compatibility() -> Result<(), crate::Error> {
let test_cases = [
vec![0x00, 0x01, 0x02, 0x03], vec![0xFC, 0xFD, 0xFE, 0xFF], (0..256u16).map(|x| (x % 256) as u8).collect::<Vec<u8>>(), ];
for test_data in &test_cases {
let encrypted = encrypt_data(PASSWORD, test_data)?;
let decrypted = decrypt_data(PASSWORD, &encrypted)?;
assert_eq!(test_data, &decrypted, "Cross-platform compatibility failed");
}
Ok(())
}
#[test]
fn test_memory_safety_with_large_passwords() -> Result<(), crate::Error> {
let data = b"test data";
let large_passwords = [
vec![b'a'; 1024], vec![b'x'; 10 * 1024], (0..=255u8).cycle().take(5000).collect::<Vec<u8>>(), ];
for password in &large_passwords {
let encrypted = encrypt_data(password, data)?;
let decrypted = decrypt_data(password, &encrypted)?;
assert_eq!(data, decrypted.as_slice(), "Failed with large password of size {}", password.len());
}
Ok(())
}
#[test]
fn test_concurrent_encryption_safety() -> Result<(), crate::Error> {
use std::sync::Arc;
use std::thread;
let data = Arc::new(b"concurrent test data".to_vec());
let password = Arc::new(b"concurrent_password".to_vec());
let handles: Vec<_> = (0..10)
.map(|i| {
let data = Arc::clone(&data);
let password = Arc::clone(&password);
thread::spawn(move || {
let encrypted = encrypt_data(&password, &data).expect("Encryption should succeed");
let decrypted = decrypt_data(&password, &encrypted).expect("Decryption should succeed");
assert_eq!(**data, decrypted, "Thread {i} failed");
})
})
.collect();
for handle in handles {
handle.join().expect("Thread should complete successfully");
}
Ok(())
}