diff options
| author | Yuval Adam <_@yuv.al> | 2025-06-24 10:52:30 +0200 |
|---|---|---|
| committer | Yuval Adam <_@yuv.al> | 2025-06-24 10:52:30 +0200 |
| commit | 657cabfb515ac0e18dc0c2e2ca4fc03e2e24cf65 (patch) | |
| tree | 8cd9997fd4bd35ec2e556216e29013c236af0180 /tests/integration_tests.rs | |
| parent | d151456417ff4a531101f94c90207263e3319406 (diff) | |
Claude round of fixes starting to look good
Diffstat (limited to 'tests/integration_tests.rs')
| -rw-r--r-- | tests/integration_tests.rs | 129 |
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(()) +} |
