#[cfg(test)]
mod encryption_tests {
use super::*;
use tempfile::NamedTempFile;
#[test]
fn test_encrypted_roundtrip() {
let commands = vec![
"git status".to_string(),
"git commit -m test".to_string(),
"cargo build --release".to_string(),
];
let mut model = MarkovModel::new(3);
model.train(&commands);
let file = NamedTempFile::new().expect("temp file");
let password = "test_password_123";
model
.save_encrypted(file.path(), password)
.expect("save encrypted");
let loaded = MarkovModel::load_encrypted(file.path(), password).expect("load encrypted");
assert_eq!(loaded.n, model.n);
assert_eq!(loaded.total_commands, model.total_commands);
assert_eq!(loaded.command_freq, model.command_freq);
}
#[test]
fn test_encrypted_wrong_password_fails() {
let commands = vec!["git status".to_string()];
let mut model = MarkovModel::new(3);
model.train(&commands);
let file = NamedTempFile::new().expect("temp file");
model
.save_encrypted(file.path(), "correct_password")
.expect("save");
let result = MarkovModel::load_encrypted(file.path(), "wrong_password");
assert!(result.is_err(), "Should fail with wrong password");
}
#[test]
fn test_encrypted_suggestions_match() {
let commands = vec![
"git status".to_string(),
"git commit".to_string(),
"git push".to_string(),
];
let mut model = MarkovModel::new(3);
model.train(&commands);
let file = NamedTempFile::new().expect("temp file");
let password = "test_password";
let before_suggestions: std::collections::HashSet<_> = model
.suggest("git ", 5)
.into_iter()
.map(|(s, _)| s)
.collect();
model.save_encrypted(file.path(), password).expect("save");
let loaded = MarkovModel::load_encrypted(file.path(), password).expect("load");
let after_suggestions: std::collections::HashSet<_> = loaded
.suggest("git ", 5)
.into_iter()
.map(|(s, _)| s)
.collect();
assert_eq!(
before_suggestions, after_suggestions,
"Suggestions should match"
);
}
#[test]
fn test_is_encrypted_detection() {
let commands = vec!["git status".to_string()];
let mut model = MarkovModel::new(3);
model.train(&commands);
let unenc_file = NamedTempFile::new().expect("temp file");
model.save(unenc_file.path()).expect("save unencrypted");
let enc_file = NamedTempFile::new().expect("temp file");
model
.save_encrypted(enc_file.path(), "password")
.expect("save encrypted");
assert!(
!MarkovModel::is_encrypted(unenc_file.path()).unwrap(),
"Unencrypted should be detected"
);
assert!(
MarkovModel::is_encrypted(enc_file.path()).unwrap(),
"Encrypted should be detected"
);
}
#[test]
fn test_unencrypted_model_loads_without_password() {
let commands = vec!["git status".to_string()];
let mut model = MarkovModel::new(3);
model.train(&commands);
let file = NamedTempFile::new().expect("temp file");
model.save(file.path()).expect("save");
let loaded = MarkovModel::load(file.path()).expect("load");
assert_eq!(loaded.total_commands, 1);
}
#[test]
fn test_encrypted_model_fails_without_password() {
let commands = vec!["git status".to_string()];
let mut model = MarkovModel::new(3);
model.train(&commands);
let file = NamedTempFile::new().expect("temp file");
model
.save_encrypted(file.path(), "password")
.expect("save encrypted");
let result = MarkovModel::load(file.path());
assert!(
result.is_err(),
"Loading encrypted without password should fail"
);
}
}
#[cfg(all(test, feature = "format-compression"))]
mod compression_tests {
use super::*;
use tempfile::NamedTempFile;
#[test]
fn test_compressed_roundtrip() {
let commands: Vec<String> = (0..100)
.map(|i| format!("git commit -m 'message {i}'"))
.collect();
let mut model = MarkovModel::new(3);
model.train(&commands);
let file = NamedTempFile::new().expect("temp file");
model.save_compressed(file.path()).expect("save compressed");
let loaded = MarkovModel::load(file.path()).expect("load");
assert_eq!(loaded.n, model.n);
assert_eq!(loaded.total_commands, model.total_commands);
assert_eq!(loaded.command_freq.len(), model.command_freq.len());
}
#[test]
fn test_compressed_smaller_than_plain() {
let commands: Vec<String> = (0..2000)
.map(|i| {
format!(
"git commit -m 'fix: resolve issue #{} with detailed message about the bug fix'"
, i % 100 )
})
.collect();
let mut model = MarkovModel::new(3);
model.train(&commands);
let plain_file = NamedTempFile::new().expect("temp file");
let compressed_file = NamedTempFile::new().expect("temp file");
model.save(plain_file.path()).expect("save plain");
model
.save_compressed(compressed_file.path())
.expect("save compressed");
let plain_size = std::fs::metadata(plain_file.path())
.expect("metadata")
.len();
let compressed_size = std::fs::metadata(compressed_file.path())
.expect("metadata")
.len();
println!("Plain: {plain_size}, Compressed: {compressed_size}");
assert!(compressed_size > 0, "Compressed file should exist");
}
#[test]
fn test_compression_metadata() {
let commands: Vec<String> = (0..1000)
.map(|i| format!("kubectl apply -f deployment-{}.yaml", i % 50))
.collect();
let mut model = MarkovModel::new(3);
model.train(&commands);
let compressed_file = NamedTempFile::new().expect("temp file");
model
.save_compressed(compressed_file.path())
.expect("save compressed");
let info = format::inspect(compressed_file.path()).expect("inspect");
assert!(info.payload_size > 0, "Should have payload");
assert!(info.uncompressed_size > 0, "Should have uncompressed size");
}
#[test]
fn test_compressed_suggestions_match() {
let commands = vec![
"git status".to_string(),
"git commit".to_string(),
"git push".to_string(),
];
let mut model = MarkovModel::new(3);
model.train(&commands);
let before = model.suggest("git", 5);
let file = NamedTempFile::new().expect("temp file");
model.save_compressed(file.path()).expect("save");
let loaded = MarkovModel::load(file.path()).expect("load");
let after = loaded.suggest("git", 5);
assert_eq!(before.len(), after.len(), "Suggestion count should match");
}
#[test]
fn test_compressed_encrypted_roundtrip() {
let commands: Vec<String> = (0..50)
.map(|i| format!("docker run container-{i}"))
.collect();
let mut model = MarkovModel::new(3);
model.train(&commands);
let file = NamedTempFile::new().expect("temp file");
let password = "secure-password-123";
model
.save_compressed_encrypted(file.path(), password)
.expect("save compressed+encrypted");
let loaded = MarkovModel::load_encrypted(file.path(), password).expect("load");
assert_eq!(loaded.n, model.n);
assert_eq!(loaded.total_commands, model.total_commands);
}
}