use crate::codecs::g711::*;
use crate::types::{AudioCodec, AudioCodecExt, CodecConfig, CodecType, SampleRate};
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_alaw_decoding_basic() {
let test_values = vec![0u8, 0x55, 0xD5, 0x2A, 0xFF];
for &encoded in &test_values {
let decoded = alaw_expand(encoded);
assert!(decoded >= i16::MIN && decoded <= i16::MAX);
}
}
#[test]
fn test_mulaw_decoding_basic() {
let test_values = vec![0u8, 0x7F, 0xFF, 0x80, 0x00];
for &encoded in &test_values {
let decoded = ulaw_expand(encoded);
assert!(decoded >= i16::MIN && decoded <= i16::MAX);
}
}
#[test]
fn test_decoding_all_values() {
for encoded in 0u8..=255u8 {
let alaw_decoded = alaw_expand(encoded);
let mulaw_decoded = ulaw_expand(encoded);
assert!(alaw_decoded >= i16::MIN && alaw_decoded <= i16::MAX);
assert!(mulaw_decoded >= i16::MIN && mulaw_decoded <= i16::MAX);
}
}
#[test]
fn test_decoding_boundary_encoded_values() {
let boundary_encoded = vec![
0u8, 127u8, 128u8, 255u8, ];
for &encoded in &boundary_encoded {
let alaw_decoded = alaw_expand(encoded);
let mulaw_decoded = ulaw_expand(encoded);
println!(
"Encoded 0x{:02x}: A-law -> {}, μ-law -> {}",
encoded, alaw_decoded, mulaw_decoded
);
assert!(alaw_decoded >= i16::MIN && alaw_decoded <= i16::MAX);
assert!(mulaw_decoded >= i16::MIN && mulaw_decoded <= i16::MAX);
}
}
#[test]
fn test_codec_decoding_operations() {
let config_mu = CodecConfig::new(CodecType::G711Pcmu)
.with_sample_rate(SampleRate::Rate8000)
.with_channels(1);
let mut codec_mu = G711Codec::new_pcmu(config_mu).unwrap();
let config_a = CodecConfig::new(CodecType::G711Pcma)
.with_sample_rate(SampleRate::Rate8000)
.with_channels(1);
let mut codec_a = G711Codec::new_pcma(config_a).unwrap();
let encoded = vec![100u8; 160];
let decoded_mu = codec_mu.decode(&encoded).unwrap();
let decoded_a = codec_a.decode(&encoded).unwrap();
assert_eq!(decoded_mu.len(), 160);
assert_eq!(decoded_a.len(), 160);
assert_ne!(decoded_mu, decoded_a);
}
#[test]
fn test_codec_decode_to_buffer_is_bit_exact_for_all_values() {
let config_mu = CodecConfig::new(CodecType::G711Pcmu)
.with_sample_rate(SampleRate::Rate8000)
.with_channels(1);
let mut codec_mu = G711Codec::new_pcmu(config_mu).unwrap();
let config_a = CodecConfig::new(CodecType::G711Pcma)
.with_sample_rate(SampleRate::Rate8000)
.with_channels(1);
let mut codec_a = G711Codec::new_pcma(config_a).unwrap();
let encoded = (0u8..=255u8).collect::<Vec<_>>();
let mut decoded = vec![0i16; encoded.len()];
let decoded_len = codec_mu
.decode_to_buffer(&encoded, &mut decoded)
.expect("decode μ-law");
assert_eq!(decoded_len, encoded.len());
for (&encoded, &decoded) in encoded.iter().zip(decoded.iter()) {
assert_eq!(
decoded,
ulaw_expand(encoded),
"μ-law mismatch for {encoded}"
);
}
let decoded_len = codec_a
.decode_to_buffer(&encoded, &mut decoded)
.expect("decode A-law");
assert_eq!(decoded_len, encoded.len());
for (&encoded, &decoded) in encoded.iter().zip(decoded.iter()) {
assert_eq!(
decoded,
alaw_expand(encoded),
"A-law mismatch for {encoded}"
);
}
}
#[test]
fn test_decoding_repeatability() {
let encoded = vec![123u8; 160];
let decoded1: Vec<i16> = encoded.iter().map(|&e| alaw_expand(e)).collect();
let decoded2: Vec<i16> = encoded.iter().map(|&e| alaw_expand(e)).collect();
let decoded3: Vec<i16> = encoded.iter().map(|&e| alaw_expand(e)).collect();
assert_eq!(decoded1, decoded2);
assert_eq!(decoded2, decoded3);
}
#[test]
fn test_decoding_reconstruction_quality() {
let mut encoded = Vec::new();
for i in 0..160 {
encoded.push((i % 16 + 128) as u8);
}
let decoded: Vec<i16> = encoded.iter().map(|&e| alaw_expand(e)).collect();
for i in 0..15 {
let diff = (decoded[i] - decoded[i + 16]).abs();
assert!(
diff < 5000,
"Similar encoded values should decode similarly"
);
}
}
#[test]
fn test_alaw_vs_mulaw_decoding_differences() {
let encoded = vec![123u8; 160];
let decoded_a: Vec<i16> = encoded.iter().map(|&e| alaw_expand(e)).collect();
let decoded_mu: Vec<i16> = encoded.iter().map(|&e| ulaw_expand(e)).collect();
assert_ne!(decoded_a, decoded_mu);
assert_eq!(decoded_a.len(), decoded_mu.len());
}
#[test]
fn test_decoding_performance_characteristics() {
let encoded = vec![100u8; 160];
let start = std::time::Instant::now();
for _ in 0..1000 {
let _decoded: Vec<i16> = encoded.iter().map(|&e| alaw_expand(e)).collect();
}
let duration = start.elapsed();
assert!(
duration.as_millis() < 100,
"Decoding should be fast: {:?}",
duration
);
}
#[test]
fn test_decoding_round_trip_basic() {
let original_samples = vec![1000i16; 160];
let alaw_encoded: Vec<u8> = original_samples.iter().map(|&s| alaw_compress(s)).collect();
let alaw_decoded: Vec<i16> = alaw_encoded.iter().map(|&e| alaw_expand(e)).collect();
assert_eq!(alaw_decoded.len(), original_samples.len());
for (&original, &decoded) in original_samples.iter().zip(alaw_decoded.iter()) {
let error = (original - decoded).abs();
assert!(error < 2000, "A-law round-trip error too large: {}", error);
}
let mulaw_encoded: Vec<u8> = original_samples.iter().map(|&s| ulaw_compress(s)).collect();
let mulaw_decoded: Vec<i16> = mulaw_encoded.iter().map(|&e| ulaw_expand(e)).collect();
for (&original, &decoded) in original_samples.iter().zip(mulaw_decoded.iter()) {
let error = (original - decoded).abs();
assert!(error < 2000, "μ-law round-trip error too large: {}", error);
}
}
#[test]
fn test_decoding_sign_preservation() {
let positive_samples = vec![5000i16; 80];
let negative_samples = vec![-5000i16; 80];
let pos_alaw_encoded: Vec<u8> =
positive_samples.iter().map(|&s| alaw_compress(s)).collect();
let pos_alaw_decoded: Vec<i16> = pos_alaw_encoded.iter().map(|&e| alaw_expand(e)).collect();
let pos_mulaw_encoded: Vec<u8> =
positive_samples.iter().map(|&s| ulaw_compress(s)).collect();
let pos_mulaw_decoded: Vec<i16> =
pos_mulaw_encoded.iter().map(|&e| ulaw_expand(e)).collect();
let neg_alaw_encoded: Vec<u8> =
negative_samples.iter().map(|&s| alaw_compress(s)).collect();
let neg_alaw_decoded: Vec<i16> = neg_alaw_encoded.iter().map(|&e| alaw_expand(e)).collect();
let neg_mulaw_encoded: Vec<u8> =
negative_samples.iter().map(|&s| ulaw_compress(s)).collect();
let neg_mulaw_decoded: Vec<i16> =
neg_mulaw_encoded.iter().map(|&e| ulaw_expand(e)).collect();
for &sample in &pos_alaw_decoded {
assert!(sample > 0, "Positive A-law values should stay positive");
}
for &sample in &pos_mulaw_decoded {
assert!(sample > 0, "Positive μ-law values should stay positive");
}
for &sample in &neg_alaw_decoded {
assert!(sample < 0, "Negative A-law values should stay negative");
}
for &sample in &neg_mulaw_decoded {
assert!(sample < 0, "Negative μ-law values should stay negative");
}
}
}