use desperado::{IqFormat, IqSource};
use std::fs;
use tempfile::NamedTempFile;
fn temp_iq(data: &[u8]) -> (NamedTempFile, String) {
let f = NamedTempFile::new().expect("Failed to create temp file");
let path = f.path().to_str().unwrap().to_string();
fs::write(&path, data).expect("Failed to write test file");
(f, path)
}
#[test]
fn test_iqformat_bytes_per_sample_cu8() {
let format = IqFormat::Cu8;
let samples = vec![127, 127, 128, 128, 255, 255]; let (_tmp, path) = temp_iq(&samples);
let mut iq_source = IqSource::from_file(&path, 162_000_000, 96_000, 3, format)
.expect("Failed to create IQ source");
let chunk = iq_source.next().expect("No data").expect("Read error");
assert_eq!(chunk.len(), 3, "Should read exactly 3 samples from 6 bytes");
}
#[test]
fn test_iqformat_bytes_per_sample_cs8() {
let format = IqFormat::Cs8;
let samples = vec![0, 0, 127, 127]; let (_tmp, path) = temp_iq(&samples);
let mut iq_source = IqSource::from_file(&path, 162_000_000, 96_000, 2, format)
.expect("Failed to create IQ source");
let chunk = iq_source.next().expect("No data").expect("Read error");
assert_eq!(chunk.len(), 2, "Should read exactly 2 samples from 4 bytes");
}
#[test]
fn test_iqformat_bytes_per_sample_cs16() {
let format = IqFormat::Cs16;
let samples = vec![0, 0, 0, 0, 0xFF, 0x7F, 0xFF, 0x7F]; let (_tmp, path) = temp_iq(&samples);
let mut iq_source = IqSource::from_file(&path, 162_000_000, 96_000, 2, format)
.expect("Failed to create IQ source");
let chunk = iq_source.next().expect("No data").expect("Read error");
assert_eq!(chunk.len(), 2, "Should read exactly 2 samples from 8 bytes");
}
#[test]
fn test_iqformat_bytes_per_sample_cf32() {
let format = IqFormat::Cf32;
let mut samples = Vec::new();
samples.extend_from_slice(&0.5f32.to_le_bytes());
samples.extend_from_slice(&(-0.5f32).to_le_bytes());
samples.extend_from_slice(&1.0f32.to_le_bytes());
samples.extend_from_slice(&(-1.0f32).to_le_bytes());
let (_tmp, path) = temp_iq(&samples);
let mut iq_source = IqSource::from_file(&path, 162_000_000, 96_000, 2, format)
.expect("Failed to create IQ source");
let chunk = iq_source.next().expect("No data").expect("Read error");
assert_eq!(
chunk.len(),
2,
"Should read exactly 2 samples from 16 bytes"
);
}
#[test]
fn test_expanduser_with_tilde() {
let home = dirs::home_dir().expect("Could not get home directory");
let unique_name = format!(".desperado_test_{}.iq", std::process::id());
let test_file = home.join(&unique_name);
let samples = vec![127, 127, 128, 128]; fs::write(&test_file, &samples).expect("Failed to write test file");
let tilde_path = format!("~/{}", unique_name);
let result = IqSource::from_file(&tilde_path, 162_000_000, 96_000, 2, IqFormat::Cu8);
assert!(
result.is_ok(),
"Failed to open file with tilde path: {:?}",
result.err()
);
let mut iq_source = result.unwrap();
let chunk = iq_source.next().expect("No data").expect("Read error");
assert_eq!(chunk.len(), 2, "Should read 2 samples from tilde path");
fs::remove_file(&test_file).ok();
}
#[test]
fn test_expanduser_without_tilde() {
let samples = vec![127, 127];
let (_tmp, path) = temp_iq(&samples);
let result = IqSource::from_file(&path, 162_000_000, 96_000, 1, IqFormat::Cu8);
assert!(result.is_ok(), "Failed to open file with regular path");
}
#[test]
fn test_expanduser_nonexistent_file() {
let result = IqSource::from_file(
"~/nonexistent_file_12345.iq",
162_000_000,
96_000,
100,
IqFormat::Cu8,
);
assert!(result.is_err(), "Should return error for nonexistent file");
let err = result.err().unwrap();
assert!(matches!(err, desperado::Error::Io(_)));
}
#[test]
fn test_iqread_integration_multiple_chunks() {
let mut samples = Vec::new();
for chunk_idx in 0..3 {
for sample_idx in 0..10 {
let value = (chunk_idx * 10 + sample_idx) as u8;
samples.push(value);
samples.push(value);
}
}
let (_tmp, path) = temp_iq(&samples);
let mut iq_source = IqSource::from_file(
&path,
162_000_000,
96_000,
10, IqFormat::Cu8,
)
.expect("Failed to create IQ source");
for chunk_idx in 0..3 {
let chunk = iq_source
.next()
.unwrap_or_else(|| panic!("Chunk {} missing", chunk_idx))
.expect("Read error");
assert_eq!(
chunk.len(),
10,
"Chunk {} should have 10 samples",
chunk_idx
);
}
assert!(
iq_source.next().is_none(),
"Should reach EOF after 3 chunks"
);
}
#[test]
fn test_iqread_integration_partial_chunk() {
let mut samples = Vec::new();
for i in 0..25 {
samples.push(i as u8);
samples.push(i as u8);
}
let (_tmp, path) = temp_iq(&samples);
let mut iq_source = IqSource::from_file(&path, 162_000_000, 96_000, 10, IqFormat::Cu8)
.expect("Failed to create IQ source");
for i in 0..2 {
let chunk = iq_source
.next()
.expect("Missing chunk")
.expect("Read error");
assert_eq!(chunk.len(), 10, "Chunk {} should be full", i);
}
let result = iq_source.next();
assert!(result.is_none(), "Partial chunk should result in EOF");
}
#[test]
fn test_iqread_from_stdin_creation() {
let result = IqSource::from_stdin(162_000_000, 96_000, 100, IqFormat::Cu8);
assert!(result.is_ok(), "Failed to create stdin IQ source");
}
#[test]
fn test_iqread_from_tcp_invalid_address() {
let result = IqSource::from_tcp(
"invalid.nonexistent.host.test",
12345,
162_000_000,
96_000,
100,
IqFormat::Cu8,
);
assert!(
result.is_err(),
"Should return error for invalid TCP address"
);
}