use ush::audio::AudioConfig;
use ush::modulation::{FskModulator, FskDemodulator, ModulationConfig};
use ush::protocol::{ProtocolEncoder, ProtocolDecoder, Message};
use ush::{UshError, UshResult};
#[tokio::test]
async fn test_full_pipeline() -> UshResult<()> {
let modulation_config = ModulationConfig::default();
let modulator = FskModulator::new(modulation_config.clone());
let demodulator = FskDemodulator::new(modulation_config);
let mut encoder = ProtocolEncoder::new();
let mut decoder = ProtocolDecoder::new();
let original_text = "Hello, ultrasonic world! 🌊";
let frame_data = encoder.encode_text(original_text)?;
let audio_samples = modulator.encode_bytes(&frame_data);
let decoded_frame_data = demodulator.decode_bytes(&audio_samples)?;
let messages = decoder.feed_data(&decoded_frame_data);
assert!(!messages.is_empty(), "No messages decoded");
let decoded_text = messages[0].get_text()?;
assert_eq!(original_text, decoded_text);
println!("✓ Full pipeline test passed: \"{}\"", decoded_text);
Ok(())
}
#[tokio::test]
async fn test_multiple_messages() -> UshResult<()> {
let modulation_config = ModulationConfig::default();
let modulator = FskModulator::new(modulation_config.clone());
let demodulator = FskDemodulator::new(modulation_config);
let mut encoder = ProtocolEncoder::new();
let mut decoder = ProtocolDecoder::new();
let messages = vec![
"First message",
"Second message with numbers: 12345",
"Third message with symbols: @#$%^&*()",
];
let mut decoded_messages = Vec::new();
for message in &messages {
let frame_data = encoder.encode_text(message)?;
let samples = modulator.encode_bytes(&frame_data);
let decoded_bytes = demodulator.decode_bytes(&samples)?;
let messages_decoded = decoder.feed_data(&decoded_bytes);
decoded_messages.extend(messages_decoded);
}
assert_eq!(messages.len(), decoded_messages.len(), "Message count mismatch");
for (i, decoded_msg) in decoded_messages.iter().enumerate() {
let decoded_text = decoded_msg.get_text()?;
assert_eq!(messages[i], decoded_text, "Message {} mismatch", i);
println!("✓ Message {}: \"{}\"", i + 1, decoded_text);
}
Ok(())
}
#[tokio::test]
async fn test_noisy_environment() -> UshResult<()> {
let modulation_config = ModulationConfig::default();
let modulator = FskModulator::new(modulation_config.clone());
let demodulator = FskDemodulator::new(modulation_config);
let mut encoder = ProtocolEncoder::new();
let mut decoder = ProtocolDecoder::new();
let test_message = "Noise test message";
let frame_data = encoder.encode_text(test_message)?;
let mut audio_samples = modulator.encode_bytes(&frame_data);
use std::f32::consts::PI;
let noise_level = 0.05; for (i, sample) in audio_samples.iter_mut().enumerate() {
let noise = ((i as f32 * 0.1).sin() + (i as f32 * 0.17).cos()) * noise_level;
*sample += noise;
}
let decoded_bytes = demodulator.decode_bytes(&audio_samples);
match decoded_bytes {
Ok(bytes) => {
let messages = decoder.feed_data(&bytes);
if !messages.is_empty() {
let decoded_text = messages[0].get_text()?;
if decoded_text == test_message {
println!("✓ Successfully decoded despite noise: \"{}\"", decoded_text);
} else {
println!("âš Decoded with errors: \"{}\" (expected: \"{}\")", decoded_text, test_message);
}
} else {
println!("âš No messages decoded from noisy signal");
}
}
Err(e) => {
println!("âš Failed to decode noisy signal: {}", e);
}
}
Ok(())
}
#[tokio::test]
async fn test_different_message_lengths() -> UshResult<()> {
let modulation_config = ModulationConfig::default();
let modulator = FskModulator::new(modulation_config.clone());
let demodulator = FskDemodulator::new(modulation_config);
let mut encoder = ProtocolEncoder::new();
let mut decoder = ProtocolDecoder::new();
let test_messages = vec![
"A", "Hello", "This is a medium-length message for testing purposes.", "This is a very long message that contains many words and should test the system's ability to handle longer text transmissions. It includes various characters like numbers 123456789 and symbols !@#$%^&*()_+-=[]{}|;:,.<>? to ensure comprehensive testing coverage.", ];
for (i, message) in test_messages.iter().enumerate() {
let frame_data = encoder.encode_text(message)?;
let samples = modulator.encode_bytes(&frame_data);
let decoded_bytes = demodulator.decode_bytes(&samples)?;
let messages = decoder.feed_data(&decoded_bytes);
assert!(!messages.is_empty(), "No messages decoded for test {}", i);
let decoded_text = messages[0].get_text()?;
assert_eq!(*message, decoded_text, "Message {} length test failed", i);
println!("✓ Length test {}: {} chars -> {} samples",
i + 1, message.len(), samples.len());
}
Ok(())
}
#[tokio::test]
async fn test_frequency_separation() -> UshResult<()> {
let configs = vec![
(17000.0, 19000.0), (18500.0, 19500.0), (19000.0, 21000.0), ];
let test_message = "Frequency test";
for (i, (freq_0, freq_1)) in configs.iter().enumerate() {
let modulation_config = ModulationConfig {
sample_rate: 44100,
freq_0: *freq_0,
freq_1: *freq_1,
symbol_duration: 0.01,
ramp_duration: 0.002,
};
let modulator = FskModulator::new(modulation_config.clone());
let demodulator = FskDemodulator::new(modulation_config);
let mut encoder = ProtocolEncoder::new();
let mut decoder = ProtocolDecoder::new();
let frame_data = encoder.encode_text(test_message)?;
let samples = modulator.encode_bytes(&frame_data);
let decoded_bytes = demodulator.decode_bytes(&samples)?;
let messages = decoder.feed_data(&decoded_bytes);
if !messages.is_empty() {
let decoded_text = messages[0].get_text()?;
if decoded_text == test_message {
println!("✓ Frequency config {}: {:.0}Hz/{:.0}Hz - SUCCESS",
i + 1, freq_0, freq_1);
} else {
println!("âš Frequency config {}: {:.0}Hz/{:.0}Hz - DECODE ERROR",
i + 1, freq_0, freq_1);
}
} else {
println!("âš Frequency config {}: {:.0}Hz/{:.0}Hz - NO MESSAGES",
i + 1, freq_0, freq_1);
}
}
Ok(())
}
#[tokio::test]
async fn test_protocol_corruption_recovery() -> UshResult<()> {
let mut encoder = ProtocolEncoder::new();
let mut decoder = ProtocolDecoder::new();
let test_message = "Corruption test message";
let mut frame_data = encoder.encode_text(test_message)?;
if frame_data.len() > 10 {
let mid_idx = frame_data.len() / 2;
frame_data[mid_idx] = 0xFF;
frame_data[mid_idx + 1] = 0x00;
}
let messages = decoder.feed_data(&frame_data);
if messages.is_empty() {
println!("✓ Correctly rejected corrupted message");
} else {
for message in messages {
if let Ok(is_valid) = message.verify_checksum() {
if !is_valid {
println!("✓ Checksum validation caught corruption");
} else {
println!("âš Corrupted message passed checksum validation");
}
}
}
}
Ok(())
}
#[tokio::test]
async fn test_performance_benchmarks() -> UshResult<()> {
use std::time::Instant;
let modulation_config = ModulationConfig::default();
let modulator = FskModulator::new(modulation_config.clone());
let demodulator = FskDemodulator::new(modulation_config);
let mut encoder = ProtocolEncoder::new();
let test_message = "Performance test message for benchmarking encoding and decoding speed.";
let start = Instant::now();
let frame_data = encoder.encode_text(test_message)?;
let protocol_encode_time = start.elapsed();
let start = Instant::now();
let samples = modulator.encode_bytes(&frame_data);
let modulation_encode_time = start.elapsed();
let start = Instant::now();
let decoded_bytes = demodulator.decode_bytes(&samples)?;
let modulation_decode_time = start.elapsed();
let mut decoder = ProtocolDecoder::new();
let start = Instant::now();
let messages = decoder.feed_data(&decoded_bytes);
let protocol_decode_time = start.elapsed();
assert!(!messages.is_empty());
let decoded_text = messages[0].get_text()?;
assert_eq!(test_message, decoded_text);
println!("Performance benchmarks:");
println!(" Protocol encode: {:?}", protocol_encode_time);
println!(" Modulation encode: {:?}", modulation_encode_time);
println!(" Modulation decode: {:?}", modulation_decode_time);
println!(" Protocol decode: {:?}", protocol_decode_time);
println!(" Total roundtrip: {:?}",
protocol_encode_time + modulation_encode_time +
modulation_decode_time + protocol_decode_time);
println!(" Audio duration: {:.2}s", samples.len() as f32 / 44100.0);
println!(" Data rate: {:.1} chars/s",
test_message.len() as f32 / (samples.len() as f32 / 44100.0));
Ok(())
}
#[tokio::test]
async fn test_unicode_support() -> UshResult<()> {
let modulation_config = ModulationConfig::default();
let modulator = FskModulator::new(modulation_config.clone());
let demodulator = FskDemodulator::new(modulation_config);
let mut encoder = ProtocolEncoder::new();
let mut decoder = ProtocolDecoder::new();
let unicode_messages = vec![
"Hello 世界", "Привет мир", "Ù…Ø±ØØ¨Ø§ بالعالم", "🌊🔊📡💻🚀", "Café naïve résumé", ];
for (i, message) in unicode_messages.iter().enumerate() {
let frame_data = encoder.encode_text(message)?;
let samples = modulator.encode_bytes(&frame_data);
let decoded_bytes = demodulator.decode_bytes(&samples)?;
let messages = decoder.feed_data(&decoded_bytes);
assert!(!messages.is_empty(), "No messages decoded for Unicode test {}", i);
let decoded_text = messages[0].get_text()?;
assert_eq!(*message, decoded_text, "Unicode test {} failed", i);
println!("✓ Unicode test {}: \"{}\"", i + 1, decoded_text);
}
Ok(())
}