use thiserror::Error;
#[derive(Debug, Clone, PartialEq, Eq, Error)]
pub enum OpusError {
#[error("opus encode error: {0}")]
Encode(String),
#[error("opus decode error: {0}")]
Decode(String),
#[error("invalid sample rate: {0} Hz")]
InvalidSampleRate(u32),
#[error("invalid channel count: {0}")]
InvalidChannelCount(u16),
#[error("unsupported channel count for opus: {0} (only 1 or 2 allowed)")]
UnsupportedChannels(u16),
#[error("buffer too small: needed {needed} samples, have {have}")]
BufferTooSmall {
needed: usize,
have: usize,
},
#[error("layout mismatch: {0}")]
LayoutMismatch(String),
#[error("opus worker thread error: {0}")]
WorkerThread(String),
}
pub type Result<T> = core::result::Result<T, OpusError>;
#[cfg(test)]
mod tests {
use super::{OpusError, Result};
#[test]
fn encode_display_includes_message() {
let msg = OpusError::Encode("bad arg".into()).to_string();
assert_eq!(msg, "opus encode error: bad arg");
}
#[test]
fn decode_display_includes_message() {
let msg = OpusError::Decode("corrupt packet".into()).to_string();
assert_eq!(msg, "opus decode error: corrupt packet");
}
#[test]
fn invalid_sample_rate_display_includes_value() {
let msg = OpusError::InvalidSampleRate(0).to_string();
assert_eq!(msg, "invalid sample rate: 0 Hz");
}
#[test]
fn invalid_channel_count_display_includes_value() {
let msg = OpusError::InvalidChannelCount(0).to_string();
assert_eq!(msg, "invalid channel count: 0");
}
#[test]
fn unsupported_channels_display_includes_value() {
let msg = OpusError::UnsupportedChannels(6).to_string();
assert_eq!(
msg,
"unsupported channel count for opus: 6 (only 1 or 2 allowed)",
);
}
#[test]
fn buffer_too_small_display_includes_both_counts() {
let msg = OpusError::BufferTooSmall {
needed: 960,
have: 128,
}
.to_string();
assert_eq!(msg, "buffer too small: needed 960 samples, have 128",);
}
#[test]
fn layout_mismatch_display_includes_reason() {
let msg = OpusError::LayoutMismatch("length 5 is not a multiple of 2 channels".into())
.to_string();
assert_eq!(
msg,
"layout mismatch: length 5 is not a multiple of 2 channels"
);
}
#[test]
fn worker_thread_display_includes_reason() {
let msg = OpusError::WorkerThread("spawn failed: EAGAIN".into()).to_string();
assert_eq!(msg, "opus worker thread error: spawn failed: EAGAIN");
}
#[test]
fn result_alias_ok_carries_value() {
let ok: Result<u32> = Ok(42);
assert_eq!(ok.map(|v| v + 1), Ok(43));
}
#[test]
fn result_alias_err_carries_opus_error() {
let err: Result<u32> = Err(OpusError::InvalidSampleRate(0));
assert_eq!(err.err(), Some(OpusError::InvalidSampleRate(0)));
}
#[test]
fn clone_and_partial_eq_hold_across_variants() {
let a = OpusError::BufferTooSmall { needed: 2, have: 1 };
assert_eq!(a.clone(), a);
assert_ne!(
OpusError::InvalidSampleRate(1),
OpusError::InvalidChannelCount(1),
);
assert_ne!(
OpusError::InvalidChannelCount(2),
OpusError::UnsupportedChannels(2),
);
assert_eq!(OpusError::Encode("x".into()), OpusError::Encode("x".into()),);
}
}