use assert_cmd::Command;
use std::process::{Command as StdCommand, Stdio};
use std::time::{Duration, Instant};
use tempfile::TempDir;
#[test]
fn test_startup_time_measurement() {
let start = Instant::now();
let mut cmd = Command::cargo_bin("voirs").unwrap();
cmd.arg("--version").assert().success();
let startup_time = start.elapsed();
assert!(
startup_time < Duration::from_secs(2),
"Startup time too slow: {startup_time:?}"
);
println!("Cold startup time: {startup_time:?}");
}
#[test]
fn test_warm_startup_performance() {
let mut cmd = Command::cargo_bin("voirs").unwrap();
cmd.arg("--version").assert().success();
let start = Instant::now();
let mut cmd = Command::cargo_bin("voirs").unwrap();
cmd.arg("--version").assert().success();
let warm_time = start.elapsed();
assert!(
warm_time < Duration::from_millis(500),
"Warm startup too slow: {warm_time:?}"
);
println!("Warm startup time: {warm_time:?}");
}
#[test]
fn test_memory_usage_profiling() {
if std::env::var("VOIRS_RUN_SLOW_TESTS").is_err() {
println!("Skipping slow test. Set VOIRS_RUN_SLOW_TESTS=1 to run.");
return;
}
let temp_dir = TempDir::new().unwrap();
let output_file = temp_dir.path().join("memory_test.wav");
if is_tool_available("ps") || is_tool_available("tasklist") {
test_memory_with_external_tools(&output_file);
} else {
let mut cmd = Command::cargo_bin("voirs").unwrap();
cmd.arg("synthesize")
.arg("This is a memory usage test with a longer text to see how the application handles memory allocation and deallocation during synthesis.")
.arg("--output")
.arg(output_file.to_str().unwrap())
.timeout(Duration::from_secs(120)) .assert()
.success();
assert!(output_file.exists());
}
}
fn test_memory_with_external_tools(output_file: &std::path::Path) {
let start = Instant::now();
let mut cmd = Command::cargo_bin("voirs").unwrap();
cmd.arg("synthesize")
.arg("Memory usage test with extended text content.")
.arg("--output")
.arg(output_file.to_str().unwrap())
.timeout(Duration::from_secs(120)) .assert()
.success();
let duration = start.elapsed();
println!("Synthesis completed in: {duration:?}");
}
#[test]
fn test_batch_processing_efficiency() {
let temp_dir = TempDir::new().unwrap();
let input_file = temp_dir.path().join("batch_input.txt");
let output_dir = temp_dir.path().join("batch_output");
let test_sentences = [
"First test sentence for batch processing.",
"Second sentence with different content.",
"Third sentence to measure efficiency.",
"Fourth sentence for performance testing.",
"Fifth and final sentence for the batch.",
];
std::fs::write(&input_file, test_sentences.join("\n")).unwrap();
std::fs::create_dir_all(&output_dir).unwrap();
let start = Instant::now();
let mut cmd = Command::cargo_bin("voirs").unwrap();
cmd.arg("batch")
.arg(input_file.to_str().unwrap())
.arg("--output-dir")
.arg(output_dir.to_str().unwrap())
.arg("--workers")
.arg("2")
.timeout(Duration::from_secs(600))
.assert()
.success();
let batch_time = start.elapsed();
let output_files: Vec<_> = std::fs::read_dir(&output_dir)
.unwrap()
.filter_map(|entry| entry.ok())
.collect();
assert!(
output_files.len() >= test_sentences.len(),
"Not all batch files were created"
);
println!(
"Batch processing time for {} sentences: {:?}",
test_sentences.len(),
batch_time
);
let time_per_sentence = batch_time.as_millis() / test_sentences.len() as u128;
assert!(
time_per_sentence < 300000, "Batch processing too slow: {time_per_sentence}ms per sentence"
);
}
#[test]
fn test_interactive_mode_responsiveness() {
let start = Instant::now();
let mut cmd = Command::cargo_bin("voirs").unwrap();
cmd.arg("interactive")
.arg("--no-audio")
.arg("--debug")
.write_stdin("quit\n")
.timeout(Duration::from_secs(120))
.assert()
.success();
let interactive_startup = start.elapsed();
assert!(
interactive_startup < Duration::from_secs(90),
"Interactive mode startup too slow: {interactive_startup:?}"
);
println!("Interactive mode startup time: {interactive_startup:?}");
}
#[test]
fn test_large_text_synthesis_performance() {
if std::env::var("VOIRS_RUN_SLOW_TESTS").is_err() {
println!("Skipping slow test. Set VOIRS_RUN_SLOW_TESTS=1 to run.");
return;
}
let temp_dir = TempDir::new().unwrap();
let output_file = temp_dir.path().join("large_text.wav");
let large_text = "This is a performance test with a moderately large text input. ".repeat(25);
let start = Instant::now();
let mut cmd = Command::cargo_bin("voirs").unwrap();
cmd.arg("synthesize")
.arg(&large_text)
.arg("--output")
.arg(output_file.to_str().unwrap())
.timeout(Duration::from_secs(90))
.assert()
.success();
let synthesis_time = start.elapsed();
assert!(output_file.exists());
println!("Large text synthesis time: {synthesis_time:?}");
assert!(
synthesis_time < Duration::from_secs(60),
"Large text synthesis too slow: {synthesis_time:?}"
);
}
#[test]
fn test_concurrent_operations_performance() {
if std::env::var("VOIRS_RUN_SLOW_TESTS").is_err() {
println!("Skipping slow test. Set VOIRS_RUN_SLOW_TESTS=1 to run.");
return;
}
let temp_dir = TempDir::new().unwrap();
let start = Instant::now();
let handles: Vec<_> = (0..3)
.map(|i| {
let output_file = temp_dir.path().join(format!("concurrent_{i}.wav"));
let output_path = output_file.to_string_lossy().to_string();
std::thread::spawn(move || {
let mut cmd = Command::cargo_bin("voirs").unwrap();
cmd.arg("synthesize")
.arg(format!("Concurrent synthesis test number {i}"))
.arg("--output")
.arg(&output_path)
.timeout(Duration::from_secs(120)) .assert()
.success();
})
})
.collect();
for handle in handles {
handle.join().unwrap();
}
let concurrent_time = start.elapsed();
println!("Concurrent operations time: {concurrent_time:?}");
for i in 0..3 {
let output_file = temp_dir.path().join(format!("concurrent_{i}.wav"));
assert!(output_file.exists(), "Concurrent file {i} not created");
}
}
#[test]
fn test_help_command_performance() {
let commands = vec![
"--help",
"synthesize --help",
"list-voices --help",
"config --help",
];
for cmd_args in commands {
let start = Instant::now();
let mut cmd = Command::cargo_bin("voirs").unwrap();
let args: Vec<&str> = cmd_args.split_whitespace().collect();
for arg in args {
cmd.arg(arg);
}
cmd.assert().success();
let help_time = start.elapsed();
assert!(
help_time < Duration::from_millis(500),
"Help command '{cmd_args}' too slow: {help_time:?}"
);
println!("Help command '{cmd_args}' time: {help_time:?}");
}
}
#[test]
fn test_configuration_loading_performance() {
let temp_dir = TempDir::new().unwrap();
let config_file = temp_dir.path().join("perf_test_config.toml");
let mut cmd = Command::cargo_bin("voirs").unwrap();
cmd.arg("config")
.arg("--init")
.arg("--path")
.arg(config_file.to_str().unwrap())
.assert()
.success();
let start = Instant::now();
let mut cmd = Command::cargo_bin("voirs").unwrap();
cmd.arg("--config")
.arg(config_file.to_str().unwrap())
.arg("config")
.arg("--show")
.assert()
.success();
let config_load_time = start.elapsed();
assert!(
config_load_time < Duration::from_millis(200),
"Configuration loading too slow: {config_load_time:?}"
);
println!("Configuration loading time: {config_load_time:?}");
}
#[test]
fn test_voice_listing_performance() {
let start = Instant::now();
let mut cmd = Command::cargo_bin("voirs").unwrap();
cmd.arg("list-voices")
.timeout(Duration::from_secs(60))
.assert()
.success();
let voice_list_time = start.elapsed();
assert!(
voice_list_time < Duration::from_secs(30),
"Voice listing too slow: {voice_list_time:?}"
);
println!("Voice listing time: {voice_list_time:?}");
}
fn is_tool_available(tool: &str) -> bool {
StdCommand::new(tool)
.arg("--version")
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
.map(|status| status.success())
.unwrap_or(false)
}
#[test]
fn test_resource_cleanup() {
let temp_dir = TempDir::new().unwrap();
let output_file = temp_dir.path().join("cleanup_test.wav");
let mut cmd = Command::cargo_bin("voirs").unwrap();
cmd.arg("synthesize")
.arg("Resource cleanup test")
.arg(output_file.to_str().unwrap())
.timeout(Duration::from_secs(120))
.assert()
.success();
assert!(output_file.exists());
}