1use ff_format::{ErrorSeverity, MediaError};
4use std::path::PathBuf;
5use thiserror::Error;
6
7#[derive(Error, Debug)]
9pub enum ProbeError {
10 #[error("File not found: {path}")]
12 FileNotFound {
13 path: PathBuf,
15 },
16
17 #[error("Cannot open file: {path} - {reason}")]
19 CannotOpen {
20 path: PathBuf,
22 reason: String,
24 },
25
26 #[error("Invalid media file: {path} - {reason}")]
28 InvalidMedia {
29 path: PathBuf,
31 reason: String,
33 },
34
35 #[error("No streams found in file: {path}")]
37 NoStreams {
38 path: PathBuf,
40 },
41
42 #[error("IO error: {0}")]
44 Io(#[from] std::io::Error),
45
46 #[error("ffmpeg error: {message} (code={code})")]
48 Ffmpeg {
49 code: i32,
51 message: String,
53 },
54}
55
56impl MediaError for ProbeError {
57 fn severity(&self) -> ErrorSeverity {
58 match self {
59 Self::Ffmpeg { .. } => ErrorSeverity::Other,
60 Self::FileNotFound { .. }
61 | Self::CannotOpen { .. }
62 | Self::InvalidMedia { .. }
63 | Self::NoStreams { .. }
64 | Self::Io(_) => ErrorSeverity::Fatal,
65 }
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72
73 #[test]
74 fn test_file_not_found_error() {
75 let err = ProbeError::FileNotFound {
76 path: PathBuf::from("/path/to/missing.mp4"),
77 };
78 let msg = err.to_string();
79 assert!(msg.contains("File not found"));
80 assert!(msg.contains("missing.mp4"));
81 }
82
83 #[test]
84 fn test_cannot_open_error() {
85 let err = ProbeError::CannotOpen {
86 path: PathBuf::from("/path/to/file.mp4"),
87 reason: "permission denied".to_string(),
88 };
89 let msg = err.to_string();
90 assert!(msg.contains("Cannot open file"));
91 assert!(msg.contains("permission denied"));
92 }
93
94 #[test]
95 fn test_invalid_media_error() {
96 let err = ProbeError::InvalidMedia {
97 path: PathBuf::from("/path/to/bad.mp4"),
98 reason: "corrupted header".to_string(),
99 };
100 let msg = err.to_string();
101 assert!(msg.contains("Invalid media file"));
102 assert!(msg.contains("corrupted header"));
103 }
104
105 #[test]
106 fn test_no_streams_error() {
107 let err = ProbeError::NoStreams {
108 path: PathBuf::from("/path/to/empty.mp4"),
109 };
110 let msg = err.to_string();
111 assert!(msg.contains("No streams found"));
112 }
113
114 #[test]
115 fn ffmpeg_should_display_code_and_message() {
116 let err = ProbeError::Ffmpeg {
117 code: -2,
118 message: "codec not found".to_string(),
119 };
120 let msg = err.to_string();
121 assert!(msg.contains("ffmpeg error"));
122 assert!(msg.contains("codec not found"));
123 assert!(msg.contains("code=-2"));
124 }
125
126 #[test]
127 fn test_io_error_conversion() {
128 let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
129 let err: ProbeError = io_err.into();
130 assert!(matches!(err, ProbeError::Io(_)));
131 }
132
133 #[test]
134 fn probe_io_should_be_fatal() {
135 let e: ProbeError = std::io::Error::other("x").into();
136 assert!(e.is_fatal() && !e.is_recoverable());
137 }
138
139 #[test]
140 fn probe_ffmpeg_should_be_other() {
141 let e = ProbeError::Ffmpeg {
142 code: -22,
143 message: "x".into(),
144 };
145 assert!(!e.is_fatal() && !e.is_recoverable());
146 }
147}