summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorYuval Adam <_@yuv.al>2025-06-24 10:52:30 +0200
committerYuval Adam <_@yuv.al>2025-06-24 10:52:30 +0200
commit657cabfb515ac0e18dc0c2e2ca4fc03e2e24cf65 (patch)
tree8cd9997fd4bd35ec2e556216e29013c236af0180 /tests
parentd151456417ff4a531101f94c90207263e3319406 (diff)
Claude round of fixes starting to look good
Diffstat (limited to 'tests')
-rw-r--r--tests/integration_tests.rs129
1 files changed, 92 insertions, 37 deletions
diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs
index cc1cfb3..666fdb0 100644
--- a/tests/integration_tests.rs
+++ b/tests/integration_tests.rs
@@ -112,34 +112,37 @@ const TEST_CASES: &[TestCase] = &[
#[test]
fn run_comprehensive_test_suite() -> Result<()> {
println!("Running comprehensive Morse decoder test suite...");
-
+
// Create test directory
fs::create_dir_all("test_outputs")?;
-
+
let mut results = Vec::new();
let mut total_tests = 0;
let mut passed_tests = 0;
-
+
// Create a detailed report file
let mut report_file = fs::File::create("test_outputs/test_report.txt")?;
writeln!(report_file, "Morse Decoder Test Report")?;
writeln!(report_file, "=========================")?;
writeln!(report_file)?;
-
+
for test_case in TEST_CASES {
total_tests += 1;
println!("Running test: {}", test_case.name);
-
+
let result = run_single_test(test_case);
let passed = result.is_ok();
if passed {
passed_tests += 1;
}
-
+
// Log detailed results
match &result {
Ok(test_result) => {
- println!(" ✓ PASSED - Accuracy: {:.1}%", test_result.accuracy * 100.0);
+ println!(
+ " ✓ PASSED - Accuracy: {:.1}%",
+ test_result.accuracy * 100.0
+ );
writeln!(
report_file,
"TEST: {} - PASSED\n Expected: '{}'\n Decoded: '{}'\n Accuracy: {:.1}%\n WPM: {}, Freq: {}Hz, SR: {}Hz\n",
@@ -166,10 +169,10 @@ fn run_comprehensive_test_suite() -> Result<()> {
)?;
}
}
-
+
results.push((test_case, result));
}
-
+
// Summary
let pass_rate = (passed_tests as f32 / total_tests as f32) * 100.0;
println!("\nTest Summary:");
@@ -177,27 +180,35 @@ fn run_comprehensive_test_suite() -> Result<()> {
println!(" Passed: {}", passed_tests);
println!(" Failed: {}", total_tests - passed_tests);
println!(" Pass rate: {:.1}%", pass_rate);
-
+
writeln!(report_file, "\nSUMMARY:")?;
writeln!(report_file, " Total tests: {}", total_tests)?;
writeln!(report_file, " Passed: {}", passed_tests)?;
writeln!(report_file, " Failed: {}", total_tests - passed_tests)?;
writeln!(report_file, " Pass rate: {:.1}%", pass_rate)?;
-
+
// Analyze failure patterns
let failed_tests: Vec<_> = results.iter().filter(|(_, r)| r.is_err()).collect();
if !failed_tests.is_empty() {
writeln!(report_file, "\nFAILURE ANALYSIS:")?;
for (test_case, error) in failed_tests {
- writeln!(report_file, " {} - {}", test_case.name, error.as_ref().unwrap_err())?;
+ writeln!(
+ report_file,
+ " {} - {}",
+ test_case.name,
+ error.as_ref().unwrap_err()
+ )?;
}
}
-
+
+ // Clean up test directory
+ std::fs::remove_dir_all("test_outputs").ok();
+
// If overall pass rate is too low, fail the test
if pass_rate < 50.0 {
- panic!("Test suite failed with pass rate of {:.1}%. Check test_outputs/test_report.txt for details.", pass_rate);
+ panic!("Test suite failed with pass rate of {:.1}%.", pass_rate);
}
-
+
Ok(())
}
@@ -208,22 +219,25 @@ struct TestResult {
}
fn run_single_test(test_case: &TestCase) -> Result<TestResult> {
- // Generate the test WAV file
+ // Generate the test WAV file in a temporary location
let generator = MorseGenerator::new(test_case.sample_rate, test_case.frequency, test_case.wpm);
let wav_path = format!("test_outputs/{}.wav", test_case.name);
generator.generate_wav_file(test_case.text, &wav_path)?;
-
+
// Decode the WAV file
let decoded_text = decode_wav_file(&wav_path)?;
-
+
// Calculate accuracy
let accuracy = calculate_accuracy(test_case.text, &decoded_text);
-
+
let result = TestResult {
decoded_text,
accuracy,
};
-
+
+ // Clean up the temporary WAV file
+ std::fs::remove_file(&wav_path).ok();
+
// Check if accuracy meets threshold
if accuracy >= test_case.expected_accuracy {
Ok(result)
@@ -239,17 +253,17 @@ fn run_single_test(test_case: &TestCase) -> Result<TestResult> {
fn decode_wav_file(path: &str) -> Result<String> {
let mut reader = WavReader::open(path)?;
let spec = reader.spec();
-
+
if spec.sample_format != SampleFormat::Int && spec.sample_format != SampleFormat::Float {
return Err(anyhow::anyhow!(
"Unsupported sample format: {:?}",
spec.sample_format
));
}
-
+
// Create decoder
let mut decoder = MorseDecoder::new(spec.sample_rate, TARGET_SAMPLE_RATE)?;
-
+
// Read and process audio
let samples_f32: Vec<f32> = if spec.sample_format == SampleFormat::Int {
reader
@@ -259,7 +273,7 @@ fn decode_wav_file(path: &str) -> Result<String> {
} else {
reader.samples::<f32>().map(|s| s.unwrap()).collect()
};
-
+
// Convert to mono if necessary
let mono_samples: Vec<f32> = if spec.channels > 1 {
samples_f32
@@ -269,12 +283,12 @@ fn decode_wav_file(path: &str) -> Result<String> {
} else {
samples_f32
};
-
+
// Process in chunks
for chunk in mono_samples.chunks(CHUNK_SIZE) {
decoder.process(chunk)?;
}
-
+
// Finalize and get result
decoder.finalize()
}
@@ -283,39 +297,80 @@ fn calculate_accuracy(expected: &str, actual: &str) -> f32 {
if expected.is_empty() {
return if actual.is_empty() { 1.0 } else { 0.0 };
}
-
+
let expected_clean = expected.to_uppercase().replace(" ", "");
let actual_clean = actual.to_uppercase().replace(" ", "").replace("?", "");
-
+
if expected_clean.is_empty() {
return if actual_clean.is_empty() { 1.0 } else { 0.0 };
}
-
+
// Simple character-by-character comparison
let expected_chars: Vec<char> = expected_clean.chars().collect();
let actual_chars: Vec<char> = actual_clean.chars().collect();
-
+
let max_len = expected_chars.len().max(actual_chars.len());
let mut matches = 0;
-
+
for i in 0..max_len {
let expected_char = expected_chars.get(i);
let actual_char = actual_chars.get(i);
-
+
if expected_char == actual_char {
matches += 1;
}
}
-
+
matches as f32 / max_len as f32
}
#[test]
fn test_accuracy_calculation() {
assert_eq!(calculate_accuracy("SOS", "SOS"), 1.0);
- assert_eq!(calculate_accuracy("SOS", "SO"), 2.0/3.0);
- assert_eq!(calculate_accuracy("SOS", "XOS"), 2.0/3.0);
- assert_eq!(calculate_accuracy("HELLO", "WORLD"), 1.0/5.0); // Only L matches
+ assert_eq!(calculate_accuracy("SOS", "SO"), 2.0 / 3.0);
+ assert_eq!(calculate_accuracy("SOS", "XOS"), 2.0 / 3.0);
+ assert_eq!(calculate_accuracy("HELLO", "WORLD"), 1.0 / 5.0); // Only L matches
assert_eq!(calculate_accuracy("", ""), 1.0);
assert_eq!(calculate_accuracy("A", ""), 0.0);
-} \ No newline at end of file
+}
+
+#[test]
+fn baseline_decoder_test() -> Result<()> {
+ // Clean baseline test to establish current decoder status
+ println!("=== DECODER BASELINE TEST ===");
+
+ std::env::set_var("RUST_LOG", "info");
+ env_logger::try_init().ok();
+
+ let generator = MorseGenerator::new(12000, 600.0, 20.0);
+
+ let test_cases = [
+ ("EEEE", "4 dots"),
+ ("TTTT", "4 dashes"),
+ ("ETET", "dot-dash-dot-dash"),
+ ];
+
+ for (i, (test_text, description)) in test_cases.iter().enumerate() {
+ println!("\n--- Test {}: {} ({}) ---", i + 1, test_text, description);
+
+ let temp_file = format!("baseline_test_{}.wav", i);
+ generator.generate_wav_file(test_text, &temp_file)?;
+ let decoded = decode_wav_file(&temp_file)?;
+ println!(
+ "Expected: {} | Decoded: {} | Success: {}",
+ test_text,
+ decoded,
+ decoded == *test_text
+ );
+
+ // Clean up immediately
+ std::fs::remove_file(&temp_file).ok();
+ }
+
+ // Summary
+ println!("\n=== BASELINE SUMMARY ===");
+ println!("This establishes our current decoder capabilities");
+ println!("Focus on getting these 3 simple patterns working first");
+
+ Ok(())
+}